diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..890383d Binary files /dev/null and b/.DS_Store differ diff --git a/Avatar/.DS_Store b/Avatar/.DS_Store new file mode 100644 index 0000000..d56fe24 Binary files /dev/null and b/Avatar/.DS_Store differ diff --git a/Avatar/App/.DS_Store b/Avatar/App/.DS_Store new file mode 100644 index 0000000..de78fb0 Binary files /dev/null and b/Avatar/App/.DS_Store differ diff --git a/Avatar/App/Avatar.entitlements b/Avatar/App/Avatar.entitlements new file mode 100644 index 0000000..7db7d55 --- /dev/null +++ b/Avatar/App/Avatar.entitlements @@ -0,0 +1,44 @@ + + + + + platform-application + + com.apple.private.security.no-container + + com.apple.private.skip-library-validation + + get-task-allow + + com.apple.security.iokit-user-client-class + + AGXCommandQueue + AGXDevice + AGXDeviceUserClient + AGXSharedUserClient + AppleCredentialManagerUserClient + AppleJPEGDriverUserClient + ApplePPMUserClient + AppleSPUHIDDeviceUserClient + AppleSPUHIDDriverUserClient + IOAccelContext + IOAccelContext2 + IOAccelDevice + IOAccelDevice2 + IOAccelSharedUserClient + IOAccelSharedUserClient2 + IOAccelSubmitter2 + IOHIDEventServiceFastPathUserClient + IOHIDLibUserClient + IOMobileFramebufferUserClient + IOReportUserClient + IOSurfaceAcceleratorClient + IOSurfaceRootUserClient + RootDomainUserClient + + com.apple.security.exception.files.home-relative-path.read-write + + /var/mobile/Library/Preferences/com.TitanD3v.AvatarApp.plist + + + \ No newline at end of file diff --git a/Avatar/App/Avatar.xcodeproj/project.pbxproj b/Avatar/App/Avatar.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d523be1 --- /dev/null +++ b/Avatar/App/Avatar.xcodeproj/project.pbxproj @@ -0,0 +1,862 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 8415462527348E690085E3DD /* Emoji.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8415462427348E690085E3DD /* Emoji.plist */; }; + 8415463C27348EC80085E3DD /* TDEmojiPickerCellHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415462727348EC80085E3DD /* TDEmojiPickerCellHeaderView.m */; }; + 8415463D27348EC80085E3DD /* TDAvatarIdentityToolsCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415462927348EC80085E3DD /* TDAvatarIdentityToolsCell.m */; }; + 8415463E27348EC80085E3DD /* TDAvatarIdentityEmojiCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415462A27348EC80085E3DD /* TDAvatarIdentityEmojiCell.m */; }; + 8415463F27348EC80085E3DD /* TDAvatarIdentityStickerCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415462E27348EC80085E3DD /* TDAvatarIdentityStickerCell.m */; }; + 8415464027348EC80085E3DD /* TDEmojiPickerCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415463027348EC80085E3DD /* TDEmojiPickerCell.m */; }; + 8415464127348EC80085E3DD /* TDAvatarIdentityPickerDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415463227348EC80085E3DD /* TDAvatarIdentityPickerDataSource.m */; }; + 8415464227348EC80085E3DD /* TDEmojiPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415463327348EC80085E3DD /* TDEmojiPickerViewController.m */; }; + 8415464327348EC80085E3DD /* TDAvatarIdentityPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415463527348EC80085E3DD /* TDAvatarIdentityPickerViewController.m */; }; + 8415464427348EC80085E3DD /* TDAvatarIdentityCellHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415463627348EC80085E3DD /* TDAvatarIdentityCellHeaderView.m */; }; + 8415464527348EC80085E3DD /* TDHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415463927348EC80085E3DD /* TDHeaderView.m */; }; + 8415464827349C740085E3DD /* RecordingActionMenuCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415464627349C740085E3DD /* RecordingActionMenuCell.m */; }; + 8415464B27354EB30085E3DD /* RecordingButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415464A27354EB30085E3DD /* RecordingButton.m */; }; + 8415464F273566D10085E3DD /* LibraryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415464E273566D10085E3DD /* LibraryViewController.m */; }; + 84154652273568F80085E3DD /* LibraryCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 84154650273568F80085E3DD /* LibraryCell.m */; }; + 8415465527356B830085E3DD /* LibraryDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415465427356B830085E3DD /* LibraryDataSource.m */; }; + 841546942735C6EE0085E3DD /* Stickers.plist in Resources */ = {isa = PBXBuildFile; fileRef = 841546932735C6EE0085E3DD /* Stickers.plist */; }; + 841546A02735C7260085E3DD /* StickerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 841546962735C7260085E3DD /* StickerView.m */; }; + 841546A12735C7260085E3DD /* TDStickerPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 841546982735C7260085E3DD /* TDStickerPickerViewController.m */; }; + 841546A22735C7260085E3DD /* TDStickerPickerCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 841546992735C7260085E3DD /* TDStickerPickerCell.m */; }; + 841546A32735C7260085E3DD /* SingleHandGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415469A2735C7260085E3DD /* SingleHandGestureRecognizer.m */; }; + 841546A42735C7260085E3DD /* TDStickerPickerCellHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8415469C2735C7260085E3DD /* TDStickerPickerCellHeaderView.m */; }; + 841546A72735D5FB0085E3DD /* ARConfiguration+Overrides.m in Sources */ = {isa = PBXBuildFile; fileRef = 841546A62735D5FB0085E3DD /* ARConfiguration+Overrides.m */; }; + 841546AC2735F3600085E3DD /* AvimojiViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 841546AB2735F3600085E3DD /* AvimojiViewController.m */; }; + 841546AF2735F39C0085E3DD /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 841546AE2735F39C0085E3DD /* SettingsViewController.m */; }; + 841546B32736C80D0085E3DD /* TutorialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546B22736C80D0085E3DD /* TutorialViewController.swift */; }; + 841546C12736C8A80085E3DD /* WhatsNewContentTitleFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546B62736C8A80085E3DD /* WhatsNewContentTitleFormat.swift */; }; + 841546C22736C8A80085E3DD /* WhatsNewContentCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546B72736C8A80085E3DD /* WhatsNewContentCard.swift */; }; + 841546C32736C8A80085E3DD /* WhatsNewContentTitle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546B82736C8A80085E3DD /* WhatsNewContentTitle.swift */; }; + 841546C42736C8A80085E3DD /* WhatsNewContentBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546B92736C8A80085E3DD /* WhatsNewContentBase.swift */; }; + 841546C52736C8A80085E3DD /* WhatsNewContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546BA2736C8A80085E3DD /* WhatsNewContent.swift */; }; + 841546C62736C8A80085E3DD /* WhatsNewContentButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546BB2736C8A80085E3DD /* WhatsNewContentButton.swift */; }; + 841546C72736C8A80085E3DD /* WhatsNewPrimaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546BD2736C8A80085E3DD /* WhatsNewPrimaryButton.swift */; }; + 841546C82736C8A80085E3DD /* WhatsNewCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546BE2736C8A80085E3DD /* WhatsNewCardView.swift */; }; + 841546C92736C8A80085E3DD /* WhatsNewCardsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546BF2736C8A80085E3DD /* WhatsNewCardsListView.swift */; }; + 841546CA2736C8A80085E3DD /* WhatsNewBaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546C02736C8A80085E3DD /* WhatsNewBaseView.swift */; }; + 841546CC2736C8CB0085E3DD /* Constraints.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841546CB2736C8CB0085E3DD /* Constraints.swift */; }; + 841548BD2737FBBF0085E3DD /* RecordingOnboardingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 841548BC2737FBBF0085E3DD /* RecordingOnboardingViewController.m */; }; + 843D1F73273946F700C2E0B7 /* DefaultMemojiViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 843D1F72273946F700C2E0B7 /* DefaultMemojiViewController.m */; }; + 843D1F772739683C00C2E0B7 /* SocialCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 843D1F752739683C00C2E0B7 /* SocialCell.m */; }; + 843D1F7A27396DC200C2E0B7 /* SwitchCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 843D1F7927396DC200C2E0B7 /* SwitchCell.m */; }; + 846BED012733456B00DC42D5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED002733456B00DC42D5 /* AppDelegate.m */; }; + 846BED042733456B00DC42D5 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED032733456B00DC42D5 /* SceneDelegate.m */; }; + 846BED072733456B00DC42D5 /* HomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED062733456B00DC42D5 /* HomeViewController.m */; }; + 846BED0C2733456E00DC42D5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 846BED0B2733456E00DC42D5 /* Assets.xcassets */; }; + 846BED0F2733456E00DC42D5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 846BED0D2733456E00DC42D5 /* LaunchScreen.storyboard */; }; + 846BED122733456E00DC42D5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED112733456E00DC42D5 /* main.m */; }; + 846BED1B2733484000DC42D5 /* ConstraintExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED1A2733484000DC42D5 /* ConstraintExtension.m */; }; + 846BED2927334B2000DC42D5 /* AvatarManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED2827334B2000DC42D5 /* AvatarManager.m */; }; + 846BED3727334DFD00DC42D5 /* AnimojiPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED3627334DFD00DC42D5 /* AnimojiPickerViewController.m */; }; + 846BED3A27334E1D00DC42D5 /* AnimojiPickerCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED3927334E1C00DC42D5 /* AnimojiPickerCell.m */; }; + 846BED3D273352B500DC42D5 /* RecordingStudioViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED3C273352B500DC42D5 /* RecordingStudioViewController.m */; }; + 846BED40273352EA00DC42D5 /* AvatarMotionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED3F273352EA00DC42D5 /* AvatarMotionView.m */; }; + 846BED452733F86900DC42D5 /* AvatarKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 846BED442733F86900DC42D5 /* AvatarKit.framework */; }; + 846BED482733FA8C00DC42D5 /* RecordingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED472733FA8C00DC42D5 /* RecordingManager.m */; }; + 846BED542734235B00DC42D5 /* AvatarVideoPreviewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED532734235B00DC42D5 /* AvatarVideoPreviewViewController.m */; }; + 846BED6027346AAF00DC42D5 /* Theme.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 846BED5F27346AAF00DC42D5 /* Theme.xcassets */; }; + 846BED6627346E3D00DC42D5 /* UtilitiesView.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED6227346E3D00DC42D5 /* UtilitiesView.m */; }; + 846BED6727346E3D00DC42D5 /* GridView.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED6327346E3D00DC42D5 /* GridView.m */; }; + 846BED6A273475CB00DC42D5 /* HomeNavigationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED69273475CB00DC42D5 /* HomeNavigationViewController.m */; }; + 846BED6D27348B7000DC42D5 /* SettingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 846BED6C27348B7000DC42D5 /* SettingManager.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 8415462427348E690085E3DD /* Emoji.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Emoji.plist; sourceTree = ""; }; + 8415462727348EC80085E3DD /* TDEmojiPickerCellHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDEmojiPickerCellHeaderView.m; sourceTree = ""; }; + 8415462827348EC80085E3DD /* TDAvatarIdentityPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAvatarIdentityPickerViewController.h; sourceTree = ""; }; + 8415462927348EC80085E3DD /* TDAvatarIdentityToolsCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAvatarIdentityToolsCell.m; sourceTree = ""; }; + 8415462A27348EC80085E3DD /* TDAvatarIdentityEmojiCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAvatarIdentityEmojiCell.m; sourceTree = ""; }; + 8415462B27348EC80085E3DD /* TDAvatarIdentityEmojiCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAvatarIdentityEmojiCell.h; sourceTree = ""; }; + 8415462C27348EC80085E3DD /* TDAvatarIdentityToolsCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAvatarIdentityToolsCell.h; sourceTree = ""; }; + 8415462D27348EC80085E3DD /* TDAvatarIdentityStickerCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAvatarIdentityStickerCell.h; sourceTree = ""; }; + 8415462E27348EC80085E3DD /* TDAvatarIdentityStickerCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAvatarIdentityStickerCell.m; sourceTree = ""; }; + 8415462F27348EC80085E3DD /* TDEmojiPickerCellHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDEmojiPickerCellHeaderView.h; sourceTree = ""; }; + 8415463027348EC80085E3DD /* TDEmojiPickerCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDEmojiPickerCell.m; sourceTree = ""; }; + 8415463127348EC80085E3DD /* TDEmojiPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDEmojiPickerViewController.h; sourceTree = ""; }; + 8415463227348EC80085E3DD /* TDAvatarIdentityPickerDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAvatarIdentityPickerDataSource.m; sourceTree = ""; }; + 8415463327348EC80085E3DD /* TDEmojiPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDEmojiPickerViewController.m; sourceTree = ""; }; + 8415463427348EC80085E3DD /* TDEmojiPickerCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDEmojiPickerCell.h; sourceTree = ""; }; + 8415463527348EC80085E3DD /* TDAvatarIdentityPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAvatarIdentityPickerViewController.m; sourceTree = ""; }; + 8415463627348EC80085E3DD /* TDAvatarIdentityCellHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAvatarIdentityCellHeaderView.m; sourceTree = ""; }; + 8415463727348EC80085E3DD /* TDAvatarIdentityPickerDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAvatarIdentityPickerDataSource.h; sourceTree = ""; }; + 8415463827348EC80085E3DD /* TDHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDHeaderView.h; sourceTree = ""; }; + 8415463927348EC80085E3DD /* TDHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDHeaderView.m; sourceTree = ""; }; + 8415463A27348EC80085E3DD /* PrivateBlurEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrivateBlurEffect.h; sourceTree = ""; }; + 8415463B27348EC80085E3DD /* TDAvatarIdentityCellHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAvatarIdentityCellHeaderView.h; sourceTree = ""; }; + 8415464627349C740085E3DD /* RecordingActionMenuCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecordingActionMenuCell.m; sourceTree = ""; }; + 8415464727349C740085E3DD /* RecordingActionMenuCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordingActionMenuCell.h; sourceTree = ""; }; + 8415464927354EB30085E3DD /* RecordingButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordingButton.h; sourceTree = ""; }; + 8415464A27354EB30085E3DD /* RecordingButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecordingButton.m; sourceTree = ""; }; + 8415464D273566D10085E3DD /* LibraryViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LibraryViewController.h; sourceTree = ""; }; + 8415464E273566D10085E3DD /* LibraryViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LibraryViewController.m; sourceTree = ""; }; + 84154650273568F80085E3DD /* LibraryCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LibraryCell.m; sourceTree = ""; }; + 84154651273568F80085E3DD /* LibraryCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LibraryCell.h; sourceTree = ""; }; + 8415465327356B830085E3DD /* LibraryDataSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LibraryDataSource.h; sourceTree = ""; }; + 8415465427356B830085E3DD /* LibraryDataSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LibraryDataSource.m; sourceTree = ""; }; + 841546932735C6EE0085E3DD /* Stickers.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Stickers.plist; sourceTree = ""; }; + 841546962735C7260085E3DD /* StickerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StickerView.m; sourceTree = ""; }; + 841546972735C7260085E3DD /* TDStickerPickerCellHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDStickerPickerCellHeaderView.h; sourceTree = ""; }; + 841546982735C7260085E3DD /* TDStickerPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDStickerPickerViewController.m; sourceTree = ""; }; + 841546992735C7260085E3DD /* TDStickerPickerCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDStickerPickerCell.m; sourceTree = ""; }; + 8415469A2735C7260085E3DD /* SingleHandGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SingleHandGestureRecognizer.m; sourceTree = ""; }; + 8415469B2735C7260085E3DD /* StickerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StickerView.h; sourceTree = ""; }; + 8415469C2735C7260085E3DD /* TDStickerPickerCellHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDStickerPickerCellHeaderView.m; sourceTree = ""; }; + 8415469D2735C7260085E3DD /* TDStickerPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDStickerPickerViewController.h; sourceTree = ""; }; + 8415469E2735C7260085E3DD /* TDStickerPickerCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDStickerPickerCell.h; sourceTree = ""; }; + 8415469F2735C7260085E3DD /* SingleHandGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SingleHandGestureRecognizer.h; sourceTree = ""; }; + 841546A52735D5FB0085E3DD /* ARConfiguration+Overrides.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARConfiguration+Overrides.h"; sourceTree = ""; }; + 841546A62735D5FB0085E3DD /* ARConfiguration+Overrides.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ARConfiguration+Overrides.m"; sourceTree = ""; }; + 841546AA2735F3600085E3DD /* AvimojiViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvimojiViewController.h; sourceTree = ""; }; + 841546AB2735F3600085E3DD /* AvimojiViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AvimojiViewController.m; sourceTree = ""; }; + 841546AD2735F39C0085E3DD /* SettingsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = ""; }; + 841546AE2735F39C0085E3DD /* SettingsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = ""; }; + 841546B12736C80D0085E3DD /* Avatar-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Avatar-Bridging-Header.h"; sourceTree = ""; }; + 841546B22736C80D0085E3DD /* TutorialViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TutorialViewController.swift; sourceTree = ""; }; + 841546B62736C8A80085E3DD /* WhatsNewContentTitleFormat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewContentTitleFormat.swift; sourceTree = ""; }; + 841546B72736C8A80085E3DD /* WhatsNewContentCard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewContentCard.swift; sourceTree = ""; }; + 841546B82736C8A80085E3DD /* WhatsNewContentTitle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewContentTitle.swift; sourceTree = ""; }; + 841546B92736C8A80085E3DD /* WhatsNewContentBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewContentBase.swift; sourceTree = ""; }; + 841546BA2736C8A80085E3DD /* WhatsNewContent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewContent.swift; sourceTree = ""; }; + 841546BB2736C8A80085E3DD /* WhatsNewContentButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewContentButton.swift; sourceTree = ""; }; + 841546BD2736C8A80085E3DD /* WhatsNewPrimaryButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewPrimaryButton.swift; sourceTree = ""; }; + 841546BE2736C8A80085E3DD /* WhatsNewCardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewCardView.swift; sourceTree = ""; }; + 841546BF2736C8A80085E3DD /* WhatsNewCardsListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewCardsListView.swift; sourceTree = ""; }; + 841546C02736C8A80085E3DD /* WhatsNewBaseView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewBaseView.swift; sourceTree = ""; }; + 841546CB2736C8CB0085E3DD /* Constraints.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constraints.swift; sourceTree = ""; }; + 841548BB2737FBBF0085E3DD /* RecordingOnboardingViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RecordingOnboardingViewController.h; sourceTree = ""; }; + 841548BC2737FBBF0085E3DD /* RecordingOnboardingViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RecordingOnboardingViewController.m; sourceTree = ""; }; + 843D1F71273946F700C2E0B7 /* DefaultMemojiViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DefaultMemojiViewController.h; sourceTree = ""; }; + 843D1F72273946F700C2E0B7 /* DefaultMemojiViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DefaultMemojiViewController.m; sourceTree = ""; }; + 843D1F752739683C00C2E0B7 /* SocialCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SocialCell.m; sourceTree = ""; }; + 843D1F762739683C00C2E0B7 /* SocialCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SocialCell.h; sourceTree = ""; }; + 843D1F7827396DC200C2E0B7 /* SwitchCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwitchCell.h; sourceTree = ""; }; + 843D1F7927396DC200C2E0B7 /* SwitchCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SwitchCell.m; sourceTree = ""; }; + 846BECFC2733456B00DC42D5 /* Avatar.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Avatar.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 846BECFF2733456B00DC42D5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 846BED002733456B00DC42D5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 846BED022733456B00DC42D5 /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; }; + 846BED032733456B00DC42D5 /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; }; + 846BED052733456B00DC42D5 /* HomeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HomeViewController.h; sourceTree = ""; }; + 846BED062733456B00DC42D5 /* HomeViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HomeViewController.m; sourceTree = ""; }; + 846BED0B2733456E00DC42D5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 846BED0E2733456E00DC42D5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 846BED102733456E00DC42D5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 846BED112733456E00DC42D5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 846BED192733484000DC42D5 /* ConstraintExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstraintExtension.h; sourceTree = ""; }; + 846BED1A2733484000DC42D5 /* ConstraintExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConstraintExtension.m; sourceTree = ""; }; + 846BED2727334B2000DC42D5 /* AvatarManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvatarManager.h; sourceTree = ""; }; + 846BED2827334B2000DC42D5 /* AvatarManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvatarManager.m; sourceTree = ""; }; + 846BED2B27334C6700DC42D5 /* AVTAnimoji.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVTAnimoji.h; sourceTree = ""; }; + 846BED2C27334C6700DC42D5 /* AVTAvatar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVTAvatar.h; sourceTree = ""; }; + 846BED2E27334C6700DC42D5 /* AVTView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVTView.h; sourceTree = ""; }; + 846BED2F27334C6700DC42D5 /* AVTRecordView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVTRecordView.h; sourceTree = ""; }; + 846BED3127334C6700DC42D5 /* AVTAvatarStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVTAvatarStore.h; sourceTree = ""; }; + 846BED3227334C6700DC42D5 /* AVTAvatarLibraryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVTAvatarLibraryViewController.h; sourceTree = ""; }; + 846BED3527334DFD00DC42D5 /* AnimojiPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimojiPickerViewController.h; sourceTree = ""; }; + 846BED3627334DFD00DC42D5 /* AnimojiPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnimojiPickerViewController.m; sourceTree = ""; }; + 846BED3827334E1C00DC42D5 /* AnimojiPickerCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimojiPickerCell.h; sourceTree = ""; }; + 846BED3927334E1C00DC42D5 /* AnimojiPickerCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnimojiPickerCell.m; sourceTree = ""; }; + 846BED3B273352B500DC42D5 /* RecordingStudioViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordingStudioViewController.h; sourceTree = ""; }; + 846BED3C273352B500DC42D5 /* RecordingStudioViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecordingStudioViewController.m; sourceTree = ""; }; + 846BED3E273352EA00DC42D5 /* AvatarMotionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvatarMotionView.h; sourceTree = ""; }; + 846BED3F273352EA00DC42D5 /* AvatarMotionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvatarMotionView.m; sourceTree = ""; }; + 846BED442733F86900DC42D5 /* AvatarKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = AvatarKit.framework; sourceTree = ""; }; + 846BED462733FA8C00DC42D5 /* RecordingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordingManager.h; sourceTree = ""; }; + 846BED472733FA8C00DC42D5 /* RecordingManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecordingManager.m; sourceTree = ""; }; + 846BED522734235B00DC42D5 /* AvatarVideoPreviewViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvatarVideoPreviewViewController.h; sourceTree = ""; }; + 846BED532734235B00DC42D5 /* AvatarVideoPreviewViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AvatarVideoPreviewViewController.m; sourceTree = ""; }; + 846BED5F27346AAF00DC42D5 /* Theme.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Theme.xcassets; sourceTree = ""; }; + 846BED6227346E3D00DC42D5 /* UtilitiesView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UtilitiesView.m; sourceTree = ""; }; + 846BED6327346E3D00DC42D5 /* GridView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GridView.m; sourceTree = ""; }; + 846BED6427346E3D00DC42D5 /* GridView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GridView.h; sourceTree = ""; }; + 846BED6527346E3D00DC42D5 /* UtilitiesView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UtilitiesView.h; sourceTree = ""; }; + 846BED68273475CB00DC42D5 /* HomeNavigationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HomeNavigationViewController.h; sourceTree = ""; }; + 846BED69273475CB00DC42D5 /* HomeNavigationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeNavigationViewController.m; sourceTree = ""; }; + 846BED6B27348B7000DC42D5 /* SettingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingManager.h; sourceTree = ""; }; + 846BED6C27348B7000DC42D5 /* SettingManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingManager.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 846BECF92733456B00DC42D5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 846BED452733F86900DC42D5 /* AvatarKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8415462627348E900085E3DD /* AvatarPicker */ = { + isa = PBXGroup; + children = ( + 8415463A27348EC80085E3DD /* PrivateBlurEffect.h */, + 8415463B27348EC80085E3DD /* TDAvatarIdentityCellHeaderView.h */, + 8415463627348EC80085E3DD /* TDAvatarIdentityCellHeaderView.m */, + 8415462B27348EC80085E3DD /* TDAvatarIdentityEmojiCell.h */, + 8415462A27348EC80085E3DD /* TDAvatarIdentityEmojiCell.m */, + 8415463727348EC80085E3DD /* TDAvatarIdentityPickerDataSource.h */, + 8415463227348EC80085E3DD /* TDAvatarIdentityPickerDataSource.m */, + 8415462827348EC80085E3DD /* TDAvatarIdentityPickerViewController.h */, + 8415463527348EC80085E3DD /* TDAvatarIdentityPickerViewController.m */, + 8415462D27348EC80085E3DD /* TDAvatarIdentityStickerCell.h */, + 8415462E27348EC80085E3DD /* TDAvatarIdentityStickerCell.m */, + 8415462C27348EC80085E3DD /* TDAvatarIdentityToolsCell.h */, + 8415462927348EC80085E3DD /* TDAvatarIdentityToolsCell.m */, + 8415463427348EC80085E3DD /* TDEmojiPickerCell.h */, + 8415463027348EC80085E3DD /* TDEmojiPickerCell.m */, + 8415462F27348EC80085E3DD /* TDEmojiPickerCellHeaderView.h */, + 8415462727348EC80085E3DD /* TDEmojiPickerCellHeaderView.m */, + 8415463127348EC80085E3DD /* TDEmojiPickerViewController.h */, + 8415463327348EC80085E3DD /* TDEmojiPickerViewController.m */, + 8415463827348EC80085E3DD /* TDHeaderView.h */, + 8415463927348EC80085E3DD /* TDHeaderView.m */, + ); + path = AvatarPicker; + sourceTree = ""; + }; + 8415464C273566AC0085E3DD /* Library */ = { + isa = PBXGroup; + children = ( + 8415464D273566D10085E3DD /* LibraryViewController.h */, + 8415464E273566D10085E3DD /* LibraryViewController.m */, + 8415465327356B830085E3DD /* LibraryDataSource.h */, + 8415465427356B830085E3DD /* LibraryDataSource.m */, + 84154651273568F80085E3DD /* LibraryCell.h */, + 84154650273568F80085E3DD /* LibraryCell.m */, + ); + path = Library; + sourceTree = ""; + }; + 841546952735C6F50085E3DD /* StickerPicker */ = { + isa = PBXGroup; + children = ( + 8415469F2735C7260085E3DD /* SingleHandGestureRecognizer.h */, + 8415469A2735C7260085E3DD /* SingleHandGestureRecognizer.m */, + 8415469B2735C7260085E3DD /* StickerView.h */, + 841546962735C7260085E3DD /* StickerView.m */, + 8415469E2735C7260085E3DD /* TDStickerPickerCell.h */, + 841546992735C7260085E3DD /* TDStickerPickerCell.m */, + 841546972735C7260085E3DD /* TDStickerPickerCellHeaderView.h */, + 8415469C2735C7260085E3DD /* TDStickerPickerCellHeaderView.m */, + 8415469D2735C7260085E3DD /* TDStickerPickerViewController.h */, + 841546982735C7260085E3DD /* TDStickerPickerViewController.m */, + ); + path = StickerPicker; + sourceTree = ""; + }; + 841546A82735F33B0085E3DD /* Settings */ = { + isa = PBXGroup; + children = ( + 841546AD2735F39C0085E3DD /* SettingsViewController.h */, + 841546AE2735F39C0085E3DD /* SettingsViewController.m */, + 843D1F762739683C00C2E0B7 /* SocialCell.h */, + 843D1F752739683C00C2E0B7 /* SocialCell.m */, + 843D1F7827396DC200C2E0B7 /* SwitchCell.h */, + 843D1F7927396DC200C2E0B7 /* SwitchCell.m */, + ); + path = Settings; + sourceTree = ""; + }; + 841546A92735F3460085E3DD /* Avimoji */ = { + isa = PBXGroup; + children = ( + 841546AA2735F3600085E3DD /* AvimojiViewController.h */, + 841546AB2735F3600085E3DD /* AvimojiViewController.m */, + ); + path = Avimoji; + sourceTree = ""; + }; + 841546B02736C7DE0085E3DD /* Swift */ = { + isa = PBXGroup; + children = ( + 841546B42736C8A80085E3DD /* What's New */, + 841546CB2736C8CB0085E3DD /* Constraints.swift */, + 841546B22736C80D0085E3DD /* TutorialViewController.swift */, + 841546B12736C80D0085E3DD /* Avatar-Bridging-Header.h */, + ); + path = Swift; + sourceTree = ""; + }; + 841546B42736C8A80085E3DD /* What's New */ = { + isa = PBXGroup; + children = ( + 841546B52736C8A80085E3DD /* Content */, + 841546BC2736C8A80085E3DD /* Views */, + ); + path = "What's New"; + sourceTree = ""; + }; + 841546B52736C8A80085E3DD /* Content */ = { + isa = PBXGroup; + children = ( + 841546B62736C8A80085E3DD /* WhatsNewContentTitleFormat.swift */, + 841546B72736C8A80085E3DD /* WhatsNewContentCard.swift */, + 841546B82736C8A80085E3DD /* WhatsNewContentTitle.swift */, + 841546B92736C8A80085E3DD /* WhatsNewContentBase.swift */, + 841546BA2736C8A80085E3DD /* WhatsNewContent.swift */, + 841546BB2736C8A80085E3DD /* WhatsNewContentButton.swift */, + ); + path = Content; + sourceTree = ""; + }; + 841546BC2736C8A80085E3DD /* Views */ = { + isa = PBXGroup; + children = ( + 841546BD2736C8A80085E3DD /* WhatsNewPrimaryButton.swift */, + 841546BE2736C8A80085E3DD /* WhatsNewCardView.swift */, + 841546BF2736C8A80085E3DD /* WhatsNewCardsListView.swift */, + 841546C02736C8A80085E3DD /* WhatsNewBaseView.swift */, + ); + path = Views; + sourceTree = ""; + }; + 843D1F742739475B00C2E0B7 /* Onboarding */ = { + isa = PBXGroup; + children = ( + 843D1F71273946F700C2E0B7 /* DefaultMemojiViewController.h */, + 843D1F72273946F700C2E0B7 /* DefaultMemojiViewController.m */, + 841548BB2737FBBF0085E3DD /* RecordingOnboardingViewController.h */, + 841548BC2737FBBF0085E3DD /* RecordingOnboardingViewController.m */, + ); + path = Onboarding; + sourceTree = ""; + }; + 846BECF32733456B00DC42D5 = { + isa = PBXGroup; + children = ( + 846BECFE2733456B00DC42D5 /* Avatar */, + 846BECFD2733456B00DC42D5 /* Products */, + 846BED1C273348B500DC42D5 /* Frameworks */, + ); + sourceTree = ""; + }; + 846BECFD2733456B00DC42D5 /* Products */ = { + isa = PBXGroup; + children = ( + 846BECFC2733456B00DC42D5 /* Avatar.app */, + ); + name = Products; + sourceTree = ""; + }; + 846BECFE2733456B00DC42D5 /* Avatar */ = { + isa = PBXGroup; + children = ( + 841546B02736C7DE0085E3DD /* Swift */, + 846BED2627334B0900DC42D5 /* Manager */, + 846BED2A27334C6700DC42D5 /* AvatarKit */, + 846BED5A273444F500DC42D5 /* Extensions */, + 846BED6127346D9800DC42D5 /* CustomClasses */, + 8415462627348E900085E3DD /* AvatarPicker */, + 841546952735C6F50085E3DD /* StickerPicker */, + 846BED182733459A00DC42D5 /* Core */, + 846BED59273444DB00DC42D5 /* Home */, + 846BED5D27345D6400DC42D5 /* Animoji */, + 846BED5C27345D5900DC42D5 /* Recording */, + 8415464C273566AC0085E3DD /* Library */, + 846BED5B27344A3000DC42D5 /* Preview */, + 841546A92735F3460085E3DD /* Avimoji */, + 841546A82735F33B0085E3DD /* Settings */, + 843D1F742739475B00C2E0B7 /* Onboarding */, + 846BED0B2733456E00DC42D5 /* Assets.xcassets */, + 846BED5F27346AAF00DC42D5 /* Theme.xcassets */, + 846BED0D2733456E00DC42D5 /* LaunchScreen.storyboard */, + 846BED102733456E00DC42D5 /* Info.plist */, + 846BED112733456E00DC42D5 /* main.m */, + ); + path = Avatar; + sourceTree = ""; + }; + 846BED182733459A00DC42D5 /* Core */ = { + isa = PBXGroup; + children = ( + 841546932735C6EE0085E3DD /* Stickers.plist */, + 8415462427348E690085E3DD /* Emoji.plist */, + 846BECFF2733456B00DC42D5 /* AppDelegate.h */, + 846BED002733456B00DC42D5 /* AppDelegate.m */, + 846BED022733456B00DC42D5 /* SceneDelegate.h */, + 846BED032733456B00DC42D5 /* SceneDelegate.m */, + ); + path = Core; + sourceTree = ""; + }; + 846BED1C273348B500DC42D5 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + 846BED2627334B0900DC42D5 /* Manager */ = { + isa = PBXGroup; + children = ( + 841546A52735D5FB0085E3DD /* ARConfiguration+Overrides.h */, + 841546A62735D5FB0085E3DD /* ARConfiguration+Overrides.m */, + 846BED462733FA8C00DC42D5 /* RecordingManager.h */, + 846BED472733FA8C00DC42D5 /* RecordingManager.m */, + 846BED2727334B2000DC42D5 /* AvatarManager.h */, + 846BED2827334B2000DC42D5 /* AvatarManager.m */, + 846BED6B27348B7000DC42D5 /* SettingManager.h */, + 846BED6C27348B7000DC42D5 /* SettingManager.m */, + ); + path = Manager; + sourceTree = ""; + }; + 846BED2A27334C6700DC42D5 /* AvatarKit */ = { + isa = PBXGroup; + children = ( + 846BED442733F86900DC42D5 /* AvatarKit.framework */, + 846BED3E273352EA00DC42D5 /* AvatarMotionView.h */, + 846BED3F273352EA00DC42D5 /* AvatarMotionView.m */, + 846BED2B27334C6700DC42D5 /* AVTAnimoji.h */, + 846BED2C27334C6700DC42D5 /* AVTAvatar.h */, + 846BED2E27334C6700DC42D5 /* AVTView.h */, + 846BED2F27334C6700DC42D5 /* AVTRecordView.h */, + 846BED3127334C6700DC42D5 /* AVTAvatarStore.h */, + 846BED3227334C6700DC42D5 /* AVTAvatarLibraryViewController.h */, + ); + path = AvatarKit; + sourceTree = ""; + }; + 846BED59273444DB00DC42D5 /* Home */ = { + isa = PBXGroup; + children = ( + 846BED052733456B00DC42D5 /* HomeViewController.h */, + 846BED062733456B00DC42D5 /* HomeViewController.m */, + ); + path = Home; + sourceTree = ""; + }; + 846BED5A273444F500DC42D5 /* Extensions */ = { + isa = PBXGroup; + children = ( + 846BED192733484000DC42D5 /* ConstraintExtension.h */, + 846BED1A2733484000DC42D5 /* ConstraintExtension.m */, + ); + path = Extensions; + sourceTree = ""; + }; + 846BED5B27344A3000DC42D5 /* Preview */ = { + isa = PBXGroup; + children = ( + 846BED522734235B00DC42D5 /* AvatarVideoPreviewViewController.h */, + 846BED532734235B00DC42D5 /* AvatarVideoPreviewViewController.m */, + ); + path = Preview; + sourceTree = ""; + }; + 846BED5C27345D5900DC42D5 /* Recording */ = { + isa = PBXGroup; + children = ( + 846BED3B273352B500DC42D5 /* RecordingStudioViewController.h */, + 846BED3C273352B500DC42D5 /* RecordingStudioViewController.m */, + 8415464727349C740085E3DD /* RecordingActionMenuCell.h */, + 8415464627349C740085E3DD /* RecordingActionMenuCell.m */, + ); + path = Recording; + sourceTree = ""; + }; + 846BED5D27345D6400DC42D5 /* Animoji */ = { + isa = PBXGroup; + children = ( + 846BED3527334DFD00DC42D5 /* AnimojiPickerViewController.h */, + 846BED3627334DFD00DC42D5 /* AnimojiPickerViewController.m */, + 846BED3827334E1C00DC42D5 /* AnimojiPickerCell.h */, + 846BED3927334E1C00DC42D5 /* AnimojiPickerCell.m */, + ); + path = Animoji; + sourceTree = ""; + }; + 846BED6127346D9800DC42D5 /* CustomClasses */ = { + isa = PBXGroup; + children = ( + 846BED68273475CB00DC42D5 /* HomeNavigationViewController.h */, + 846BED69273475CB00DC42D5 /* HomeNavigationViewController.m */, + 846BED6427346E3D00DC42D5 /* GridView.h */, + 846BED6327346E3D00DC42D5 /* GridView.m */, + 846BED6527346E3D00DC42D5 /* UtilitiesView.h */, + 846BED6227346E3D00DC42D5 /* UtilitiesView.m */, + 8415464927354EB30085E3DD /* RecordingButton.h */, + 8415464A27354EB30085E3DD /* RecordingButton.m */, + ); + path = CustomClasses; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 846BECFB2733456B00DC42D5 /* Avatar */ = { + isa = PBXNativeTarget; + buildConfigurationList = 846BED152733456E00DC42D5 /* Build configuration list for PBXNativeTarget "Avatar" */; + buildPhases = ( + 846BECF82733456B00DC42D5 /* Sources */, + 846BECF92733456B00DC42D5 /* Frameworks */, + 846BECFA2733456B00DC42D5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Avatar; + productName = Avatar; + productReference = 846BECFC2733456B00DC42D5 /* Avatar.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 846BECF42733456B00DC42D5 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1300; + TargetAttributes = { + 846BECFB2733456B00DC42D5 = { + CreatedOnToolsVersion = 13.0; + LastSwiftMigration = 1300; + }; + }; + }; + buildConfigurationList = 846BECF72733456B00DC42D5 /* Build configuration list for PBXProject "Avatar" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 846BECF32733456B00DC42D5; + productRefGroup = 846BECFD2733456B00DC42D5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 846BECFB2733456B00DC42D5 /* Avatar */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 846BECFA2733456B00DC42D5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 841546942735C6EE0085E3DD /* Stickers.plist in Resources */, + 846BED0F2733456E00DC42D5 /* LaunchScreen.storyboard in Resources */, + 8415462527348E690085E3DD /* Emoji.plist in Resources */, + 846BED6027346AAF00DC42D5 /* Theme.xcassets in Resources */, + 846BED0C2733456E00DC42D5 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 846BECF82733456B00DC42D5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8415465527356B830085E3DD /* LibraryDataSource.m in Sources */, + 8415463C27348EC80085E3DD /* TDEmojiPickerCellHeaderView.m in Sources */, + 841546B32736C80D0085E3DD /* TutorialViewController.swift in Sources */, + 846BED3727334DFD00DC42D5 /* AnimojiPickerViewController.m in Sources */, + 841546C62736C8A80085E3DD /* WhatsNewContentButton.swift in Sources */, + 846BED2927334B2000DC42D5 /* AvatarManager.m in Sources */, + 8415464427348EC80085E3DD /* TDAvatarIdentityCellHeaderView.m in Sources */, + 841546C52736C8A80085E3DD /* WhatsNewContent.swift in Sources */, + 846BED6A273475CB00DC42D5 /* HomeNavigationViewController.m in Sources */, + 841546C12736C8A80085E3DD /* WhatsNewContentTitleFormat.swift in Sources */, + 846BED6727346E3D00DC42D5 /* GridView.m in Sources */, + 843D1F73273946F700C2E0B7 /* DefaultMemojiViewController.m in Sources */, + 846BED6D27348B7000DC42D5 /* SettingManager.m in Sources */, + 8415464B27354EB30085E3DD /* RecordingButton.m in Sources */, + 8415463F27348EC80085E3DD /* TDAvatarIdentityStickerCell.m in Sources */, + 841546CA2736C8A80085E3DD /* WhatsNewBaseView.swift in Sources */, + 8415464227348EC80085E3DD /* TDEmojiPickerViewController.m in Sources */, + 846BED482733FA8C00DC42D5 /* RecordingManager.m in Sources */, + 841546AF2735F39C0085E3DD /* SettingsViewController.m in Sources */, + 846BED542734235B00DC42D5 /* AvatarVideoPreviewViewController.m in Sources */, + 841546CC2736C8CB0085E3DD /* Constraints.swift in Sources */, + 841546A22735C7260085E3DD /* TDStickerPickerCell.m in Sources */, + 841546AC2735F3600085E3DD /* AvimojiViewController.m in Sources */, + 84154652273568F80085E3DD /* LibraryCell.m in Sources */, + 841546C92736C8A80085E3DD /* WhatsNewCardsListView.swift in Sources */, + 841546C72736C8A80085E3DD /* WhatsNewPrimaryButton.swift in Sources */, + 843D1F772739683C00C2E0B7 /* SocialCell.m in Sources */, + 8415464F273566D10085E3DD /* LibraryViewController.m in Sources */, + 841546C82736C8A80085E3DD /* WhatsNewCardView.swift in Sources */, + 8415464127348EC80085E3DD /* TDAvatarIdentityPickerDataSource.m in Sources */, + 846BED3A27334E1D00DC42D5 /* AnimojiPickerCell.m in Sources */, + 846BED072733456B00DC42D5 /* HomeViewController.m in Sources */, + 841546A72735D5FB0085E3DD /* ARConfiguration+Overrides.m in Sources */, + 846BED6627346E3D00DC42D5 /* UtilitiesView.m in Sources */, + 846BED40273352EA00DC42D5 /* AvatarMotionView.m in Sources */, + 8415464327348EC80085E3DD /* TDAvatarIdentityPickerViewController.m in Sources */, + 8415464027348EC80085E3DD /* TDEmojiPickerCell.m in Sources */, + 843D1F7A27396DC200C2E0B7 /* SwitchCell.m in Sources */, + 841546A12735C7260085E3DD /* TDStickerPickerViewController.m in Sources */, + 846BED012733456B00DC42D5 /* AppDelegate.m in Sources */, + 841548BD2737FBBF0085E3DD /* RecordingOnboardingViewController.m in Sources */, + 846BED122733456E00DC42D5 /* main.m in Sources */, + 841546A02735C7260085E3DD /* StickerView.m in Sources */, + 841546C32736C8A80085E3DD /* WhatsNewContentTitle.swift in Sources */, + 8415463E27348EC80085E3DD /* TDAvatarIdentityEmojiCell.m in Sources */, + 841546A32735C7260085E3DD /* SingleHandGestureRecognizer.m in Sources */, + 8415464827349C740085E3DD /* RecordingActionMenuCell.m in Sources */, + 846BED1B2733484000DC42D5 /* ConstraintExtension.m in Sources */, + 846BED042733456B00DC42D5 /* SceneDelegate.m in Sources */, + 8415464527348EC80085E3DD /* TDHeaderView.m in Sources */, + 841546C22736C8A80085E3DD /* WhatsNewContentCard.swift in Sources */, + 841546A42735C7260085E3DD /* TDStickerPickerCellHeaderView.m in Sources */, + 8415463D27348EC80085E3DD /* TDAvatarIdentityToolsCell.m in Sources */, + 846BED3D273352B500DC42D5 /* RecordingStudioViewController.m in Sources */, + 841546C42736C8A80085E3DD /* WhatsNewContentBase.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 846BED0D2733456E00DC42D5 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 846BED0E2733456E00DC42D5 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 846BED132733456E00DC42D5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 846BED142733456E00DC42D5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 846BED162733456E00DC42D5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Avatar", + "$(PROJECT_DIR)/Avatar/Manager/AvatarKit", + "$(PROJECT_DIR)/Avatar/AvatarKit", + ); + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = Avatar/Info.plist; + INFOPLIST_KEY_NSCameraUsageDescription = "I need to access your camera to capture your facial expressions"; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "I need access to the microphone to record audio"; + INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "I need access to your photo library to save your video"; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.titand3v.Avatar; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "Avatar/Swift/Avatar-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Debug; + }; + 846BED172733456E00DC42D5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Avatar", + "$(PROJECT_DIR)/Avatar/Manager/AvatarKit", + "$(PROJECT_DIR)/Avatar/AvatarKit", + ); + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = Avatar/Info.plist; + INFOPLIST_KEY_NSCameraUsageDescription = "I need to access your camera to capture your facial expressions"; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "I need access to the microphone to record audio"; + INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "I need access to your photo library to save your video"; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.titand3v.Avatar; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "Avatar/Swift/Avatar-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 846BECF72733456B00DC42D5 /* Build configuration list for PBXProject "Avatar" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 846BED132733456E00DC42D5 /* Debug */, + 846BED142733456E00DC42D5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 846BED152733456E00DC42D5 /* Build configuration list for PBXNativeTarget "Avatar" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 846BED162733456E00DC42D5 /* Debug */, + 846BED172733456E00DC42D5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 846BECF42733456B00DC42D5 /* Project object */; +} diff --git a/Avatar/App/Avatar.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Avatar/App/Avatar.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Avatar/App/Avatar.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Avatar/App/Avatar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Avatar/App/Avatar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Avatar/App/Avatar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Avatar/App/Avatar.xcodeproj/project.xcworkspace/xcuserdata/Prysm.xcuserdatad/UserInterfaceState.xcuserstate b/Avatar/App/Avatar.xcodeproj/project.xcworkspace/xcuserdata/Prysm.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..b628e2e Binary files /dev/null and b/Avatar/App/Avatar.xcodeproj/project.xcworkspace/xcuserdata/Prysm.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Avatar/App/Avatar.xcodeproj/xcuserdata/Prysm.xcuserdatad/xcschemes/xcschememanagement.plist b/Avatar/App/Avatar.xcodeproj/xcuserdata/Prysm.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..2d14bd4 --- /dev/null +++ b/Avatar/App/Avatar.xcodeproj/xcuserdata/Prysm.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + Avatar.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/Avatar/App/Avatar/Animoji/AnimojiPickerCell.h b/Avatar/App/Avatar/Animoji/AnimojiPickerCell.h new file mode 100644 index 0000000..c146123 --- /dev/null +++ b/Avatar/App/Avatar/Animoji/AnimojiPickerCell.h @@ -0,0 +1,7 @@ +@import UIKit; +#import "AVTAnimoji.h" + +@interface AnimojiPickerCell : UICollectionViewCell +@property (nonatomic, strong) UIImageView *puppetImageView; +@property (nonatomic, copy) NSString *puppetName; +@end diff --git a/Avatar/App/Avatar/Animoji/AnimojiPickerCell.m b/Avatar/App/Avatar/Animoji/AnimojiPickerCell.m new file mode 100644 index 0000000..6798018 --- /dev/null +++ b/Avatar/App/Avatar/Animoji/AnimojiPickerCell.m @@ -0,0 +1,38 @@ +#import "AnimojiPickerCell.h" + + +@implementation AnimojiPickerCell + +- (void)willMoveToSuperview:(UIView *)newSuperview { + [super willMoveToSuperview:newSuperview]; + + [self layoutImageView]; +} + + +- (void)layoutImageView { + + if (self.puppetImageView) return; + + self.puppetImageView = [UIImageView new]; + self.puppetImageView.contentMode = UIViewContentModeScaleAspectFit; + self.puppetImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + self.puppetImageView.frame = self.contentView.bounds; + [self.contentView addSubview:self.puppetImageView]; + + [self updateImage]; +} + + +- (void)setPuppetName:(NSString *)puppetName { + _puppetName = [puppetName copy]; + [self updateImage]; +} + + +- (void)updateImage { + if (!_puppetName.length) return; + self.puppetImageView.image = [ASAnimoji thumbnailForAnimojiNamed:_puppetName options:nil]; +} + +@end diff --git a/Avatar/App/Avatar/Animoji/AnimojiPickerViewController.h b/Avatar/App/Avatar/Animoji/AnimojiPickerViewController.h new file mode 100644 index 0000000..30313ff --- /dev/null +++ b/Avatar/App/Avatar/Animoji/AnimojiPickerViewController.h @@ -0,0 +1,17 @@ +#import +#import "AVTAnimoji.h" +#import "AnimojiPickerCell.h" + + +@protocol AnimojiPickerDelegate +- (void)didSelectAnimojiWithName:(NSString *)animojiName; +@end + + +@interface AnimojiPickerViewController : UIViewController +@property (nonatomic, weak) id delegate; +@property (nonatomic, assign) CGFloat referenceHeight; +-(void)selectPuppetWithName:(NSString *)puppetName; +@property (nonatomic, strong) UICollectionViewFlowLayout *flowLayout; +@property (nonatomic, strong) UICollectionView *collectionView; +@end diff --git a/Avatar/App/Avatar/Animoji/AnimojiPickerViewController.m b/Avatar/App/Avatar/Animoji/AnimojiPickerViewController.m new file mode 100644 index 0000000..f05aa97 --- /dev/null +++ b/Avatar/App/Avatar/Animoji/AnimojiPickerViewController.m @@ -0,0 +1,94 @@ +#import "AnimojiPickerViewController.h" + +@interface AnimojiPickerViewController () +@property (nonatomic, copy) NSArray *puppetNames; +@end + + +@implementation AnimojiPickerViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Primary"]; + self.puppetNames = [ASAnimoji puppetNames]; + + [self layoutCollectionView]; +} + + +- (void)layoutCollectionView { + + self.flowLayout = [self makeFlowLayout]; + self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:self.flowLayout]; + self.collectionView.showsVerticalScrollIndicator = NO; + self.collectionView.showsHorizontalScrollIndicator = NO; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.backgroundView = nil; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + self.collectionView.frame = self.view.bounds; + [self.collectionView registerClass:[AnimojiPickerCell class] forCellWithReuseIdentifier:@"AnimojiCell"]; + [self.view addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (UICollectionViewFlowLayout *)makeFlowLayout { + + UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new]; + layout.scrollDirection = UICollectionViewScrollDirectionVertical; + + CGFloat itemSize; + CGFloat padding = 28; + CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width; + CGFloat puppetsPerLine = 3; + + itemSize = (screenWidth / puppetsPerLine) - (padding * puppetsPerLine) + (padding * 2); + + layout.sectionInset = UIEdgeInsetsMake(padding, padding, padding, padding); + layout.itemSize = CGSizeMake(itemSize, itemSize); + + return layout; +} + + +- (void)setPuppetNames:(NSArray *)puppetNames { + _puppetNames = [puppetNames copy]; + [self.collectionView reloadData]; +} + + +- (void)selectPuppetWithName:(NSString *)puppetName { + if (![self.puppetNames containsObject:puppetName]) return; + NSUInteger idx = [self.puppetNames indexOfObject:puppetName]; + [self.collectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:idx inSection:0] animated:NO scrollPosition:UICollectionViewScrollPositionCenteredHorizontally]; +} + + +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { + return 1; +} + + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.puppetNames.count; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + AnimojiPickerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AnimojiCell" forIndexPath:indexPath]; + + cell.puppetName = self.puppetNames[indexPath.item]; + + return cell; +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + NSString *animoji = self.puppetNames[indexPath.item]; + [self.delegate didSelectAnimojiWithName:animoji]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/Avatar/App/Avatar/Assets.xcassets/AccentColor.colorset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/AppIcon.appiconset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..c83c82b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,100 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "icon-120.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "icon-180.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/AppIcon.appiconset/icon-120.png b/Avatar/App/Avatar/Assets.xcassets/AppIcon.appiconset/icon-120.png new file mode 100644 index 0000000..8c75455 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/AppIcon.appiconset/icon-120.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/AppIcon.appiconset/icon-180.png b/Avatar/App/Avatar/Assets.xcassets/AppIcon.appiconset/icon-180.png new file mode 100644 index 0000000..a6f64c4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/AppIcon.appiconset/icon-180.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Onboarding/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Onboarding/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Onboarding/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Onboarding/recording-tutorial.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Onboarding/recording-tutorial.imageset/Contents.json new file mode 100644 index 0000000..eacdbbe --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Onboarding/recording-tutorial.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "recording-tutorial.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Onboarding/recording-tutorial.imageset/recording-tutorial.png b/Avatar/App/Avatar/Assets.xcassets/Onboarding/recording-tutorial.imageset/recording-tutorial.png new file mode 100644 index 0000000..17bb67e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Onboarding/recording-tutorial.imageset/recording-tutorial.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Social/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Social/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Social/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Social/discord.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Social/discord.imageset/Contents.json new file mode 100644 index 0000000..5411b23 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Social/discord.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "discord.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Social/discord.imageset/discord.png b/Avatar/App/Avatar/Assets.xcassets/Social/discord.imageset/discord.png new file mode 100644 index 0000000..4af26f4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Social/discord.imageset/discord.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Social/paypal.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Social/paypal.imageset/Contents.json new file mode 100644 index 0000000..c659efb --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Social/paypal.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "paypal.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Social/paypal.imageset/paypal.png b/Avatar/App/Avatar/Assets.xcassets/Social/paypal.imageset/paypal.png new file mode 100644 index 0000000..a4bc7f5 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Social/paypal.imageset/paypal.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Social/twitter.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Social/twitter.imageset/Contents.json new file mode 100644 index 0000000..2c808b8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Social/twitter.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "twitter.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Social/twitter.imageset/twitter.png b/Avatar/App/Avatar/Assets.xcassets/Social/twitter.imageset/twitter.png new file mode 100644 index 0000000..7f96314 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Social/twitter.imageset/twitter.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/Contents.json new file mode 100644 index 0000000..b3a1d25 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "btn_delete@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "btn_delete@3x.png", + "idiom" : "universal", + "scale" : "3x" + }, + { + "filename" : "btn_delete~ipad.png", + "idiom" : "ipad", + "scale" : "1x" + }, + { + "filename" : "btn_delete@2x~ipad.png", + "idiom" : "ipad", + "scale" : "2x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete@2x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete@2x.png new file mode 100644 index 0000000..dfbd123 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete@2x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete@2x~ipad.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete@2x~ipad.png new file mode 100644 index 0000000..c6d90e5 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete@2x~ipad.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete@3x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete@3x.png new file mode 100644 index 0000000..900ddd1 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete@3x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete~ipad.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete~ipad.png new file mode 100644 index 0000000..843ccec Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_delete.imageset/btn_delete~ipad.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/Contents.json new file mode 100644 index 0000000..27c0493 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "btn_flip@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "btn_flip@3x.png", + "idiom" : "universal", + "scale" : "3x" + }, + { + "filename" : "btn_flip~ipad.png", + "idiom" : "ipad", + "scale" : "1x" + }, + { + "filename" : "btn_flip@2x~ipad.png", + "idiom" : "ipad", + "scale" : "2x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip@2x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip@2x.png new file mode 100644 index 0000000..008e5e4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip@2x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip@2x~ipad.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip@2x~ipad.png new file mode 100644 index 0000000..47bd407 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip@2x~ipad.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip@3x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip@3x.png new file mode 100644 index 0000000..236c3a1 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip@3x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip~ipad.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip~ipad.png new file mode 100644 index 0000000..e0e7444 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_flip.imageset/btn_flip~ipad.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/Contents.json new file mode 100644 index 0000000..62f2c00 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "btn_resize@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "btn_resize@3x.png", + "idiom" : "universal", + "scale" : "3x" + }, + { + "filename" : "btn_resize~ipad.png", + "idiom" : "ipad", + "scale" : "1x" + }, + { + "filename" : "btn_resize@2x~ipad.png", + "idiom" : "ipad", + "scale" : "2x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize@2x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize@2x.png new file mode 100644 index 0000000..98b5d99 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize@2x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize@2x~ipad.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize@2x~ipad.png new file mode 100644 index 0000000..890fe73 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize@2x~ipad.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize@3x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize@3x.png new file mode 100644 index 0000000..a1f2595 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize@3x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize~ipad.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize~ipad.png new file mode 100644 index 0000000..a9f729a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_resize.imageset/btn_resize~ipad.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/Contents.json new file mode 100644 index 0000000..2c137c5 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/Contents.json @@ -0,0 +1,32 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "btn_smile@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "btn_smile@3x.png", + "idiom" : "universal", + "scale" : "3x" + }, + { + "filename" : "btn_smile~ipad.png", + "idiom" : "ipad", + "scale" : "1x" + }, + { + "filename" : "btn_smile@2x~ipad.png", + "idiom" : "ipad", + "scale" : "2x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile@2x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile@2x.png new file mode 100644 index 0000000..7b46d5e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile@2x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile@2x~ipad.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile@2x~ipad.png new file mode 100644 index 0000000..8a1461c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile@2x~ipad.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile@3x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile@3x.png new file mode 100644 index 0000000..6bef98c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile@3x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile~ipad.png b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile~ipad.png new file mode 100644 index 0000000..f5791a1 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers Action/btn_smile.imageset/btn_smile~ipad.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_000.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_000.imageset/Contents.json new file mode 100644 index 0000000..89a8b35 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_000.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_000.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_000.imageset/icons_000.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_000.imageset/icons_000.png new file mode 100644 index 0000000..de60131 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_000.imageset/icons_000.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_001.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_001.imageset/Contents.json new file mode 100644 index 0000000..0410544 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_001.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_001.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_001.imageset/icons_001.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_001.imageset/icons_001.png new file mode 100644 index 0000000..2434a92 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_001.imageset/icons_001.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_002.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_002.imageset/Contents.json new file mode 100644 index 0000000..865acc8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_002.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_002.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_002.imageset/icons_002.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_002.imageset/icons_002.png new file mode 100644 index 0000000..7a4efe9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_002.imageset/icons_002.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_003.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_003.imageset/Contents.json new file mode 100644 index 0000000..92dc408 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_003.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_003.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_003.imageset/icons_003.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_003.imageset/icons_003.png new file mode 100644 index 0000000..beedb67 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_003.imageset/icons_003.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_004.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_004.imageset/Contents.json new file mode 100644 index 0000000..183e561 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_004.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_004.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_004.imageset/icons_004.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_004.imageset/icons_004.png new file mode 100644 index 0000000..8eb0407 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_004.imageset/icons_004.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_005.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_005.imageset/Contents.json new file mode 100644 index 0000000..85b90d0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_005.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_005.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_005.imageset/icons_005.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_005.imageset/icons_005.png new file mode 100644 index 0000000..fd2b733 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_005.imageset/icons_005.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_006.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_006.imageset/Contents.json new file mode 100644 index 0000000..15890f9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_006.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_006.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_006.imageset/icons_006.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_006.imageset/icons_006.png new file mode 100644 index 0000000..84f1e30 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_006.imageset/icons_006.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_007.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_007.imageset/Contents.json new file mode 100644 index 0000000..d7e55aa --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_007.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_007.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_007.imageset/icons_007.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_007.imageset/icons_007.png new file mode 100644 index 0000000..5b6f1b8 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_007.imageset/icons_007.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_008.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_008.imageset/Contents.json new file mode 100644 index 0000000..5311ac9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_008.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_008.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_008.imageset/icons_008.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_008.imageset/icons_008.png new file mode 100644 index 0000000..3cf6e1f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_008.imageset/icons_008.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_009.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_009.imageset/Contents.json new file mode 100644 index 0000000..2ba33ad --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_009.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_009.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_009.imageset/icons_009.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_009.imageset/icons_009.png new file mode 100644 index 0000000..d1ef2c0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_009.imageset/icons_009.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_010.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_010.imageset/Contents.json new file mode 100644 index 0000000..dbcc9f8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_010.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_010.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_010.imageset/icons_010.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_010.imageset/icons_010.png new file mode 100644 index 0000000..b962671 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_010.imageset/icons_010.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_011.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_011.imageset/Contents.json new file mode 100644 index 0000000..d2cff23 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_011.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_011.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_011.imageset/icons_011.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_011.imageset/icons_011.png new file mode 100644 index 0000000..835d3eb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_011.imageset/icons_011.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_012.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_012.imageset/Contents.json new file mode 100644 index 0000000..c1f0728 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_012.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_012.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_012.imageset/icons_012.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_012.imageset/icons_012.png new file mode 100644 index 0000000..84cc52e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_012.imageset/icons_012.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_013.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_013.imageset/Contents.json new file mode 100644 index 0000000..0a43390 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_013.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_013.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_013.imageset/icons_013.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_013.imageset/icons_013.png new file mode 100644 index 0000000..24c002c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_013.imageset/icons_013.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_014.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_014.imageset/Contents.json new file mode 100644 index 0000000..1bb945f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_014.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_014.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_014.imageset/icons_014.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_014.imageset/icons_014.png new file mode 100644 index 0000000..44ed734 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_014.imageset/icons_014.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_015.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_015.imageset/Contents.json new file mode 100644 index 0000000..8d345da --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_015.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_015.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_015.imageset/icons_015.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_015.imageset/icons_015.png new file mode 100644 index 0000000..8978bb3 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_015.imageset/icons_015.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_016.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_016.imageset/Contents.json new file mode 100644 index 0000000..d8b6519 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_016.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_016.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_016.imageset/icons_016.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_016.imageset/icons_016.png new file mode 100644 index 0000000..6a0f1e5 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_016.imageset/icons_016.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_017.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_017.imageset/Contents.json new file mode 100644 index 0000000..5e9287f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_017.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_017.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_017.imageset/icons_017.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_017.imageset/icons_017.png new file mode 100644 index 0000000..fd93322 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_017.imageset/icons_017.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_018.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_018.imageset/Contents.json new file mode 100644 index 0000000..5bbdf23 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_018.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_018.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_018.imageset/icons_018.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_018.imageset/icons_018.png new file mode 100644 index 0000000..7ed31bf Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_018.imageset/icons_018.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_019.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_019.imageset/Contents.json new file mode 100644 index 0000000..95a28e8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_019.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_019.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_019.imageset/icons_019.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_019.imageset/icons_019.png new file mode 100644 index 0000000..dc21510 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_019.imageset/icons_019.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_020.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_020.imageset/Contents.json new file mode 100644 index 0000000..935f1c7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_020.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_020.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_020.imageset/icons_020.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_020.imageset/icons_020.png new file mode 100644 index 0000000..42097b6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_020.imageset/icons_020.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_021.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_021.imageset/Contents.json new file mode 100644 index 0000000..bff38c5 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_021.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_021.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_021.imageset/icons_021.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_021.imageset/icons_021.png new file mode 100644 index 0000000..c5fd5ff Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_021.imageset/icons_021.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_022.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_022.imageset/Contents.json new file mode 100644 index 0000000..b9f7868 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_022.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_022.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_022.imageset/icons_022.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_022.imageset/icons_022.png new file mode 100644 index 0000000..c264e21 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_022.imageset/icons_022.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_023.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_023.imageset/Contents.json new file mode 100644 index 0000000..421657e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_023.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_023.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_023.imageset/icons_023.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_023.imageset/icons_023.png new file mode 100644 index 0000000..3086247 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_023.imageset/icons_023.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_024.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_024.imageset/Contents.json new file mode 100644 index 0000000..e1f351c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_024.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_024.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_024.imageset/icons_024.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_024.imageset/icons_024.png new file mode 100644 index 0000000..03971e8 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_024.imageset/icons_024.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_025.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_025.imageset/Contents.json new file mode 100644 index 0000000..99507b7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_025.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_025.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_025.imageset/icons_025.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_025.imageset/icons_025.png new file mode 100644 index 0000000..9051490 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_025.imageset/icons_025.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_026.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_026.imageset/Contents.json new file mode 100644 index 0000000..1f2ec9a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_026.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_026.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_026.imageset/icons_026.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_026.imageset/icons_026.png new file mode 100644 index 0000000..1604b5d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_026.imageset/icons_026.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_027.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_027.imageset/Contents.json new file mode 100644 index 0000000..49384c6 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_027.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_027.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_027.imageset/icons_027.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_027.imageset/icons_027.png new file mode 100644 index 0000000..ea73c86 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_027.imageset/icons_027.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_028.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_028.imageset/Contents.json new file mode 100644 index 0000000..60cb444 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_028.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_028.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_028.imageset/icons_028.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_028.imageset/icons_028.png new file mode 100644 index 0000000..19f7d3b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_028.imageset/icons_028.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_029.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_029.imageset/Contents.json new file mode 100644 index 0000000..ff97b04 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_029.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_029.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_029.imageset/icons_029.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_029.imageset/icons_029.png new file mode 100644 index 0000000..19282fd Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_029.imageset/icons_029.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_030.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_030.imageset/Contents.json new file mode 100644 index 0000000..6f003d9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_030.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_030.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_030.imageset/icons_030.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_030.imageset/icons_030.png new file mode 100644 index 0000000..4442698 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_030.imageset/icons_030.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_031.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_031.imageset/Contents.json new file mode 100644 index 0000000..99382e8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_031.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_031.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_031.imageset/icons_031.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_031.imageset/icons_031.png new file mode 100644 index 0000000..d0c9832 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_031.imageset/icons_031.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_032.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_032.imageset/Contents.json new file mode 100644 index 0000000..0a4deca --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_032.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_032.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_032.imageset/icons_032.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_032.imageset/icons_032.png new file mode 100644 index 0000000..14d348d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_032.imageset/icons_032.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_033.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_033.imageset/Contents.json new file mode 100644 index 0000000..3a1f1f3 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_033.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_033.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_033.imageset/icons_033.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_033.imageset/icons_033.png new file mode 100644 index 0000000..2a692b4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_033.imageset/icons_033.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_034.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_034.imageset/Contents.json new file mode 100644 index 0000000..e65984c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_034.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_034.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_034.imageset/icons_034.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_034.imageset/icons_034.png new file mode 100644 index 0000000..c86a583 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_034.imageset/icons_034.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_035.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_035.imageset/Contents.json new file mode 100644 index 0000000..e98accf --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_035.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_035.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_035.imageset/icons_035.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_035.imageset/icons_035.png new file mode 100644 index 0000000..73f09cf Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_035.imageset/icons_035.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_036.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_036.imageset/Contents.json new file mode 100644 index 0000000..63a60f8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_036.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_036.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_036.imageset/icons_036.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_036.imageset/icons_036.png new file mode 100644 index 0000000..ee23a0b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_036.imageset/icons_036.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_037.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_037.imageset/Contents.json new file mode 100644 index 0000000..9e255e2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_037.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_037.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_037.imageset/icons_037.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_037.imageset/icons_037.png new file mode 100644 index 0000000..9674d45 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_037.imageset/icons_037.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_038.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_038.imageset/Contents.json new file mode 100644 index 0000000..57f6ab9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_038.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_038.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_038.imageset/icons_038.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_038.imageset/icons_038.png new file mode 100644 index 0000000..517efff Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_038.imageset/icons_038.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_039.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_039.imageset/Contents.json new file mode 100644 index 0000000..71f2f04 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_039.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_039.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_039.imageset/icons_039.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_039.imageset/icons_039.png new file mode 100644 index 0000000..dbc9dcb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_039.imageset/icons_039.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_040.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_040.imageset/Contents.json new file mode 100644 index 0000000..cb69921 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_040.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_040.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_040.imageset/icons_040.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_040.imageset/icons_040.png new file mode 100644 index 0000000..226b179 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_040.imageset/icons_040.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_041.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_041.imageset/Contents.json new file mode 100644 index 0000000..77d7f2b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_041.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_041.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_041.imageset/icons_041.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_041.imageset/icons_041.png new file mode 100644 index 0000000..656cdc9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_041.imageset/icons_041.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_042.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_042.imageset/Contents.json new file mode 100644 index 0000000..88b9811 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_042.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_042.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_042.imageset/icons_042.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_042.imageset/icons_042.png new file mode 100644 index 0000000..9e9a103 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_042.imageset/icons_042.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_043.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_043.imageset/Contents.json new file mode 100644 index 0000000..ff436b4 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_043.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_043.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_043.imageset/icons_043.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_043.imageset/icons_043.png new file mode 100644 index 0000000..9518dda Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_043.imageset/icons_043.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_044.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_044.imageset/Contents.json new file mode 100644 index 0000000..9fada1b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_044.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_044.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_044.imageset/icons_044.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_044.imageset/icons_044.png new file mode 100644 index 0000000..a430b48 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_044.imageset/icons_044.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_045.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_045.imageset/Contents.json new file mode 100644 index 0000000..33579da --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_045.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_045.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_045.imageset/icons_045.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_045.imageset/icons_045.png new file mode 100644 index 0000000..2e3a854 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_045.imageset/icons_045.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_046.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_046.imageset/Contents.json new file mode 100644 index 0000000..554cb9c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_046.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_046.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_046.imageset/icons_046.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_046.imageset/icons_046.png new file mode 100644 index 0000000..e9f3f3a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_046.imageset/icons_046.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_047.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_047.imageset/Contents.json new file mode 100644 index 0000000..b7790c0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_047.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_047.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_047.imageset/icons_047.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_047.imageset/icons_047.png new file mode 100644 index 0000000..5d4cf94 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_047.imageset/icons_047.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_048.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_048.imageset/Contents.json new file mode 100644 index 0000000..d2f867a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_048.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_048.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_048.imageset/icons_048.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_048.imageset/icons_048.png new file mode 100644 index 0000000..fc4172d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_048.imageset/icons_048.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_049.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_049.imageset/Contents.json new file mode 100644 index 0000000..40ad6ef --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_049.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_049.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_049.imageset/icons_049.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_049.imageset/icons_049.png new file mode 100644 index 0000000..2853814 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_049.imageset/icons_049.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_050.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_050.imageset/Contents.json new file mode 100644 index 0000000..9d038ed --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_050.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_050.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_050.imageset/icons_050.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_050.imageset/icons_050.png new file mode 100644 index 0000000..60aa791 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_050.imageset/icons_050.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_051.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_051.imageset/Contents.json new file mode 100644 index 0000000..00d0386 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_051.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_051.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_051.imageset/icons_051.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_051.imageset/icons_051.png new file mode 100644 index 0000000..65c0b8d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_051.imageset/icons_051.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_052.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_052.imageset/Contents.json new file mode 100644 index 0000000..648bdc7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_052.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_052.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_052.imageset/icons_052.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_052.imageset/icons_052.png new file mode 100644 index 0000000..e329199 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_052.imageset/icons_052.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_053.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_053.imageset/Contents.json new file mode 100644 index 0000000..191084e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_053.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_053.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_053.imageset/icons_053.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_053.imageset/icons_053.png new file mode 100644 index 0000000..654aafd Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_053.imageset/icons_053.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_054.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_054.imageset/Contents.json new file mode 100644 index 0000000..e261014 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_054.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_054.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_054.imageset/icons_054.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_054.imageset/icons_054.png new file mode 100644 index 0000000..30af995 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_054.imageset/icons_054.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_055.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_055.imageset/Contents.json new file mode 100644 index 0000000..ac64519 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_055.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_055.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_055.imageset/icons_055.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_055.imageset/icons_055.png new file mode 100644 index 0000000..1698235 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_055.imageset/icons_055.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_056.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_056.imageset/Contents.json new file mode 100644 index 0000000..7fa01ba --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_056.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_056.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_056.imageset/icons_056.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_056.imageset/icons_056.png new file mode 100644 index 0000000..809c66c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_056.imageset/icons_056.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_057.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_057.imageset/Contents.json new file mode 100644 index 0000000..42a5c5a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_057.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_057.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_057.imageset/icons_057.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_057.imageset/icons_057.png new file mode 100644 index 0000000..3474f57 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_057.imageset/icons_057.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_058.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_058.imageset/Contents.json new file mode 100644 index 0000000..b11893b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_058.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_058.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_058.imageset/icons_058.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_058.imageset/icons_058.png new file mode 100644 index 0000000..2ba11e6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_058.imageset/icons_058.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_059.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_059.imageset/Contents.json new file mode 100644 index 0000000..5a1cff7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_059.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_059.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_059.imageset/icons_059.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_059.imageset/icons_059.png new file mode 100644 index 0000000..1ea24e7 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_059.imageset/icons_059.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_060.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_060.imageset/Contents.json new file mode 100644 index 0000000..7dce52b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_060.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_060.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_060.imageset/icons_060.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_060.imageset/icons_060.png new file mode 100644 index 0000000..fb60062 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_060.imageset/icons_060.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_061.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_061.imageset/Contents.json new file mode 100644 index 0000000..a0af53f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_061.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_061.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_061.imageset/icons_061.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_061.imageset/icons_061.png new file mode 100644 index 0000000..b744df0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_061.imageset/icons_061.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_062.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_062.imageset/Contents.json new file mode 100644 index 0000000..87f8ca9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_062.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_062.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_062.imageset/icons_062.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_062.imageset/icons_062.png new file mode 100644 index 0000000..a598b38 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_062.imageset/icons_062.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_063.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_063.imageset/Contents.json new file mode 100644 index 0000000..d6b922f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_063.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_063.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_063.imageset/icons_063.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_063.imageset/icons_063.png new file mode 100644 index 0000000..bef047b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_063.imageset/icons_063.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_064.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_064.imageset/Contents.json new file mode 100644 index 0000000..6d68715 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_064.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_064.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_064.imageset/icons_064.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_064.imageset/icons_064.png new file mode 100644 index 0000000..2a4db35 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_064.imageset/icons_064.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_065.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_065.imageset/Contents.json new file mode 100644 index 0000000..ef34bbe --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_065.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_065.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_065.imageset/icons_065.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_065.imageset/icons_065.png new file mode 100644 index 0000000..00c470b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_065.imageset/icons_065.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_066.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_066.imageset/Contents.json new file mode 100644 index 0000000..66f588f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_066.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_066.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_066.imageset/icons_066.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_066.imageset/icons_066.png new file mode 100644 index 0000000..7b03b8e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_066.imageset/icons_066.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_067.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_067.imageset/Contents.json new file mode 100644 index 0000000..3eb349b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_067.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_067.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_067.imageset/icons_067.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_067.imageset/icons_067.png new file mode 100644 index 0000000..62e9e43 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_067.imageset/icons_067.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_068.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_068.imageset/Contents.json new file mode 100644 index 0000000..1a114b6 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_068.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_068.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_068.imageset/icons_068.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_068.imageset/icons_068.png new file mode 100644 index 0000000..04c56fe Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_068.imageset/icons_068.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_069.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_069.imageset/Contents.json new file mode 100644 index 0000000..628d073 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_069.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_069.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_069.imageset/icons_069.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_069.imageset/icons_069.png new file mode 100644 index 0000000..b5fa6c1 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_069.imageset/icons_069.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_070.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_070.imageset/Contents.json new file mode 100644 index 0000000..c73a3a2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_070.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_070.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_070.imageset/icons_070.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_070.imageset/icons_070.png new file mode 100644 index 0000000..06b8679 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_070.imageset/icons_070.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_071.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_071.imageset/Contents.json new file mode 100644 index 0000000..05fd5b5 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_071.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_071.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_071.imageset/icons_071.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_071.imageset/icons_071.png new file mode 100644 index 0000000..5dfdc57 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_071.imageset/icons_071.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_072.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_072.imageset/Contents.json new file mode 100644 index 0000000..bf55394 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_072.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_072.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_072.imageset/icons_072.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_072.imageset/icons_072.png new file mode 100644 index 0000000..c442264 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_072.imageset/icons_072.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_073.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_073.imageset/Contents.json new file mode 100644 index 0000000..d5f6604 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_073.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_073.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_073.imageset/icons_073.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_073.imageset/icons_073.png new file mode 100644 index 0000000..206957a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_073.imageset/icons_073.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_074.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_074.imageset/Contents.json new file mode 100644 index 0000000..151b164 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_074.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_074.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_074.imageset/icons_074.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_074.imageset/icons_074.png new file mode 100644 index 0000000..86aa4c7 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_074.imageset/icons_074.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_075.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_075.imageset/Contents.json new file mode 100644 index 0000000..aa4d087 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_075.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_075.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_075.imageset/icons_075.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_075.imageset/icons_075.png new file mode 100644 index 0000000..18a3ae3 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_075.imageset/icons_075.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_076.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_076.imageset/Contents.json new file mode 100644 index 0000000..bb6dbc9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_076.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_076.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_076.imageset/icons_076.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_076.imageset/icons_076.png new file mode 100644 index 0000000..b6980a2 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_076.imageset/icons_076.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_077.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_077.imageset/Contents.json new file mode 100644 index 0000000..6174fd8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_077.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_077.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_077.imageset/icons_077.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_077.imageset/icons_077.png new file mode 100644 index 0000000..a8a05c9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_077.imageset/icons_077.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_078.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_078.imageset/Contents.json new file mode 100644 index 0000000..160c404 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_078.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_078.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_078.imageset/icons_078.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_078.imageset/icons_078.png new file mode 100644 index 0000000..940cc97 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_078.imageset/icons_078.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_079.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_079.imageset/Contents.json new file mode 100644 index 0000000..5ac0f55 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_079.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_079.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_079.imageset/icons_079.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_079.imageset/icons_079.png new file mode 100644 index 0000000..bd0bf39 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_079.imageset/icons_079.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_080.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_080.imageset/Contents.json new file mode 100644 index 0000000..f8af109 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_080.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_080.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_080.imageset/icons_080.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_080.imageset/icons_080.png new file mode 100644 index 0000000..567d744 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_080.imageset/icons_080.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_081.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_081.imageset/Contents.json new file mode 100644 index 0000000..dd34875 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_081.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_081.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_081.imageset/icons_081.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_081.imageset/icons_081.png new file mode 100644 index 0000000..b5dc9d7 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_081.imageset/icons_081.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_082.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_082.imageset/Contents.json new file mode 100644 index 0000000..f058683 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_082.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_082.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_082.imageset/icons_082.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_082.imageset/icons_082.png new file mode 100644 index 0000000..3cf98fb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_082.imageset/icons_082.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_083.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_083.imageset/Contents.json new file mode 100644 index 0000000..33d8ad9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_083.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_083.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_083.imageset/icons_083.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_083.imageset/icons_083.png new file mode 100644 index 0000000..85c1801 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_083.imageset/icons_083.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_084.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_084.imageset/Contents.json new file mode 100644 index 0000000..4301030 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_084.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_084.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_084.imageset/icons_084.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_084.imageset/icons_084.png new file mode 100644 index 0000000..0992fdf Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_084.imageset/icons_084.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_085.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_085.imageset/Contents.json new file mode 100644 index 0000000..9891c17 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_085.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_085.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_085.imageset/icons_085.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_085.imageset/icons_085.png new file mode 100644 index 0000000..71bfa7b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_085.imageset/icons_085.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_086.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_086.imageset/Contents.json new file mode 100644 index 0000000..e8d6fd8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_086.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_086.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_086.imageset/icons_086.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_086.imageset/icons_086.png new file mode 100644 index 0000000..54bc30d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_086.imageset/icons_086.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_087.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_087.imageset/Contents.json new file mode 100644 index 0000000..0307766 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_087.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "icons_087.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_087.imageset/icons_087.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_087.imageset/icons_087.png new file mode 100644 index 0000000..ad3e23e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/icons_087.imageset/icons_087.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_000.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_000.imageset/Contents.json new file mode 100644 index 0000000..ae4bdb7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_000.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_000.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_000.imageset/love_000.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_000.imageset/love_000.png new file mode 100644 index 0000000..0567e92 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_000.imageset/love_000.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_001.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_001.imageset/Contents.json new file mode 100644 index 0000000..8307913 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_001.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_001.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_001.imageset/love_001.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_001.imageset/love_001.png new file mode 100644 index 0000000..2e55c96 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_001.imageset/love_001.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_002.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_002.imageset/Contents.json new file mode 100644 index 0000000..1f3cbf0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_002.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_002.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_002.imageset/love_002.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_002.imageset/love_002.png new file mode 100644 index 0000000..908a396 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_002.imageset/love_002.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_003.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_003.imageset/Contents.json new file mode 100644 index 0000000..a157b3e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_003.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_003.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_003.imageset/love_003.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_003.imageset/love_003.png new file mode 100644 index 0000000..774b8e6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_003.imageset/love_003.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_004.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_004.imageset/Contents.json new file mode 100644 index 0000000..3fab13e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_004.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_004.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_004.imageset/love_004.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_004.imageset/love_004.png new file mode 100644 index 0000000..03c542e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_004.imageset/love_004.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_005.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_005.imageset/Contents.json new file mode 100644 index 0000000..b9f66fe --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_005.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_005.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_005.imageset/love_005.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_005.imageset/love_005.png new file mode 100644 index 0000000..bf23888 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_005.imageset/love_005.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_006.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_006.imageset/Contents.json new file mode 100644 index 0000000..62f7c61 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_006.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_006.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_006.imageset/love_006.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_006.imageset/love_006.png new file mode 100644 index 0000000..db31f5d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_006.imageset/love_006.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_007.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_007.imageset/Contents.json new file mode 100644 index 0000000..0d6dde2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_007.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_007.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_007.imageset/love_007.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_007.imageset/love_007.png new file mode 100644 index 0000000..d22f4cb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_007.imageset/love_007.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_008.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_008.imageset/Contents.json new file mode 100644 index 0000000..395bc3f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_008.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_008.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_008.imageset/love_008.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_008.imageset/love_008.png new file mode 100644 index 0000000..5e647f0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_008.imageset/love_008.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_009.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_009.imageset/Contents.json new file mode 100644 index 0000000..8f773c8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_009.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_009.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_009.imageset/love_009.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_009.imageset/love_009.png new file mode 100644 index 0000000..a9c40b9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_009.imageset/love_009.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_010.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_010.imageset/Contents.json new file mode 100644 index 0000000..ff01360 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_010.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_010.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_010.imageset/love_010.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_010.imageset/love_010.png new file mode 100644 index 0000000..929f732 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_010.imageset/love_010.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_011.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_011.imageset/Contents.json new file mode 100644 index 0000000..dd154c0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_011.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_011.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_011.imageset/love_011.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_011.imageset/love_011.png new file mode 100644 index 0000000..9c0de8f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_011.imageset/love_011.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_012.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_012.imageset/Contents.json new file mode 100644 index 0000000..313615a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_012.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_012.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_012.imageset/love_012.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_012.imageset/love_012.png new file mode 100644 index 0000000..608caa5 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_012.imageset/love_012.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_013.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_013.imageset/Contents.json new file mode 100644 index 0000000..e54c956 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_013.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_013.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_013.imageset/love_013.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_013.imageset/love_013.png new file mode 100644 index 0000000..ef1f658 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_013.imageset/love_013.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_014.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_014.imageset/Contents.json new file mode 100644 index 0000000..c13e2e7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_014.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_014.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_014.imageset/love_014.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_014.imageset/love_014.png new file mode 100644 index 0000000..e59a0a9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_014.imageset/love_014.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_015.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_015.imageset/Contents.json new file mode 100644 index 0000000..93ff440 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_015.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_015.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_015.imageset/love_015.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_015.imageset/love_015.png new file mode 100644 index 0000000..02108de Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_015.imageset/love_015.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_016.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_016.imageset/Contents.json new file mode 100644 index 0000000..73be3b8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_016.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_016.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_016.imageset/love_016.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_016.imageset/love_016.png new file mode 100644 index 0000000..256288f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_016.imageset/love_016.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_017.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_017.imageset/Contents.json new file mode 100644 index 0000000..2eb7fce --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_017.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_017.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_017.imageset/love_017.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_017.imageset/love_017.png new file mode 100644 index 0000000..7946894 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_017.imageset/love_017.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_018.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_018.imageset/Contents.json new file mode 100644 index 0000000..cdcd4c6 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_018.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_018.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_018.imageset/love_018.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_018.imageset/love_018.png new file mode 100644 index 0000000..f191dd6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_018.imageset/love_018.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_019.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_019.imageset/Contents.json new file mode 100644 index 0000000..6913cb3 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_019.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_019.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_019.imageset/love_019.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_019.imageset/love_019.png new file mode 100644 index 0000000..df4ec92 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_019.imageset/love_019.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_020.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_020.imageset/Contents.json new file mode 100644 index 0000000..69e2e81 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_020.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_020.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_020.imageset/love_020.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_020.imageset/love_020.png new file mode 100644 index 0000000..f00ea23 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_020.imageset/love_020.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_021.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_021.imageset/Contents.json new file mode 100644 index 0000000..04dabf3 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_021.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_021.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_021.imageset/love_021.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_021.imageset/love_021.png new file mode 100644 index 0000000..2b509fa Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_021.imageset/love_021.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_022.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_022.imageset/Contents.json new file mode 100644 index 0000000..982e83f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_022.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_022.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_022.imageset/love_022.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_022.imageset/love_022.png new file mode 100644 index 0000000..062ab1c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_022.imageset/love_022.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_023.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_023.imageset/Contents.json new file mode 100644 index 0000000..d7666e0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_023.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_023.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_023.imageset/love_023.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_023.imageset/love_023.png new file mode 100644 index 0000000..37a601d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_023.imageset/love_023.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_024.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_024.imageset/Contents.json new file mode 100644 index 0000000..5f949f6 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_024.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_024.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_024.imageset/love_024.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_024.imageset/love_024.png new file mode 100644 index 0000000..8aa5d2f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_024.imageset/love_024.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_025.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_025.imageset/Contents.json new file mode 100644 index 0000000..c5a8df1 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_025.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_025.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_025.imageset/love_025.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_025.imageset/love_025.png new file mode 100644 index 0000000..7e3b173 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_025.imageset/love_025.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_026.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_026.imageset/Contents.json new file mode 100644 index 0000000..7c56592 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_026.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_026.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_026.imageset/love_026.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_026.imageset/love_026.png new file mode 100644 index 0000000..f59eb0a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_026.imageset/love_026.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_027.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_027.imageset/Contents.json new file mode 100644 index 0000000..959ef80 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_027.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_027.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_027.imageset/love_027.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_027.imageset/love_027.png new file mode 100644 index 0000000..f683664 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_027.imageset/love_027.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_028.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_028.imageset/Contents.json new file mode 100644 index 0000000..19fb002 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_028.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_028.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_028.imageset/love_028.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_028.imageset/love_028.png new file mode 100644 index 0000000..f0492bb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_028.imageset/love_028.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_029.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_029.imageset/Contents.json new file mode 100644 index 0000000..f12247f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_029.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_029.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_029.imageset/love_029.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_029.imageset/love_029.png new file mode 100644 index 0000000..f5191a8 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_029.imageset/love_029.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_030.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_030.imageset/Contents.json new file mode 100644 index 0000000..ad82383 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_030.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_030.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_030.imageset/love_030.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_030.imageset/love_030.png new file mode 100644 index 0000000..9cb767e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_030.imageset/love_030.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_031.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_031.imageset/Contents.json new file mode 100644 index 0000000..a4204d7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_031.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_031.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_031.imageset/love_031.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_031.imageset/love_031.png new file mode 100644 index 0000000..ec87cd4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_031.imageset/love_031.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_032.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_032.imageset/Contents.json new file mode 100644 index 0000000..bf761f0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_032.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_032.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_032.imageset/love_032.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_032.imageset/love_032.png new file mode 100644 index 0000000..2f04871 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_032.imageset/love_032.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_033.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_033.imageset/Contents.json new file mode 100644 index 0000000..0a0201e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_033.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_033.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_033.imageset/love_033.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_033.imageset/love_033.png new file mode 100644 index 0000000..8fa97d9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_033.imageset/love_033.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_034.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_034.imageset/Contents.json new file mode 100644 index 0000000..6a0f620 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_034.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_034.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_034.imageset/love_034.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_034.imageset/love_034.png new file mode 100644 index 0000000..ac39e17 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_034.imageset/love_034.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_035.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_035.imageset/Contents.json new file mode 100644 index 0000000..1436e11 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_035.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_035.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_035.imageset/love_035.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_035.imageset/love_035.png new file mode 100644 index 0000000..d727650 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_035.imageset/love_035.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_036.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_036.imageset/Contents.json new file mode 100644 index 0000000..5f433c7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_036.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_036.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_036.imageset/love_036.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_036.imageset/love_036.png new file mode 100644 index 0000000..ace624a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_036.imageset/love_036.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_037.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_037.imageset/Contents.json new file mode 100644 index 0000000..3622cc3 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_037.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_037.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_037.imageset/love_037.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_037.imageset/love_037.png new file mode 100644 index 0000000..2730986 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_037.imageset/love_037.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_038.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_038.imageset/Contents.json new file mode 100644 index 0000000..2fb0049 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_038.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_038.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_038.imageset/love_038.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_038.imageset/love_038.png new file mode 100644 index 0000000..6fc3288 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_038.imageset/love_038.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_039.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_039.imageset/Contents.json new file mode 100644 index 0000000..6876f91 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_039.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_039.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_039.imageset/love_039.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_039.imageset/love_039.png new file mode 100644 index 0000000..fe49109 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_039.imageset/love_039.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_040.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_040.imageset/Contents.json new file mode 100644 index 0000000..915ce55 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_040.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_040.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_040.imageset/love_040.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_040.imageset/love_040.png new file mode 100644 index 0000000..6dd9530 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_040.imageset/love_040.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_041.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_041.imageset/Contents.json new file mode 100644 index 0000000..fb1e125 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_041.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_041.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_041.imageset/love_041.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_041.imageset/love_041.png new file mode 100644 index 0000000..81f44a6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_041.imageset/love_041.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_042.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_042.imageset/Contents.json new file mode 100644 index 0000000..0985eea --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_042.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_042.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_042.imageset/love_042.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_042.imageset/love_042.png new file mode 100644 index 0000000..d68285b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_042.imageset/love_042.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_043.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_043.imageset/Contents.json new file mode 100644 index 0000000..e8516b1 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_043.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_043.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_043.imageset/love_043.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_043.imageset/love_043.png new file mode 100644 index 0000000..8390141 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_043.imageset/love_043.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_044.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_044.imageset/Contents.json new file mode 100644 index 0000000..0efb758 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_044.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_044.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_044.imageset/love_044.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_044.imageset/love_044.png new file mode 100644 index 0000000..2ea786c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_044.imageset/love_044.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_045.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_045.imageset/Contents.json new file mode 100644 index 0000000..69d2345 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_045.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_045.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_045.imageset/love_045.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_045.imageset/love_045.png new file mode 100644 index 0000000..1eda248 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_045.imageset/love_045.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_046.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_046.imageset/Contents.json new file mode 100644 index 0000000..9a82203 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_046.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_046.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_046.imageset/love_046.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_046.imageset/love_046.png new file mode 100644 index 0000000..60c6141 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_046.imageset/love_046.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_047.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_047.imageset/Contents.json new file mode 100644 index 0000000..2edb892 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_047.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_047.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_047.imageset/love_047.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_047.imageset/love_047.png new file mode 100644 index 0000000..a415842 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_047.imageset/love_047.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_048.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_048.imageset/Contents.json new file mode 100644 index 0000000..4529ba2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_048.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_048.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_048.imageset/love_048.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_048.imageset/love_048.png new file mode 100644 index 0000000..f98d90b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_048.imageset/love_048.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_049.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_049.imageset/Contents.json new file mode 100644 index 0000000..7cc65ad --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_049.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_049.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_049.imageset/love_049.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_049.imageset/love_049.png new file mode 100644 index 0000000..0ed734a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_049.imageset/love_049.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_050.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_050.imageset/Contents.json new file mode 100644 index 0000000..a182fbf --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_050.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_050.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_050.imageset/love_050.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_050.imageset/love_050.png new file mode 100644 index 0000000..bc7d1be Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_050.imageset/love_050.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_051.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_051.imageset/Contents.json new file mode 100644 index 0000000..31ea213 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_051.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_051.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_051.imageset/love_051.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_051.imageset/love_051.png new file mode 100644 index 0000000..e30bd20 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_051.imageset/love_051.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_052.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_052.imageset/Contents.json new file mode 100644 index 0000000..cff4636 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_052.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_052.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_052.imageset/love_052.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_052.imageset/love_052.png new file mode 100644 index 0000000..dd51410 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_052.imageset/love_052.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_053.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_053.imageset/Contents.json new file mode 100644 index 0000000..ecc9598 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_053.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_053.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_053.imageset/love_053.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_053.imageset/love_053.png new file mode 100644 index 0000000..73e760a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_053.imageset/love_053.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_054.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_054.imageset/Contents.json new file mode 100644 index 0000000..d0d5769 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_054.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_054.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_054.imageset/love_054.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_054.imageset/love_054.png new file mode 100644 index 0000000..dad8ffb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_054.imageset/love_054.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_055.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_055.imageset/Contents.json new file mode 100644 index 0000000..17b227a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_055.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_055.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_055.imageset/love_055.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_055.imageset/love_055.png new file mode 100644 index 0000000..19922a1 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_055.imageset/love_055.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_056.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_056.imageset/Contents.json new file mode 100644 index 0000000..f86203f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_056.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_056.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_056.imageset/love_056.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_056.imageset/love_056.png new file mode 100644 index 0000000..0a227bd Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_056.imageset/love_056.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_057.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_057.imageset/Contents.json new file mode 100644 index 0000000..6b7473f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_057.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_057.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_057.imageset/love_057.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_057.imageset/love_057.png new file mode 100644 index 0000000..3d347c6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_057.imageset/love_057.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_058.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_058.imageset/Contents.json new file mode 100644 index 0000000..222ba21 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_058.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_058.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_058.imageset/love_058.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_058.imageset/love_058.png new file mode 100644 index 0000000..c977b76 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_058.imageset/love_058.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_059.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_059.imageset/Contents.json new file mode 100644 index 0000000..a52622c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_059.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_059.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_059.imageset/love_059.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_059.imageset/love_059.png new file mode 100644 index 0000000..ee2ff74 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_059.imageset/love_059.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_060.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_060.imageset/Contents.json new file mode 100644 index 0000000..7664e46 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_060.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_060.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_060.imageset/love_060.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_060.imageset/love_060.png new file mode 100644 index 0000000..4e00e98 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_060.imageset/love_060.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_061.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_061.imageset/Contents.json new file mode 100644 index 0000000..f94a3f6 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_061.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_061.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_061.imageset/love_061.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_061.imageset/love_061.png new file mode 100644 index 0000000..e617170 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_061.imageset/love_061.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_062.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_062.imageset/Contents.json new file mode 100644 index 0000000..89f6c85 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_062.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_062.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_062.imageset/love_062.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_062.imageset/love_062.png new file mode 100644 index 0000000..246fc15 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_062.imageset/love_062.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_063.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_063.imageset/Contents.json new file mode 100644 index 0000000..ee572ce --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_063.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_063.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_063.imageset/love_063.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_063.imageset/love_063.png new file mode 100644 index 0000000..1759080 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_063.imageset/love_063.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_064.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_064.imageset/Contents.json new file mode 100644 index 0000000..22d1ca5 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_064.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_064.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_064.imageset/love_064.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_064.imageset/love_064.png new file mode 100644 index 0000000..246d78c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_064.imageset/love_064.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_065.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_065.imageset/Contents.json new file mode 100644 index 0000000..4573789 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_065.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_065.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_065.imageset/love_065.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_065.imageset/love_065.png new file mode 100644 index 0000000..8ce4ed0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_065.imageset/love_065.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_066.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_066.imageset/Contents.json new file mode 100644 index 0000000..8f70268 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_066.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_066.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_066.imageset/love_066.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_066.imageset/love_066.png new file mode 100644 index 0000000..db41ed5 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_066.imageset/love_066.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_067.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_067.imageset/Contents.json new file mode 100644 index 0000000..733e9b7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_067.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_067.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_067.imageset/love_067.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_067.imageset/love_067.png new file mode 100644 index 0000000..cf964ea Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_067.imageset/love_067.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_068.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_068.imageset/Contents.json new file mode 100644 index 0000000..598d17b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_068.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_068.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_068.imageset/love_068.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_068.imageset/love_068.png new file mode 100644 index 0000000..9c85612 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_068.imageset/love_068.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_069.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_069.imageset/Contents.json new file mode 100644 index 0000000..4d93882 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_069.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_069.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_069.imageset/love_069.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_069.imageset/love_069.png new file mode 100644 index 0000000..a2b4320 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_069.imageset/love_069.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_070.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_070.imageset/Contents.json new file mode 100644 index 0000000..24ad1fe --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_070.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_070.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_070.imageset/love_070.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_070.imageset/love_070.png new file mode 100644 index 0000000..ade7614 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_070.imageset/love_070.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_071.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_071.imageset/Contents.json new file mode 100644 index 0000000..49aa4be --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_071.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_071.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_071.imageset/love_071.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_071.imageset/love_071.png new file mode 100644 index 0000000..edcb933 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_071.imageset/love_071.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_072.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_072.imageset/Contents.json new file mode 100644 index 0000000..7654a29 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_072.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_072.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_072.imageset/love_072.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_072.imageset/love_072.png new file mode 100644 index 0000000..27d5574 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_072.imageset/love_072.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_073.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_073.imageset/Contents.json new file mode 100644 index 0000000..3c607c5 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_073.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_073.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_073.imageset/love_073.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_073.imageset/love_073.png new file mode 100644 index 0000000..fb58189 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_073.imageset/love_073.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_074.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_074.imageset/Contents.json new file mode 100644 index 0000000..292307c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_074.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_074.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_074.imageset/love_074.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_074.imageset/love_074.png new file mode 100644 index 0000000..4a2ddaf Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_074.imageset/love_074.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_075.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_075.imageset/Contents.json new file mode 100644 index 0000000..3b67c2f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_075.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_075.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_075.imageset/love_075.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_075.imageset/love_075.png new file mode 100644 index 0000000..c809953 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_075.imageset/love_075.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_076.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_076.imageset/Contents.json new file mode 100644 index 0000000..ec43583 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_076.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_076.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_076.imageset/love_076.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_076.imageset/love_076.png new file mode 100644 index 0000000..315c3b0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_076.imageset/love_076.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_077.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_077.imageset/Contents.json new file mode 100644 index 0000000..e73e7c7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_077.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_077.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_077.imageset/love_077.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_077.imageset/love_077.png new file mode 100644 index 0000000..07cd43b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_077.imageset/love_077.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_078.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_078.imageset/Contents.json new file mode 100644 index 0000000..7126eda --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_078.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_078.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_078.imageset/love_078.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_078.imageset/love_078.png new file mode 100644 index 0000000..488e008 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_078.imageset/love_078.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_079.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_079.imageset/Contents.json new file mode 100644 index 0000000..ff13564 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_079.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_079.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_079.imageset/love_079.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_079.imageset/love_079.png new file mode 100644 index 0000000..0d6069d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_079.imageset/love_079.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_080.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_080.imageset/Contents.json new file mode 100644 index 0000000..667ec38 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_080.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_080.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_080.imageset/love_080.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_080.imageset/love_080.png new file mode 100644 index 0000000..1b47f38 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_080.imageset/love_080.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_081.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_081.imageset/Contents.json new file mode 100644 index 0000000..0f511be --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_081.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_081.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_081.imageset/love_081.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_081.imageset/love_081.png new file mode 100644 index 0000000..e6f982c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_081.imageset/love_081.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_082.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_082.imageset/Contents.json new file mode 100644 index 0000000..ef09845 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_082.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_082.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_082.imageset/love_082.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_082.imageset/love_082.png new file mode 100644 index 0000000..9bf4689 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_082.imageset/love_082.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_083.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_083.imageset/Contents.json new file mode 100644 index 0000000..80f7f6a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_083.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_083.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_083.imageset/love_083.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_083.imageset/love_083.png new file mode 100644 index 0000000..c4d61e8 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_083.imageset/love_083.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_084.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_084.imageset/Contents.json new file mode 100644 index 0000000..c191870 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_084.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_084.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_084.imageset/love_084.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_084.imageset/love_084.png new file mode 100644 index 0000000..57d1c5f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_084.imageset/love_084.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_085.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_085.imageset/Contents.json new file mode 100644 index 0000000..8761054 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_085.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_085.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_085.imageset/love_085.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_085.imageset/love_085.png new file mode 100644 index 0000000..a035a22 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_085.imageset/love_085.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_086.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_086.imageset/Contents.json new file mode 100644 index 0000000..3e128ac --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_086.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_086.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_086.imageset/love_086.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_086.imageset/love_086.png new file mode 100644 index 0000000..5bf819b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_086.imageset/love_086.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_087.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_087.imageset/Contents.json new file mode 100644 index 0000000..f1f37a9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_087.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_087.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_087.imageset/love_087.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_087.imageset/love_087.png new file mode 100644 index 0000000..e51186a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_087.imageset/love_087.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_088.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_088.imageset/Contents.json new file mode 100644 index 0000000..f887fdb --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_088.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_088.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_088.imageset/love_088.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_088.imageset/love_088.png new file mode 100644 index 0000000..4b8b40a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_088.imageset/love_088.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_089.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_089.imageset/Contents.json new file mode 100644 index 0000000..55d7fd0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_089.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_089.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_089.imageset/love_089.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_089.imageset/love_089.png new file mode 100644 index 0000000..0d1183c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_089.imageset/love_089.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_090.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_090.imageset/Contents.json new file mode 100644 index 0000000..4b12011 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_090.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_090.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_090.imageset/love_090.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_090.imageset/love_090.png new file mode 100644 index 0000000..cb3976f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_090.imageset/love_090.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_091.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_091.imageset/Contents.json new file mode 100644 index 0000000..0481f1b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_091.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_091.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_091.imageset/love_091.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_091.imageset/love_091.png new file mode 100644 index 0000000..ba14ca3 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_091.imageset/love_091.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_092.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_092.imageset/Contents.json new file mode 100644 index 0000000..5791679 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_092.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_092.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_092.imageset/love_092.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_092.imageset/love_092.png new file mode 100644 index 0000000..896c59b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_092.imageset/love_092.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_093.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_093.imageset/Contents.json new file mode 100644 index 0000000..470d870 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_093.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_093.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_093.imageset/love_093.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_093.imageset/love_093.png new file mode 100644 index 0000000..2ed68b3 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_093.imageset/love_093.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_094.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_094.imageset/Contents.json new file mode 100644 index 0000000..aba0c8d --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_094.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "love_094.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/love_094.imageset/love_094.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_094.imageset/love_094.png new file mode 100644 index 0000000..8760209 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/love_094.imageset/love_094.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_000.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_000.imageset/Contents.json new file mode 100644 index 0000000..78b728d --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_000.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_000.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_000.imageset/passions_000.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_000.imageset/passions_000.png new file mode 100644 index 0000000..37d2098 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_000.imageset/passions_000.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_001.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_001.imageset/Contents.json new file mode 100644 index 0000000..c0182e7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_001.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_001.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_001.imageset/passions_001.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_001.imageset/passions_001.png new file mode 100644 index 0000000..09808f9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_001.imageset/passions_001.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_002.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_002.imageset/Contents.json new file mode 100644 index 0000000..9ff876d --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_002.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_002.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_002.imageset/passions_002.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_002.imageset/passions_002.png new file mode 100644 index 0000000..a0d45ab Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_002.imageset/passions_002.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_003.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_003.imageset/Contents.json new file mode 100644 index 0000000..a5f1559 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_003.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_003.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_003.imageset/passions_003.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_003.imageset/passions_003.png new file mode 100644 index 0000000..106fa62 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_003.imageset/passions_003.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_004.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_004.imageset/Contents.json new file mode 100644 index 0000000..c5b2798 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_004.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_004.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_004.imageset/passions_004.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_004.imageset/passions_004.png new file mode 100644 index 0000000..ab9d871 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_004.imageset/passions_004.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_005.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_005.imageset/Contents.json new file mode 100644 index 0000000..57b3038 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_005.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_005.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_005.imageset/passions_005.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_005.imageset/passions_005.png new file mode 100644 index 0000000..23cd99a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_005.imageset/passions_005.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_006.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_006.imageset/Contents.json new file mode 100644 index 0000000..15a49eb --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_006.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_006.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_006.imageset/passions_006.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_006.imageset/passions_006.png new file mode 100644 index 0000000..a229265 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_006.imageset/passions_006.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_007.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_007.imageset/Contents.json new file mode 100644 index 0000000..d0f9e24 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_007.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_007.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_007.imageset/passions_007.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_007.imageset/passions_007.png new file mode 100644 index 0000000..e735f2b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_007.imageset/passions_007.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_008.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_008.imageset/Contents.json new file mode 100644 index 0000000..55f9005 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_008.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_008.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_008.imageset/passions_008.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_008.imageset/passions_008.png new file mode 100644 index 0000000..7a7c947 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_008.imageset/passions_008.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_009.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_009.imageset/Contents.json new file mode 100644 index 0000000..248a3bb --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_009.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_009.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_009.imageset/passions_009.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_009.imageset/passions_009.png new file mode 100644 index 0000000..91ea1b4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_009.imageset/passions_009.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_010.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_010.imageset/Contents.json new file mode 100644 index 0000000..38d8cd3 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_010.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_010.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_010.imageset/passions_010.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_010.imageset/passions_010.png new file mode 100644 index 0000000..bd3f913 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_010.imageset/passions_010.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_011.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_011.imageset/Contents.json new file mode 100644 index 0000000..1abcadb --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_011.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_011.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_011.imageset/passions_011.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_011.imageset/passions_011.png new file mode 100644 index 0000000..24e9c1c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_011.imageset/passions_011.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_012.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_012.imageset/Contents.json new file mode 100644 index 0000000..29df10f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_012.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_012.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_012.imageset/passions_012.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_012.imageset/passions_012.png new file mode 100644 index 0000000..8e2bcab Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_012.imageset/passions_012.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_013.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_013.imageset/Contents.json new file mode 100644 index 0000000..ec2782b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_013.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_013.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_013.imageset/passions_013.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_013.imageset/passions_013.png new file mode 100644 index 0000000..680be7e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_013.imageset/passions_013.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_014.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_014.imageset/Contents.json new file mode 100644 index 0000000..c46e7ed --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_014.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_014.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_014.imageset/passions_014.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_014.imageset/passions_014.png new file mode 100644 index 0000000..8515ee0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_014.imageset/passions_014.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_015.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_015.imageset/Contents.json new file mode 100644 index 0000000..5495a25 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_015.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_015.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_015.imageset/passions_015.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_015.imageset/passions_015.png new file mode 100644 index 0000000..4bca564 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_015.imageset/passions_015.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_016.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_016.imageset/Contents.json new file mode 100644 index 0000000..f92e067 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_016.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_016.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_016.imageset/passions_016.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_016.imageset/passions_016.png new file mode 100644 index 0000000..51515fc Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_016.imageset/passions_016.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_017.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_017.imageset/Contents.json new file mode 100644 index 0000000..1e8cce6 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_017.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_017.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_017.imageset/passions_017.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_017.imageset/passions_017.png new file mode 100644 index 0000000..e73a26d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_017.imageset/passions_017.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_018.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_018.imageset/Contents.json new file mode 100644 index 0000000..eca19b5 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_018.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_018.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_018.imageset/passions_018.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_018.imageset/passions_018.png new file mode 100644 index 0000000..f462c49 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_018.imageset/passions_018.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_019.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_019.imageset/Contents.json new file mode 100644 index 0000000..969a307 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_019.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_019.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_019.imageset/passions_019.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_019.imageset/passions_019.png new file mode 100644 index 0000000..512e449 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_019.imageset/passions_019.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_020.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_020.imageset/Contents.json new file mode 100644 index 0000000..e31b44f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_020.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_020.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_020.imageset/passions_020.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_020.imageset/passions_020.png new file mode 100644 index 0000000..2969734 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_020.imageset/passions_020.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_021.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_021.imageset/Contents.json new file mode 100644 index 0000000..3e6c5f5 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_021.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_021.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_021.imageset/passions_021.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_021.imageset/passions_021.png new file mode 100644 index 0000000..6e1f82e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_021.imageset/passions_021.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_022.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_022.imageset/Contents.json new file mode 100644 index 0000000..90232ca --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_022.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_022.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_022.imageset/passions_022.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_022.imageset/passions_022.png new file mode 100644 index 0000000..db0b4a9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_022.imageset/passions_022.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_023.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_023.imageset/Contents.json new file mode 100644 index 0000000..9088dbe --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_023.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_023.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_023.imageset/passions_023.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_023.imageset/passions_023.png new file mode 100644 index 0000000..03449f2 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_023.imageset/passions_023.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_024.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_024.imageset/Contents.json new file mode 100644 index 0000000..5afaba3 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_024.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_024.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_024.imageset/passions_024.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_024.imageset/passions_024.png new file mode 100644 index 0000000..15d6344 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_024.imageset/passions_024.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_025.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_025.imageset/Contents.json new file mode 100644 index 0000000..6c8681c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_025.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_025.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_025.imageset/passions_025.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_025.imageset/passions_025.png new file mode 100644 index 0000000..10ec84a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_025.imageset/passions_025.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_026.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_026.imageset/Contents.json new file mode 100644 index 0000000..89c326b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_026.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_026.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_026.imageset/passions_026.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_026.imageset/passions_026.png new file mode 100644 index 0000000..50c018b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_026.imageset/passions_026.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_027.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_027.imageset/Contents.json new file mode 100644 index 0000000..d915b44 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_027.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_027.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_027.imageset/passions_027.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_027.imageset/passions_027.png new file mode 100644 index 0000000..790915f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_027.imageset/passions_027.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_028.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_028.imageset/Contents.json new file mode 100644 index 0000000..2cffe10 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_028.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_028.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_028.imageset/passions_028.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_028.imageset/passions_028.png new file mode 100644 index 0000000..b34efee Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_028.imageset/passions_028.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_029.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_029.imageset/Contents.json new file mode 100644 index 0000000..fa258e0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_029.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_029.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_029.imageset/passions_029.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_029.imageset/passions_029.png new file mode 100644 index 0000000..47ac798 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_029.imageset/passions_029.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_030.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_030.imageset/Contents.json new file mode 100644 index 0000000..443c2a0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_030.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_030.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_030.imageset/passions_030.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_030.imageset/passions_030.png new file mode 100644 index 0000000..1a6439e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_030.imageset/passions_030.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_031.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_031.imageset/Contents.json new file mode 100644 index 0000000..d07388a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_031.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_031.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_031.imageset/passions_031.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_031.imageset/passions_031.png new file mode 100644 index 0000000..cd0a8b1 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_031.imageset/passions_031.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_032.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_032.imageset/Contents.json new file mode 100644 index 0000000..f53d1cb --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_032.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_032.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_032.imageset/passions_032.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_032.imageset/passions_032.png new file mode 100644 index 0000000..72deab7 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_032.imageset/passions_032.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_033.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_033.imageset/Contents.json new file mode 100644 index 0000000..532f9cf --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_033.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_033.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_033.imageset/passions_033.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_033.imageset/passions_033.png new file mode 100644 index 0000000..3366295 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_033.imageset/passions_033.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_034.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_034.imageset/Contents.json new file mode 100644 index 0000000..d2d6385 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_034.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_034.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_034.imageset/passions_034.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_034.imageset/passions_034.png new file mode 100644 index 0000000..41bef47 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_034.imageset/passions_034.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_035.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_035.imageset/Contents.json new file mode 100644 index 0000000..74b4fe8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_035.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_035.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_035.imageset/passions_035.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_035.imageset/passions_035.png new file mode 100644 index 0000000..6c550f6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_035.imageset/passions_035.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_036.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_036.imageset/Contents.json new file mode 100644 index 0000000..13a2545 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_036.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_036.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_036.imageset/passions_036.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_036.imageset/passions_036.png new file mode 100644 index 0000000..6650a20 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_036.imageset/passions_036.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_037.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_037.imageset/Contents.json new file mode 100644 index 0000000..5c34079 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_037.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_037.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_037.imageset/passions_037.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_037.imageset/passions_037.png new file mode 100644 index 0000000..6fc506f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_037.imageset/passions_037.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_038.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_038.imageset/Contents.json new file mode 100644 index 0000000..8abeb80 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_038.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_038.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_038.imageset/passions_038.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_038.imageset/passions_038.png new file mode 100644 index 0000000..7e6545f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_038.imageset/passions_038.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_039.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_039.imageset/Contents.json new file mode 100644 index 0000000..ac652b5 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_039.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_039.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_039.imageset/passions_039.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_039.imageset/passions_039.png new file mode 100644 index 0000000..3d65e32 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_039.imageset/passions_039.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_040.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_040.imageset/Contents.json new file mode 100644 index 0000000..e2aaff2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_040.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_040.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_040.imageset/passions_040.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_040.imageset/passions_040.png new file mode 100644 index 0000000..15cb60c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_040.imageset/passions_040.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_041.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_041.imageset/Contents.json new file mode 100644 index 0000000..109f17f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_041.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_041.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_041.imageset/passions_041.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_041.imageset/passions_041.png new file mode 100644 index 0000000..cc2919f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_041.imageset/passions_041.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_042.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_042.imageset/Contents.json new file mode 100644 index 0000000..8857c03 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_042.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_042.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_042.imageset/passions_042.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_042.imageset/passions_042.png new file mode 100644 index 0000000..c53b67a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_042.imageset/passions_042.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_043.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_043.imageset/Contents.json new file mode 100644 index 0000000..90c89c8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_043.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_043.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_043.imageset/passions_043.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_043.imageset/passions_043.png new file mode 100644 index 0000000..f34dfe7 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_043.imageset/passions_043.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_044.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_044.imageset/Contents.json new file mode 100644 index 0000000..f919509 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_044.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_044.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_044.imageset/passions_044.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_044.imageset/passions_044.png new file mode 100644 index 0000000..caccefc Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_044.imageset/passions_044.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_045.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_045.imageset/Contents.json new file mode 100644 index 0000000..e2c7df2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_045.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_045.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_045.imageset/passions_045.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_045.imageset/passions_045.png new file mode 100644 index 0000000..351f2d8 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_045.imageset/passions_045.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_046.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_046.imageset/Contents.json new file mode 100644 index 0000000..0455950 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_046.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_046.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_046.imageset/passions_046.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_046.imageset/passions_046.png new file mode 100644 index 0000000..5bd297b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_046.imageset/passions_046.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_047.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_047.imageset/Contents.json new file mode 100644 index 0000000..3bf0827 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_047.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_047.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_047.imageset/passions_047.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_047.imageset/passions_047.png new file mode 100644 index 0000000..010985e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_047.imageset/passions_047.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_048.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_048.imageset/Contents.json new file mode 100644 index 0000000..5158ee1 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_048.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_048.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_048.imageset/passions_048.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_048.imageset/passions_048.png new file mode 100644 index 0000000..da74354 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_048.imageset/passions_048.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_049.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_049.imageset/Contents.json new file mode 100644 index 0000000..ae5ec4c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_049.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_049.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_049.imageset/passions_049.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_049.imageset/passions_049.png new file mode 100644 index 0000000..e4a089a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_049.imageset/passions_049.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_050.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_050.imageset/Contents.json new file mode 100644 index 0000000..84efcc8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_050.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_050.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_050.imageset/passions_050.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_050.imageset/passions_050.png new file mode 100644 index 0000000..14dcda6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_050.imageset/passions_050.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_051.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_051.imageset/Contents.json new file mode 100644 index 0000000..a2baed1 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_051.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_051.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_051.imageset/passions_051.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_051.imageset/passions_051.png new file mode 100644 index 0000000..41a1016 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_051.imageset/passions_051.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_052.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_052.imageset/Contents.json new file mode 100644 index 0000000..15f69f4 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_052.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_052.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_052.imageset/passions_052.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_052.imageset/passions_052.png new file mode 100644 index 0000000..bf17ce6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_052.imageset/passions_052.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_053.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_053.imageset/Contents.json new file mode 100644 index 0000000..d64ebea --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_053.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_053.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_053.imageset/passions_053.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_053.imageset/passions_053.png new file mode 100644 index 0000000..dd87a5f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_053.imageset/passions_053.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_054.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_054.imageset/Contents.json new file mode 100644 index 0000000..38a2121 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_054.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_054.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_054.imageset/passions_054.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_054.imageset/passions_054.png new file mode 100644 index 0000000..5b38e18 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_054.imageset/passions_054.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_055.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_055.imageset/Contents.json new file mode 100644 index 0000000..cb5c83c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_055.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_055.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_055.imageset/passions_055.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_055.imageset/passions_055.png new file mode 100644 index 0000000..38f6d72 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_055.imageset/passions_055.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_056.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_056.imageset/Contents.json new file mode 100644 index 0000000..2c388cc --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_056.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_056.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_056.imageset/passions_056.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_056.imageset/passions_056.png new file mode 100644 index 0000000..82289e6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_056.imageset/passions_056.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_057.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_057.imageset/Contents.json new file mode 100644 index 0000000..3a105ac --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_057.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_057.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_057.imageset/passions_057.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_057.imageset/passions_057.png new file mode 100644 index 0000000..6d1ae77 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_057.imageset/passions_057.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_058.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_058.imageset/Contents.json new file mode 100644 index 0000000..dfc3443 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_058.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_058.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_058.imageset/passions_058.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_058.imageset/passions_058.png new file mode 100644 index 0000000..eabeacb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_058.imageset/passions_058.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_059.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_059.imageset/Contents.json new file mode 100644 index 0000000..5593a45 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_059.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_059.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_059.imageset/passions_059.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_059.imageset/passions_059.png new file mode 100644 index 0000000..0595c56 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_059.imageset/passions_059.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_060.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_060.imageset/Contents.json new file mode 100644 index 0000000..49eb115 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_060.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_060.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_060.imageset/passions_060.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_060.imageset/passions_060.png new file mode 100644 index 0000000..8a2284a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_060.imageset/passions_060.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_061.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_061.imageset/Contents.json new file mode 100644 index 0000000..45e091a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_061.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "passions_061.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_061.imageset/passions_061.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_061.imageset/passions_061.png new file mode 100644 index 0000000..ffa180b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/passions_061.imageset/passions_061.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_000.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_000.imageset/Contents.json new file mode 100644 index 0000000..a0c4772 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_000.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_000.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_000.imageset/smileys_000.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_000.imageset/smileys_000.png new file mode 100644 index 0000000..5c2536d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_000.imageset/smileys_000.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_001.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_001.imageset/Contents.json new file mode 100644 index 0000000..2f1492a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_001.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_001.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_001.imageset/smileys_001.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_001.imageset/smileys_001.png new file mode 100644 index 0000000..5d4a8ef Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_001.imageset/smileys_001.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_002.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_002.imageset/Contents.json new file mode 100644 index 0000000..34e5807 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_002.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_002.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_002.imageset/smileys_002.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_002.imageset/smileys_002.png new file mode 100644 index 0000000..223bad4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_002.imageset/smileys_002.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_003.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_003.imageset/Contents.json new file mode 100644 index 0000000..45b95a0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_003.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_003.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_003.imageset/smileys_003.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_003.imageset/smileys_003.png new file mode 100644 index 0000000..07a3f0f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_003.imageset/smileys_003.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_004.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_004.imageset/Contents.json new file mode 100644 index 0000000..3f0188d --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_004.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_004.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_004.imageset/smileys_004.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_004.imageset/smileys_004.png new file mode 100644 index 0000000..b271423 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_004.imageset/smileys_004.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_005.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_005.imageset/Contents.json new file mode 100644 index 0000000..c7c425c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_005.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_005.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_005.imageset/smileys_005.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_005.imageset/smileys_005.png new file mode 100644 index 0000000..11d4162 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_005.imageset/smileys_005.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_006.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_006.imageset/Contents.json new file mode 100644 index 0000000..9d5f21b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_006.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_006.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_006.imageset/smileys_006.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_006.imageset/smileys_006.png new file mode 100644 index 0000000..ef7e92e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_006.imageset/smileys_006.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_007.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_007.imageset/Contents.json new file mode 100644 index 0000000..3411d77 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_007.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_007.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_007.imageset/smileys_007.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_007.imageset/smileys_007.png new file mode 100644 index 0000000..c2ec07c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_007.imageset/smileys_007.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_008.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_008.imageset/Contents.json new file mode 100644 index 0000000..5eb3b4d --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_008.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_008.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_008.imageset/smileys_008.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_008.imageset/smileys_008.png new file mode 100644 index 0000000..f87654b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_008.imageset/smileys_008.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_009.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_009.imageset/Contents.json new file mode 100644 index 0000000..1cd1025 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_009.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_009.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_009.imageset/smileys_009.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_009.imageset/smileys_009.png new file mode 100644 index 0000000..7e3b173 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_009.imageset/smileys_009.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_010.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_010.imageset/Contents.json new file mode 100644 index 0000000..e247c51 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_010.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_010.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_010.imageset/smileys_010.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_010.imageset/smileys_010.png new file mode 100644 index 0000000..1b47f38 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_010.imageset/smileys_010.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_011.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_011.imageset/Contents.json new file mode 100644 index 0000000..ea3a7cf --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_011.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_011.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_011.imageset/smileys_011.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_011.imageset/smileys_011.png new file mode 100644 index 0000000..a06b705 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_011.imageset/smileys_011.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_012.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_012.imageset/Contents.json new file mode 100644 index 0000000..85cd23b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_012.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_012.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_012.imageset/smileys_012.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_012.imageset/smileys_012.png new file mode 100644 index 0000000..4b737f8 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_012.imageset/smileys_012.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_013.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_013.imageset/Contents.json new file mode 100644 index 0000000..af7b15d --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_013.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_013.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_013.imageset/smileys_013.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_013.imageset/smileys_013.png new file mode 100644 index 0000000..b56a729 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_013.imageset/smileys_013.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_014.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_014.imageset/Contents.json new file mode 100644 index 0000000..c58c300 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_014.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_014.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_014.imageset/smileys_014.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_014.imageset/smileys_014.png new file mode 100644 index 0000000..7d3b335 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_014.imageset/smileys_014.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_015.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_015.imageset/Contents.json new file mode 100644 index 0000000..d60ec4a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_015.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_015.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_015.imageset/smileys_015.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_015.imageset/smileys_015.png new file mode 100644 index 0000000..c0cca29 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_015.imageset/smileys_015.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_016.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_016.imageset/Contents.json new file mode 100644 index 0000000..25f09bb --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_016.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_016.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_016.imageset/smileys_016.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_016.imageset/smileys_016.png new file mode 100644 index 0000000..cba49ab Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_016.imageset/smileys_016.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_017.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_017.imageset/Contents.json new file mode 100644 index 0000000..2595316 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_017.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_017.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_017.imageset/smileys_017.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_017.imageset/smileys_017.png new file mode 100644 index 0000000..1b3a42c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_017.imageset/smileys_017.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_018.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_018.imageset/Contents.json new file mode 100644 index 0000000..2a19d4d --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_018.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_018.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_018.imageset/smileys_018.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_018.imageset/smileys_018.png new file mode 100644 index 0000000..80f59d8 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_018.imageset/smileys_018.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_019.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_019.imageset/Contents.json new file mode 100644 index 0000000..e768666 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_019.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_019.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_019.imageset/smileys_019.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_019.imageset/smileys_019.png new file mode 100644 index 0000000..69acd07 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_019.imageset/smileys_019.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_020.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_020.imageset/Contents.json new file mode 100644 index 0000000..f8be15a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_020.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_020.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_020.imageset/smileys_020.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_020.imageset/smileys_020.png new file mode 100644 index 0000000..70fe41d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_020.imageset/smileys_020.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_021.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_021.imageset/Contents.json new file mode 100644 index 0000000..fc225ca --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_021.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_021.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_021.imageset/smileys_021.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_021.imageset/smileys_021.png new file mode 100644 index 0000000..8a80383 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_021.imageset/smileys_021.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_022.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_022.imageset/Contents.json new file mode 100644 index 0000000..a3793f3 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_022.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_022.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_022.imageset/smileys_022.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_022.imageset/smileys_022.png new file mode 100644 index 0000000..ba40abd Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_022.imageset/smileys_022.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_023.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_023.imageset/Contents.json new file mode 100644 index 0000000..74214c0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_023.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_023.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_023.imageset/smileys_023.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_023.imageset/smileys_023.png new file mode 100644 index 0000000..2416e17 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_023.imageset/smileys_023.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_024.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_024.imageset/Contents.json new file mode 100644 index 0000000..ce853de --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_024.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_024.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_024.imageset/smileys_024.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_024.imageset/smileys_024.png new file mode 100644 index 0000000..dd91e30 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_024.imageset/smileys_024.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_025.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_025.imageset/Contents.json new file mode 100644 index 0000000..b55c508 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_025.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_025.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_025.imageset/smileys_025.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_025.imageset/smileys_025.png new file mode 100644 index 0000000..c8fa4bd Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_025.imageset/smileys_025.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_026.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_026.imageset/Contents.json new file mode 100644 index 0000000..b31bdf9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_026.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_026.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_026.imageset/smileys_026.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_026.imageset/smileys_026.png new file mode 100644 index 0000000..ae7f9ef Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_026.imageset/smileys_026.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_027.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_027.imageset/Contents.json new file mode 100644 index 0000000..f7e7833 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_027.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_027.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_027.imageset/smileys_027.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_027.imageset/smileys_027.png new file mode 100644 index 0000000..6177a00 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_027.imageset/smileys_027.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_028.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_028.imageset/Contents.json new file mode 100644 index 0000000..ec35da8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_028.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_028.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_028.imageset/smileys_028.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_028.imageset/smileys_028.png new file mode 100644 index 0000000..c80e724 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_028.imageset/smileys_028.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_029.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_029.imageset/Contents.json new file mode 100644 index 0000000..78b1305 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_029.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_029.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_029.imageset/smileys_029.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_029.imageset/smileys_029.png new file mode 100644 index 0000000..9d2f0ec Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_029.imageset/smileys_029.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_030.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_030.imageset/Contents.json new file mode 100644 index 0000000..3686503 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_030.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_030.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_030.imageset/smileys_030.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_030.imageset/smileys_030.png new file mode 100644 index 0000000..66a2d07 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_030.imageset/smileys_030.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_031.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_031.imageset/Contents.json new file mode 100644 index 0000000..7d6b9dd --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_031.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_031.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_031.imageset/smileys_031.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_031.imageset/smileys_031.png new file mode 100644 index 0000000..ba8f446 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_031.imageset/smileys_031.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_032.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_032.imageset/Contents.json new file mode 100644 index 0000000..e60e60f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_032.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_032.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_032.imageset/smileys_032.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_032.imageset/smileys_032.png new file mode 100644 index 0000000..e01254c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_032.imageset/smileys_032.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_033.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_033.imageset/Contents.json new file mode 100644 index 0000000..f47f133 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_033.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_033.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_033.imageset/smileys_033.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_033.imageset/smileys_033.png new file mode 100644 index 0000000..6ededa3 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_033.imageset/smileys_033.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_034.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_034.imageset/Contents.json new file mode 100644 index 0000000..b439cb8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_034.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_034.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_034.imageset/smileys_034.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_034.imageset/smileys_034.png new file mode 100644 index 0000000..8e5d741 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_034.imageset/smileys_034.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_035.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_035.imageset/Contents.json new file mode 100644 index 0000000..0ebe120 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_035.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_035.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_035.imageset/smileys_035.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_035.imageset/smileys_035.png new file mode 100644 index 0000000..67a3519 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_035.imageset/smileys_035.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_036.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_036.imageset/Contents.json new file mode 100644 index 0000000..a57e76f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_036.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_036.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_036.imageset/smileys_036.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_036.imageset/smileys_036.png new file mode 100644 index 0000000..67e0d55 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_036.imageset/smileys_036.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_037.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_037.imageset/Contents.json new file mode 100644 index 0000000..d35b47a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_037.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_037.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_037.imageset/smileys_037.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_037.imageset/smileys_037.png new file mode 100644 index 0000000..1ec4b13 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_037.imageset/smileys_037.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_038.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_038.imageset/Contents.json new file mode 100644 index 0000000..1d10070 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_038.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_038.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_038.imageset/smileys_038.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_038.imageset/smileys_038.png new file mode 100644 index 0000000..49e572b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_038.imageset/smileys_038.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_039.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_039.imageset/Contents.json new file mode 100644 index 0000000..e90525f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_039.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_039.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_039.imageset/smileys_039.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_039.imageset/smileys_039.png new file mode 100644 index 0000000..0954c53 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_039.imageset/smileys_039.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_040.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_040.imageset/Contents.json new file mode 100644 index 0000000..c6fc6ab --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_040.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_040.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_040.imageset/smileys_040.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_040.imageset/smileys_040.png new file mode 100644 index 0000000..0d7ad69 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_040.imageset/smileys_040.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_041.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_041.imageset/Contents.json new file mode 100644 index 0000000..7291baa --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_041.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_041.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_041.imageset/smileys_041.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_041.imageset/smileys_041.png new file mode 100644 index 0000000..915a4a4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_041.imageset/smileys_041.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_042.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_042.imageset/Contents.json new file mode 100644 index 0000000..7829489 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_042.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_042.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_042.imageset/smileys_042.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_042.imageset/smileys_042.png new file mode 100644 index 0000000..865b5e2 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_042.imageset/smileys_042.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_043.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_043.imageset/Contents.json new file mode 100644 index 0000000..c632394 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_043.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_043.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_043.imageset/smileys_043.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_043.imageset/smileys_043.png new file mode 100644 index 0000000..888e34b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_043.imageset/smileys_043.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_044.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_044.imageset/Contents.json new file mode 100644 index 0000000..9686195 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_044.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_044.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_044.imageset/smileys_044.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_044.imageset/smileys_044.png new file mode 100644 index 0000000..fb9288f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_044.imageset/smileys_044.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_045.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_045.imageset/Contents.json new file mode 100644 index 0000000..e26e4ba --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_045.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_045.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_045.imageset/smileys_045.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_045.imageset/smileys_045.png new file mode 100644 index 0000000..65db321 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_045.imageset/smileys_045.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_046.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_046.imageset/Contents.json new file mode 100644 index 0000000..49570c6 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_046.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_046.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_046.imageset/smileys_046.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_046.imageset/smileys_046.png new file mode 100644 index 0000000..b1193e4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_046.imageset/smileys_046.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_047.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_047.imageset/Contents.json new file mode 100644 index 0000000..7b029b3 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_047.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_047.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_047.imageset/smileys_047.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_047.imageset/smileys_047.png new file mode 100644 index 0000000..3939919 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_047.imageset/smileys_047.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_048.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_048.imageset/Contents.json new file mode 100644 index 0000000..d67e383 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_048.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_048.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_048.imageset/smileys_048.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_048.imageset/smileys_048.png new file mode 100644 index 0000000..c5c1d48 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_048.imageset/smileys_048.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_049.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_049.imageset/Contents.json new file mode 100644 index 0000000..c254a87 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_049.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_049.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_049.imageset/smileys_049.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_049.imageset/smileys_049.png new file mode 100644 index 0000000..b06faca Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_049.imageset/smileys_049.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_050.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_050.imageset/Contents.json new file mode 100644 index 0000000..ab346a2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_050.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_050.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_050.imageset/smileys_050.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_050.imageset/smileys_050.png new file mode 100644 index 0000000..c6a35d3 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_050.imageset/smileys_050.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_051.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_051.imageset/Contents.json new file mode 100644 index 0000000..2b2b89e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_051.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_051.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_051.imageset/smileys_051.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_051.imageset/smileys_051.png new file mode 100644 index 0000000..0ae9bae Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_051.imageset/smileys_051.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_052.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_052.imageset/Contents.json new file mode 100644 index 0000000..eed1bee --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_052.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_052.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_052.imageset/smileys_052.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_052.imageset/smileys_052.png new file mode 100644 index 0000000..cabb5d2 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_052.imageset/smileys_052.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_053.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_053.imageset/Contents.json new file mode 100644 index 0000000..292fc6f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_053.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_053.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_053.imageset/smileys_053.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_053.imageset/smileys_053.png new file mode 100644 index 0000000..ea02c1b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_053.imageset/smileys_053.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_054.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_054.imageset/Contents.json new file mode 100644 index 0000000..f2aac02 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_054.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_054.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_054.imageset/smileys_054.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_054.imageset/smileys_054.png new file mode 100644 index 0000000..b197aa2 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_054.imageset/smileys_054.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_055.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_055.imageset/Contents.json new file mode 100644 index 0000000..a3f74b7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_055.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_055.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_055.imageset/smileys_055.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_055.imageset/smileys_055.png new file mode 100644 index 0000000..ce1735a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_055.imageset/smileys_055.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_056.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_056.imageset/Contents.json new file mode 100644 index 0000000..cea911a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_056.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_056.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_056.imageset/smileys_056.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_056.imageset/smileys_056.png new file mode 100644 index 0000000..37e7903 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_056.imageset/smileys_056.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_057.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_057.imageset/Contents.json new file mode 100644 index 0000000..fe64796 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_057.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_057.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_057.imageset/smileys_057.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_057.imageset/smileys_057.png new file mode 100644 index 0000000..1567dc4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_057.imageset/smileys_057.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_058.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_058.imageset/Contents.json new file mode 100644 index 0000000..9a3bf1a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_058.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_058.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_058.imageset/smileys_058.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_058.imageset/smileys_058.png new file mode 100644 index 0000000..97d9935 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_058.imageset/smileys_058.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_059.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_059.imageset/Contents.json new file mode 100644 index 0000000..ad4ac84 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_059.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_059.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_059.imageset/smileys_059.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_059.imageset/smileys_059.png new file mode 100644 index 0000000..c6c8e3b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_059.imageset/smileys_059.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_060.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_060.imageset/Contents.json new file mode 100644 index 0000000..2f18716 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_060.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_060.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_060.imageset/smileys_060.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_060.imageset/smileys_060.png new file mode 100644 index 0000000..6aebd29 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_060.imageset/smileys_060.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_061.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_061.imageset/Contents.json new file mode 100644 index 0000000..8334cf4 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_061.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_061.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_061.imageset/smileys_061.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_061.imageset/smileys_061.png new file mode 100644 index 0000000..3a04856 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_061.imageset/smileys_061.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_062.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_062.imageset/Contents.json new file mode 100644 index 0000000..9f2e6cf --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_062.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_062.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_062.imageset/smileys_062.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_062.imageset/smileys_062.png new file mode 100644 index 0000000..ba06091 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_062.imageset/smileys_062.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_063.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_063.imageset/Contents.json new file mode 100644 index 0000000..3e0aa65 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_063.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_063.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_063.imageset/smileys_063.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_063.imageset/smileys_063.png new file mode 100644 index 0000000..97fc0f4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_063.imageset/smileys_063.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_064.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_064.imageset/Contents.json new file mode 100644 index 0000000..c0b91bd --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_064.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_064.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_064.imageset/smileys_064.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_064.imageset/smileys_064.png new file mode 100644 index 0000000..13936b9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_064.imageset/smileys_064.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_065.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_065.imageset/Contents.json new file mode 100644 index 0000000..6e7eba6 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_065.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_065.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_065.imageset/smileys_065.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_065.imageset/smileys_065.png new file mode 100644 index 0000000..897864a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_065.imageset/smileys_065.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_066.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_066.imageset/Contents.json new file mode 100644 index 0000000..8e4982f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_066.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_066.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_066.imageset/smileys_066.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_066.imageset/smileys_066.png new file mode 100644 index 0000000..d317663 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_066.imageset/smileys_066.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_067.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_067.imageset/Contents.json new file mode 100644 index 0000000..e833167 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_067.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_067.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_067.imageset/smileys_067.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_067.imageset/smileys_067.png new file mode 100644 index 0000000..7ff785b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_067.imageset/smileys_067.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_068.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_068.imageset/Contents.json new file mode 100644 index 0000000..3557874 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_068.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_068.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_068.imageset/smileys_068.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_068.imageset/smileys_068.png new file mode 100644 index 0000000..0be736e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_068.imageset/smileys_068.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_069.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_069.imageset/Contents.json new file mode 100644 index 0000000..3055f48 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_069.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_069.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_069.imageset/smileys_069.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_069.imageset/smileys_069.png new file mode 100644 index 0000000..7dc2b8c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_069.imageset/smileys_069.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_070.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_070.imageset/Contents.json new file mode 100644 index 0000000..47c918f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_070.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_070.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_070.imageset/smileys_070.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_070.imageset/smileys_070.png new file mode 100644 index 0000000..3a3ac38 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_070.imageset/smileys_070.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_071.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_071.imageset/Contents.json new file mode 100644 index 0000000..62dfdbd --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_071.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_071.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_071.imageset/smileys_071.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_071.imageset/smileys_071.png new file mode 100644 index 0000000..19173cb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_071.imageset/smileys_071.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_072.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_072.imageset/Contents.json new file mode 100644 index 0000000..5b7ef2b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_072.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_072.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_072.imageset/smileys_072.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_072.imageset/smileys_072.png new file mode 100644 index 0000000..7597d50 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_072.imageset/smileys_072.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_073.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_073.imageset/Contents.json new file mode 100644 index 0000000..83f4874 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_073.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_073.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_073.imageset/smileys_073.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_073.imageset/smileys_073.png new file mode 100644 index 0000000..ad9c2f6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_073.imageset/smileys_073.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_074.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_074.imageset/Contents.json new file mode 100644 index 0000000..568c658 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_074.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_074.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_074.imageset/smileys_074.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_074.imageset/smileys_074.png new file mode 100644 index 0000000..c5e0fcb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_074.imageset/smileys_074.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_075.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_075.imageset/Contents.json new file mode 100644 index 0000000..43ebc2b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_075.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_075.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_075.imageset/smileys_075.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_075.imageset/smileys_075.png new file mode 100644 index 0000000..a81e363 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_075.imageset/smileys_075.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_076.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_076.imageset/Contents.json new file mode 100644 index 0000000..fac7109 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_076.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_076.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_076.imageset/smileys_076.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_076.imageset/smileys_076.png new file mode 100644 index 0000000..90e4f98 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_076.imageset/smileys_076.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_077.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_077.imageset/Contents.json new file mode 100644 index 0000000..188354a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_077.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_077.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_077.imageset/smileys_077.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_077.imageset/smileys_077.png new file mode 100644 index 0000000..f20fd6a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_077.imageset/smileys_077.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_078.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_078.imageset/Contents.json new file mode 100644 index 0000000..11c381f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_078.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_078.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_078.imageset/smileys_078.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_078.imageset/smileys_078.png new file mode 100644 index 0000000..ed92118 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_078.imageset/smileys_078.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_079.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_079.imageset/Contents.json new file mode 100644 index 0000000..391dc22 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_079.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_079.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_079.imageset/smileys_079.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_079.imageset/smileys_079.png new file mode 100644 index 0000000..970163c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_079.imageset/smileys_079.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_080.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_080.imageset/Contents.json new file mode 100644 index 0000000..00dc1b2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_080.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_080.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_080.imageset/smileys_080.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_080.imageset/smileys_080.png new file mode 100644 index 0000000..0bb9e83 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_080.imageset/smileys_080.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_081.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_081.imageset/Contents.json new file mode 100644 index 0000000..fe78abe --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_081.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_081.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_081.imageset/smileys_081.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_081.imageset/smileys_081.png new file mode 100644 index 0000000..20d63ba Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_081.imageset/smileys_081.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_082.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_082.imageset/Contents.json new file mode 100644 index 0000000..78cf3ec --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_082.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "smileys_082.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_082.imageset/smileys_082.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_082.imageset/smileys_082.png new file mode 100644 index 0000000..35d935a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/smileys_082.imageset/smileys_082.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_000.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_000.imageset/Contents.json new file mode 100644 index 0000000..2330f66 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_000.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_000.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_000.imageset/sticker_000.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_000.imageset/sticker_000.png new file mode 100644 index 0000000..9679831 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_000.imageset/sticker_000.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_001.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_001.imageset/Contents.json new file mode 100644 index 0000000..4b3d537 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_001.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_001.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_001.imageset/sticker_001.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_001.imageset/sticker_001.png new file mode 100644 index 0000000..256288f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_001.imageset/sticker_001.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_002.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_002.imageset/Contents.json new file mode 100644 index 0000000..afe57b7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_002.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_002.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_002.imageset/sticker_002.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_002.imageset/sticker_002.png new file mode 100644 index 0000000..6b286d1 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_002.imageset/sticker_002.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_003.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_003.imageset/Contents.json new file mode 100644 index 0000000..6427426 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_003.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_003.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_003.imageset/sticker_003.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_003.imageset/sticker_003.png new file mode 100644 index 0000000..2730986 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_003.imageset/sticker_003.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_004.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_004.imageset/Contents.json new file mode 100644 index 0000000..32d5e6b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_004.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_004.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_004.imageset/sticker_004.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_004.imageset/sticker_004.png new file mode 100644 index 0000000..492d409 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_004.imageset/sticker_004.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_005.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_005.imageset/Contents.json new file mode 100644 index 0000000..c9ec4d2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_005.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_005.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_005.imageset/sticker_005.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_005.imageset/sticker_005.png new file mode 100644 index 0000000..2186e29 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_005.imageset/sticker_005.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_006.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_006.imageset/Contents.json new file mode 100644 index 0000000..8f90dfc --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_006.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_006.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_006.imageset/sticker_006.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_006.imageset/sticker_006.png new file mode 100644 index 0000000..d04ba0b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_006.imageset/sticker_006.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_007.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_007.imageset/Contents.json new file mode 100644 index 0000000..140beca --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_007.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_007.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_007.imageset/sticker_007.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_007.imageset/sticker_007.png new file mode 100644 index 0000000..536fce6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_007.imageset/sticker_007.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_008.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_008.imageset/Contents.json new file mode 100644 index 0000000..869aaed --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_008.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_008.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_008.imageset/sticker_008.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_008.imageset/sticker_008.png new file mode 100644 index 0000000..f4d1eac Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_008.imageset/sticker_008.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_009.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_009.imageset/Contents.json new file mode 100644 index 0000000..30c89b9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_009.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_009.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_009.imageset/sticker_009.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_009.imageset/sticker_009.png new file mode 100644 index 0000000..77aa1b0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_009.imageset/sticker_009.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_010.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_010.imageset/Contents.json new file mode 100644 index 0000000..60a229d --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_010.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_010.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_010.imageset/sticker_010.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_010.imageset/sticker_010.png new file mode 100644 index 0000000..0bd3a63 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_010.imageset/sticker_010.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_011.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_011.imageset/Contents.json new file mode 100644 index 0000000..02c20f0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_011.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_011.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_011.imageset/sticker_011.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_011.imageset/sticker_011.png new file mode 100644 index 0000000..07fcf26 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_011.imageset/sticker_011.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_012.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_012.imageset/Contents.json new file mode 100644 index 0000000..07cd64c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_012.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_012.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_012.imageset/sticker_012.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_012.imageset/sticker_012.png new file mode 100644 index 0000000..5d4ad7d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_012.imageset/sticker_012.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_013.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_013.imageset/Contents.json new file mode 100644 index 0000000..f420611 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_013.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_013.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_013.imageset/sticker_013.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_013.imageset/sticker_013.png new file mode 100644 index 0000000..f33ec15 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_013.imageset/sticker_013.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_014.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_014.imageset/Contents.json new file mode 100644 index 0000000..d9f2e05 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_014.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_014.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_014.imageset/sticker_014.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_014.imageset/sticker_014.png new file mode 100644 index 0000000..90546db Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_014.imageset/sticker_014.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_015.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_015.imageset/Contents.json new file mode 100644 index 0000000..2732a7f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_015.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_015.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_015.imageset/sticker_015.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_015.imageset/sticker_015.png new file mode 100644 index 0000000..a13677c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_015.imageset/sticker_015.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_016.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_016.imageset/Contents.json new file mode 100644 index 0000000..cab4499 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_016.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_016.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_016.imageset/sticker_016.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_016.imageset/sticker_016.png new file mode 100644 index 0000000..89850c8 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_016.imageset/sticker_016.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_017.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_017.imageset/Contents.json new file mode 100644 index 0000000..f6818ce --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_017.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_017.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_017.imageset/sticker_017.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_017.imageset/sticker_017.png new file mode 100644 index 0000000..b51432e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_017.imageset/sticker_017.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_018.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_018.imageset/Contents.json new file mode 100644 index 0000000..9ab357e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_018.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_018.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_018.imageset/sticker_018.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_018.imageset/sticker_018.png new file mode 100644 index 0000000..a62d4b9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_018.imageset/sticker_018.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_019.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_019.imageset/Contents.json new file mode 100644 index 0000000..5227219 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_019.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_019.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_019.imageset/sticker_019.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_019.imageset/sticker_019.png new file mode 100644 index 0000000..b32768d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_019.imageset/sticker_019.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_020.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_020.imageset/Contents.json new file mode 100644 index 0000000..4e59e62 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_020.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_020.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_020.imageset/sticker_020.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_020.imageset/sticker_020.png new file mode 100644 index 0000000..aefac17 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_020.imageset/sticker_020.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_021.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_021.imageset/Contents.json new file mode 100644 index 0000000..368c0ff --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_021.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_021.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_021.imageset/sticker_021.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_021.imageset/sticker_021.png new file mode 100644 index 0000000..c347bb4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_021.imageset/sticker_021.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_022.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_022.imageset/Contents.json new file mode 100644 index 0000000..0c0404a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_022.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_022.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_022.imageset/sticker_022.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_022.imageset/sticker_022.png new file mode 100644 index 0000000..25436cd Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_022.imageset/sticker_022.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_023.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_023.imageset/Contents.json new file mode 100644 index 0000000..883c7d3 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_023.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_023.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_023.imageset/sticker_023.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_023.imageset/sticker_023.png new file mode 100644 index 0000000..877fe36 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_023.imageset/sticker_023.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_024.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_024.imageset/Contents.json new file mode 100644 index 0000000..afe1364 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_024.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_024.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_024.imageset/sticker_024.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_024.imageset/sticker_024.png new file mode 100644 index 0000000..b013325 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_024.imageset/sticker_024.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_025.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_025.imageset/Contents.json new file mode 100644 index 0000000..43de963 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_025.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_025.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_025.imageset/sticker_025.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_025.imageset/sticker_025.png new file mode 100644 index 0000000..466ea58 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_025.imageset/sticker_025.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_026.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_026.imageset/Contents.json new file mode 100644 index 0000000..7331d8a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_026.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_026.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_026.imageset/sticker_026.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_026.imageset/sticker_026.png new file mode 100644 index 0000000..a65d85b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_026.imageset/sticker_026.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_027.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_027.imageset/Contents.json new file mode 100644 index 0000000..6f2d3ba --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_027.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_027.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_027.imageset/sticker_027.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_027.imageset/sticker_027.png new file mode 100644 index 0000000..bcff4cd Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_027.imageset/sticker_027.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_028.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_028.imageset/Contents.json new file mode 100644 index 0000000..dea0f4a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_028.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_028.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_028.imageset/sticker_028.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_028.imageset/sticker_028.png new file mode 100644 index 0000000..3027a2b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_028.imageset/sticker_028.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_029.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_029.imageset/Contents.json new file mode 100644 index 0000000..64308b4 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_029.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_029.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_029.imageset/sticker_029.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_029.imageset/sticker_029.png new file mode 100644 index 0000000..fcc24be Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_029.imageset/sticker_029.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_030.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_030.imageset/Contents.json new file mode 100644 index 0000000..7b37677 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_030.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_030.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_030.imageset/sticker_030.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_030.imageset/sticker_030.png new file mode 100644 index 0000000..37a7080 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_030.imageset/sticker_030.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_031.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_031.imageset/Contents.json new file mode 100644 index 0000000..60425d1 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_031.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_031.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_031.imageset/sticker_031.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_031.imageset/sticker_031.png new file mode 100644 index 0000000..64e1d84 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_031.imageset/sticker_031.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_032.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_032.imageset/Contents.json new file mode 100644 index 0000000..49ebfe9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_032.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_032.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_032.imageset/sticker_032.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_032.imageset/sticker_032.png new file mode 100644 index 0000000..6d9b797 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_032.imageset/sticker_032.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_033.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_033.imageset/Contents.json new file mode 100644 index 0000000..75dd745 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_033.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_033.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_033.imageset/sticker_033.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_033.imageset/sticker_033.png new file mode 100644 index 0000000..ccaa407 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_033.imageset/sticker_033.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_034.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_034.imageset/Contents.json new file mode 100644 index 0000000..d00b968 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_034.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_034.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_034.imageset/sticker_034.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_034.imageset/sticker_034.png new file mode 100644 index 0000000..515f3c0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_034.imageset/sticker_034.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_035.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_035.imageset/Contents.json new file mode 100644 index 0000000..92fc2ce --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_035.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_035.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_035.imageset/sticker_035.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_035.imageset/sticker_035.png new file mode 100644 index 0000000..d8843a5 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_035.imageset/sticker_035.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_036.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_036.imageset/Contents.json new file mode 100644 index 0000000..40cd072 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_036.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_036.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_036.imageset/sticker_036.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_036.imageset/sticker_036.png new file mode 100644 index 0000000..552d999 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_036.imageset/sticker_036.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_037.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_037.imageset/Contents.json new file mode 100644 index 0000000..889b0ec --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_037.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_037.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_037.imageset/sticker_037.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_037.imageset/sticker_037.png new file mode 100644 index 0000000..745ee4c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_037.imageset/sticker_037.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_038.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_038.imageset/Contents.json new file mode 100644 index 0000000..4c52161 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_038.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_038.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_038.imageset/sticker_038.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_038.imageset/sticker_038.png new file mode 100644 index 0000000..cce36df Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_038.imageset/sticker_038.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_039.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_039.imageset/Contents.json new file mode 100644 index 0000000..9d52314 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_039.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_039.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_039.imageset/sticker_039.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_039.imageset/sticker_039.png new file mode 100644 index 0000000..2263133 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_039.imageset/sticker_039.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_040.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_040.imageset/Contents.json new file mode 100644 index 0000000..838f5e4 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_040.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_040.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_040.imageset/sticker_040.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_040.imageset/sticker_040.png new file mode 100644 index 0000000..c90bb23 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_040.imageset/sticker_040.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_041.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_041.imageset/Contents.json new file mode 100644 index 0000000..3c60414 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_041.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_041.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_041.imageset/sticker_041.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_041.imageset/sticker_041.png new file mode 100644 index 0000000..b623517 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_041.imageset/sticker_041.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_042.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_042.imageset/Contents.json new file mode 100644 index 0000000..064933b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_042.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_042.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_042.imageset/sticker_042.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_042.imageset/sticker_042.png new file mode 100644 index 0000000..c39ab75 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_042.imageset/sticker_042.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_043.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_043.imageset/Contents.json new file mode 100644 index 0000000..21262eb --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_043.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_043.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_043.imageset/sticker_043.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_043.imageset/sticker_043.png new file mode 100644 index 0000000..5b6dd9c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_043.imageset/sticker_043.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_044.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_044.imageset/Contents.json new file mode 100644 index 0000000..d52aa8e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_044.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_044.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_044.imageset/sticker_044.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_044.imageset/sticker_044.png new file mode 100644 index 0000000..bca83a0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_044.imageset/sticker_044.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_045.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_045.imageset/Contents.json new file mode 100644 index 0000000..ca8426a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_045.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_045.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_045.imageset/sticker_045.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_045.imageset/sticker_045.png new file mode 100644 index 0000000..703b053 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_045.imageset/sticker_045.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_046.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_046.imageset/Contents.json new file mode 100644 index 0000000..6fe50b9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_046.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_046.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_046.imageset/sticker_046.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_046.imageset/sticker_046.png new file mode 100644 index 0000000..087d7ca Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_046.imageset/sticker_046.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_047.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_047.imageset/Contents.json new file mode 100644 index 0000000..79dc1b2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_047.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_047.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_047.imageset/sticker_047.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_047.imageset/sticker_047.png new file mode 100644 index 0000000..3947442 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_047.imageset/sticker_047.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_048.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_048.imageset/Contents.json new file mode 100644 index 0000000..a0565c4 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_048.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_048.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_048.imageset/sticker_048.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_048.imageset/sticker_048.png new file mode 100644 index 0000000..03c73d9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_048.imageset/sticker_048.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_049.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_049.imageset/Contents.json new file mode 100644 index 0000000..d11817e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_049.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_049.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_049.imageset/sticker_049.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_049.imageset/sticker_049.png new file mode 100644 index 0000000..c40a5cb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_049.imageset/sticker_049.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_050.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_050.imageset/Contents.json new file mode 100644 index 0000000..7d5def9 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_050.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_050.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_050.imageset/sticker_050.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_050.imageset/sticker_050.png new file mode 100644 index 0000000..65bca65 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_050.imageset/sticker_050.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_051.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_051.imageset/Contents.json new file mode 100644 index 0000000..a5d809e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_051.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_051.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_051.imageset/sticker_051.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_051.imageset/sticker_051.png new file mode 100644 index 0000000..f45c46c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_051.imageset/sticker_051.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_052.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_052.imageset/Contents.json new file mode 100644 index 0000000..504b6aa --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_052.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_052.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_052.imageset/sticker_052.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_052.imageset/sticker_052.png new file mode 100644 index 0000000..f7efe47 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_052.imageset/sticker_052.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_053.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_053.imageset/Contents.json new file mode 100644 index 0000000..153b2d0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_053.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_053.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_053.imageset/sticker_053.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_053.imageset/sticker_053.png new file mode 100644 index 0000000..b834038 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_053.imageset/sticker_053.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_054.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_054.imageset/Contents.json new file mode 100644 index 0000000..fdc9826 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_054.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_054.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_054.imageset/sticker_054.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_054.imageset/sticker_054.png new file mode 100644 index 0000000..009ad7f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_054.imageset/sticker_054.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_055.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_055.imageset/Contents.json new file mode 100644 index 0000000..9a5293d --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_055.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_055.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_055.imageset/sticker_055.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_055.imageset/sticker_055.png new file mode 100644 index 0000000..d269b77 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_055.imageset/sticker_055.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_056.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_056.imageset/Contents.json new file mode 100644 index 0000000..03de70b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_056.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_056.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_056.imageset/sticker_056.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_056.imageset/sticker_056.png new file mode 100644 index 0000000..1bab469 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_056.imageset/sticker_056.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_057.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_057.imageset/Contents.json new file mode 100644 index 0000000..ff19c99 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_057.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_057.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_057.imageset/sticker_057.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_057.imageset/sticker_057.png new file mode 100644 index 0000000..c0d3b04 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_057.imageset/sticker_057.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_058.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_058.imageset/Contents.json new file mode 100644 index 0000000..e8b1945 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_058.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_058.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_058.imageset/sticker_058.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_058.imageset/sticker_058.png new file mode 100644 index 0000000..4848840 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_058.imageset/sticker_058.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_059.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_059.imageset/Contents.json new file mode 100644 index 0000000..ff307c6 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_059.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_059.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_059.imageset/sticker_059.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_059.imageset/sticker_059.png new file mode 100644 index 0000000..1a9558e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_059.imageset/sticker_059.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_060.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_060.imageset/Contents.json new file mode 100644 index 0000000..ae3b545 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_060.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_060.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_060.imageset/sticker_060.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_060.imageset/sticker_060.png new file mode 100644 index 0000000..17d6a19 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_060.imageset/sticker_060.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_061.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_061.imageset/Contents.json new file mode 100644 index 0000000..06b6208 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_061.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_061.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_061.imageset/sticker_061.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_061.imageset/sticker_061.png new file mode 100644 index 0000000..5573581 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_061.imageset/sticker_061.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_062.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_062.imageset/Contents.json new file mode 100644 index 0000000..0296d70 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_062.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_062.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_062.imageset/sticker_062.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_062.imageset/sticker_062.png new file mode 100644 index 0000000..66a8177 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_062.imageset/sticker_062.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_063.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_063.imageset/Contents.json new file mode 100644 index 0000000..72edcee --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_063.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_063.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_063.imageset/sticker_063.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_063.imageset/sticker_063.png new file mode 100644 index 0000000..64e3600 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_063.imageset/sticker_063.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_064.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_064.imageset/Contents.json new file mode 100644 index 0000000..fa170e1 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_064.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_064.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_064.imageset/sticker_064.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_064.imageset/sticker_064.png new file mode 100644 index 0000000..93252da Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_064.imageset/sticker_064.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_065.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_065.imageset/Contents.json new file mode 100644 index 0000000..b8e1b5f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_065.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_065.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_065.imageset/sticker_065.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_065.imageset/sticker_065.png new file mode 100644 index 0000000..8e0530f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_065.imageset/sticker_065.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_066.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_066.imageset/Contents.json new file mode 100644 index 0000000..c892029 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_066.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_066.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_066.imageset/sticker_066.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_066.imageset/sticker_066.png new file mode 100644 index 0000000..6301bdb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_066.imageset/sticker_066.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_067.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_067.imageset/Contents.json new file mode 100644 index 0000000..0e14e7c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_067.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_067.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_067.imageset/sticker_067.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_067.imageset/sticker_067.png new file mode 100644 index 0000000..71b6d88 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_067.imageset/sticker_067.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_068.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_068.imageset/Contents.json new file mode 100644 index 0000000..a6cd70e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_068.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "sticker_068.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_068.imageset/sticker_068.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_068.imageset/sticker_068.png new file mode 100644 index 0000000..be15f8c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/sticker_068.imageset/sticker_068.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers.imageset/Contents.json new file mode 100644 index 0000000..77d36b0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "stickers@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "stickers@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers.imageset/stickers@2x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers.imageset/stickers@2x.png new file mode 100644 index 0000000..6e5d956 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers.imageset/stickers@2x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers.imageset/stickers@3x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers.imageset/stickers@3x.png new file mode 100644 index 0000000..b43e862 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers.imageset/stickers@3x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers_selected.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers_selected.imageset/Contents.json new file mode 100644 index 0000000..5f782b2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers_selected.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "stickers_selected@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "stickers_selected@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers_selected.imageset/stickers_selected@2x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers_selected.imageset/stickers_selected@2x.png new file mode 100644 index 0000000..b0456e3 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers_selected.imageset/stickers_selected@2x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers_selected.imageset/stickers_selected@3x.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers_selected.imageset/stickers_selected@3x.png new file mode 100644 index 0000000..49642b7 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/stickers_selected.imageset/stickers_selected@3x.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_000.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_000.imageset/Contents.json new file mode 100644 index 0000000..1a83ed3 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_000.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_000.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_000.imageset/texts_000.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_000.imageset/texts_000.png new file mode 100644 index 0000000..102a566 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_000.imageset/texts_000.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_001.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_001.imageset/Contents.json new file mode 100644 index 0000000..af24323 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_001.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_001.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_001.imageset/texts_001.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_001.imageset/texts_001.png new file mode 100644 index 0000000..9a1400a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_001.imageset/texts_001.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_002.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_002.imageset/Contents.json new file mode 100644 index 0000000..63ecfe8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_002.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_002.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_002.imageset/texts_002.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_002.imageset/texts_002.png new file mode 100644 index 0000000..bf490c0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_002.imageset/texts_002.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_003.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_003.imageset/Contents.json new file mode 100644 index 0000000..e01da32 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_003.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_003.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_003.imageset/texts_003.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_003.imageset/texts_003.png new file mode 100644 index 0000000..7378cd6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_003.imageset/texts_003.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_004.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_004.imageset/Contents.json new file mode 100644 index 0000000..55d58eb --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_004.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_004.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_004.imageset/texts_004.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_004.imageset/texts_004.png new file mode 100644 index 0000000..168105e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_004.imageset/texts_004.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_005.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_005.imageset/Contents.json new file mode 100644 index 0000000..90eb04a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_005.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_005.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_005.imageset/texts_005.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_005.imageset/texts_005.png new file mode 100644 index 0000000..f00ea23 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_005.imageset/texts_005.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_006.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_006.imageset/Contents.json new file mode 100644 index 0000000..b370e35 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_006.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_006.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_006.imageset/texts_006.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_006.imageset/texts_006.png new file mode 100644 index 0000000..ed78d6b Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_006.imageset/texts_006.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_007.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_007.imageset/Contents.json new file mode 100644 index 0000000..2de7f0a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_007.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_007.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_007.imageset/texts_007.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_007.imageset/texts_007.png new file mode 100644 index 0000000..72e2635 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_007.imageset/texts_007.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_008.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_008.imageset/Contents.json new file mode 100644 index 0000000..550cc36 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_008.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_008.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_008.imageset/texts_008.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_008.imageset/texts_008.png new file mode 100644 index 0000000..efb1c99 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_008.imageset/texts_008.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_009.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_009.imageset/Contents.json new file mode 100644 index 0000000..bb49e66 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_009.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_009.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_009.imageset/texts_009.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_009.imageset/texts_009.png new file mode 100644 index 0000000..e24d0a2 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_009.imageset/texts_009.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_010.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_010.imageset/Contents.json new file mode 100644 index 0000000..1558eee --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_010.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_010.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_010.imageset/texts_010.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_010.imageset/texts_010.png new file mode 100644 index 0000000..d902f1d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_010.imageset/texts_010.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_011.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_011.imageset/Contents.json new file mode 100644 index 0000000..9d5cdd6 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_011.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_011.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_011.imageset/texts_011.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_011.imageset/texts_011.png new file mode 100644 index 0000000..b1203c7 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_011.imageset/texts_011.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_012.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_012.imageset/Contents.json new file mode 100644 index 0000000..16ad9bf --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_012.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_012.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_012.imageset/texts_012.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_012.imageset/texts_012.png new file mode 100644 index 0000000..8a27692 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_012.imageset/texts_012.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_013.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_013.imageset/Contents.json new file mode 100644 index 0000000..ef5609c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_013.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_013.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_013.imageset/texts_013.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_013.imageset/texts_013.png new file mode 100644 index 0000000..e3b7fba Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_013.imageset/texts_013.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_014.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_014.imageset/Contents.json new file mode 100644 index 0000000..3448b62 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_014.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_014.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_014.imageset/texts_014.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_014.imageset/texts_014.png new file mode 100644 index 0000000..1667b38 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_014.imageset/texts_014.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_015.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_015.imageset/Contents.json new file mode 100644 index 0000000..7af2238 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_015.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_015.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_015.imageset/texts_015.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_015.imageset/texts_015.png new file mode 100644 index 0000000..e261b9e Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_015.imageset/texts_015.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_016.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_016.imageset/Contents.json new file mode 100644 index 0000000..715533b --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_016.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_016.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_016.imageset/texts_016.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_016.imageset/texts_016.png new file mode 100644 index 0000000..bba2376 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_016.imageset/texts_016.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_017.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_017.imageset/Contents.json new file mode 100644 index 0000000..6b13113 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_017.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_017.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_017.imageset/texts_017.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_017.imageset/texts_017.png new file mode 100644 index 0000000..c79e13f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_017.imageset/texts_017.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_018.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_018.imageset/Contents.json new file mode 100644 index 0000000..97d73d2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_018.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_018.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_018.imageset/texts_018.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_018.imageset/texts_018.png new file mode 100644 index 0000000..f040b09 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_018.imageset/texts_018.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_019.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_019.imageset/Contents.json new file mode 100644 index 0000000..f225f4c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_019.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_019.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_019.imageset/texts_019.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_019.imageset/texts_019.png new file mode 100644 index 0000000..1129217 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_019.imageset/texts_019.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_020.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_020.imageset/Contents.json new file mode 100644 index 0000000..fc6ed61 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_020.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_020.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_020.imageset/texts_020.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_020.imageset/texts_020.png new file mode 100644 index 0000000..57c850d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_020.imageset/texts_020.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_021.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_021.imageset/Contents.json new file mode 100644 index 0000000..01ad537 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_021.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_021.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_021.imageset/texts_021.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_021.imageset/texts_021.png new file mode 100644 index 0000000..2d6eb6d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_021.imageset/texts_021.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_022.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_022.imageset/Contents.json new file mode 100644 index 0000000..9a594aa --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_022.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_022.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_022.imageset/texts_022.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_022.imageset/texts_022.png new file mode 100644 index 0000000..5979e11 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_022.imageset/texts_022.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_023.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_023.imageset/Contents.json new file mode 100644 index 0000000..6cba6cd --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_023.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_023.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_023.imageset/texts_023.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_023.imageset/texts_023.png new file mode 100644 index 0000000..376cbf7 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_023.imageset/texts_023.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_024.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_024.imageset/Contents.json new file mode 100644 index 0000000..5888366 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_024.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_024.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_024.imageset/texts_024.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_024.imageset/texts_024.png new file mode 100644 index 0000000..01e4ae4 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_024.imageset/texts_024.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_025.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_025.imageset/Contents.json new file mode 100644 index 0000000..dc2f2dc --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_025.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_025.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_025.imageset/texts_025.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_025.imageset/texts_025.png new file mode 100644 index 0000000..d98d660 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_025.imageset/texts_025.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_026.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_026.imageset/Contents.json new file mode 100644 index 0000000..1edbee3 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_026.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_026.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_026.imageset/texts_026.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_026.imageset/texts_026.png new file mode 100644 index 0000000..e5b1755 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_026.imageset/texts_026.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_027.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_027.imageset/Contents.json new file mode 100644 index 0000000..795a3d6 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_027.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_027.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_027.imageset/texts_027.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_027.imageset/texts_027.png new file mode 100644 index 0000000..e951512 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_027.imageset/texts_027.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_028.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_028.imageset/Contents.json new file mode 100644 index 0000000..a9a03c0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_028.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_028.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_028.imageset/texts_028.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_028.imageset/texts_028.png new file mode 100644 index 0000000..db1f0a9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_028.imageset/texts_028.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_029.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_029.imageset/Contents.json new file mode 100644 index 0000000..8b952f7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_029.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_029.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_029.imageset/texts_029.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_029.imageset/texts_029.png new file mode 100644 index 0000000..bd9bbef Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_029.imageset/texts_029.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_030.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_030.imageset/Contents.json new file mode 100644 index 0000000..b3cbf6f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_030.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_030.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_030.imageset/texts_030.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_030.imageset/texts_030.png new file mode 100644 index 0000000..8c28d69 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_030.imageset/texts_030.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_031.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_031.imageset/Contents.json new file mode 100644 index 0000000..18c3926 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_031.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_031.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_031.imageset/texts_031.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_031.imageset/texts_031.png new file mode 100644 index 0000000..0f43321 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_031.imageset/texts_031.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_032.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_032.imageset/Contents.json new file mode 100644 index 0000000..d5304b2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_032.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_032.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_032.imageset/texts_032.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_032.imageset/texts_032.png new file mode 100644 index 0000000..4dfd250 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_032.imageset/texts_032.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_033.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_033.imageset/Contents.json new file mode 100644 index 0000000..4611e86 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_033.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_033.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_033.imageset/texts_033.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_033.imageset/texts_033.png new file mode 100644 index 0000000..67c56c0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_033.imageset/texts_033.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_034.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_034.imageset/Contents.json new file mode 100644 index 0000000..52ba3be --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_034.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_034.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_034.imageset/texts_034.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_034.imageset/texts_034.png new file mode 100644 index 0000000..9cda9a6 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_034.imageset/texts_034.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_035.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_035.imageset/Contents.json new file mode 100644 index 0000000..db20e98 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_035.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_035.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_035.imageset/texts_035.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_035.imageset/texts_035.png new file mode 100644 index 0000000..44c613d Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_035.imageset/texts_035.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_036.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_036.imageset/Contents.json new file mode 100644 index 0000000..0cd0257 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_036.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_036.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_036.imageset/texts_036.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_036.imageset/texts_036.png new file mode 100644 index 0000000..f0ec319 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_036.imageset/texts_036.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_037.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_037.imageset/Contents.json new file mode 100644 index 0000000..926b403 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_037.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_037.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_037.imageset/texts_037.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_037.imageset/texts_037.png new file mode 100644 index 0000000..17331c0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_037.imageset/texts_037.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_038.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_038.imageset/Contents.json new file mode 100644 index 0000000..1585337 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_038.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_038.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_038.imageset/texts_038.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_038.imageset/texts_038.png new file mode 100644 index 0000000..9a33de3 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_038.imageset/texts_038.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_039.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_039.imageset/Contents.json new file mode 100644 index 0000000..d396a15 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_039.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_039.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_039.imageset/texts_039.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_039.imageset/texts_039.png new file mode 100644 index 0000000..8de9f61 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_039.imageset/texts_039.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_040.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_040.imageset/Contents.json new file mode 100644 index 0000000..276fd34 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_040.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_040.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_040.imageset/texts_040.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_040.imageset/texts_040.png new file mode 100644 index 0000000..08f5a5f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_040.imageset/texts_040.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_041.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_041.imageset/Contents.json new file mode 100644 index 0000000..4a5f2ec --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_041.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_041.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_041.imageset/texts_041.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_041.imageset/texts_041.png new file mode 100644 index 0000000..5286ac5 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_041.imageset/texts_041.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_042.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_042.imageset/Contents.json new file mode 100644 index 0000000..c3e980f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_042.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_042.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_042.imageset/texts_042.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_042.imageset/texts_042.png new file mode 100644 index 0000000..c38d9a9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_042.imageset/texts_042.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_043.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_043.imageset/Contents.json new file mode 100644 index 0000000..820e202 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_043.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_043.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_043.imageset/texts_043.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_043.imageset/texts_043.png new file mode 100644 index 0000000..8fcb8fb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_043.imageset/texts_043.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_044.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_044.imageset/Contents.json new file mode 100644 index 0000000..de4b54f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_044.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_044.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_044.imageset/texts_044.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_044.imageset/texts_044.png new file mode 100644 index 0000000..c2b2f21 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_044.imageset/texts_044.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_045.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_045.imageset/Contents.json new file mode 100644 index 0000000..96a1c59 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_045.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_045.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_045.imageset/texts_045.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_045.imageset/texts_045.png new file mode 100644 index 0000000..d6db237 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_045.imageset/texts_045.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_046.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_046.imageset/Contents.json new file mode 100644 index 0000000..357027e --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_046.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_046.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_046.imageset/texts_046.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_046.imageset/texts_046.png new file mode 100644 index 0000000..ab680bd Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_046.imageset/texts_046.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_047.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_047.imageset/Contents.json new file mode 100644 index 0000000..94260c1 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_047.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_047.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_047.imageset/texts_047.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_047.imageset/texts_047.png new file mode 100644 index 0000000..4010e62 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_047.imageset/texts_047.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_048.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_048.imageset/Contents.json new file mode 100644 index 0000000..d63cd9a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_048.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_048.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_048.imageset/texts_048.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_048.imageset/texts_048.png new file mode 100644 index 0000000..1e577a3 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_048.imageset/texts_048.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_049.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_049.imageset/Contents.json new file mode 100644 index 0000000..e0d903f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_049.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_049.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_049.imageset/texts_049.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_049.imageset/texts_049.png new file mode 100644 index 0000000..2c113a7 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_049.imageset/texts_049.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_050.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_050.imageset/Contents.json new file mode 100644 index 0000000..d464121 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_050.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_050.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_050.imageset/texts_050.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_050.imageset/texts_050.png new file mode 100644 index 0000000..f30fc28 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_050.imageset/texts_050.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_051.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_051.imageset/Contents.json new file mode 100644 index 0000000..a33757f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_051.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_051.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_051.imageset/texts_051.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_051.imageset/texts_051.png new file mode 100644 index 0000000..5ce9648 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_051.imageset/texts_051.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_052.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_052.imageset/Contents.json new file mode 100644 index 0000000..3bbd1fc --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_052.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_052.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_052.imageset/texts_052.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_052.imageset/texts_052.png new file mode 100644 index 0000000..9eaa063 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_052.imageset/texts_052.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_053.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_053.imageset/Contents.json new file mode 100644 index 0000000..70adc79 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_053.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_053.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_053.imageset/texts_053.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_053.imageset/texts_053.png new file mode 100644 index 0000000..960d8a3 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_053.imageset/texts_053.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_054.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_054.imageset/Contents.json new file mode 100644 index 0000000..293d73f --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_054.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_054.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_054.imageset/texts_054.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_054.imageset/texts_054.png new file mode 100644 index 0000000..1152f59 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_054.imageset/texts_054.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_055.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_055.imageset/Contents.json new file mode 100644 index 0000000..0495e10 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_055.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_055.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_055.imageset/texts_055.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_055.imageset/texts_055.png new file mode 100644 index 0000000..f13ae36 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_055.imageset/texts_055.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_056.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_056.imageset/Contents.json new file mode 100644 index 0000000..86e8c6a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_056.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_056.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_056.imageset/texts_056.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_056.imageset/texts_056.png new file mode 100644 index 0000000..254d710 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_056.imageset/texts_056.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_057.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_057.imageset/Contents.json new file mode 100644 index 0000000..333e904 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_057.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_057.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_057.imageset/texts_057.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_057.imageset/texts_057.png new file mode 100644 index 0000000..ef23df9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_057.imageset/texts_057.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_058.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_058.imageset/Contents.json new file mode 100644 index 0000000..54ed9d7 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_058.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_058.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_058.imageset/texts_058.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_058.imageset/texts_058.png new file mode 100644 index 0000000..ba108bb Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_058.imageset/texts_058.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_059.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_059.imageset/Contents.json new file mode 100644 index 0000000..9360ae0 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_059.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_059.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_059.imageset/texts_059.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_059.imageset/texts_059.png new file mode 100644 index 0000000..e37c31a Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_059.imageset/texts_059.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_060.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_060.imageset/Contents.json new file mode 100644 index 0000000..55ed995 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_060.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_060.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_060.imageset/texts_060.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_060.imageset/texts_060.png new file mode 100644 index 0000000..edf5478 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_060.imageset/texts_060.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_061.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_061.imageset/Contents.json new file mode 100644 index 0000000..69e42fb --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_061.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_061.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_061.imageset/texts_061.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_061.imageset/texts_061.png new file mode 100644 index 0000000..cc04941 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_061.imageset/texts_061.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_062.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_062.imageset/Contents.json new file mode 100644 index 0000000..02e6e75 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_062.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_062.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_062.imageset/texts_062.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_062.imageset/texts_062.png new file mode 100644 index 0000000..cc68248 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_062.imageset/texts_062.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_063.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_063.imageset/Contents.json new file mode 100644 index 0000000..e385295 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_063.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_063.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_063.imageset/texts_063.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_063.imageset/texts_063.png new file mode 100644 index 0000000..f11c6c0 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_063.imageset/texts_063.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_064.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_064.imageset/Contents.json new file mode 100644 index 0000000..4f4657a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_064.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_064.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_064.imageset/texts_064.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_064.imageset/texts_064.png new file mode 100644 index 0000000..a5ae127 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_064.imageset/texts_064.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_065.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_065.imageset/Contents.json new file mode 100644 index 0000000..9970d2a --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_065.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_065.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_065.imageset/texts_065.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_065.imageset/texts_065.png new file mode 100644 index 0000000..fc67203 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_065.imageset/texts_065.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_066.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_066.imageset/Contents.json new file mode 100644 index 0000000..c1c327c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_066.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_066.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_066.imageset/texts_066.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_066.imageset/texts_066.png new file mode 100644 index 0000000..4c3474f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_066.imageset/texts_066.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_067.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_067.imageset/Contents.json new file mode 100644 index 0000000..88a3314 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_067.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_067.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_067.imageset/texts_067.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_067.imageset/texts_067.png new file mode 100644 index 0000000..3b36ba7 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_067.imageset/texts_067.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_068.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_068.imageset/Contents.json new file mode 100644 index 0000000..27e33d8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_068.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "texts_068.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_068.imageset/texts_068.png b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_068.imageset/texts_068.png new file mode 100644 index 0000000..32d4877 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/Stickers/texts_068.imageset/texts_068.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/animoji.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/animoji.imageset/Contents.json new file mode 100644 index 0000000..25018f2 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/animoji.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "animoji.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/animoji.imageset/animoji.png b/Avatar/App/Avatar/Assets.xcassets/animoji.imageset/animoji.png new file mode 100644 index 0000000..75ff96c Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/animoji.imageset/animoji.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/avatar.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/avatar.imageset/Contents.json new file mode 100644 index 0000000..09cea8c --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/avatar.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "avatar.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/avatar.imageset/avatar.png b/Avatar/App/Avatar/Assets.xcassets/avatar.imageset/avatar.png new file mode 100644 index 0000000..b0a3872 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/avatar.imageset/avatar.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/avimoji.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/avimoji.imageset/Contents.json new file mode 100644 index 0000000..8284679 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/avimoji.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "avimoji.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/avimoji.imageset/avimoji.png b/Avatar/App/Avatar/Assets.xcassets/avimoji.imageset/avimoji.png new file mode 100644 index 0000000..8e8e239 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/avimoji.imageset/avimoji.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/cover.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/cover.imageset/Contents.json new file mode 100644 index 0000000..ea0c697 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/cover.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "cover.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/cover.imageset/cover.png b/Avatar/App/Avatar/Assets.xcassets/cover.imageset/cover.png new file mode 100644 index 0000000..252d44f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/cover.imageset/cover.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/default-avatar.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/default-avatar.imageset/Contents.json new file mode 100644 index 0000000..b664d10 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/default-avatar.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "default-avatar.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/default-avatar.imageset/default-avatar.png b/Avatar/App/Avatar/Assets.xcassets/default-avatar.imageset/default-avatar.png new file mode 100644 index 0000000..8cc3aa9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/default-avatar.imageset/default-avatar.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/library.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/library.imageset/Contents.json new file mode 100644 index 0000000..7a8e1d8 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/library.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "library.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/library.imageset/library.png b/Avatar/App/Avatar/Assets.xcassets/library.imageset/library.png new file mode 100644 index 0000000..cc8e15f Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/library.imageset/library.png differ diff --git a/Avatar/App/Avatar/Assets.xcassets/memoji.imageset/Contents.json b/Avatar/App/Avatar/Assets.xcassets/memoji.imageset/Contents.json new file mode 100644 index 0000000..499c979 --- /dev/null +++ b/Avatar/App/Avatar/Assets.xcassets/memoji.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "memoji.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Assets.xcassets/memoji.imageset/memoji.png b/Avatar/App/Avatar/Assets.xcassets/memoji.imageset/memoji.png new file mode 100644 index 0000000..6336fa9 Binary files /dev/null and b/Avatar/App/Avatar/Assets.xcassets/memoji.imageset/memoji.png differ diff --git a/Avatar/App/Avatar/AvatarKit/AVTAnimoji.h b/Avatar/App/Avatar/AvatarKit/AVTAnimoji.h new file mode 100644 index 0000000..aa585e4 --- /dev/null +++ b/Avatar/App/Avatar/AvatarKit/AVTAnimoji.h @@ -0,0 +1,23 @@ +@import Foundation; +@import SceneKit; + + +@interface AVTAvatarInstance: NSObject +@end + + +@interface AVTAnimoji: NSObject ++ (instancetype)animojiNamed:(NSString *)name; ++ (NSArray *)animojiNames; ++ (UIImage *)thumbnailForAnimojiNamed:(NSString *)name options:(NSDictionary *)options; +@property (readonly) SCNNode *avatarNode; +@property (readonly) SCNNode *lightingNode; +@end + + +@interface AVTAvatar: NSObject ++ (instancetype)avatarWithDataRepresentation:(NSData *)data error:(NSError **)outError; +@end + +#define ASAnimoji NSClassFromString(@"AVTAnimoji") +#define ASAvatar NSClassFromString(@"AVTAvatar") diff --git a/Avatar/App/Avatar/AvatarKit/AVTAvatar.h b/Avatar/App/Avatar/AvatarKit/AVTAvatar.h new file mode 100644 index 0000000..b5e0167 --- /dev/null +++ b/Avatar/App/Avatar/AvatarKit/AVTAvatar.h @@ -0,0 +1,4 @@ +@import Foundation; + +@interface AVTAvatar : NSObject +@end diff --git a/Avatar/App/Avatar/AvatarKit/AVTAvatarLibraryViewController.h b/Avatar/App/Avatar/AvatarKit/AVTAvatarLibraryViewController.h new file mode 100644 index 0000000..30fdf58 --- /dev/null +++ b/Avatar/App/Avatar/AvatarKit/AVTAvatarLibraryViewController.h @@ -0,0 +1,9 @@ +@import UIKit; + +@class AVTAvatarStore; + +@interface AVTAvatarLibraryViewController: UIViewController +- (instancetype)initWithAvatarStore:(AVTAvatarStore *)store; +@end + +#define ASAvatarLibraryViewController NSClassFromString(@"AVTAvatarLibraryViewController") diff --git a/Avatar/App/Avatar/AvatarKit/AVTAvatarStore.h b/Avatar/App/Avatar/AvatarKit/AVTAvatarStore.h new file mode 100644 index 0000000..22e0161 --- /dev/null +++ b/Avatar/App/Avatar/AvatarKit/AVTAvatarStore.h @@ -0,0 +1,7 @@ +@import Foundation; + +@interface AVTAvatarStore: NSObject +- (instancetype)initWithDomainIdentifier:(NSString *)identifier; +@end + +#define ASAvatarStore NSClassFromString(@"AVTAvatarStore") diff --git a/Avatar/App/Avatar/AvatarKit/AVTRecordView.h b/Avatar/App/Avatar/AvatarKit/AVTRecordView.h new file mode 100644 index 0000000..e4e13b5 --- /dev/null +++ b/Avatar/App/Avatar/AvatarKit/AVTRecordView.h @@ -0,0 +1,23 @@ +@import Foundation; +@import ARKit; +@class AVTAvatar; +#import "AVTView.h" + + +@interface AVTRecordView: AVTView +@property (getter=isPreviewing, nonatomic, readonly) bool previewing; +@property (getter=isRecording, nonatomic, readonly) bool recording; +- (void)audioPlayerItemDidReachEnd:(id)arg1; +- (bool)exportMovieToURL:(NSURL *)movieURL options:(NSDictionary *)options completionHandler:(void (^)(NSError *error))completion; +- (NSTimeInterval)recordingDuration; +- (void)startPreviewing; +- (void)startRecording; +- (void)stopPreviewing; +- (void)stopRecording; +- (void)faceIsFullyActive; +- (void)fadePuppetToWhite:(int)arg; +- (void)setAvatar:(id)arg1; +- (void)setup; +@property (readonly) AVTAnimoji *puppet; +@property (nonatomic, readonly) ARSession *arSession; +@end diff --git a/Avatar/App/Avatar/AvatarKit/AVTView.h b/Avatar/App/Avatar/AvatarKit/AVTView.h new file mode 100644 index 0000000..0dbd7a7 --- /dev/null +++ b/Avatar/App/Avatar/AvatarKit/AVTView.h @@ -0,0 +1,7 @@ +@import SceneKit; + +#import "AVTAnimoji.h" + +@interface AVTView : SCNView +@property (nonatomic, retain) AVTAvatar *avatar; +@end diff --git a/Avatar/App/Avatar/AvatarKit/AvatarKit.framework/AvatarKit.tbd b/Avatar/App/Avatar/AvatarKit/AvatarKit.framework/AvatarKit.tbd new file mode 100755 index 0000000..579ac05 --- /dev/null +++ b/Avatar/App/Avatar/AvatarKit/AvatarKit.framework/AvatarKit.tbd @@ -0,0 +1,11 @@ +--- +archs: [ arm64 ] +platform: ios +install-name: /System/Library/PrivateFrameworks/AvatarKit.framework/AvatarKit +current-version: 181.3 +exports: + - archs: [ arm64 ] + symbols: [ ] + objc-classes: [ _AVTAnimoji, _AVTRecordView, _AVTAvatar ] + objc-ivars: [ ] +... diff --git a/Avatar/App/Avatar/AvatarKit/AvatarMotionView.h b/Avatar/App/Avatar/AvatarKit/AvatarMotionView.h new file mode 100644 index 0000000..9600926 --- /dev/null +++ b/Avatar/App/Avatar/AvatarKit/AvatarMotionView.h @@ -0,0 +1,6 @@ +@import UIKit; +#import "AVTRecordView.h" + +@interface AvatarMotionView : AVTRecordView +- (void)resetTracking; +@end diff --git a/Avatar/App/Avatar/AvatarKit/AvatarMotionView.m b/Avatar/App/Avatar/AvatarKit/AvatarMotionView.m new file mode 100644 index 0000000..a0ba852 --- /dev/null +++ b/Avatar/App/Avatar/AvatarKit/AvatarMotionView.m @@ -0,0 +1,15 @@ +@import ARKit; +#import "AvatarMotionView.h" +#import "AVTAnimoji.h" +@import SceneKit; +#import + +@implementation AvatarMotionView + +- (void)resetTracking { + ARConfiguration *config = [self.arSession.configuration copy]; + config.providesAudioData = NO; + [self.arSession runWithConfiguration:config options:ARSessionRunOptionResetTracking|ARSessionRunOptionRemoveExistingAnchors]; +} + +@end diff --git a/Avatar/App/Avatar/AvatarPicker/PrivateBlurEffect.h b/Avatar/App/Avatar/AvatarPicker/PrivateBlurEffect.h new file mode 100644 index 0000000..b1a9c13 --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/PrivateBlurEffect.h @@ -0,0 +1,24 @@ +#import + +@interface _UIBackdropView : UIView +-(id)initWithFrame:(CGRect)arg1 autosizesToFitSuperview:(BOOL)arg2 settings:(id)arg3 ; +-(id)initWithSettings:(id)arg1 ; +-(id)initWithStyle:(long long)arg1 ; +- (void)setBlurFilterWithRadius:(float)arg1 blurQuality:(id)arg2 blurHardEdges:(int)arg3; +- (void)setBlurFilterWithRadius:(float)arg1 blurQuality:(id)arg2; +- (void)setBlurHardEdges:(int)arg1; +- (void)setBlurQuality:(id)arg1; +- (void)setBlurRadius:(float)arg1; +- (void)setBlurRadiusSetOnce:(BOOL)arg1; +- (void)setBlursBackground:(BOOL)arg1; +- (void)setBlursWithHardEdges:(BOOL)arg1; +@end + +@interface _UIBackdropViewSettings : NSObject +@property (assign,getter=isEnabled,nonatomic) BOOL enabled; +@property (assign,nonatomic) double blurRadius; +@property (nonatomic,copy) NSString * blurQuality; +@property (assign,nonatomic) BOOL usesBackdropEffectView; +-(id)initWithDefaultValues; ++(id)settingsForStyle:(long long)arg1 ; +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityCellHeaderView.h b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityCellHeaderView.h new file mode 100644 index 0000000..1f31794 --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityCellHeaderView.h @@ -0,0 +1,8 @@ +#import + +@interface TDAvatarIdentityCellHeaderView : UICollectionReusableView +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *headerLabel; +@end + + diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityCellHeaderView.m b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityCellHeaderView.m new file mode 100644 index 0000000..f3af4c1 --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityCellHeaderView.m @@ -0,0 +1,28 @@ +#import "TDAvatarIdentityCellHeaderView.h" + +@implementation TDAvatarIdentityCellHeaderView + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] initWithFrame:self.bounds]; + self.baseView.clipsToBounds = YES; + [self addSubview:self.baseView]; + + + self.headerLabel = [[UILabel alloc] init]; + self.headerLabel.textColor = UIColor.tertiaryLabelColor; + self.headerLabel.font = [UIFont boldSystemFontOfSize:18]; + [self.baseView addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = YES; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:20].active = YES; + + } + return self; +} + +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityEmojiCell.h b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityEmojiCell.h new file mode 100644 index 0000000..2f7caba --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityEmojiCell.h @@ -0,0 +1,7 @@ +#import +#import "ConstraintExtension.h" + +@interface TDAvatarIdentityEmojiCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *emojiLabel; +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityEmojiCell.m b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityEmojiCell.m new file mode 100644 index 0000000..546c20f --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityEmojiCell.m @@ -0,0 +1,40 @@ +#import "TDAvatarIdentityEmojiCell.h" + +@implementation TDAvatarIdentityEmojiCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = self.frame.size.width/2; + self.clipsToBounds = true; + + + self.baseView = [[UIView alloc] initWithFrame:self.contentView.bounds]; + self.baseView.layer.cornerRadius = self.frame.size.width/2; + self.baseView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + + self.emojiLabel = [[UILabel alloc] init]; + self.emojiLabel.textAlignment = NSTextAlignmentCenter; + self.emojiLabel.font = [UIFont systemFontOfSize:45]; + [self.baseView addSubview:self.emojiLabel]; + + [self.emojiLabel x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.emojiLabel.text = nil; +} + + +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerDataSource.h b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerDataSource.h new file mode 100644 index 0000000..0198b6d --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerDataSource.h @@ -0,0 +1,16 @@ +#import +#import + +@interface TDAvatarIdentityPickerEmojiDataModel : NSObject +-(id)initWithEmoji:(NSString *)emoji colour:(NSString *)colour; +@property (nonatomic, retain) NSString *emoji; +@property (nonatomic, retain) NSString *colour; +@end + +@interface TDAvatarIdentityPickerDataSource : NSObject ++(instancetype)sharedInstance; +-(id)init; + +-(NSMutableArray*)stickersData; +-(NSMutableArray*)emojiData; +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerDataSource.m b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerDataSource.m new file mode 100644 index 0000000..f4a66f8 --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerDataSource.m @@ -0,0 +1,101 @@ +#import "TDAvatarIdentityPickerDataSource.h" + +@implementation TDAvatarIdentityPickerEmojiDataModel +-(id)initWithEmoji:(NSString *)emoji colour:(NSString *)colour { + self = [super init]; + if(self) { + self.emoji = emoji; + self.colour = colour; + } + return self; +} +@end + + +@implementation TDAvatarIdentityPickerDataSource + ++(instancetype)sharedInstance { + static TDAvatarIdentityPickerDataSource *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[TDAvatarIdentityPickerDataSource alloc] init]; + }); + return sharedInstance; +} + + +-(id)init { + return self; +} + + +-(NSMutableArray*)stickersData { + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + NSString *stickersPath = @"/var/mobile/Library/Avatar/Stickers"; + + NSMutableArray *folders = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:stickersPath error:nil] mutableCopy]; + + for (int i = 0; i < folders.count; i++) { + + NSString *path = [folders objectAtIndex:i]; + if ([path hasSuffix:@".png"]){ + [array addObject:path]; + } + } + + [array sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + + return array; +} + + +-(NSMutableArray*)emojiData { + + NSMutableArray *array = [[NSMutableArray alloc] init]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"😀" colour:@"a8e6cf"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🥶" colour:@"d0e1f9"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"😜" colour:@"a8e6cf"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"😍" colour:@"ffaaa5"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"😘" colour:@"eedbdb"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🥳" colour:@"dddddd"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"😻" colour:@"e4dcf1"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"💋" colour:@"eee3e7"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"💍" colour:@"e7d3d3"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🦄" colour:@"fec8c1"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🍻" colour:@"96ceb4"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🥂" colour:@"ff6f69"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🍿" colour:@"ffdbac"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"⚽️" colour:@"64a1f4"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🏈" colour:@"add6ff"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🏒" colour:@"ffefd7"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🚗" colour:@"a8e6cf"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🛴" colour:@"dcedc1"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🚀" colour:@"ffcc5c"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"💻" colour:@"b3cde0"]]; + return array; +} + +@end + + + + + + + + + + + + + + + + + + + + + diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerViewController.h b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerViewController.h new file mode 100644 index 0000000..5609c91 --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerViewController.h @@ -0,0 +1,33 @@ +#import +#import "ConstraintExtension.h" +#import "TDHeaderView.h" +#import "TDAvatarIdentityToolsCell.h" +#import "TDAvatarIdentityCellHeaderView.h" +#import "TDAvatarIdentityStickerCell.h" +#import "TDAvatarIdentityEmojiCell.h" +#import "TDAvatarIdentityPickerDataSource.h" +#import "TDEmojiPickerViewController.h" + +@protocol TDAvatarPickerProtocol +@required +-(void)didCreatedAvatar:(UIImage *)avatar; +-(void)didDismissedAvatarPicker; +@end + +@interface TDAvatarIdentityPickerViewController : UIViewController +-(instancetype)initWithTitle:(NSString *)title showDefaultAvatar:(BOOL)defaultAvatar avatarImage:(UIImage *)avatar accent:(UIColor *)accent; +@property (nonatomic, retain) TDHeaderView *headerView; +@property (nonatomic, retain) UIView *preview; +@property (nonatomic, retain) UIImageView *previewImage; +@property (nonatomic, retain) UIImageView *stickerImage; +@property (nonatomic, retain) UILabel *emojiLabel; +@property (nonatomic, retain) UITextField *textField; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *stickersArray; +@property (nonatomic, retain) NSMutableArray *emojisArray; +@property(nonatomic,assign)id delegate; +@property (nonatomic, retain) NSString *titleString; +@property (nonatomic) BOOL useDefaultAvatarImage; +@property (nonatomic, retain) UIImage *defaultAvatar; +@property (nonatomic, retain) UIColor *accentColour; +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerViewController.m b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerViewController.m new file mode 100644 index 0000000..57e498a --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityPickerViewController.m @@ -0,0 +1,451 @@ +#import "TDAvatarIdentityPickerViewController.h" + +@implementation TDAvatarIdentityPickerViewController + +-(instancetype)initWithTitle:(NSString *)title showDefaultAvatar:(BOOL)defaultAvatar avatarImage:(UIImage *)avatar accent:(UIColor *)accent { + + self = [super init]; + if (self) { + self.titleString = title; + self.useDefaultAvatarImage = defaultAvatar; + self.defaultAvatar = avatar; + self.accentColour = accent; + } + return self; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.systemBackgroundColor; + self.view.tintColor = self.accentColour; + + UIWindow *window = [UIApplication sharedApplication].windows.firstObject; + window.tintColor = self.accentColour; + + self.stickersArray = [[TDAvatarIdentityPickerDataSource sharedInstance] stickersData]; + self.emojisArray = [[TDAvatarIdentityPickerDataSource sharedInstance] emojiData]; + + [self layoutHeaderView]; + [self layoutCollectionView]; +} + + +-(void)layoutHeaderView { + + self.headerView = [[TDHeaderView alloc] initWithTitle:self.titleString accent:self.accentColour leftIcon:@"xmark" leftAction:@selector(dismissVC) rightIcon:@"checkmark" rightAction:@selector(applyAvatar)]; + self.headerView.rightButton.backgroundColor = self.accentColour; + self.headerView.rightButton.tintColor = UIColor.whiteColor; + self.headerView.rightButton.alpha = 0; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.topAnchor padding:0]; + + + self.preview = [[UIView alloc] init]; + self.preview.backgroundColor = [self colorWithHexString:@"64a1f4"]; + self.preview.layer.cornerRadius = 55; + self.preview.clipsToBounds = YES; + [self.view addSubview:self.preview]; + + [self.preview size:CGSizeMake(110, 110)]; + [self.preview x:self.view.centerXAnchor]; + [self.preview top:self.headerView.bottomAnchor padding:20]; + + + self.previewImage = [[UIImageView alloc] init]; + self.previewImage.contentMode = UIViewContentModeScaleAspectFill; + if (!self.useDefaultAvatarImage) { + self.previewImage.image = self.defaultAvatar; + } + [self.preview addSubview:self.previewImage]; + + [self.previewImage size:CGSizeMake(110, 110)]; + [self.previewImage x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; + + + self.stickerImage = [[UIImageView alloc] init]; + self.stickerImage.contentMode = UIViewContentModeScaleAspectFill; + self.stickerImage.alpha = 0; + [self.preview addSubview:self.stickerImage]; + + [self.stickerImage size:CGSizeMake(80, 80)]; + [self.stickerImage x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; + + + self.emojiLabel = [[UILabel alloc] init]; + self.emojiLabel.textAlignment = NSTextAlignmentCenter; + self.emojiLabel.font = [UIFont systemFontOfSize:67]; + if (self.useDefaultAvatarImage) { + self.emojiLabel.text = @"😀"; + } else { + self.emojiLabel.alpha = 0; + } + [self.preview addSubview:self.emojiLabel]; + + [self.emojiLabel x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; + + + self.textField = [[UITextField alloc] init]; + self.textField.backgroundColor = UIColor.clearColor; + self.textField.tintColor = self.accentColour; + self.textField.textAlignment = NSTextAlignmentCenter; + self.textField.font = [UIFont systemFontOfSize:47 weight:UIFontWeightBold]; + self.textField.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters; + self.textField.delegate = self; + self.textField.returnKeyType = UIReturnKeyDone; + self.textField.alpha = 0; + [self.preview addSubview:self.textField]; + + [self.textField size:CGSizeMake(105, 105)]; + [self.textField x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[TDAvatarIdentityToolsCell class] forCellWithReuseIdentifier:@"ToolsCell"]; + [self.collectionView registerClass:[TDAvatarIdentityStickerCell class] forCellWithReuseIdentifier:@"StickerCell"]; + [self.collectionView registerClass:[TDAvatarIdentityEmojiCell class] forCellWithReuseIdentifier:@"EmojiCell"]; + [self.collectionView registerClass:[TDAvatarIdentityCellHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; + [self.view addSubview:self.collectionView]; + + [self.collectionView top:self.preview.bottomAnchor padding:20]; + [self.collectionView bottom:self.view.bottomAnchor padding:-20]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView { + return 3; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { + return CGSizeMake(self.view.frame.size.width, 45); +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + + if (section == 0) { + return 4; + } else if (section == 1) { + return self.stickersArray.count; + } else { + return self.emojisArray.count; + } +} + + +-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + UICollectionReusableView *reusableview = nil; + + if (kind == UICollectionElementKindSectionHeader) { + + TDAvatarIdentityCellHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; + + NSArray *titleArray = [[NSArray alloc] initWithObjects:@"", @"Stickers", @"More", nil]; + + headerView.headerLabel.text = [titleArray objectAtIndex:indexPath.section]; + reusableview = headerView; + } + + return reusableview; + +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + if (indexPath.section == 0) { + + TDAvatarIdentityToolsCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ToolsCell" forIndexPath:indexPath]; + + cell.baseView.backgroundColor = [self.accentColour colorWithAlphaComponent:0.4]; + cell.baseView.layer.borderWidth = 0.8; + cell.baseView.layer.borderColor = [self.accentColour colorWithAlphaComponent:0.7].CGColor; + cell.iconImage.tintColor = self.accentColour; + + if (indexPath.row == 0) { + cell.iconImage.image = [UIImage systemImageNamed:@"photo.fill.on.rectangle.fill"]; + } else if (indexPath.row == 1) { + cell.iconImage.image = [UIImage systemImageNamed:@"paintpalette.fill"]; + } else if (indexPath.row == 2) { + cell.iconImage.image = [UIImage systemImageNamed:@"face.smiling.fill"]; + } else if (indexPath.row == 3) { + cell.iconImage.image = [UIImage systemImageNamed:@"textformat"]; + } + + return cell; + + } else if (indexPath.section == 1) { + + TDAvatarIdentityStickerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"StickerCell" forIndexPath:indexPath]; + + cell.iconImage.image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/var/mobile/Library/Avatar/Stickers/%@", [self.stickersArray objectAtIndex:indexPath.row]]]; + return cell; + + } else { + + TDAvatarIdentityEmojiCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"EmojiCell" forIndexPath:indexPath]; + + TDAvatarIdentityPickerEmojiDataModel *emojiData = [self.emojisArray objectAtIndex:indexPath.row]; + + cell.baseView.backgroundColor = [self colorWithHexString:emojiData.colour]; + cell.emojiLabel.text = emojiData.emoji; + + return cell; + } + +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ + return CGSizeMake(self.view.frame.size.width/4-20, self.view.frame.size.width/4-20); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + self.modalInPresentation = YES; + self.headerView.rightButton.alpha = 1; + + if (indexPath.section == 0) { + + if (indexPath.row == 0) { + [self presentPhotoPickerVC]; + } else if (indexPath.row == 1) { + [self presentColourPickerVC]; + } else if (indexPath.row == 2) { + [self presentEmojiPickerVC]; + } else if (indexPath.row == 3) { + [self presentKeyboardEditing]; + } + + } else if (indexPath.section == 1) { + + [self.textField resignFirstResponder]; + self.previewImage.alpha = 0; + self.emojiLabel.alpha = 0; + self.stickerImage.alpha = 1; + self.textField.alpha = 0; + self.stickerImage.image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/var/mobile/Library/Avatar/Stickers/%@", [self.stickersArray objectAtIndex:indexPath.row]]]; + + } else if (indexPath.section == 2) { + + [self.textField resignFirstResponder]; + self.previewImage.alpha = 0; + self.emojiLabel.alpha = 1; + self.stickerImage.alpha = 0; + self.textField.alpha = 0; + + TDAvatarIdentityPickerEmojiDataModel *emojiData = [self.emojisArray objectAtIndex:indexPath.row]; + self.preview.backgroundColor = [self colorWithHexString:emojiData.colour]; + self.emojiLabel.text = emojiData.emoji; + } + + +} + + +-(void)presentPhotoPickerVC { + + UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init]; + imagePickerController.delegate = self; + imagePickerController.allowsEditing = false; + imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [self presentViewController:imagePickerController animated:YES completion:nil]; + +} + + +-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(nonnull NSDictionary *)info { + + [self.textField resignFirstResponder]; + self.previewImage.alpha = 1; + self.stickerImage.alpha = 0; + self.emojiLabel.alpha = 0; + self.textField.alpha = 0; + + self.previewImage.image = info[UIImagePickerControllerOriginalImage]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentColourPickerVC { + [self.textField resignFirstResponder]; + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + colourPickerVC.selectedColor = self.preview.backgroundColor; + colourPickerVC.supportsAlpha = NO; + [self presentViewController:colourPickerVC animated:YES completion:nil]; +} + + +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + self.previewImage.alpha = 0; + UIColor *cpSelectedColour = viewController.selectedColor; + self.preview.backgroundColor = cpSelectedColour; +} + + +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + self.previewImage.alpha = 0; + UIColor *cpSelectedColour = viewController.selectedColor; + self.preview.backgroundColor = cpSelectedColour; +} + + +-(void)presentEmojiPickerVC { + [self.textField resignFirstResponder]; + TDEmojiPickerViewController *vc = [[TDEmojiPickerViewController alloc] init]; + vc.delegate = self; + [self presentViewController:vc animated:YES completion:nil]; +} + + +-(void)presentKeyboardEditing { + + self.emojiLabel.alpha = 0; + self.previewImage.alpha = 0; + self.textField.alpha = 1; + self.stickerImage.alpha = 0; + self.emojiLabel.text = 0; + + [self.textField becomeFirstResponder]; + +} + + +-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { + + if (textField.text.length >= 2 && range.length == 0) { + return NO; + } else { + return YES; + + } +} + + +-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + textField.userInteractionEnabled = NO; + return YES; +} + + +-(void)textFieldDidEndEditing:(UITextField *)textField { + textField.userInteractionEnabled = YES; +} + + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + if (textField.text.length >= 1) { + [textField resignFirstResponder]; + return YES; + } else { + return NO; + } +} + + +-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ + [self.view endEditing:YES]; +} + + +-(void)didSelectEmoji:(NSString *)emoji { + self.emojiLabel.alpha = 1; + self.previewImage.alpha = 0; + self.textField.alpha = 0; + self.stickerImage.alpha = 0; + self.emojiLabel.text = emoji; +} + + +-(void)didDismissedEmojiPicker { + NSLog(@"Emoji picker dismissed"); +} + + +-(void)dismissVC { + [self.delegate didDismissedAvatarPicker]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)applyAvatar { + [self.textField resignFirstResponder]; + [self.delegate didCreatedAvatar:[self avatarSnapshot]]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(UIImage *)avatarSnapshot { + + UIGraphicsBeginImageContextWithOptions(self.preview.frame.size, NO, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); + [self.preview.layer renderInContext:context]; + UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext(); + return snapshotImage; +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityStickerCell.h b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityStickerCell.h new file mode 100644 index 0000000..bb1ea84 --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityStickerCell.h @@ -0,0 +1,7 @@ +#import +#import "ConstraintExtension.h" + +@interface TDAvatarIdentityStickerCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityStickerCell.m b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityStickerCell.m new file mode 100644 index 0000000..6e71c20 --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityStickerCell.m @@ -0,0 +1,32 @@ +#import "TDAvatarIdentityStickerCell.h" + +@implementation TDAvatarIdentityStickerCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + + self.baseView = [[UIView alloc] initWithFrame:self.contentView.bounds]; + [self.contentView addSubview:self.baseView]; + + + self.iconImage = [[UIImageView alloc] init]; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(self.frame.size.width, self.frame.size.width)]; + [self.iconImage x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.iconImage.image = nil; +} + + +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityToolsCell.h b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityToolsCell.h new file mode 100644 index 0000000..18d7dda --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityToolsCell.h @@ -0,0 +1,7 @@ +#import +#import "ConstraintExtension.h" + +@interface TDAvatarIdentityToolsCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityToolsCell.m b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityToolsCell.m new file mode 100644 index 0000000..b5a1d78 --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDAvatarIdentityToolsCell.m @@ -0,0 +1,39 @@ +#import "TDAvatarIdentityToolsCell.h" + +@implementation TDAvatarIdentityToolsCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = self.frame.size.width/2; + self.clipsToBounds = true; + + + self.baseView = [[UIView alloc] initWithFrame:self.contentView.bounds]; + self.baseView.layer.cornerRadius = self.frame.size.width/2; + self.baseView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(self.frame.size.width/2, self.frame.size.width/2)]; + [self.iconImage x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.iconImage.image = nil; +} + + +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCell.h b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCell.h new file mode 100644 index 0000000..af3811c --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCell.h @@ -0,0 +1,7 @@ +#import +#import "ConstraintExtension.h" + +@interface TDEmojiPickerCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *emojiLabel; +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCell.m b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCell.m new file mode 100644 index 0000000..9221023 --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCell.m @@ -0,0 +1,31 @@ +#import "TDEmojiPickerCell.h" + +@implementation TDEmojiPickerCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] initWithFrame:self.contentView.bounds]; + [self.contentView addSubview:self.baseView]; + + self.emojiLabel = [[UILabel alloc] init]; + self.emojiLabel.textAlignment = NSTextAlignmentCenter; + self.emojiLabel.font = [UIFont systemFontOfSize:30]; + [self.baseView addSubview:self.emojiLabel]; + + [self.emojiLabel x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.emojiLabel.text = nil; +} + + +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCellHeaderView.h b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCellHeaderView.h new file mode 100644 index 0000000..999f2da --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCellHeaderView.h @@ -0,0 +1,8 @@ +#import + +@interface TDEmojiPickerCellHeaderView : UICollectionReusableView +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *headerLabel; +@end + + diff --git a/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCellHeaderView.m b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCellHeaderView.m new file mode 100644 index 0000000..e9f9faa --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerCellHeaderView.m @@ -0,0 +1,28 @@ +#import "TDEmojiPickerCellHeaderView.h" + +@implementation TDEmojiPickerCellHeaderView + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] initWithFrame:self.bounds]; + self.baseView.clipsToBounds = YES; + [self addSubview:self.baseView]; + + + self.headerLabel = [[UILabel alloc] init]; + self.headerLabel.textColor = UIColor.tertiaryLabelColor; + self.headerLabel.font = [UIFont boldSystemFontOfSize:18]; + [self.baseView addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = YES; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:20].active = YES; + + } + return self; +} + +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerViewController.h b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerViewController.h new file mode 100644 index 0000000..6c3a493 --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerViewController.h @@ -0,0 +1,21 @@ +#import +#import "ConstraintExtension.h" +#import "TDEmojiPickerCell.h" +#import "TDEmojiPickerCellHeaderView.h" +#import "PrivateBlurEffect.h" + +@protocol TDEmojiPickerProtocol +@required +-(void)didSelectEmoji:(NSString *)emoji; +-(void)didDismissedEmojiPicker; +@end + +@interface TDEmojiPickerViewController : UIViewController +@property (nonatomic, strong) _UIBackdropViewSettings *blurSetting; +@property (nonatomic, strong) _UIBackdropView *blurView; +@property (nonatomic, retain) UIVisualEffectView *grabberView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *emojiArray; +@property(nonatomic,assign)id delegate; +@property (nonatomic) BOOL didSelectEmoji; +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerViewController.m b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerViewController.m new file mode 100644 index 0000000..467225a --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDEmojiPickerViewController.m @@ -0,0 +1,134 @@ +#import "TDEmojiPickerViewController.h" + +@implementation TDEmojiPickerViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.clearColor; + + self.blurSetting = [_UIBackdropViewSettings settingsForStyle:2]; + self.blurView = [[_UIBackdropView alloc] initWithSettings:self.blurSetting]; + self.blurView.frame = self.view.bounds; + [self.view insertSubview:self.blurView atIndex:0]; + + + NSString *myFile = [[NSBundle mainBundle]pathForResource:@"Emoji" ofType:@"plist"]; + self.emojiArray = [[NSMutableArray alloc] initWithContentsOfFile:myFile]; + + [self layoutGrabberView]; + [self layoutCollectionView]; +} + + +-(void)layoutGrabberView { + + self.grabberView = [[UIVisualEffectView alloc] init]; + self.grabberView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemMaterial]; + self.grabberView.layer.cornerRadius = 3; + self.grabberView.clipsToBounds = YES; + [self.view addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.view.centerXAnchor]; + [self.grabberView top:self.view.topAnchor padding:10]; +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[TDEmojiPickerCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.collectionView registerClass:[TDEmojiPickerCellHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; + [self.view addSubview:self.collectionView]; + + [self.collectionView top:self.grabberView.bottomAnchor padding:20]; + [self.collectionView bottom:self.view.bottomAnchor padding:-20]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView { + return self.emojiArray.count; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { + return CGSizeMake(self.view.frame.size.width, 45); +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return [[[self.emojiArray objectAtIndex: section] objectForKey:@"Emojis"] count]; +} + + +-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + UICollectionReusableView *reusableview = nil; + + if (kind == UICollectionElementKindSectionHeader) { + + TDEmojiPickerCellHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; + headerView.headerLabel.text = [[self.emojiArray objectAtIndex:indexPath.section] objectForKey: @"Title"]; + reusableview = headerView; + } + + return reusableview; + +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + TDEmojiPickerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + cell.emojiLabel.text = [[[self.emojiArray objectAtIndex: indexPath.section] objectForKey: @"Emojis"] objectAtIndex: indexPath.row]; + + return cell; + +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ + return CGSizeMake(self.view.frame.size.width/8, self.view.frame.size.width/8); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + self.didSelectEmoji = YES; + [self.delegate didSelectEmoji:[[[self.emojiArray objectAtIndex: indexPath.section] objectForKey: @"Emojis"] objectAtIndex: indexPath.row]]; + [self dismissVC]; +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + + if (!self.didSelectEmoji) { + [self.delegate didDismissedEmojiPicker]; + } +} + +@end diff --git a/Avatar/App/Avatar/AvatarPicker/TDHeaderView.h b/Avatar/App/Avatar/AvatarPicker/TDHeaderView.h new file mode 100644 index 0000000..e5fa6bf --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDHeaderView.h @@ -0,0 +1,14 @@ +#import +#import "ConstraintExtension.h" + +@interface TDHeaderView : UIView +@property (nonatomic, retain) UIView *grabberView; +@property (nonatomic, retain) UIView *headerView; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIButton *leftButton; +@property (nonatomic, retain) UIButton *rightButton; + +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction; +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction rightIcon:(NSString *)rightIconString rightAction:(SEL)rightAction; +@end + diff --git a/Avatar/App/Avatar/AvatarPicker/TDHeaderView.m b/Avatar/App/Avatar/AvatarPicker/TDHeaderView.m new file mode 100644 index 0000000..8635a04 --- /dev/null +++ b/Avatar/App/Avatar/AvatarPicker/TDHeaderView.m @@ -0,0 +1,129 @@ +#import "TDHeaderView.h" + +@implementation TDHeaderView + + +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction { + + self = [super init]; + if (self) { + + self.clipsToBounds = YES; + + self.headerView = [[UIView alloc] init]; + [self addSubview:self.headerView]; + + [self.headerView fill]; + + + self.grabberView = [[UIView alloc] init]; + self.grabberView.backgroundColor = UIColor.tertiarySystemFillColor; + self.grabberView.layer.cornerRadius = 3; + [self.headerView addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.headerView.centerXAnchor]; + [self.grabberView top:self.headerView.topAnchor padding:10]; + + + self.leftButton = [[UIButton alloc] init]; + self.leftButton.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.leftButton.layer.cornerRadius = 12; + self.leftButton.layer.cornerCurve = kCACornerCurveContinuous; + UIImage *leftIcon = [UIImage systemImageNamed:leftIconString]; + [self.leftButton setImage:leftIcon forState:UIControlStateNormal]; + self.leftButton.tintColor = accent; + [self.leftButton addTarget:self.superview action:leftAction forControlEvents:UIControlEventTouchUpInside]; + [self.headerView addSubview:self.leftButton]; + + [self.leftButton size:CGSizeMake(40, 40)]; + [self.leftButton y:self.headerView.centerYAnchor padding:5]; + [self.leftButton leading:self.headerView.leadingAnchor padding:20]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold]; + self.titleLabel.text = title; + [self.headerView addSubview:self.titleLabel]; + + [self.titleLabel y:self.headerView.centerYAnchor padding:5]; + [self.titleLabel x:self.headerView.centerXAnchor]; + + } + + return self; +} + + +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction rightIcon:(NSString *)rightIconString rightAction:(SEL)rightAction { + + self = [super init]; + if (self) { + + self.clipsToBounds = YES; + + self.headerView = [[UIView alloc] init]; + [self addSubview:self.headerView]; + + [self.headerView fill]; + + + self.grabberView = [[UIView alloc] init]; + self.grabberView.backgroundColor = UIColor.tertiarySystemFillColor; + self.grabberView.layer.cornerRadius = 3; + [self.headerView addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.headerView.centerXAnchor]; + [self.grabberView top:self.headerView.topAnchor padding:10]; + + + self.leftButton = [[UIButton alloc] init]; + self.leftButton.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.leftButton.layer.cornerRadius = 12; + self.leftButton.layer.cornerCurve = kCACornerCurveContinuous; + UIImage *leftIcon = [UIImage systemImageNamed:leftIconString]; + [self.leftButton setImage:leftIcon forState:UIControlStateNormal]; + self.leftButton.tintColor = accent; + [self.leftButton addTarget:self.superview action:leftAction forControlEvents:UIControlEventTouchUpInside]; + [self.headerView addSubview:self.leftButton]; + + [self.leftButton size:CGSizeMake(40, 40)]; + [self.leftButton y:self.headerView.centerYAnchor padding:5]; + [self.leftButton leading:self.headerView.leadingAnchor padding:20]; + + + self.rightButton = [[UIButton alloc] init]; + self.rightButton.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.rightButton.layer.cornerRadius = 12; + self.rightButton.layer.cornerCurve = kCACornerCurveContinuous; + UIImage *rightIcon = [UIImage systemImageNamed:rightIconString]; + [self.rightButton setImage:rightIcon forState:UIControlStateNormal]; + [self.rightButton addTarget:self.superview action:rightAction forControlEvents:UIControlEventTouchUpInside]; + self.rightButton.tintColor = accent; + [self.headerView addSubview:self.rightButton]; + + [self.rightButton size:CGSizeMake(40, 40)]; + [self.rightButton y:self.headerView.centerYAnchor padding:5]; + [self.rightButton trailing:self.headerView.trailingAnchor padding:-20]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold]; + self.titleLabel.text = title; + [self.headerView addSubview:self.titleLabel]; + + [self.titleLabel y:self.headerView.centerYAnchor padding:5]; + [self.titleLabel x:self.headerView.centerXAnchor]; + + } + + return self; +} + + +@end diff --git a/Avatar/App/Avatar/Avimoji/AvimojiViewController.h b/Avatar/App/Avatar/Avimoji/AvimojiViewController.h new file mode 100644 index 0000000..3c1a5d0 --- /dev/null +++ b/Avatar/App/Avatar/Avimoji/AvimojiViewController.h @@ -0,0 +1,29 @@ +#import +#import "ConstraintExtension.h" +#import "TDHeaderView.h" + +#import "TDAvatarIdentityToolsCell.h" +#import "TDAvatarIdentityCellHeaderView.h" +#import "TDAvatarIdentityStickerCell.h" +#import "TDAvatarIdentityEmojiCell.h" +#import "TDAvatarIdentityPickerDataSource.h" +#import "TDEmojiPickerViewController.h" + +@interface AvimojiViewController : UIViewController +@property (nonatomic, retain) TDHeaderView *headerView; +@property (nonatomic, retain) UIView *preview; +@property (nonatomic, retain) UIImageView *previewImage; +@property (nonatomic, retain) UIImageView *stickerImage; +@property (nonatomic, retain) UILabel *emojiLabel; +@property (nonatomic, retain) UITextField *textField; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *stickersArray; +@property (nonatomic, retain) NSMutableArray *emojisArray; +@property (nonatomic, retain) UIColor *accentColour; +@end + + + + + + diff --git a/Avatar/App/Avatar/Avimoji/AvimojiViewController.m b/Avatar/App/Avatar/Avimoji/AvimojiViewController.m new file mode 100644 index 0000000..4045501 --- /dev/null +++ b/Avatar/App/Avatar/Avimoji/AvimojiViewController.m @@ -0,0 +1,525 @@ +#import "AvimojiViewController.h" + +@implementation AvimojiViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Primary"]; + + self.accentColour = UIColor.systemBlueColor; + + self.view.tintColor = self.accentColour; + + UIWindow *window = [UIApplication sharedApplication].windows.firstObject; + window.tintColor = self.accentColour; + + self.stickersArray = [[TDAvatarIdentityPickerDataSource sharedInstance] stickersData]; + self.emojisArray = [[TDAvatarIdentityPickerDataSource sharedInstance] emojiData]; + + [self layoutHeaderView]; + [self layoutCollectionView]; +} + + +-(void)layoutHeaderView { + + self.headerView = [[TDHeaderView alloc] initWithTitle:@"Avimoji" accent:UIColor.systemBlueColor leftIcon:@"chevron.left" leftAction:@selector(dismissVC) rightIcon:@"paperplane.fill" rightAction:nil]; + self.headerView.grabberView.alpha = 0; + self.headerView.leftButton.backgroundColor = [UIColor colorNamed:@"Secondary"]; + self.headerView.rightButton.backgroundColor = self.accentColour; + self.headerView.rightButton.tintColor = UIColor.whiteColor; + self.headerView.rightButton.alpha = 0; + self.headerView.rightButton.menu = [self optionsManager]; + self.headerView.rightButton.showsMenuAsPrimaryAction = true; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 55)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.safeAreaLayoutGuide.topAnchor padding:0]; + + + self.preview = [[UIView alloc] init]; + self.preview.backgroundColor = [self colorWithHexString:@"a8e6cf"]; + self.preview.layer.cornerRadius = 125; + self.preview.clipsToBounds = YES; + self.preview.layer.masksToBounds = YES; + [self.view addSubview:self.preview]; + + [self.preview size:CGSizeMake(250, 250)]; + [self.preview x:self.view.centerXAnchor]; + [self.preview top:self.headerView.bottomAnchor padding:20]; + + + self.previewImage = [[UIImageView alloc] init]; + self.previewImage.contentMode = UIViewContentModeScaleAspectFill; + [self.preview addSubview:self.previewImage]; + + [self.previewImage size:CGSizeMake(250, 250)]; + [self.previewImage x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; + + + self.stickerImage = [[UIImageView alloc] init]; + self.stickerImage.contentMode = UIViewContentModeScaleAspectFill; + self.stickerImage.alpha = 0; + [self.preview addSubview:self.stickerImage]; + + [self.stickerImage size:CGSizeMake(200, 200)]; + [self.stickerImage x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; + + + self.emojiLabel = [[UILabel alloc] init]; + self.emojiLabel.textAlignment = NSTextAlignmentCenter; + self.emojiLabel.font = [UIFont systemFontOfSize:170]; + self.emojiLabel.text = @"😀"; + [self.preview addSubview:self.emojiLabel]; + + [self.emojiLabel x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; + + + self.textField = [[UITextField alloc] init]; + self.textField.backgroundColor = UIColor.clearColor; + self.textField.tintColor = self.accentColour; + self.textField.textAlignment = NSTextAlignmentCenter; + self.textField.font = [UIFont systemFontOfSize:100 weight:UIFontWeightBold]; + self.textField.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters; + self.textField.delegate = self; + self.textField.returnKeyType = UIReturnKeyDone; + self.textField.alpha = 0; + [self.preview addSubview:self.textField]; + + [self.textField size:CGSizeMake(230, 230)]; + [self.textField x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[TDAvatarIdentityToolsCell class] forCellWithReuseIdentifier:@"ToolsCell"]; + [self.collectionView registerClass:[TDAvatarIdentityStickerCell class] forCellWithReuseIdentifier:@"StickerCell"]; + [self.collectionView registerClass:[TDAvatarIdentityEmojiCell class] forCellWithReuseIdentifier:@"EmojiCell"]; + [self.collectionView registerClass:[TDAvatarIdentityCellHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; + [self.view addSubview:self.collectionView]; + + [self.collectionView top:self.preview.bottomAnchor padding:20]; + [self.collectionView bottom:self.view.bottomAnchor padding:-20]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView { + return 3; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { + return CGSizeMake(self.view.frame.size.width, 45); +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + + if (section == 0) { + return 7; + } else if (section == 1) { + return self.stickersArray.count; + } else { + return self.emojisArray.count; + } +} + + +-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + UICollectionReusableView *reusableview = nil; + + if (kind == UICollectionElementKindSectionHeader) { + + TDAvatarIdentityCellHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; + + NSArray *titleArray = [[NSArray alloc] initWithObjects:@"", @"Stickers", @"More", nil]; + + headerView.headerLabel.text = [titleArray objectAtIndex:indexPath.section]; + reusableview = headerView; + } + + return reusableview; + +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + if (indexPath.section == 0) { + + TDAvatarIdentityToolsCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ToolsCell" forIndexPath:indexPath]; + + cell.baseView.backgroundColor = [self.accentColour colorWithAlphaComponent:0.4]; + cell.baseView.layer.borderWidth = 0.8; + cell.baseView.layer.borderColor = [self.accentColour colorWithAlphaComponent:0.7].CGColor; + cell.iconImage.tintColor = self.accentColour; + + if (indexPath.row == 0) { + cell.iconImage.image = [UIImage systemImageNamed:@"photo.fill.on.rectangle.fill"]; + } else if (indexPath.row == 1) { + cell.iconImage.image = [UIImage systemImageNamed:@"paintpalette.fill"]; + } else if (indexPath.row == 2) { + cell.iconImage.image = [UIImage systemImageNamed:@"face.smiling.fill"]; + } else if (indexPath.row == 3) { + cell.iconImage.image = [UIImage systemImageNamed:@"textformat"]; + } else if (indexPath.row == 4) { + cell.iconImage.image = [UIImage systemImageNamed:@"squareshape.fill"]; + } else if (indexPath.row == 5) { + cell.iconImage.image = [UIImage systemImageNamed:@"square.fill"]; + } else if (indexPath.row == 6) { + cell.iconImage.image = [UIImage systemImageNamed:@"circle.fill"]; + } + + return cell; + + } else if (indexPath.section == 1) { + + TDAvatarIdentityStickerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"StickerCell" forIndexPath:indexPath]; + + cell.iconImage.image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/var/mobile/Library/Avatar/Stickers/%@", [self.stickersArray objectAtIndex:indexPath.row]]]; + return cell; + + } else { + + TDAvatarIdentityEmojiCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"EmojiCell" forIndexPath:indexPath]; + + TDAvatarIdentityPickerEmojiDataModel *emojiData = [self.emojisArray objectAtIndex:indexPath.row]; + + cell.baseView.backgroundColor = [self colorWithHexString:emojiData.colour]; + cell.emojiLabel.text = emojiData.emoji; + + return cell; + } + +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ + return CGSizeMake(self.view.frame.size.width/4-20, self.view.frame.size.width/4-20); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + self.modalInPresentation = YES; + self.headerView.rightButton.alpha = 1; + + if (indexPath.section == 0) { + + if (indexPath.row == 0) { + [self presentPhotoPickerVC]; + } else if (indexPath.row == 1) { + [self presentColourPickerVC]; + } else if (indexPath.row == 2) { + [self presentEmojiPickerVC]; + } else if (indexPath.row == 3) { + [self presentKeyboardEditing]; + } else if (indexPath.row == 4) { + self.preview.layer.cornerRadius = 0; + } else if (indexPath.row == 5) { + self.preview.layer.cornerRadius = 25; + } else if (indexPath.row == 6) { + self.preview.layer.cornerRadius = 125; + } + + } else if (indexPath.section == 1) { + + [self.textField resignFirstResponder]; + //self.previewImage.alpha = 0; + self.emojiLabel.alpha = 0; + self.stickerImage.alpha = 1; + self.textField.alpha = 0; + self.stickerImage.image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/var/mobile/Library/Avatar/Stickers/%@", [self.stickersArray objectAtIndex:indexPath.row]]]; + + } else if (indexPath.section == 2) { + + [self.textField resignFirstResponder]; + self.previewImage.alpha = 0; + self.emojiLabel.alpha = 1; + self.stickerImage.alpha = 0; + self.textField.alpha = 0; + + TDAvatarIdentityPickerEmojiDataModel *emojiData = [self.emojisArray objectAtIndex:indexPath.row]; + self.preview.backgroundColor = [self colorWithHexString:emojiData.colour]; + self.emojiLabel.text = emojiData.emoji; + } + + +} + + +-(void)presentPhotoPickerVC { + + UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init]; + imagePickerController.delegate = self; + imagePickerController.allowsEditing = false; + imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [self presentViewController:imagePickerController animated:YES completion:nil]; + +} + + +-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(nonnull NSDictionary *)info { + + [self.textField resignFirstResponder]; + self.previewImage.alpha = 1; + //self.stickerImage.alpha = 0; + //self.emojiLabel.alpha = 0; + //self.textField.alpha = 0; + + self.previewImage.image = info[UIImagePickerControllerOriginalImage]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentColourPickerVC { + [self.textField resignFirstResponder]; + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + colourPickerVC.selectedColor = self.preview.backgroundColor; + colourPickerVC.supportsAlpha = NO; + [self presentViewController:colourPickerVC animated:YES completion:nil]; +} + + +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + self.previewImage.alpha = 0; + UIColor *cpSelectedColour = viewController.selectedColor; + self.preview.backgroundColor = cpSelectedColour; +} + + +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + self.previewImage.alpha = 0; + UIColor *cpSelectedColour = viewController.selectedColor; + self.preview.backgroundColor = cpSelectedColour; +} + + +-(void)presentEmojiPickerVC { + [self.textField resignFirstResponder]; + TDEmojiPickerViewController *vc = [[TDEmojiPickerViewController alloc] init]; + vc.delegate = self; + [self presentViewController:vc animated:YES completion:nil]; +} + + +-(void)presentKeyboardEditing { + + self.emojiLabel.alpha = 0; + //self.previewImage.alpha = 0; + self.textField.alpha = 1; + self.stickerImage.alpha = 0; + self.emojiLabel.text = 0; + + [self.textField becomeFirstResponder]; + +} + + +-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { + + if (textField.text.length >= 2 && range.length == 0) { + return NO; + } else { + return YES; + + } +} + + +-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + textField.userInteractionEnabled = NO; + return YES; +} + + +-(void)textFieldDidEndEditing:(UITextField *)textField { + textField.userInteractionEnabled = YES; +} + + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + if (textField.text.length >= 1) { + [textField resignFirstResponder]; + return YES; + } else { + return NO; + } +} + + +-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ + [self.view endEditing:YES]; +} + + +-(void)didSelectEmoji:(NSString *)emoji { + self.emojiLabel.alpha = 1; + //self.previewImage.alpha = 0; + self.textField.alpha = 0; + self.stickerImage.alpha = 0; + self.emojiLabel.text = emoji; +} + + +-(void)didDismissedEmojiPicker { + NSLog(@"Emoji picker dismissed"); +} + + +-(void)applyAvatar { + +} + + +-(UIImage *)avatarSnapshot { + + UIGraphicsBeginImageContextWithOptions(self.preview.frame.size, NO, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); + [self.preview.layer renderInContext:context]; + UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext(); + return snapshotImage; +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)dismissVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + + +-(UIMenu *)optionsManager { + + UIAction *saveAction = [UIAction actionWithTitle:@"Save to photo library" image:[UIImage systemImageNamed:@"photo.fill"] identifier:nil handler:^(UIAction *action) { + [self saveSticker]; + }]; + + UIAction *shareAction = [UIAction actionWithTitle:@"Share" image:[UIImage systemImageNamed:@"square.and.arrow.up.fill"] identifier:nil handler:^(UIAction *action) { + [self shareSticker]; + }]; + + UIAction *resetAction = [UIAction actionWithTitle:@"Reset" image:[UIImage systemImageNamed:@"trash.fill"] identifier:nil handler:^(UIAction *action) { + [self resetSticker]; + }]; + resetAction.attributes = UIMenuElementAttributesDestructive; + + return [UIMenu menuWithTitle:@"" children:@[saveAction, shareAction, resetAction]]; +} + + +-(void)saveSticker { + + UIGraphicsBeginImageContextWithOptions(self.preview.frame.size, YES, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); + [self.preview.layer renderInContext:context]; + UIImage *contextImage = UIGraphicsGetImageFromCurrentImageContext(); + UIImageWriteToSavedPhotosAlbum(contextImage, nil, nil, nil); + + [self showAlertWithTitle:@"Successful!" subtitle:@"Your Avimoji was saved to your photo library."]; +} + + +-(void)shareSticker { + + UIGraphicsBeginImageContextWithOptions(self.preview.frame.size, YES, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); + [self.preview.layer renderInContext:context]; + UIImage *contextImage = UIGraphicsGetImageFromCurrentImageContext(); + + NSString *title = @"Avimoji"; + NSArray *dataToShare = @[contextImage, title]; + + UIActivityViewController *controller = [[UIActivityViewController alloc]initWithActivityItems:dataToShare applicationActivities:nil]; + controller.excludedActivityTypes = @[UIActivityTypeAirDrop]; + [self presentViewController:controller animated:YES completion:nil]; + + + [controller setCompletionWithItemsHandler:^(UIActivityType _Nullable activityType, BOOL completed, NSArray * _Nullable returnedItems, NSError * _Nullable activityError) { + }]; + +} + + +-(void)resetSticker { + self.preview.backgroundColor = [self colorWithHexString:@"a8e6cf"]; + self.preview.layer.cornerRadius = 125; + self.previewImage.image = nil; + self.stickerImage.image = nil; + self.stickerImage.alpha = 0; + self.emojiLabel.alpha = 1; + self.emojiLabel.text = @"😀"; + self.textField.text = @""; + self.textField.alpha = 0; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + + +@end diff --git a/Avatar/App/Avatar/Base.lproj/LaunchScreen.storyboard b/Avatar/App/Avatar/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/Avatar/App/Avatar/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Avatar/App/Avatar/Core/AppDelegate.h b/Avatar/App/Avatar/Core/AppDelegate.h new file mode 100644 index 0000000..d79858b --- /dev/null +++ b/Avatar/App/Avatar/Core/AppDelegate.h @@ -0,0 +1,7 @@ +#import + +@interface AppDelegate : UIResponder + + +@end + diff --git a/Avatar/App/Avatar/Core/AppDelegate.m b/Avatar/App/Avatar/Core/AppDelegate.m new file mode 100644 index 0000000..8c7fce9 --- /dev/null +++ b/Avatar/App/Avatar/Core/AppDelegate.m @@ -0,0 +1,33 @@ +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + return YES; +} + + +#pragma mark - UISceneSession lifecycle + + +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; +} + + +- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. +} + + +@end diff --git a/Avatar/App/Avatar/Core/Emoji.plist b/Avatar/App/Avatar/Core/Emoji.plist new file mode 100644 index 0000000..f2fefa4 --- /dev/null +++ b/Avatar/App/Avatar/Core/Emoji.plist @@ -0,0 +1,3136 @@ + + + + + + + Title + Smileys & People + Emojis + + 😀 + 😃 + 😄 + 😁 + 😆 + 😅 + 😂 + 🤣 + ☺️ + 😊 + 😇 + 🙂 + 🙃 + 😉 + 😌 + 😍 + 🥰 + 😘 + 😗 + 😙 + 😚 + 😋 + 😛 + 😝 + 😜 + 🤪 + 🤨 + 🧐 + 🤓 + 😎 + 🤩 + 🥳 + 😏 + 😒 + 😞 + 😔 + 😟 + 😕 + 🙁 + ☹️ + 😣 + 😖 + 😫 + 😩 + 🥺 + 😢 + 😭 + 😤 + 😠 + 😡 + 🤬 + 🤯 + 😳 + 🥵 + 🥶 + 😱 + 😨 + 😰 + 😥 + 😓 + 🤗 + 🤔 + 🤭 + 🤫 + 🤥 + 😶 + 😐 + 😑 + 😬 + 🙄 + 😯 + 😦 + 😧 + 😮 + 😲 + 🥱 + 😴 + 🤤 + 😪 + 😵 + 🤐 + 🥴 + 🤢 + 🤮 + 🤧 + 😷 + 🤒 + 🤕 + 🤑 + 🤠 + 😈 + 👿 + 👹 + 👺 + 🤡 + 💩 + 👻 + 💀 + ☠️ + 👽 + 👾 + 🤖 + 🎃 + 😺 + 😸 + 😹 + 😻 + 😼 + 😽 + 🙀 + 😿 + 😾 + 🤲 + 🤲🏻 + 🤲🏼 + 🤲🏽 + 🤲🏾 + 🤲🏿 + 👐 + 👐🏻 + 👐🏼 + 👐🏽 + 👐🏾 + 👐🏿 + 🙌 + 🙌🏻 + 🙌🏼 + 🙌🏽 + 🙌🏾 + 🙌🏿 + 👏 + 👏🏻 + 👏🏼 + 👏🏽 + 👏🏾 + 👏🏿 + 🤝 + 👍 + 👍🏻 + 👍🏼 + 👍🏽 + 👍🏾 + 👍🏿 + 👎 + 👎🏻 + 👎🏼 + 👎🏽 + 👎🏾 + 👎🏿 + 👊 + 👊🏻 + 👊🏼 + 👊🏽 + 👊🏾 + 👊🏿 + + ✊🏻 + ✊🏼 + ✊🏽 + ✊🏾 + ✊🏿 + 🤛 + 🤛🏻 + 🤛🏼 + 🤛🏽 + 🤛🏾 + 🤛🏿 + 🤜 + 🤜🏻 + 🤜🏼 + 🤜🏽 + 🤜🏾 + 🤜🏿 + 🤞 + 🤞🏻 + 🤞🏼 + 🤞🏽 + 🤞🏾 + 🤞🏿 + ✌️ + ✌🏻 + ✌🏼 + ✌🏽 + ✌🏾 + ✌🏿 + 🤟 + 🤟🏻 + 🤟🏼 + 🤟🏽 + 🤟🏾 + 🤟🏿 + 🤘 + 🤘🏻 + 🤘🏼 + 🤘🏽 + 🤘🏾 + 🤘🏿 + 👌 + 👌🏻 + 👌🏼 + 👌🏽 + 👌🏾 + 👌🏿 + 🤏 + 🤏🏻 + 🤏🏼 + 🤏🏽 + 🤏🏾 + 🤏🏿 + 👈 + 👈🏻 + 👈🏼 + 👈🏽 + 👈🏾 + 👈🏿 + 👉 + 👉🏻 + 👉🏼 + 👉🏽 + 👉🏾 + 👉🏿 + 👆 + 👆🏻 + 👆🏼 + 👆🏽 + 👆🏾 + 👆🏿 + 👇 + 👇🏻 + 👇🏼 + 👇🏽 + 👇🏾 + 👇🏿 + ☝️ + ☝🏻 + ☝🏼 + ☝🏽 + ☝🏾 + ☝🏿 + + ✋🏻 + ✋🏼 + ✋🏽 + ✋🏾 + ✋🏿 + 🤚 + 🤚🏻 + 🤚🏼 + 🤚🏽 + 🤚🏾 + 🤚🏿 + 🖐 + 🖐🏻 + 🖐🏼 + 🖐🏽 + 🖐🏾 + 🖐🏿 + 🖖 + 🖖🏻 + 🖖🏼 + 🖖🏽 + 🖖🏾 + 🖖🏿 + 👋 + 👋🏻 + 👋🏼 + 👋🏽 + 👋🏾 + 👋🏿 + 🤙 + 🤙🏻 + 🤙🏼 + 🤙🏽 + 🤙🏾 + 🤙🏿 + 💪 + 💪🏻 + 💪🏼 + 💪🏽 + 💪🏾 + 💪🏿 + 🦾 + 🖕 + 🖕🏻 + 🖕🏼 + 🖕🏽 + 🖕🏾 + 🖕🏿 + ✍️ + ✍🏻 + ✍🏼 + ✍🏽 + ✍🏾 + ✍🏿 + 🙏 + 🙏🏻 + 🙏🏼 + 🙏🏽 + 🙏🏾 + 🙏🏿 + 🦶 + 🦶🏻 + 🦶🏼 + 🦶🏽 + 🦶🏾 + 🦶🏿 + 🦵 + 🦵🏻 + 🦵🏼 + 🦵🏽 + 🦵🏾 + 🦵🏿 + 🦿 + 💄 + 💋 + 👄 + 🦷 + 👅 + 👂 + 👂🏻 + 👂🏼 + 👂🏽 + 👂🏾 + 👂🏿 + 🦻 + 🦻🏻 + 🦻🏼 + 🦻🏽 + 🦻🏾 + 🦻🏿 + 👃 + 👃🏻 + 👃🏼 + 👃🏽 + 👃🏾 + 👃🏿 + 👣 + 👁 + 👀 + 🧠 + 🗣 + 👤 + 👥 + 👶 + 👶🏻 + 👶🏼 + 👶🏽 + 👶🏾 + 👶🏿 + 👧 + 👧🏻 + 👧🏼 + 👧🏽 + 👧🏾 + 👧🏿 + 🧒 + 🧒🏻 + 🧒🏼 + 🧒🏽 + 🧒🏾 + 🧒🏿 + 👦 + 👦🏻 + 👦🏼 + 👦🏽 + 👦🏾 + 👦🏿 + 👩 + 👩🏻 + 👩🏼 + 👩🏽 + 👩🏾 + 👩🏿 + 🧑 + 🧑🏻 + 🧑🏼 + 🧑🏽 + 🧑🏾 + 🧑🏿 + 👨 + 👨🏻 + 👨🏼 + 👨🏽 + 👨🏾 + 👨🏿 + 👩‍🦱 + 👩🏻‍🦱 + 👩🏼‍🦱 + 👩🏽‍🦱 + 👩🏾‍🦱 + 👩🏿‍🦱 + 🧑‍🦱 + 🧑🏻‍🦱 + 🧑🏼‍🦱 + 🧑🏽‍🦱 + 🧑🏾‍🦱 + 🧑🏿‍🦱 + 👨‍🦱 + 👨🏻‍🦱 + 👨🏼‍🦱 + 👨🏽‍🦱 + 👨🏾‍🦱 + 👨🏿‍🦱 + 👩‍🦰 + 👩🏻‍🦰 + 👩🏼‍🦰 + 👩🏽‍🦰 + 👩🏾‍🦰 + 👩🏿‍🦰 + 🧑‍🦰 + 🧑🏻‍🦰 + 🧑🏼‍🦰 + 🧑🏽‍🦰 + 🧑🏾‍🦰 + 🧑🏿‍🦰 + 👨‍🦰 + 👨🏻‍🦰 + 👨🏼‍🦰 + 👨🏽‍🦰 + 👨🏾‍🦰 + 👨🏿‍🦰 + 👱‍♀️ + 👱🏻‍♀️ + 👱🏼‍♀️ + 👱🏽‍♀️ + 👱🏾‍♀️ + 👱🏿‍♀️ + 👱 + 👱🏻 + 👱🏼 + 👱🏽 + 👱🏾 + 👱🏿 + 👱‍♂️ + 👱🏻‍♂️ + 👱🏼‍♂️ + 👱🏽‍♂️ + 👱🏾‍♂️ + 👱🏿‍♂️ + 👩‍🦳 + 👩🏻‍🦳 + 👩🏼‍🦳 + 👩🏽‍🦳 + 👩🏾‍🦳 + 👩🏿‍🦳 + 🧑‍🦳 + 🧑🏻‍🦳 + 🧑🏼‍🦳 + 🧑🏽‍🦳 + 🧑🏾‍🦳 + 🧑🏿‍🦳 + 👨‍🦳 + 👨🏻‍🦳 + 👨🏼‍🦳 + 👨🏽‍🦳 + 👨🏾‍🦳 + 👨🏿‍🦳 + 👩‍🦲 + 👩🏻‍🦲 + 👩🏼‍🦲 + 👩🏽‍🦲 + 👩🏾‍🦲 + 👩🏿‍🦲 + 🧑‍🦲 + 🧑🏻‍🦲 + 🧑🏼‍🦲 + 🧑🏽‍🦲 + 🧑🏾‍🦲 + 🧑🏿‍🦲 + 👨‍🦲 + 👨🏻‍🦲 + 👨🏼‍🦲 + 👨🏽‍🦲 + 👨🏾‍🦲 + 👨🏿‍🦲 + 🧔 + 🧔🏻 + 🧔🏼 + 🧔🏽 + 🧔🏾 + 🧔🏿 + 👵 + 👵🏻 + 👵🏼 + 👵🏽 + 👵🏾 + 👵🏿 + 🧓 + 🧓🏻 + 🧓🏼 + 🧓🏽 + 🧓🏾 + 🧓🏿 + 👴 + 👴🏻 + 👴🏼 + 👴🏽 + 👴🏾 + 👴🏿 + 👲 + 👲🏻 + 👲🏼 + 👲🏽 + 👲🏾 + 👲🏿 + 👳‍♀️ + 👳🏻‍♀️ + 👳🏼‍♀️ + 👳🏽‍♀️ + 👳🏾‍♀️ + 👳🏿‍♀️ + 👳 + 👳🏻 + 👳🏼 + 👳🏽 + 👳🏾 + 👳🏿 + 👳‍♂️ + 👳🏻‍♂️ + 👳🏼‍♂️ + 👳🏽‍♂️ + 👳🏾‍♂️ + 👳🏿‍♂️ + 🧕 + 🧕🏻 + 🧕🏼 + 🧕🏽 + 🧕🏾 + 🧕🏿 + 👮‍♀️ + 👮🏻‍♀️ + 👮🏼‍♀️ + 👮🏽‍♀️ + 👮🏾‍♀️ + 👮🏿‍♀️ + 👮 + 👮🏻 + 👮🏼 + 👮🏽 + 👮🏾 + 👮🏿 + 👮‍♂️ + 👮🏻‍♂️ + 👮🏼‍♂️ + 👮🏽‍♂️ + 👮🏾‍♂️ + 👮🏿‍♂️ + 👷‍♀️ + 👷🏻‍♀️ + 👷🏼‍♀️ + 👷🏽‍♀️ + 👷🏾‍♀️ + 👷🏿‍♀️ + 👷 + 👷🏻 + 👷🏼 + 👷🏽 + 👷🏾 + 👷🏿 + 👷‍♂️ + 👷🏻‍♂️ + 👷🏼‍♂️ + 👷🏽‍♂️ + 👷🏾‍♂️ + 👷🏿‍♂️ + 💂‍♀️ + 💂🏻‍♀️ + 💂🏼‍♀️ + 💂🏽‍♀️ + 💂🏾‍♀️ + 💂🏿‍♀️ + 💂 + 💂🏻 + 💂🏼 + 💂🏽 + 💂🏾 + 💂🏿 + 💂‍♂️ + 💂🏻‍♂️ + 💂🏼‍♂️ + 💂🏽‍♂️ + 💂🏾‍♂️ + 💂🏿‍♂️ + 🕵️‍♀️ + 🕵🏻‍♀️ + 🕵🏼‍♀️ + 🕵🏽‍♀️ + 🕵🏾‍♀️ + 🕵🏿‍♀️ + 🕵️ + 🕵🏻 + 🕵🏼 + 🕵🏽 + 🕵🏾 + 🕵🏿 + 🕵️‍♂️ + 🕵🏻‍♂️ + 🕵🏼‍♂️ + 🕵🏽‍♂️ + 🕵🏾‍♂️ + 🕵🏿‍♂️ + 👩‍⚕️ + 👩🏻‍⚕️ + 👩🏼‍⚕️ + 👩🏽‍⚕️ + 👩🏾‍⚕️ + 👩🏿‍⚕️ + 🧑‍⚕️ + 🧑🏻‍⚕️ + 🧑🏼‍⚕️ + 🧑🏽‍⚕️ + 🧑🏾‍⚕️ + 🧑🏿‍⚕️ + 👨‍⚕️ + 👨🏻‍⚕️ + 👨🏼‍⚕️ + 👨🏽‍⚕️ + 👨🏾‍⚕️ + 👨🏿‍⚕️ + 👩‍🌾 + 👩🏻‍🌾 + 👩🏼‍🌾 + 👩🏽‍🌾 + 👩🏾‍🌾 + 👩🏿‍🌾 + 🧑‍🌾 + 🧑🏻‍🌾 + 🧑🏼‍🌾 + 🧑🏽‍🌾 + 🧑🏾‍🌾 + 🧑🏿‍🌾 + 👨‍🌾 + 👨🏻‍🌾 + 👨🏼‍🌾 + 👨🏽‍🌾 + 👨🏾‍🌾 + 👨🏿‍🌾 + 👩‍🍳 + 👩🏻‍🍳 + 👩🏼‍🍳 + 👩🏽‍🍳 + 👩🏾‍🍳 + 👩🏿‍🍳 + 🧑‍🍳 + 🧑🏻‍🍳 + 🧑🏼‍🍳 + 🧑🏽‍🍳 + 🧑🏾‍🍳 + 🧑🏿‍🍳 + 👨‍🍳 + 👨🏻‍🍳 + 👨🏼‍🍳 + 👨🏽‍🍳 + 👨🏾‍🍳 + 👨🏿‍🍳 + 👩‍🎓 + 👩🏻‍🎓 + 👩🏼‍🎓 + 👩🏽‍🎓 + 👩🏾‍🎓 + 👩🏿‍🎓 + 🧑‍🎓 + 🧑🏻‍🎓 + 🧑🏼‍🎓 + 🧑🏽‍🎓 + 🧑🏾‍🎓 + 🧑🏿‍🎓 + 👨‍🎓 + 👨🏻‍🎓 + 👨🏼‍🎓 + 👨🏽‍🎓 + 👨🏾‍🎓 + 👨🏿‍🎓 + 👩‍🎤 + 👩🏻‍🎤 + 👩🏼‍🎤 + 👩🏽‍🎤 + 👩🏾‍🎤 + 👩🏿‍🎤 + 🧑‍🎤 + 🧑🏻‍🎤 + 🧑🏼‍🎤 + 🧑🏽‍🎤 + 🧑🏾‍🎤 + 🧑🏿‍🎤 + 👨‍🎤 + 👨🏻‍🎤 + 👨🏼‍🎤 + 👨🏽‍🎤 + 👨🏾‍🎤 + 👨🏿‍🎤 + 👩‍🏫 + 👩🏻‍🏫 + 👩🏼‍🏫 + 👩🏽‍🏫 + 👩🏾‍🏫 + 👩🏿‍🏫 + 🧑‍🏫 + 🧑🏻‍🏫 + 🧑🏼‍🏫 + 🧑🏽‍🏫 + 🧑🏾‍🏫 + 🧑🏿‍🏫 + 👨‍🏫 + 👨🏻‍🏫 + 👨🏼‍🏫 + 👨🏽‍🏫 + 👨🏾‍🏫 + 👨🏿‍🏫 + 👩‍🏭 + 👩🏻‍🏭 + 👩🏼‍🏭 + 👩🏽‍🏭 + 👩🏾‍🏭 + 👩🏿‍🏭 + 🧑‍🏭 + 🧑🏻‍🏭 + 🧑🏼‍🏭 + 🧑🏽‍🏭 + 🧑🏾‍🏭 + 🧑🏿‍🏭 + 👨‍🏭 + 👨🏻‍🏭 + 👨🏼‍🏭 + 👨🏽‍🏭 + 👨🏾‍🏭 + 👨🏿‍🏭 + 👩‍💻 + 👩🏻‍💻 + 👩🏼‍💻 + 👩🏽‍💻 + 👩🏾‍💻 + 👩🏿‍💻 + 🧑‍💻 + 🧑🏻‍💻 + 🧑🏼‍💻 + 🧑🏽‍💻 + 🧑🏾‍💻 + 🧑🏿‍💻 + 👨‍💻 + 👨🏻‍💻 + 👨🏼‍💻 + 👨🏽‍💻 + 👨🏾‍💻 + 👨🏿‍💻 + 👩‍💼 + 👩🏻‍💼 + 👩🏼‍💼 + 👩🏽‍💼 + 👩🏾‍💼 + 👩🏿‍💼 + 🧑‍💼 + 🧑🏻‍💼 + 🧑🏼‍💼 + 🧑🏽‍💼 + 🧑🏾‍💼 + 🧑🏿‍💼 + 👨‍💼 + 👨🏻‍💼 + 👨🏼‍💼 + 👨🏽‍💼 + 👨🏾‍💼 + 👨🏿‍💼 + 👩‍🔧 + 👩🏻‍🔧 + 👩🏼‍🔧 + 👩🏽‍🔧 + 👩🏾‍🔧 + 👩🏿‍🔧 + 🧑‍🔧 + 🧑🏻‍🔧 + 🧑🏼‍🔧 + 🧑🏽‍🔧 + 🧑🏾‍🔧 + 🧑🏿‍🔧 + 👨‍🔧 + 👨🏻‍🔧 + 👨🏼‍🔧 + 👨🏽‍🔧 + 👨🏾‍🔧 + 👨🏿‍🔧 + 👩‍🔬 + 👩🏻‍🔬 + 👩🏼‍🔬 + 👩🏽‍🔬 + 👩🏾‍🔬 + 👩🏿‍🔬 + 🧑‍🔬 + 🧑🏻‍🔬 + 🧑🏼‍🔬 + 🧑🏽‍🔬 + 🧑🏾‍🔬 + 🧑🏿‍🔬 + 👨‍🔬 + 👨🏻‍🔬 + 👨🏼‍🔬 + 👨🏽‍🔬 + 👨🏾‍🔬 + 👨🏿‍🔬 + 👩‍🎨 + 👩🏻‍🎨 + 👩🏼‍🎨 + 👩🏽‍🎨 + 👩🏾‍🎨 + 👩🏿‍🎨 + 🧑‍🎨 + 🧑🏻‍🎨 + 🧑🏼‍🎨 + 🧑🏽‍🎨 + 🧑🏾‍🎨 + 🧑🏿‍🎨 + 👨‍🎨 + 👨🏻‍🎨 + 👨🏼‍🎨 + 👨🏽‍🎨 + 👨🏾‍🎨 + 👨🏿‍🎨 + 👩‍🚒 + 👩🏻‍🚒 + 👩🏼‍🚒 + 👩🏽‍🚒 + 👩🏾‍🚒 + 👩🏿‍🚒 + 🧑‍🚒 + 🧑🏻‍🚒 + 🧑🏼‍🚒 + 🧑🏽‍🚒 + 🧑🏾‍🚒 + 🧑🏿‍🚒 + 👨‍🚒 + 👨🏻‍🚒 + 👨🏼‍🚒 + 👨🏽‍🚒 + 👨🏾‍🚒 + 👨🏿‍🚒 + 👩‍✈️ + 👩🏻‍✈️ + 👩🏼‍✈️ + 👩🏽‍✈️ + 👩🏾‍✈️ + 👩🏿‍✈️ + 🧑‍✈️ + 🧑🏻‍✈️ + 🧑🏼‍✈️ + 🧑🏽‍✈️ + 🧑🏾‍✈️ + 🧑🏿‍✈️ + 👨‍✈️ + 👨🏻‍✈️ + 👨🏼‍✈️ + 👨🏽‍✈️ + 👨🏾‍✈️ + 👨🏿‍✈️ + 👩‍🚀 + 👩🏻‍🚀 + 👩🏼‍🚀 + 👩🏽‍🚀 + 👩🏾‍🚀 + 👩🏿‍🚀 + 🧑‍🚀 + 🧑🏻‍🚀 + 🧑🏼‍🚀 + 🧑🏽‍🚀 + 🧑🏾‍🚀 + 🧑🏿‍🚀 + 👨‍🚀 + 👨🏻‍🚀 + 👨🏼‍🚀 + 👨🏽‍🚀 + 👨🏾‍🚀 + 👨🏿‍🚀 + 👩‍⚖️ + 👩🏻‍⚖️ + 👩🏼‍⚖️ + 👩🏽‍⚖️ + 👩🏾‍⚖️ + 👩🏿‍⚖️ + 🧑‍⚖️ + 🧑🏻‍⚖️ + 🧑🏼‍⚖️ + 🧑🏽‍⚖️ + 🧑🏾‍⚖️ + 🧑🏿‍⚖️ + 👨‍⚖️ + 👨🏻‍⚖️ + 👨🏼‍⚖️ + 👨🏽‍⚖️ + 👨🏾‍⚖️ + 👨🏿‍⚖️ + 👰 + 👰🏻 + 👰🏼 + 👰🏽 + 👰🏾 + 👰🏿 + 🤵 + 🤵🏻 + 🤵🏼 + 🤵🏽 + 🤵🏾 + 🤵🏿 + 👸 + 👸🏻 + 👸🏼 + 👸🏽 + 👸🏾 + 👸🏿 + 🤴 + 🤴🏻 + 🤴🏼 + 🤴🏽 + 🤴🏾 + 🤴🏿 + 🦸‍♀️ + 🦸🏻‍♀️ + 🦸🏼‍♀️ + 🦸🏽‍♀️ + 🦸🏾‍♀️ + 🦸🏿‍♀️ + 🦸 + 🦸🏻 + 🦸🏼 + 🦸🏽 + 🦸🏾 + 🦸🏿 + 🦸‍♂️ + 🦸🏻‍♂️ + 🦸🏼‍♂️ + 🦸🏽‍♂️ + 🦸🏾‍♂️ + 🦸🏿‍♂️ + 🦹‍♀️ + 🦹🏻‍♀️ + 🦹🏼‍♀️ + 🦹🏽‍♀️ + 🦹🏾‍♀️ + 🦹🏿‍♀️ + 🦹 + 🦹🏻 + 🦹🏼 + 🦹🏽 + 🦹🏾 + 🦹🏿 + 🦹‍♂️ + 🦹🏻‍♂️ + 🦹🏼‍♂️ + 🦹🏽‍♂️ + 🦹🏾‍♂️ + 🦹🏿‍♂️ + 🤶 + 🤶🏻 + 🤶🏼 + 🤶🏽 + 🤶🏾 + 🤶🏿 + 🎅 + 🎅🏻 + 🎅🏼 + 🎅🏽 + 🎅🏾 + 🎅🏿 + 🧙‍♀️ + 🧙🏻‍♀️ + 🧙🏼‍♀️ + 🧙🏽‍♀️ + 🧙🏾‍♀️ + 🧙🏿‍♀️ + 🧙 + 🧙🏻 + 🧙🏼 + 🧙🏽 + 🧙🏾 + 🧙🏿 + 🧙‍♂️ + 🧙🏻‍♂️ + 🧙🏼‍♂️ + 🧙🏽‍♂️ + 🧙🏾‍♂️ + 🧙🏿‍♂️ + 🧝‍♀️ + 🧝🏻‍♀️ + 🧝🏼‍♀️ + 🧝🏽‍♀️ + 🧝🏾‍♀️ + 🧝🏿‍♀️ + 🧝 + 🧝🏻 + 🧝🏼 + 🧝🏽 + 🧝🏾 + 🧝🏿 + 🧝‍♂️ + 🧝🏻‍♂️ + 🧝🏼‍♂️ + 🧝🏽‍♂️ + 🧝🏾‍♂️ + 🧝🏿‍♂️ + 🧛‍♀️ + 🧛🏻‍♀️ + 🧛🏼‍♀️ + 🧛🏽‍♀️ + 🧛🏾‍♀️ + 🧛🏿‍♀️ + 🧛 + 🧛🏻 + 🧛🏼 + 🧛🏽 + 🧛🏾 + 🧛🏿 + 🧛‍♂️ + 🧛🏻‍♂️ + 🧛🏼‍♂️ + 🧛🏽‍♂️ + 🧛🏾‍♂️ + 🧛🏿‍♂️ + 🧟‍♀️ + 🧟 + 🧟‍♂️ + 🧞‍♀️ + 🧞 + 🧞‍♂️ + 🧜‍♀️ + 🧜🏻‍♀️ + 🧜🏼‍♀️ + 🧜🏽‍♀️ + 🧜🏾‍♀️ + 🧜🏿‍♀️ + 🧜 + 🧜🏻 + 🧜🏼 + 🧜🏽 + 🧜🏾 + 🧜🏿 + 🧜‍♂️ + 🧜🏻‍♂️ + 🧜🏼‍♂️ + 🧜🏽‍♂️ + 🧜🏾‍♂️ + 🧜🏿‍♂️ + 🧚‍♀️ + 🧚🏻‍♀️ + 🧚🏼‍♀️ + 🧚🏽‍♀️ + 🧚🏾‍♀️ + 🧚🏿‍♀️ + 🧚 + 🧚🏻 + 🧚🏼 + 🧚🏽 + 🧚🏾 + 🧚🏿 + 🧚‍♂️ + 🧚🏻‍♂️ + 🧚🏼‍♂️ + 🧚🏽‍♂️ + 🧚🏾‍♂️ + 🧚🏿‍♂️ + 👼 + 👼🏻 + 👼🏼 + 👼🏽 + 👼🏾 + 👼🏿 + 🤰 + 🤰🏻 + 🤰🏼 + 🤰🏽 + 🤰🏾 + 🤰🏿 + 🤱 + 🤱🏻 + 🤱🏼 + 🤱🏽 + 🤱🏾 + 🤱🏿 + 🙇‍♀️ + 🙇🏻‍♀️ + 🙇🏼‍♀️ + 🙇🏽‍♀️ + 🙇🏾‍♀️ + 🙇🏿‍♀️ + 🙇 + 🙇🏻 + 🙇🏼 + 🙇🏽 + 🙇🏾 + 🙇🏿 + 🙇‍♂️ + 🙇🏻‍♂️ + 🙇🏼‍♂️ + 🙇🏽‍♂️ + 🙇🏾‍♂️ + 🙇🏿‍♂️ + 💁‍♀️ + 💁🏻‍♀️ + 💁🏼‍♀️ + 💁🏽‍♀️ + 💁🏾‍♀️ + 💁🏿‍♀️ + 💁 + 💁🏻 + 💁🏼 + 💁🏽 + 💁🏾 + 💁🏿 + 💁‍♂️ + 💁🏻‍♂️ + 💁🏼‍♂️ + 💁🏽‍♂️ + 💁🏾‍♂️ + 💁🏿‍♂️ + 🙅‍♀️ + 🙅🏻‍♀️ + 🙅🏼‍♀️ + 🙅🏽‍♀️ + 🙅🏾‍♀️ + 🙅🏿‍♀️ + 🙅 + 🙅🏻 + 🙅🏼 + 🙅🏽 + 🙅🏾 + 🙅🏿 + 🙅‍♂️ + 🙅🏻‍♂️ + 🙅🏼‍♂️ + 🙅🏽‍♂️ + 🙅🏾‍♂️ + 🙅🏿‍♂️ + 🙆‍♀️ + 🙆🏻‍♀️ + 🙆🏼‍♀️ + 🙆🏽‍♀️ + 🙆🏾‍♀️ + 🙆🏿‍♀️ + 🙆 + 🙆🏻 + 🙆🏼 + 🙆🏽 + 🙆🏾 + 🙆🏿 + 🙆‍♂️ + 🙆🏻‍♂️ + 🙆🏼‍♂️ + 🙆🏽‍♂️ + 🙆🏾‍♂️ + 🙆🏿‍♂️ + 🙋‍♀️ + 🙋🏻‍♀️ + 🙋🏼‍♀️ + 🙋🏽‍♀️ + 🙋🏾‍♀️ + 🙋🏿‍♀️ + 🙋 + 🙋🏻 + 🙋🏼 + 🙋🏽 + 🙋🏾 + 🙋🏿 + 🙋‍♂️ + 🙋🏻‍♂️ + 🙋🏼‍♂️ + 🙋🏽‍♂️ + 🙋🏾‍♂️ + 🙋🏿‍♂️ + 🧏‍♀️ + 🧏🏻‍♀️ + 🧏🏼‍♀️ + 🧏🏽‍♀️ + 🧏🏾‍♀️ + 🧏🏿‍♀️ + 🧏 + 🧏🏻 + 🧏🏼 + 🧏🏽 + 🧏🏾 + 🧏🏿 + 🧏‍♂️ + 🧏🏻‍♂️ + 🧏🏼‍♂️ + 🧏🏽‍♂️ + 🧏🏾‍♂️ + 🧏🏿‍♂️ + 🤦‍♀️ + 🤦🏻‍♀️ + 🤦🏼‍♀️ + 🤦🏽‍♀️ + 🤦🏾‍♀️ + 🤦🏿‍♀️ + 🤦 + 🤦🏻 + 🤦🏼 + 🤦🏽 + 🤦🏾 + 🤦🏿 + 🤦‍♂️ + 🤦🏻‍♂️ + 🤦🏼‍♂️ + 🤦🏽‍♂️ + 🤦🏾‍♂️ + 🤦🏿‍♂️ + 🤷‍♀️ + 🤷🏻‍♀️ + 🤷🏼‍♀️ + 🤷🏽‍♀️ + 🤷🏾‍♀️ + 🤷🏿‍♀️ + 🤷 + 🤷🏻 + 🤷🏼 + 🤷🏽 + 🤷🏾 + 🤷🏿 + 🤷‍♂️ + 🤷🏻‍♂️ + 🤷🏼‍♂️ + 🤷🏽‍♂️ + 🤷🏾‍♂️ + 🤷🏿‍♂️ + 🙎‍♀️ + 🙎🏻‍♀️ + 🙎🏼‍♀️ + 🙎🏽‍♀️ + 🙎🏾‍♀️ + 🙎🏿‍♀️ + 🙎 + 🙎🏻 + 🙎🏼 + 🙎🏽 + 🙎🏾 + 🙎🏿 + 🙎‍♂️ + 🙎🏻‍♂️ + 🙎🏼‍♂️ + 🙎🏽‍♂️ + 🙎🏾‍♂️ + 🙎🏿‍♂️ + 🙍‍♀️ + 🙍🏻‍♀️ + 🙍🏼‍♀️ + 🙍🏽‍♀️ + 🙍🏾‍♀️ + 🙍🏿‍♀️ + 🙍 + 🙍🏻 + 🙍🏼 + 🙍🏽 + 🙍🏾 + 🙍🏿 + 🙍‍♂️ + 🙍🏻‍♂️ + 🙍🏼‍♂️ + 🙍🏽‍♂️ + 🙍🏾‍♂️ + 🙍🏿‍♂️ + 💇‍♀️ + 💇🏻‍♀️ + 💇🏼‍♀️ + 💇🏽‍♀️ + 💇🏾‍♀️ + 💇🏿‍♀️ + 💇 + 💇🏻 + 💇🏼 + 💇🏽 + 💇🏾 + 💇🏿 + 💇‍♂️ + 💇🏻‍♂️ + 💇🏼‍♂️ + 💇🏽‍♂️ + 💇🏾‍♂️ + 💇🏿‍♂️ + 💆‍♀️ + 💆🏻‍♀️ + 💆🏼‍♀️ + 💆🏽‍♀️ + 💆🏾‍♀️ + 💆🏿‍♀️ + 💆 + 💆🏻 + 💆🏼 + 💆🏽 + 💆🏾 + 💆🏿 + 💆‍♂️ + 💆🏻‍♂️ + 💆🏼‍♂️ + 💆🏽‍♂️ + 💆🏾‍♂️ + 💆🏿‍♂️ + 🧖‍♀️ + 🧖🏻‍♀️ + 🧖🏼‍♀️ + 🧖🏽‍♀️ + 🧖🏾‍♀️ + 🧖🏿‍♀️ + 🧖 + 🧖🏻 + 🧖🏼 + 🧖🏽 + 🧖🏾 + 🧖🏿 + 🧖‍♂️ + 🧖🏻‍♂️ + 🧖🏼‍♂️ + 🧖🏽‍♂️ + 🧖🏾‍♂️ + 🧖🏿‍♂️ + 💅 + 💅🏻 + 💅🏼 + 💅🏽 + 💅🏾 + 💅🏿 + 🤳 + 🤳🏻 + 🤳🏼 + 🤳🏽 + 🤳🏾 + 🤳🏿 + 💃 + 💃🏻 + 💃🏼 + 💃🏽 + 💃🏾 + 💃🏿 + 🕺 + 🕺🏻 + 🕺🏼 + 🕺🏽 + 🕺🏾 + 🕺🏿 + 👯‍♀️ + 👯 + 👯‍♂️ + 🕴 + 🕴🏻 + 🕴🏼 + 🕴🏽 + 🕴🏾 + 🕴🏿 + 👩‍🦽 + 👩🏻‍🦽 + 👩🏼‍🦽 + 👩🏽‍🦽 + 👩🏾‍🦽 + 👩🏿‍🦽 + 🧑‍🦽 + 🧑🏻‍🦽 + 🧑🏼‍🦽 + 🧑🏽‍🦽 + 🧑🏾‍🦽 + 🧑🏿‍🦽 + 👨‍🦽 + 👨🏻‍🦽 + 👨🏼‍🦽 + 👨🏽‍🦽 + 👨🏾‍🦽 + 👨🏿‍🦽 + 👩‍🦼 + 👩🏻‍🦼 + 👩🏼‍🦼 + 👩🏽‍🦼 + 👩🏾‍🦼 + 👩🏿‍🦼 + 🧑‍🦼 + 🧑🏻‍🦼 + 🧑🏼‍🦼 + 🧑🏽‍🦼 + 🧑🏾‍🦼 + 🧑🏿‍🦼 + 👨‍🦼 + 👨🏻‍🦼 + 👨🏼‍🦼 + 👨🏽‍🦼 + 👨🏾‍🦼 + 👨🏿‍🦼 + 🚶‍♀️ + 🚶🏻‍♀️ + 🚶🏼‍♀️ + 🚶🏽‍♀️ + 🚶🏾‍♀️ + 🚶🏿‍♀️ + 🚶 + 🚶🏻 + 🚶🏼 + 🚶🏽 + 🚶🏾 + 🚶🏿 + 🚶‍♂️ + 🚶🏻‍♂️ + 🚶🏼‍♂️ + 🚶🏽‍♂️ + 🚶🏾‍♂️ + 🚶🏿‍♂️ + 👩‍🦯 + 👩🏻‍🦯 + 👩🏼‍🦯 + 👩🏽‍🦯 + 👩🏾‍🦯 + 👩🏿‍🦯 + 🧑‍🦯 + 🧑🏻‍🦯 + 🧑🏼‍🦯 + 🧑🏽‍🦯 + 🧑🏾‍🦯 + 🧑🏿‍🦯 + 👨‍🦯 + 👨🏻‍🦯 + 👨🏼‍🦯 + 👨🏽‍🦯 + 👨🏾‍🦯 + 👨🏿‍🦯 + 🧎‍♀️ + 🧎🏻‍♀️ + 🧎🏼‍♀️ + 🧎🏽‍♀️ + 🧎🏾‍♀️ + 🧎🏿‍♀️ + 🧎 + 🧎🏻 + 🧎🏼 + 🧎🏽 + 🧎🏾 + 🧎🏿 + 🧎‍♂️ + 🧎🏻‍♂️ + 🧎🏼‍♂️ + 🧎🏽‍♂️ + 🧎🏾‍♂️ + 🧎🏿‍♂️ + 🏃‍♀️ + 🏃🏻‍♀️ + 🏃🏼‍♀️ + 🏃🏽‍♀️ + 🏃🏾‍♀️ + 🏃🏿‍♀️ + 🏃 + 🏃🏻 + 🏃🏼 + 🏃🏽 + 🏃🏾 + 🏃🏿 + 🏃‍♂️ + 🏃🏻‍♂️ + 🏃🏼‍♂️ + 🏃🏽‍♂️ + 🏃🏾‍♂️ + 🏃🏿‍♂️ + 🧍‍♀️ + 🧍🏻‍♀️ + 🧍🏼‍♀️ + 🧍🏽‍♀️ + 🧍🏾‍♀️ + 🧍🏿‍♀️ + 🧍 + 🧍🏻 + 🧍🏼 + 🧍🏽 + 🧍🏾 + 🧍🏿 + 🧍‍♂️ + 🧍🏻‍♂️ + 🧍🏼‍♂️ + 🧍🏽‍♂️ + 🧍🏾‍♂️ + 🧍🏿‍♂️ + 👫 + 👩🏻‍🤝‍👨🏼 + 👩🏻‍🤝‍👨🏽 + 👩🏻‍🤝‍👨🏾 + 👩🏻‍🤝‍👨🏿 + 👩🏼‍🤝‍👨🏻 + 👭 + 👩🏻‍🤝‍👩🏼 + 👩🏻‍🤝‍👩🏽 + 👩🏻‍🤝‍👩🏾 + 👩🏻‍🤝‍👩🏿 + 👩🏼‍🤝‍👩🏻 + 👬 + 👨🏻‍🤝‍👨🏼 + 👨🏻‍🤝‍👨🏽 + 👨🏻‍🤝‍👨🏾 + 👨🏻‍🤝‍👨🏿 + 👨🏼‍🤝‍👨🏻 + 👩‍❤️‍👨 + 👩‍❤️‍👩 + 👨‍❤️‍👨 + 👩‍❤️‍💋‍👨 + 👩‍❤️‍💋‍👩 + 👨‍❤️‍💋‍👨 + 👨‍👩‍👦 + 👨‍👩‍👧 + 👨‍👩‍👧‍👦 + 👨‍👩‍👦‍👦 + 👨‍👩‍👧‍👧 + 👩‍👩‍👦 + 👩‍👩‍👧 + 👩‍👩‍👧‍👦 + 👩‍👩‍👦‍👦 + 👩‍👩‍👧‍👧 + 👨‍👨‍👦 + 👨‍👨‍👧 + 👨‍👨‍👧‍👦 + 👨‍👨‍👦‍👦 + 👨‍👨‍👧‍👧 + 👩‍👦 + 👩‍👧 + 👩‍👧‍👦 + 👩‍👦‍👦 + 👩‍👧‍👧 + 👨‍👦 + 👨‍👧 + 👨‍👧‍👦 + 👨‍👦‍👦 + 👨‍👧‍👧 + 🧶 + 🧵 + 🧥 + 🥼 + 🦺 + 👚 + 👕 + 👖 + 🩲 + 🩳 + 👔 + 👗 + 👙 + 👘 + 🥻 + 🩱 + 🥿 + 👠 + 👡 + 👢 + 👞 + 👟 + 🥾 + 🧦 + 🧤 + 🧣 + 🎩 + 🧢 + 👒 + 🎓 + + 👑 + 💍 + 👝 + 👛 + 👜 + 💼 + 🎒 + 🧳 + 👓 + 🕶 + 🥽 + 🌂 + + + + + Title + Animals & Nature + Emojis + + 🐶 + 🐱 + 🐭 + 🐹 + 🐰 + 🦊 + 🐻 + 🐼 + 🐨 + 🐯 + 🦁 + 🐮 + 🐷 + 🐽 + 🐸 + 🐵 + 🙈 + 🙉 + 🙊 + 🐒 + 🐔 + 🐧 + 🐦 + 🐤 + 🐣 + 🐥 + 🦆 + 🦅 + 🦉 + 🦇 + 🐺 + 🐗 + 🐴 + 🦄 + 🐝 + 🐛 + 🦋 + 🐌 + 🐞 + 🐜 + 🦟 + 🦗 + 🕷 + 🕸 + 🦂 + 🐢 + 🐍 + 🦎 + 🦖 + 🦕 + 🐙 + 🦑 + 🦐 + 🦞 + 🦀 + 🐡 + 🐠 + 🐟 + 🐬 + 🐳 + 🐋 + 🦈 + 🐊 + 🐅 + 🐆 + 🦓 + 🦍 + 🦧 + 🐘 + 🦛 + 🦏 + 🐪 + 🐫 + 🦒 + 🦘 + 🐃 + 🐂 + 🐄 + 🐎 + 🐖 + 🐏 + 🐑 + 🦙 + 🐐 + 🦌 + 🐕 + 🐩 + 🦮 + 🐕‍🦺 + 🐈 + 🐓 + 🦃 + 🦚 + 🦜 + 🦢 + 🦩 + 🕊 + 🐇 + 🦝 + 🦨 + 🦡 + 🦦 + 🦥 + 🐁 + 🐀 + 🐿 + 🦔 + 🐾 + 🐉 + 🐲 + 🌵 + 🎄 + 🌲 + 🌳 + 🌴 + 🌱 + 🌿 + ☘️ + 🍀 + 🎍 + 🎋 + 🍃 + 🍂 + 🍁 + 🍄 + 🐚 + 🌾 + 💐 + 🌷 + 🌹 + 🥀 + 🌺 + 🌸 + 🌼 + 🌻 + 🌞 + 🌝 + 🌛 + 🌜 + 🌚 + 🌕 + 🌖 + 🌗 + 🌘 + 🌑 + 🌒 + 🌓 + 🌔 + 🌙 + 🌎 + 🌍 + 🌏 + 🪐 + 💫 + ⭐️ + 🌟 + + ⚡️ + ☄️ + 💥 + 🔥 + 🌪 + 🌈 + ☀️ + 🌤 + ⛅️ + 🌥 + ☁️ + 🌦 + 🌧 + + 🌩 + 🌨 + ❄️ + ☃️ + ⛄️ + 🌬 + 💨 + 💧 + 💦 + ☔️ + ☂️ + 🌊 + 🌫 + + + + + Title + Food & Drink + Emojis + + 🍏 + 🍎 + 🍐 + 🍊 + 🍋 + 🍌 + 🍉 + 🍇 + 🍓 + 🍈 + 🍒 + 🍑 + 🥭 + 🍍 + 🥥 + 🥝 + 🍅 + 🍆 + 🥑 + 🥦 + 🥬 + 🥒 + 🌶 + 🌽 + 🥕 + 🧄 + 🧅 + 🥔 + 🍠 + 🥐 + 🥯 + 🍞 + 🥖 + 🥨 + 🧀 + 🥚 + 🍳 + 🧈 + 🥞 + 🧇 + 🥓 + 🥩 + 🍗 + 🍖 + 🦴 + 🌭 + 🍔 + 🍟 + 🍕 + 🥪 + 🥙 + 🧆 + 🌮 + 🌯 + 🥗 + 🥘 + 🥫 + 🍝 + 🍜 + 🍲 + 🍛 + 🍣 + 🍱 + 🥟 + 🦪 + 🍤 + 🍙 + 🍚 + 🍘 + 🍥 + 🥠 + 🥮 + 🍢 + 🍡 + 🍧 + 🍨 + 🍦 + 🥧 + 🧁 + 🍰 + 🎂 + 🍮 + 🍭 + 🍬 + 🍫 + 🍿 + 🍩 + 🍪 + 🌰 + 🥜 + 🍯 + 🥛 + 🍼 + ☕️ + 🍵 + 🧃 + 🥤 + 🍶 + 🍺 + 🍻 + 🥂 + 🍷 + 🥃 + 🍸 + 🍹 + 🧉 + 🍾 + 🧊 + 🥄 + 🍴 + 🍽 + 🥣 + 🥡 + 🥢 + 🧂 + + + + + Title + Activity + Emojis + + ⚽️ + 🏀 + 🏈 + ⚾️ + 🥎 + 🎾 + 🏐 + 🏉 + 🥏 + 🎱 + 🪀 + 🏓 + 🏸 + 🏒 + 🏑 + 🥍 + 🏏 + 🥅 + ⛳️ + 🪁 + 🏹 + 🎣 + 🤿 + 🥊 + 🥋 + 🎽 + 🛹 + 🛷 + + 🥌 + 🎿 + + 🏂 + 🪂 + 🏋️‍♀️ + 🏋🏻‍♀️ + 🏋🏼‍♀️ + 🏋🏽‍♀️ + 🏋🏾‍♀️ + 🏋🏿‍♀️ + 🏋️ + 🏋🏻 + 🏋🏼 + 🏋🏽 + 🏋🏾 + 🏋🏿 + 🏋️‍♂️ + 🏋🏻‍♂️ + 🏋🏼‍♂️ + 🏋🏽‍♂️ + 🏋🏾‍♂️ + 🏋🏿‍♂️ + 🤼‍♀️ + 🤼 + 🤼‍♂️ + 🤸‍♀️ + 🤸🏻‍♀️ + 🤸🏼‍♀️ + 🤸🏽‍♀️ + 🤸🏾‍♀️ + 🤸🏿‍♀️ + 🤸 + 🤸🏻 + 🤸🏼 + 🤸🏽 + 🤸🏾 + 🤸🏿 + 🤸‍♂️ + 🤸🏻‍♂️ + 🤸🏼‍♂️ + 🤸🏽‍♂️ + 🤸🏾‍♂️ + 🤸🏿‍♂️ + ⛹️‍♀️ + ⛹🏻‍♀️ + ⛹🏼‍♀️ + ⛹🏽‍♀️ + ⛹🏾‍♀️ + ⛹🏿‍♀️ + ⛹️ + ⛹🏻 + ⛹🏼 + ⛹🏽 + ⛹🏾 + ⛹🏿 + ⛹️‍♂️ + ⛹🏻‍♂️ + ⛹🏼‍♂️ + ⛹🏽‍♂️ + ⛹🏾‍♂️ + ⛹🏿‍♂️ + 🤺 + 🤾‍♀️ + 🤾🏻‍♀️ + 🤾🏼‍♀️ + 🤾🏽‍♀️ + 🤾🏾‍♀️ + 🤾🏿‍♀️ + 🤾 + 🤾🏻 + 🤾🏼 + 🤾🏽 + 🤾🏾 + 🤾🏿 + 🤾‍♂️ + 🤾🏻‍♂️ + 🤾🏼‍♂️ + 🤾🏽‍♂️ + 🤾🏾‍♂️ + 🤾🏿‍♂️ + 🏌️‍♀️ + 🏌🏻‍♀️ + 🏌🏼‍♀️ + 🏌🏽‍♀️ + 🏌🏾‍♀️ + 🏌🏿‍♀️ + 🏌️ + 🏌🏻 + 🏌🏼 + 🏌🏽 + 🏌🏾 + 🏌🏿 + 🏌️‍♂️ + 🏌🏻‍♂️ + 🏌🏼‍♂️ + 🏌🏽‍♂️ + 🏌🏾‍♂️ + 🏌🏿‍♂️ + 🏇 + 🏇🏻 + 🏇🏼 + 🏇🏽 + 🏇🏾 + 🏇🏿 + 🧘‍♀️ + 🧘🏻‍♀️ + 🧘🏼‍♀️ + 🧘🏽‍♀️ + 🧘🏾‍♀️ + 🧘🏿‍♀️ + 🧘 + 🧘🏻 + 🧘🏼 + 🧘🏽 + 🧘🏾 + 🧘🏿 + 🧘‍♂️ + 🧘🏻‍♂️ + 🧘🏼‍♂️ + 🧘🏽‍♂️ + 🧘🏾‍♂️ + 🧘🏿‍♂️ + 🏄‍♀️ + 🏄🏻‍♀️ + 🏄🏼‍♀️ + 🏄🏽‍♀️ + 🏄🏾‍♀️ + 🏄🏿‍♀️ + 🏄 + 🏄🏻 + 🏄🏼 + 🏄🏽 + 🏄🏾 + 🏄🏿 + 🏄‍♂️ + 🏄🏻‍♂️ + 🏄🏼‍♂️ + 🏄🏽‍♂️ + 🏄🏾‍♂️ + 🏄🏿‍♂️ + 🏊‍♀️ + 🏊🏻‍♀️ + 🏊🏼‍♀️ + 🏊🏽‍♀️ + 🏊🏾‍♀️ + 🏊🏿‍♀️ + 🏊 + 🏊🏻 + 🏊🏼 + 🏊🏽 + 🏊🏾 + 🏊🏿 + 🏊‍♂️ + 🏊🏻‍♂️ + 🏊🏼‍♂️ + 🏊🏽‍♂️ + 🏊🏾‍♂️ + 🏊🏿‍♂️ + 🤽‍♀️ + 🤽🏻‍♀️ + 🤽🏼‍♀️ + 🤽🏽‍♀️ + 🤽🏾‍♀️ + 🤽🏿‍♀️ + 🤽 + 🤽🏻 + 🤽🏼 + 🤽🏽 + 🤽🏾 + 🤽🏿 + 🤽‍♂️ + 🤽🏻‍♂️ + 🤽🏼‍♂️ + 🤽🏽‍♂️ + 🤽🏾‍♂️ + 🤽🏿‍♂️ + 🚣‍♀️ + 🚣🏻‍♀️ + 🚣🏼‍♀️ + 🚣🏽‍♀️ + 🚣🏾‍♀️ + 🚣🏿‍♀️ + 🚣 + 🚣🏻 + 🚣🏼 + 🚣🏽 + 🚣🏾 + 🚣🏿 + 🚣‍♂️ + 🚣🏻‍♂️ + 🚣🏼‍♂️ + 🚣🏽‍♂️ + 🚣🏾‍♂️ + 🚣🏿‍♂️ + 🧗‍♀️ + 🧗🏻‍♀️ + 🧗🏼‍♀️ + 🧗🏽‍♀️ + 🧗🏾‍♀️ + 🧗🏿‍♀️ + 🧗 + 🧗🏻 + 🧗🏼 + 🧗🏽 + 🧗🏾 + 🧗🏿 + 🧗‍♂️ + 🧗🏻‍♂️ + 🧗🏼‍♂️ + 🧗🏽‍♂️ + 🧗🏾‍♂️ + 🧗🏿‍♂️ + 🚵‍♀️ + 🚵🏻‍♀️ + 🚵🏼‍♀️ + 🚵🏽‍♀️ + 🚵🏾‍♀️ + 🚵🏿‍♀️ + 🚵 + 🚵🏻 + 🚵🏼 + 🚵🏽 + 🚵🏾 + 🚵🏿 + 🚵‍♂️ + 🚵🏻‍♂️ + 🚵🏼‍♂️ + 🚵🏽‍♂️ + 🚵🏾‍♂️ + 🚵🏿‍♂️ + 🚴‍♀️ + 🚴🏻‍♀️ + 🚴🏼‍♀️ + 🚴🏽‍♀️ + 🚴🏾‍♀️ + 🚴🏿‍♀️ + 🚴 + 🚴🏻 + 🚴🏼 + 🚴🏽 + 🚴🏾 + 🚴🏿 + 🚴‍♂️ + 🚴🏻‍♂️ + 🚴🏼‍♂️ + 🚴🏽‍♂️ + 🚴🏾‍♂️ + 🚴🏿‍♂️ + 🏆 + 🥇 + 🥈 + 🥉 + 🏅 + 🎖 + 🏵 + 🎗 + 🎫 + 🎟 + 🎪 + 🤹‍♀️ + 🤹🏻‍♀️ + 🤹🏼‍♀️ + 🤹🏽‍♀️ + 🤹🏾‍♀️ + 🤹🏿‍♀️ + 🤹 + 🤹🏻 + 🤹🏼 + 🤹🏽 + 🤹🏾 + 🤹🏿 + 🤹‍♂️ + 🤹🏻‍♂️ + 🤹🏼‍♂️ + 🤹🏽‍♂️ + 🤹🏾‍♂️ + 🤹🏿‍♂️ + 🎭 + 🩰 + 🎨 + 🎬 + 🎤 + 🎧 + 🎼 + 🎹 + 🥁 + 🎷 + 🎺 + 🎸 + 🪕 + 🎻 + 🎲 + + 🎯 + 🎳 + 🎮 + 🎰 + 🧩 + + + + + Title + Travel & Places + Emojis + + 🚗 + 🚕 + 🚙 + 🚌 + 🚎 + 🏎 + 🚓 + 🚑 + 🚒 + 🚐 + 🚚 + 🚛 + 🚜 + 🦯 + 🦽 + 🦼 + 🛴 + 🚲 + 🛵 + 🏍 + 🛺 + 🚨 + 🚔 + 🚍 + 🚘 + 🚖 + 🚡 + 🚠 + 🚟 + 🚃 + 🚋 + 🚞 + 🚝 + 🚄 + 🚅 + 🚈 + 🚂 + 🚆 + 🚇 + 🚊 + 🚉 + ✈️ + 🛫 + 🛬 + 🛩 + 💺 + 🛰 + 🚀 + 🛸 + 🚁 + 🛶 + ⛵️ + 🚤 + 🛥 + 🛳 + + 🚢 + ⚓️ + ⛽️ + 🚧 + 🚦 + 🚥 + 🚏 + 🗺 + 🗿 + 🗽 + 🗼 + 🏰 + 🏯 + 🏟 + 🎡 + 🎢 + 🎠 + ⛲️ + + 🏖 + 🏝 + 🏜 + 🌋 + + 🏔 + 🗻 + 🏕 + ⛺️ + 🏠 + 🏡 + 🏘 + 🏚 + 🏗 + 🏭 + 🏢 + 🏬 + 🏣 + 🏤 + 🏥 + 🏦 + 🏨 + 🏪 + 🏫 + 🏩 + 💒 + 🏛 + ⛪️ + 🕌 + 🕍 + 🛕 + 🕋 + + 🛤 + 🛣 + 🗾 + 🎑 + 🏞 + 🌅 + 🌄 + 🌠 + 🎇 + 🎆 + 🌇 + 🌆 + 🏙 + 🌃 + 🌌 + 🌉 + 🌁 + + + + + Title + Objects + Emojis + + ⌚️ + 📱 + 📲 + 💻 + ⌨️ + 🖥 + 🖨 + 🖱 + 🖲 + 🕹 + 🗜 + 💽 + 💾 + 💿 + 📀 + 📼 + 📷 + 📸 + 📹 + 🎥 + 📽 + 🎞 + 📞 + ☎️ + 📟 + 📠 + 📺 + 📻 + 🎙 + 🎚 + 🎛 + 🧭 + + + + 🕰 + ⌛️ + + 📡 + 🔋 + 🔌 + 💡 + 🔦 + 🕯 + 🪔 + 🧯 + 🛢 + 💸 + 💵 + 💴 + 💶 + 💷 + 💰 + 💳 + 💎 + ⚖️ + 🧰 + 🔧 + 🔨 + + 🛠 + + 🔩 + ⚙️ + 🧱 + + 🧲 + 🔫 + 💣 + 🧨 + 🪓 + 🔪 + 🗡 + ⚔️ + 🛡 + 🚬 + ⚰️ + ⚱️ + 🏺 + 🔮 + 📿 + 🧿 + 💈 + ⚗️ + 🔭 + 🔬 + 🕳 + 🩹 + 🩺 + 💊 + 💉 + 🩸 + 🧬 + 🦠 + 🧫 + 🧪 + 🌡 + 🧹 + 🧺 + 🧻 + 🚽 + 🚰 + 🚿 + 🛁 + 🛀 + 🛀🏻 + 🛀🏼 + 🛀🏽 + 🛀🏾 + 🛀🏿 + 🧼 + 🪒 + 🧽 + 🧴 + 🛎 + 🔑 + 🗝 + 🚪 + 🪑 + 🛋 + 🛏 + 🛌 + 🧸 + 🖼 + 🛍 + 🛒 + 🎁 + 🎈 + 🎏 + 🎀 + 🎊 + 🎉 + 🎎 + 🏮 + 🎐 + 🧧 + ✉️ + 📩 + 📨 + 📧 + 💌 + 📥 + 📤 + 📦 + 🏷 + 📪 + 📫 + 📬 + 📭 + 📮 + 📯 + 📜 + 📃 + 📄 + 📑 + 🧾 + 📊 + 📈 + 📉 + 🗒 + 🗓 + 📆 + 📅 + 🗑 + 📇 + 🗃 + 🗳 + 🗄 + 📋 + 📁 + 📂 + 🗂 + 🗞 + 📰 + 📓 + 📔 + 📒 + 📕 + 📗 + 📘 + 📙 + 📚 + 📖 + 🔖 + 🧷 + 🔗 + 📎 + 🖇 + 📐 + 📏 + 🧮 + 📌 + 📍 + ✂️ + 🖊 + 🖋 + ✒️ + 🖌 + 🖍 + 📝 + ✏️ + 🔍 + 🔎 + 🔏 + 🔐 + 🔒 + 🔓 + + + + + Title + Symbols + Emojis + + ❤️ + 🧡 + 💛 + 💚 + 💙 + 💜 + 🖤 + 🤍 + 🤎 + 💔 + ❣️ + 💕 + 💞 + 💓 + 💗 + 💖 + 💘 + 💝 + 💟 + ☮️ + ✝️ + ☪️ + 🕉 + ☸️ + ✡️ + 🔯 + 🕎 + ☯️ + ☦️ + 🛐 + + ♈️ + ♉️ + ♊️ + ♋️ + ♌️ + ♍️ + ♎️ + ♏️ + ♐️ + ♑️ + ♒️ + ♓️ + 🆔 + ⚛️ + 🉑 + ☢️ + ☣️ + 📴 + 📳 + 🈶 + 🈚️ + 🈸 + 🈺 + 🈷️ + ✴️ + 🆚 + 💮 + 🉐 + ㊙️ + ㊗️ + 🈴 + 🈵 + 🈹 + 🈲 + 🅰️ + 🅱️ + 🆎 + 🆑 + 🅾️ + 🆘 + + ⭕️ + 🛑 + ⛔️ + 📛 + 🚫 + 💯 + 💢 + ♨️ + 🚷 + 🚯 + 🚳 + 🚱 + 🔞 + 📵 + 🚭 + ❗️ + + + + ‼️ + ⁉️ + 🔅 + 🔆 + 〽️ + ⚠️ + 🚸 + 🔱 + ⚜️ + 🔰 + ♻️ + + 🈯️ + 💹 + ❇️ + ✳️ + + 🌐 + 💠 + Ⓜ️ + 🌀 + 💤 + 🏧 + 🚾 + ♿️ + 🅿️ + 🈳 + 🈂️ + 🛂 + 🛃 + 🛄 + 🛅 + 🚹 + 🚺 + 🚼 + 🚻 + 🚮 + 🎦 + 📶 + 🈁 + 🔣 + ℹ️ + 🔤 + 🔡 + 🔠 + 🆖 + 🆗 + 🆙 + 🆒 + 🆕 + 🆓 + 0️⃣ + 1️⃣ + 2️⃣ + 3️⃣ + 4️⃣ + 5️⃣ + 6️⃣ + 7️⃣ + 8️⃣ + 9️⃣ + 🔟 + 🔢 + #️⃣ + *️⃣ + ⏏️ + ▶️ + + + + + + + + + + + ◀️ + 🔼 + 🔽 + ➡️ + ⬅️ + ⬆️ + ⬇️ + ↗️ + ↘️ + ↙️ + ↖️ + ↕️ + ↔️ + ↪️ + ↩️ + ⤴️ + ⤵️ + 🔀 + 🔁 + 🔂 + 🔄 + 🔃 + 🎵 + 🎶 + + + + ✖️ + + 💲 + 💱 + ™️ + ©️ + ®️ + 👁‍🗨 + 🔚 + 🔙 + 🔛 + 🔝 + 🔜 + 〰️ + + + ✔️ + ☑️ + 🔘 + 🔴 + 🟠 + 🟡 + 🟢 + 🔵 + 🟣 + ⚫️ + ⚪️ + 🟤 + 🔺 + 🔻 + 🔸 + 🔹 + 🔶 + 🔷 + 🔳 + 🔲 + ▪️ + ▫️ + ◾️ + ◽️ + ◼️ + ◻️ + 🟥 + 🟧 + 🟨 + 🟩 + 🟦 + 🟪 + ⬛️ + ⬜️ + 🟫 + 🔈 + 🔇 + 🔉 + 🔊 + 🔔 + 🔕 + 📣 + 📢 + 💬 + 💭 + 🗯 + ♠️ + ♣️ + ♥️ + ♦️ + 🃏 + 🎴 + 🀄️ + 🕐 + 🕑 + 🕒 + 🕓 + 🕔 + 🕕 + 🕖 + 🕗 + 🕘 + 🕙 + 🕚 + 🕛 + 🕜 + 🕝 + 🕞 + 🕟 + 🕠 + 🕡 + 🕢 + 🕣 + 🕤 + 🕥 + 🕦 + 🕧 + + + + + Title + Flags + Emojis + + 🏳️ + 🏴 + 🏴‍☠️ + 🏁 + 🚩 + 🏳️‍🌈 + 🇺🇳 + 🇦🇫 + 🇦🇽 + 🇦🇱 + 🇩🇿 + 🇦🇸 + 🇦🇩 + 🇦🇴 + 🇦🇮 + 🇦🇶 + 🇦🇬 + 🇦🇷 + 🇦🇲 + 🇦🇼 + 🇦🇺 + 🇦🇹 + 🇦🇿 + 🇧🇸 + 🇧🇭 + 🇧🇩 + 🇧🇧 + 🇧🇾 + 🇧🇪 + 🇧🇿 + 🇧🇯 + 🇧🇲 + 🇧🇹 + 🇧🇴 + 🇧🇦 + 🇧🇼 + 🇧🇷 + 🇮🇴 + 🇻🇬 + 🇧🇳 + 🇧🇬 + 🇧🇫 + 🇧🇮 + 🇰🇭 + 🇨🇲 + 🇨🇦 + 🇮🇨 + 🇨🇻 + 🇧🇶 + 🇰🇾 + 🇨🇫 + 🇹🇩 + 🇨🇱 + 🇨🇳 + 🇨🇽 + 🇨🇨 + 🇨🇴 + 🇰🇲 + 🇨🇬 + 🇨🇩 + 🇨🇰 + 🇨🇷 + 🇨🇮 + 🇭🇷 + 🇨🇺 + 🇨🇼 + 🇨🇾 + 🇨🇿 + 🇩🇰 + 🇩🇯 + 🇩🇲 + 🇩🇴 + 🇪🇨 + 🇪🇬 + 🇸🇻 + 🇬🇶 + 🇪🇷 + 🇪🇪 + 🇸🇿 + 🇪🇹 + 🇪🇺 + 🇫🇰 + 🇫🇴 + 🇫🇯 + 🇫🇮 + 🇫🇷 + 🇬🇫 + 🇵🇫 + 🇹🇫 + 🇬🇦 + 🇬🇲 + 🇬🇪 + 🇩🇪 + 🇬🇭 + 🇬🇮 + 🇬🇷 + 🇬🇱 + 🇬🇩 + 🇬🇵 + 🇬🇺 + 🇬🇹 + 🇬🇬 + 🇬🇳 + 🇬🇼 + 🇬🇾 + 🇭🇹 + 🇭🇳 + 🇭🇰 + 🇭🇺 + 🇮🇸 + 🇮🇳 + 🇮🇩 + 🇮🇷 + 🇮🇶 + 🇮🇪 + 🇮🇲 + 🇮🇱 + 🇮🇹 + 🇯🇲 + 🇯🇵 + 🎌 + 🇯🇪 + 🇯🇴 + 🇰🇿 + 🇰🇪 + 🇰🇮 + 🇽🇰 + 🇰🇼 + 🇰🇬 + 🇱🇦 + 🇱🇻 + 🇱🇧 + 🇱🇸 + 🇱🇷 + 🇱🇾 + 🇱🇮 + 🇱🇹 + 🇱🇺 + 🇲🇴 + 🇲🇬 + 🇲🇼 + 🇲🇾 + 🇲🇻 + 🇲🇱 + 🇲🇹 + 🇲🇭 + 🇲🇶 + 🇲🇷 + 🇲🇺 + 🇾🇹 + 🇲🇽 + 🇫🇲 + 🇲🇩 + 🇲🇨 + 🇲🇳 + 🇲🇪 + 🇲🇸 + 🇲🇦 + 🇲🇿 + 🇲🇲 + 🇳🇦 + 🇳🇷 + 🇳🇵 + 🇳🇱 + 🇳🇨 + 🇳🇿 + 🇳🇮 + 🇳🇪 + 🇳🇬 + 🇳🇺 + 🇳🇫 + 🇰🇵 + 🇲🇰 + 🇲🇵 + 🇳🇴 + 🇴🇲 + 🇵🇰 + 🇵🇼 + 🇵🇸 + 🇵🇦 + 🇵🇬 + 🇵🇾 + 🇵🇪 + 🇵🇭 + 🇵🇳 + 🇵🇱 + 🇵🇹 + 🇵🇷 + 🇶🇦 + 🇷🇪 + 🇷🇴 + 🇷🇺 + 🇷🇼 + 🇼🇸 + 🇸🇲 + 🇸🇹 + 🇸🇦 + 🇸🇳 + 🇷🇸 + 🇸🇨 + 🇸🇱 + 🇸🇬 + 🇸🇽 + 🇸🇰 + 🇸🇮 + 🇬🇸 + 🇸🇧 + 🇸🇴 + 🇿🇦 + 🇰🇷 + 🇸🇸 + 🇪🇸 + 🇱🇰 + 🇧🇱 + 🇸🇭 + 🇰🇳 + 🇱🇨 + 🇵🇲 + 🇻🇨 + 🇸🇩 + 🇸🇷 + 🇸🇪 + 🇨🇭 + 🇸🇾 + 🇹🇼 + 🇹🇯 + 🇹🇿 + 🇹🇭 + 🇹🇱 + 🇹🇬 + 🇹🇰 + 🇹🇴 + 🇹🇹 + 🇹🇳 + 🇹🇷 + 🇹🇲 + 🇹🇨 + 🇹🇻 + 🇺🇬 + 🇺🇦 + 🇦🇪 + 🇬🇧 + 🏴󠁧󠁢󠁥󠁮󠁧󠁿 + 🏴󠁧󠁢󠁳󠁣󠁴󠁿 + 🏴󠁧󠁢󠁷󠁬󠁳󠁿 + 🇺🇸 + 🇺🇾 + 🇻🇮 + 🇺🇿 + 🇻🇺 + 🇻🇦 + 🇻🇪 + 🇻🇳 + 🇼🇫 + 🇪🇭 + 🇾🇪 + 🇿🇲 + 🇿🇼 + + + + + diff --git a/Avatar/App/Avatar/Core/SceneDelegate.h b/Avatar/App/Avatar/Core/SceneDelegate.h new file mode 100644 index 0000000..5cf0c81 --- /dev/null +++ b/Avatar/App/Avatar/Core/SceneDelegate.h @@ -0,0 +1,10 @@ +#import +#import "HomeNavigationViewController.h" +#import "HomeViewController.h" + +@interface SceneDelegate : UIResponder + +@property (strong, nonatomic) UIWindow * window; + +@end + diff --git a/Avatar/App/Avatar/Core/SceneDelegate.m b/Avatar/App/Avatar/Core/SceneDelegate.m new file mode 100644 index 0000000..3432373 --- /dev/null +++ b/Avatar/App/Avatar/Core/SceneDelegate.m @@ -0,0 +1,73 @@ +#import "SceneDelegate.h" +#import "AvatarManager.h" + +@implementation SceneDelegate + + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { + + self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene]; + HomeViewController *vc = [[HomeViewController alloc] init]; + HomeNavigationViewController *nvc = [[HomeNavigationViewController alloc] initWithRootViewController:vc]; + self.window.rootViewController = nvc; + [self.window makeKeyAndVisible]; + + + if (![[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/AvatarKit.framework"] load]) { + NSLog(@"Couldn't load avatar framework"); + } + [AvatarManager prepareMemojiRuntime]; + + +} + + +- (void)sceneDidDisconnect:(UIScene *)scene { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). +// dispatch_async(dispatch_get_main_queue(), ^{ +// [self checkLicenceStatus]; +// }); +} + + +- (void)sceneDidBecomeActive:(UIScene *)scene { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. +// dispatch_async(dispatch_get_main_queue(), ^{ +// [self checkLicenceStatus]; +// }); +} + + +- (void)sceneWillResignActive:(UIScene *)scene { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). +// dispatch_async(dispatch_get_main_queue(), ^{ +// [self checkLicenceStatus]; +// }); +} + + +- (void)sceneWillEnterForeground:(UIScene *)scene { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. +// dispatch_async(dispatch_get_main_queue(), ^{ +// [self checkLicenceStatus]; +// }); +} + + +- (void)sceneDidEnterBackground:(UIScene *)scene { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. +// dispatch_async(dispatch_get_main_queue(), ^{ +// [self checkLicenceStatus]; +// }); +} + + +@end diff --git a/Avatar/App/Avatar/Core/Stickers.plist b/Avatar/App/Avatar/Core/Stickers.plist new file mode 100644 index 0000000..8f21b26 --- /dev/null +++ b/Avatar/App/Avatar/Core/Stickers.plist @@ -0,0 +1,528 @@ + + + + + + + + + Title + Smileys + Stickers + + smileys_000 + smileys_001 + smileys_002 + smileys_003 + smileys_004 + smileys_005 + smileys_006 + smileys_007 + smileys_008 + smileys_009 + smileys_010 + smileys_011 + smileys_012 + smileys_013 + smileys_014 + smileys_015 + smileys_016 + smileys_017 + smileys_018 + smileys_019 + smileys_020 + smileys_021 + smileys_022 + smileys_023 + smileys_024 + smileys_025 + smileys_026 + smileys_027 + smileys_028 + smileys_029 + smileys_030 + smileys_031 + smileys_032 + smileys_033 + smileys_034 + smileys_035 + smileys_036 + smileys_037 + smileys_038 + smileys_039 + smileys_040 + smileys_041 + smileys_042 + smileys_043 + smileys_044 + smileys_045 + smileys_046 + smileys_047 + smileys_048 + smileys_049 + smileys_050 + smileys_051 + smileys_052 + smileys_053 + smileys_054 + smileys_055 + smileys_056 + smileys_057 + smileys_058 + smileys_059 + smileys_060 + smileys_061 + smileys_062 + smileys_063 + smileys_064 + smileys_065 + smileys_066 + smileys_067 + smileys_068 + smileys_069 + smileys_070 + smileys_071 + smileys_072 + smileys_073 + smileys_074 + smileys_075 + smileys_076 + smileys_077 + smileys_078 + smileys_079 + smileys_080 + smileys_081 + smileys_082 + + + + + + Title + Icons + Stickers + + icons_000 + icons_001 + icons_002 + icons_003 + icons_004 + icons_005 + icons_006 + icons_007 + icons_008 + icons_009 + icons_010 + icons_011 + icons_012 + icons_013 + icons_014 + icons_015 + icons_016 + icons_017 + icons_018 + icons_019 + icons_020 + icons_021 + icons_022 + icons_023 + icons_024 + icons_025 + icons_026 + icons_027 + icons_028 + icons_029 + icons_030 + icons_031 + icons_032 + icons_033 + icons_034 + icons_035 + icons_036 + icons_037 + icons_038 + icons_039 + icons_040 + icons_041 + icons_042 + icons_043 + icons_044 + icons_045 + icons_046 + icons_047 + icons_048 + icons_049 + icons_050 + icons_051 + icons_052 + icons_053 + icons_054 + icons_055 + icons_056 + icons_057 + icons_058 + icons_059 + icons_060 + icons_061 + icons_062 + icons_063 + icons_064 + icons_065 + icons_066 + icons_067 + icons_068 + icons_069 + icons_070 + icons_071 + icons_072 + icons_073 + icons_074 + icons_075 + icons_076 + icons_077 + icons_078 + icons_079 + icons_080 + icons_081 + icons_082 + icons_083 + icons_084 + icons_085 + icons_086 + icons_087 + + + + + + Title + Love + Stickers + + love_000 + love_001 + love_002 + love_003 + love_004 + love_005 + love_006 + love_007 + love_008 + love_009 + love_010 + love_011 + love_012 + love_013 + love_014 + love_015 + love_016 + love_017 + love_018 + love_019 + love_020 + love_021 + love_022 + love_023 + love_024 + love_025 + love_026 + love_027 + love_028 + love_029 + love_030 + love_031 + love_032 + love_033 + love_034 + love_035 + love_036 + love_037 + love_038 + love_039 + love_040 + love_041 + love_042 + love_043 + love_044 + love_045 + love_046 + love_047 + love_048 + love_049 + love_050 + love_051 + love_052 + love_053 + love_054 + love_055 + love_056 + love_057 + love_058 + love_059 + love_060 + love_061 + love_062 + love_063 + love_064 + love_065 + love_066 + love_067 + love_068 + love_069 + love_070 + love_071 + love_072 + love_073 + love_074 + love_075 + love_076 + love_077 + love_078 + love_079 + love_080 + love_081 + love_082 + love_083 + love_084 + love_085 + love_086 + love_087 + love_088 + love_089 + love_090 + love_091 + love_092 + love_093 + love_094 + + + + + + Title + Texts + Stickers + + texts_000 + texts_001 + texts_002 + texts_003 + texts_004 + texts_005 + texts_006 + texts_007 + texts_008 + texts_009 + texts_010 + texts_011 + texts_012 + texts_013 + texts_014 + texts_015 + texts_016 + texts_017 + texts_018 + texts_019 + texts_020 + texts_021 + texts_022 + texts_023 + texts_024 + texts_025 + texts_026 + texts_027 + texts_028 + texts_029 + texts_030 + texts_031 + texts_032 + texts_033 + texts_034 + texts_035 + texts_036 + texts_037 + texts_038 + texts_039 + texts_040 + texts_041 + texts_042 + texts_043 + texts_044 + texts_045 + texts_046 + texts_047 + texts_048 + texts_049 + texts_050 + texts_051 + texts_052 + texts_053 + texts_054 + texts_055 + texts_056 + texts_057 + texts_058 + texts_059 + texts_060 + texts_061 + texts_062 + texts_063 + texts_064 + texts_065 + texts_066 + texts_067 + texts_068 + + + + + + Title + Stickers + Stickers + + sticker_000 + sticker_001 + sticker_002 + sticker_003 + sticker_004 + sticker_005 + sticker_006 + sticker_007 + sticker_008 + sticker_009 + sticker_010 + sticker_011 + sticker_012 + sticker_013 + sticker_014 + sticker_015 + sticker_016 + sticker_017 + sticker_018 + sticker_019 + sticker_020 + sticker_021 + sticker_022 + sticker_023 + sticker_024 + sticker_025 + sticker_026 + sticker_027 + sticker_028 + sticker_029 + sticker_030 + sticker_031 + sticker_032 + sticker_033 + sticker_034 + sticker_035 + sticker_036 + sticker_037 + sticker_038 + sticker_039 + sticker_040 + sticker_041 + sticker_042 + sticker_043 + sticker_044 + sticker_045 + sticker_046 + sticker_047 + sticker_048 + sticker_049 + sticker_050 + sticker_051 + sticker_052 + sticker_053 + sticker_054 + sticker_055 + sticker_056 + sticker_057 + sticker_058 + sticker_059 + sticker_060 + sticker_061 + sticker_062 + sticker_063 + sticker_064 + sticker_065 + sticker_066 + sticker_067 + sticker_068 + + + + + + Title + Passions + Stickers + + passions_000 + passions_001 + passions_002 + passions_003 + passions_004 + passions_005 + passions_006 + passions_007 + passions_008 + passions_009 + passions_010 + passions_011 + passions_012 + passions_013 + passions_014 + passions_015 + passions_016 + passions_017 + passions_018 + passions_019 + passions_020 + passions_021 + passions_022 + passions_023 + passions_024 + passions_025 + passions_026 + passions_027 + passions_028 + passions_029 + passions_030 + passions_031 + passions_032 + passions_033 + passions_034 + passions_035 + passions_036 + passions_037 + passions_038 + passions_039 + passions_040 + passions_041 + passions_042 + passions_043 + passions_044 + passions_045 + passions_046 + passions_047 + passions_048 + passions_049 + passions_050 + passions_051 + passions_052 + passions_053 + passions_054 + passions_055 + passions_056 + passions_057 + passions_058 + passions_059 + passions_060 + passions_061 + + + + + diff --git a/Avatar/App/Avatar/CustomClasses/GridView.h b/Avatar/App/Avatar/CustomClasses/GridView.h new file mode 100644 index 0000000..92d55d5 --- /dev/null +++ b/Avatar/App/Avatar/CustomClasses/GridView.h @@ -0,0 +1,13 @@ +#import +#import + +@interface GridView : UIView +-(instancetype)initWithFrame:(CGRect)frame bg:(UIColor *)background icon:(UIImage *)icon iconSize:(CGFloat)size iconPadding:(CGFloat)iconPadding titleTop:(CGFloat)titleTop titleFont:(UIFont *)titleFont; +@property (nonatomic, retain) UIImageView *icon; +@property (nonatomic, retain) UILabel *title; +@property (nonatomic, retain) UIImage *iconImage; +@property (nonatomic) CGFloat iconSize; +@property (nonatomic) CGFloat iconPadding; +@property (nonatomic) CGFloat titleTopPadding; +@property (nonatomic, retain) UIFont *titleFont; +@end diff --git a/Avatar/App/Avatar/CustomClasses/GridView.m b/Avatar/App/Avatar/CustomClasses/GridView.m new file mode 100644 index 0000000..73d3dfe --- /dev/null +++ b/Avatar/App/Avatar/CustomClasses/GridView.m @@ -0,0 +1,56 @@ +#import "GridView.h" +#import "ConstraintExtension.h" + +@implementation GridView + +-(instancetype)initWithFrame:(CGRect)frame bg:(UIColor *)background icon:(UIImage *)icon iconSize:(CGFloat)size iconPadding:(CGFloat)iconPadding titleTop:(CGFloat)titleTop titleFont:(UIFont *)titleFont { + + self = [super initWithFrame:frame]; + if (self) { + + self.clipsToBounds = YES; + self.backgroundColor = background; + self.layer.cornerRadius = 30; + self.layer.cornerCurve = kCACornerCurveContinuous; + + self.iconPadding = iconPadding; + self.iconSize = size; + self.iconImage = icon; + self.titleTopPadding = titleTop; + self.titleFont = titleFont; + + [self layoutViews]; + + } + return self; +} + + +-(void)layoutViews { + + self.icon = [[UIImageView alloc] init]; + self.icon.contentMode = UIViewContentModeScaleAspectFit; + self.icon.tintColor = UIColor.whiteColor; + self.icon.image = self.iconImage; + [self addSubview:self.icon]; + + [self.icon size:CGSizeMake(self.iconSize, self.iconSize)]; + [self.icon top:self.topAnchor padding:self.iconPadding]; + [self.icon x:self.centerXAnchor]; + + + self.title = [[UILabel alloc] init]; + self.title.textAlignment = NSTextAlignmentCenter; + self.title.numberOfLines = 3; + self.title.font = self.titleFont; + self.title.textColor = UIColor.whiteColor; + [self addSubview:self.title]; + + [self.title x:self.centerXAnchor]; + [self.title top:self.icon.bottomAnchor padding:self.titleTopPadding]; + [self.title leading:self.leadingAnchor padding:20]; + [self.title trailing:self.trailingAnchor padding:-20]; + +} + +@end diff --git a/Avatar/App/Avatar/CustomClasses/HomeNavigationViewController.h b/Avatar/App/Avatar/CustomClasses/HomeNavigationViewController.h new file mode 100644 index 0000000..c832a40 --- /dev/null +++ b/Avatar/App/Avatar/CustomClasses/HomeNavigationViewController.h @@ -0,0 +1,5 @@ +#import + +@interface HomeNavigationViewController : UINavigationController +@end + diff --git a/Avatar/App/Avatar/CustomClasses/HomeNavigationViewController.m b/Avatar/App/Avatar/CustomClasses/HomeNavigationViewController.m new file mode 100644 index 0000000..3995326 --- /dev/null +++ b/Avatar/App/Avatar/CustomClasses/HomeNavigationViewController.m @@ -0,0 +1,25 @@ +#import "HomeNavigationViewController.h" + + +@implementation HomeNavigationViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + +} + + +- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated { + [super setNavigationBarHidden:hidden animated:animated]; + self.interactivePopGestureRecognizer.delegate = self; +} + + +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { + if (self.viewControllers.count > 1) { + return YES; + } + return NO; +} + +@end diff --git a/Avatar/App/Avatar/CustomClasses/RecordingButton.h b/Avatar/App/Avatar/CustomClasses/RecordingButton.h new file mode 100644 index 0000000..e7ffb27 --- /dev/null +++ b/Avatar/App/Avatar/CustomClasses/RecordingButton.h @@ -0,0 +1,8 @@ +#import +#import "ConstraintExtension.h" + +@interface RecordingButton : UIControl +-(instancetype)initWithIcon:(NSString *)iconString accent:(UIColor *)accent action:(SEL)customAction; +@property (nonatomic, retain) UIImageView *icon; +@end + diff --git a/Avatar/App/Avatar/CustomClasses/RecordingButton.m b/Avatar/App/Avatar/CustomClasses/RecordingButton.m new file mode 100644 index 0000000..275a2b1 --- /dev/null +++ b/Avatar/App/Avatar/CustomClasses/RecordingButton.m @@ -0,0 +1,59 @@ +#import "RecordingButton.h" + +@implementation RecordingButton + +-(instancetype)initWithIcon:(NSString *)iconString accent:(UIColor *)accent action:(SEL)customAction { + + self = [super init]; + if (self) { + + self.backgroundColor = accent; + self.clipsToBounds = YES; + + self.icon = [[UIImageView alloc] init]; + self.icon.contentMode = UIViewContentModeScaleAspectFit; + self.icon.tintColor = UIColor.whiteColor; + self.icon.image = [UIImage systemImageNamed:iconString]; + [self addSubview:self.icon]; + + [self.icon size:CGSizeMake(40, 40)]; + [self.icon x:self.centerXAnchor y:self.centerYAnchor]; + + [self addTarget:self.superview action:customAction forControlEvents:UIControlEventTouchUpInside]; + + } + + return self; +} + + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesBegan:touches withEvent:event]; + [self touchAnimateWithHighlighted:YES]; +} + + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesEnded:touches withEvent:event]; + [self touchAnimateWithHighlighted:NO]; +} + + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesCancelled:touches withEvent:event]; + [self touchAnimateWithHighlighted:NO]; +} + + +-(void)touchAnimateWithHighlighted:(BOOL)isHighlighted { + + [UIView animateWithDuration:0.3 animations:^{ + self.alpha = isHighlighted ? 0.8 : 1.0; + CGAffineTransform transform = self.transform; + transform = isHighlighted ? CGAffineTransformScale(transform, 0.96, 0.96) : CGAffineTransformIdentity; + self.transform = transform; + }]; + +} + +@end diff --git a/Avatar/App/Avatar/CustomClasses/UtilitiesView.h b/Avatar/App/Avatar/CustomClasses/UtilitiesView.h new file mode 100644 index 0000000..3efc57a --- /dev/null +++ b/Avatar/App/Avatar/CustomClasses/UtilitiesView.h @@ -0,0 +1,12 @@ +#import +#import "ConstraintExtension.h" + +@interface UtilitiesView : UIView +-(instancetype)initWithFrame:(CGRect)frame icon:(UIImage *)icon; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *icon; +@property (nonatomic, retain) UILabel *title; +@property (nonatomic, retain) UIImageView *arrow; +@property (nonatomic, retain) UIImage *iconImage; +@end + diff --git a/Avatar/App/Avatar/CustomClasses/UtilitiesView.m b/Avatar/App/Avatar/CustomClasses/UtilitiesView.m new file mode 100644 index 0000000..6af8683 --- /dev/null +++ b/Avatar/App/Avatar/CustomClasses/UtilitiesView.m @@ -0,0 +1,67 @@ +#import "UtilitiesView.h" + +@implementation UtilitiesView + +-(instancetype)initWithFrame:(CGRect)frame icon:(UIImage *)icon { + + self = [super initWithFrame:frame]; + if (self) { + + self.clipsToBounds = YES; + self.backgroundColor = [UIColor colorNamed:@"Secondary"]; + self.layer.cornerRadius = 20; + self.layer.cornerCurve = kCACornerCurveContinuous; + + self.iconImage = icon; + + [self layoutViews]; + + } + return self; +} + + +-(void)layoutViews { + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 20; + [self addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(40, 40)]; + [self.iconView y:self.centerYAnchor]; + [self.iconView leading:self.leadingAnchor padding:15]; + + + self.icon = [[UIImageView alloc] init]; + self.icon.contentMode = UIViewContentModeScaleAspectFit; + self.icon.tintColor = UIColor.whiteColor; + self.icon.image = self.iconImage; + [self addSubview:self.icon]; + + [self.icon size:CGSizeMake(30, 30)]; + [self.icon x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.title = [[UILabel alloc] init]; + self.title.textAlignment = NSTextAlignmentLeft; + self.title.textColor = UIColor.labelColor; + self.title.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold]; + [self addSubview:self.title]; + + [self.title y:self.centerYAnchor]; + [self.title leading:self.icon.trailingAnchor padding:15]; + + + self.arrow = [[UIImageView alloc] init]; + self.arrow.contentMode = UIViewContentModeScaleAspectFit; + self.arrow.tintColor = UIColor.tertiaryLabelColor; + self.arrow.image = [UIImage systemImageNamed:@"chevron.compact.right"]; + [self addSubview:self.arrow]; + + [self.arrow size:CGSizeMake(25, 25)]; + [self.arrow y:self.centerYAnchor]; + [self.arrow trailing:self.trailingAnchor padding:-5]; + +} + +@end diff --git a/Avatar/App/Avatar/Extensions/ConstraintExtension.h b/Avatar/App/Avatar/Extensions/ConstraintExtension.h new file mode 100644 index 0000000..e90ec61 --- /dev/null +++ b/Avatar/App/Avatar/Extensions/ConstraintExtension.h @@ -0,0 +1,20 @@ +#import + +@interface UIView (extension) + +-(void)top:(nullable NSLayoutAnchor *)top leading:(nullable NSLayoutAnchor *)leading bottom:(nullable NSLayoutAnchor *)bottom trailing:(nullable NSLayoutAnchor *)trailing padding:(UIEdgeInsets)insets; +-(void)top:(nullable NSLayoutAnchor *)top padding:(CGFloat)size; +-(void)leading:(nullable NSLayoutAnchor *)leading padding:(CGFloat)size; +-(void)trailing:(nullable NSLayoutAnchor *)trailing padding:(CGFloat)size; +-(void)bottom:(nullable NSLayoutAnchor *)bottom padding:(CGFloat)size; +-(void)size:(CGSize)size; +-(void)width:(CGFloat)size; +-(void)height:(CGFloat)size; +-(void)x:(nullable NSLayoutAnchor *)centerX; +-(void)y:(nullable NSLayoutAnchor *)centerY; +-(void)x:(nullable NSLayoutAnchor *)centerX padding:(CGFloat)size; +-(void)y:(nullable NSLayoutAnchor *)centerY padding:(CGFloat)size; +-(void)x:(nullable NSLayoutAnchor *)centerX y:(nullable NSLayoutAnchor *)centerY; +-(void)fill; + +@end diff --git a/Avatar/App/Avatar/Extensions/ConstraintExtension.m b/Avatar/App/Avatar/Extensions/ConstraintExtension.m new file mode 100644 index 0000000..bd0a3b9 --- /dev/null +++ b/Avatar/App/Avatar/Extensions/ConstraintExtension.m @@ -0,0 +1,132 @@ +#import "ConstraintExtension.h" + +@implementation UIView (extension) + +-(void)top:(nullable NSLayoutAnchor *)top leading:(nullable NSLayoutAnchor *)leading bottom:(nullable NSLayoutAnchor *)bottom trailing:(nullable NSLayoutAnchor *)trailing padding:(UIEdgeInsets)insets { + + self.translatesAutoresizingMaskIntoConstraints = NO; + + if (top) { + [self.topAnchor constraintEqualToAnchor:top constant:insets.top].active = YES; + } + + if (leading) { + [self.leadingAnchor constraintEqualToAnchor:leading constant:insets.left].active = YES; + } + + if (trailing) { + [self.trailingAnchor constraintEqualToAnchor:trailing constant:insets.right].active = YES; + } + + if (bottom) { + [self.bottomAnchor constraintEqualToAnchor:bottom constant:insets.bottom].active = YES; + } + +} + + +-(void)top:(nullable NSLayoutAnchor *)top padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (top) { + [self.topAnchor constraintEqualToAnchor:top constant:size].active = YES; + } +} + + +-(void)leading:(nullable NSLayoutAnchor *)leading padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (leading) { + [self.leadingAnchor constraintEqualToAnchor:leading constant:size].active = YES; + } +} + + +-(void)trailing:(nullable NSLayoutAnchor *)trailing padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (trailing) { + [self.trailingAnchor constraintEqualToAnchor:trailing constant:size].active = YES; + } +} + + +-(void)bottom:(nullable NSLayoutAnchor *)bottom padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (bottom) { + [self.bottomAnchor constraintEqualToAnchor:bottom constant:size].active = YES; + } +} + + +-(void)size:(CGSize)size { + + self.translatesAutoresizingMaskIntoConstraints = NO; + + if (size.width != 0) { + [self.widthAnchor constraintEqualToConstant:size.width].active = YES; + } + + if (size.height != 0) { + [self.heightAnchor constraintEqualToConstant:size.height].active = YES; + } + +} + + +-(void)width:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.widthAnchor constraintEqualToConstant:size].active = YES; +} + + +-(void)height:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.heightAnchor constraintEqualToConstant:size].active = YES; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX y:(nullable NSLayoutAnchor *)centerY { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX].active = true; + [[self centerYAnchor] constraintEqualToAnchor:centerY].active = true; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX].active = true; +} + + +-(void)y:(nullable NSLayoutAnchor *)centerY { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerYAnchor] constraintEqualToAnchor:centerY].active = true; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX constant:size].active = true; +} + + +-(void)y:(nullable NSLayoutAnchor *)centerY padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerYAnchor] constraintEqualToAnchor:centerY constant:size].active = true; +} + + +-(void)fill { + + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.topAnchor constraintEqualToAnchor:self.superview.topAnchor].active = YES; + [self.leadingAnchor constraintEqualToAnchor:self.superview.leadingAnchor].active = YES; + [self.trailingAnchor constraintEqualToAnchor:self.superview.trailingAnchor].active = YES; + [self.bottomAnchor constraintEqualToAnchor:self.superview.bottomAnchor].active = YES; + +} + +@end + + + + diff --git a/Avatar/App/Avatar/Home/HomeViewController.h b/Avatar/App/Avatar/Home/HomeViewController.h new file mode 100644 index 0000000..4943816 --- /dev/null +++ b/Avatar/App/Avatar/Home/HomeViewController.h @@ -0,0 +1,36 @@ +#import +#import "ConstraintExtension.h" +#import "AnimojiPickerViewController.h" +#import "AVTAvatarStore.h" +#import "AvatarManager.h" +#import "AVTAnimoji.h" +#import "AVTAvatarLibraryViewController.h" +#import "RecordingStudioViewController.h" +#import "GridView.h" +#import "UtilitiesView.h" +#import "SettingManager.h" +#import "TDAvatarIdentityPickerViewController.h" +#import "LibraryViewController.h" +#import "SettingsViewController.h" +#import "AvimojiViewController.h" +#import "Avatar-Swift.h" +#import "DefaultMemojiViewController.h" + +@interface HomeViewController : UIViewController +@property (nonatomic, retain) AVTAvatarLibraryViewController *memojiViewController; +@property (nonatomic, retain) UIView *headerView; +@property (nonatomic, retain) UIImageView *avatarImage; +@property (nonatomic, retain) UILabel *welcomeTitle; +@property (nonatomic, retain) UILabel *welcomeSubtitle; +@property (nonatomic, retain) UIScrollView *scrollView; +@property (nonatomic, retain) UIView *containerView; +@property (nonatomic, retain) GridView *memojiView; +@property (nonatomic, retain) GridView *animojiView; +@property (nonatomic, retain) GridView *avimojiView; +@property (nonatomic, retain) GridView *libraryView; +@property (nonatomic, retain) UILabel *utilitiesLabel; +@property (nonatomic, retain) UtilitiesView *settingView; +@property (nonatomic, retain) UtilitiesView *tutorialView; +@property (nonatomic, retain) UIView *footerView; +@end + diff --git a/Avatar/App/Avatar/Home/HomeViewController.m b/Avatar/App/Avatar/Home/HomeViewController.m new file mode 100644 index 0000000..09f3405 --- /dev/null +++ b/Avatar/App/Avatar/Home/HomeViewController.m @@ -0,0 +1,333 @@ +#import "HomeViewController.h" + +NSData *profileAvatar; + +@implementation HomeViewController + + +-(void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self.navigationController setNavigationBarHidden:YES animated:NO]; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Primary"]; + + [self layoutHeaderView]; + [self layoutScrollView]; + [self layoutGridViews]; + [self initGestures]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didSelectMemojiAvatarNotification:) name:@"DidSelectMemojiAvatar" object:nil]; + + BOOL didShowDefaultMemojiOption = [[SettingManager sharedInstance] boolForKey:@"didShowDefaultMemojiOption" defaultValue:NO]; + if (!didShowDefaultMemojiOption) { + [self presentDefaultMemojiVC]; + } +} + + +-(void)layoutHeaderView { + + self.headerView = [[UIView alloc] init]; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 60)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.safeAreaLayoutGuide.topAnchor padding:0]; + + + profileAvatar = [[SettingManager sharedInstance] objectForKey:@"profileAvatar" defaultValue:nil]; + self.avatarImage = [[UIImageView alloc] init]; + self.avatarImage.layer.cornerRadius = 25; + self.avatarImage.clipsToBounds = YES; + if (profileAvatar != nil) { + self.avatarImage.image = [UIImage imageWithData:profileAvatar]; + } else { + self.avatarImage.image = [UIImage imageNamed:@"default-avatar"]; + } + self.avatarImage.userInteractionEnabled = YES; + [self.headerView addSubview:self.avatarImage]; + + [self.avatarImage size:CGSizeMake(50, 50)]; + [self.avatarImage y:self.headerView.centerYAnchor]; + [self.avatarImage trailing:self.headerView.trailingAnchor padding:-20]; + + + self.welcomeTitle = [[UILabel alloc] init]; + self.welcomeTitle.text = @"WELCOME TO"; + self.welcomeTitle.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium]; + self.welcomeTitle.textColor = UIColor.secondaryLabelColor; + self.welcomeTitle.textAlignment = NSTextAlignmentLeft; + [self.headerView addSubview:self.welcomeTitle]; + + [self.welcomeTitle top:self.avatarImage.topAnchor padding:0]; + [self.welcomeTitle leading:self.headerView.leadingAnchor padding:20]; + [self.welcomeTitle trailing:self.avatarImage.leadingAnchor padding:-20]; + + + self.welcomeSubtitle = [[UILabel alloc] init]; + self.welcomeSubtitle.text = @"Avatar Studio"; + self.welcomeSubtitle.font = [UIFont systemFontOfSize:26 weight:UIFontWeightBold]; + self.welcomeSubtitle.textColor = UIColor.labelColor; + self.welcomeSubtitle.textAlignment = NSTextAlignmentLeft; + [self.headerView addSubview:self.welcomeSubtitle]; + + [self.welcomeSubtitle bottom:self.avatarImage.bottomAnchor padding:0]; + [self.welcomeSubtitle leading:self.headerView.leadingAnchor padding:20]; + [self.welcomeSubtitle trailing:self.avatarImage.leadingAnchor padding:-20]; + +} + + +-(void)layoutScrollView { + + self.scrollView = [[UIScrollView alloc] init]; + self.scrollView.showsVerticalScrollIndicator = NO; + self.scrollView.showsHorizontalScrollIndicator = NO; + self.scrollView.backgroundColor = UIColor.clearColor; + [self.view addSubview:self.scrollView]; + + [self.scrollView top:self.headerView.bottomAnchor padding:0]; + [self.scrollView leading:self.view.leadingAnchor padding:0]; + [self.scrollView trailing:self.view.trailingAnchor padding:0]; + [self.scrollView bottom:self.view.bottomAnchor padding:0]; + + + self.containerView = [[UIView alloc] init]; + self.containerView.backgroundColor = UIColor.clearColor; + [self.scrollView addSubview:self.containerView]; + + [self.containerView size:CGSizeMake(self.view.frame.size.width, 780)]; + [self.containerView x:self.scrollView.centerXAnchor]; + [self.containerView top:self.scrollView.topAnchor padding:0]; + +} + + +-(void)layoutGridViews { + + self.memojiView = [[GridView alloc] initWithFrame:CGRectZero bg:[self colorWithHexString:@"96CEB4"] icon:[UIImage imageNamed:@"memoji"] iconSize:120 iconPadding:20 titleTop:20 titleFont:[UIFont systemFontOfSize:22 weight:UIFontWeightBold]]; + self.memojiView.title.text = @"Memoji"; + [self.containerView addSubview:self.memojiView]; + + [self.memojiView size:CGSizeMake(self.view.frame.size.width/2-30, 200)]; + [self.memojiView top:self.containerView.topAnchor padding:20]; + [self.memojiView leading:self.containerView.leadingAnchor padding:20]; + + + self.animojiView = [[GridView alloc] initWithFrame:CGRectZero bg:[self colorWithHexString:@"FFDBAC"] icon:[UIImage imageNamed:@"animoji"] iconSize:110 iconPadding:10 titleTop:5 titleFont:[UIFont systemFontOfSize:20 weight:UIFontWeightBold]]; + self.animojiView.title.text = @"Animoji"; + [self.containerView addSubview:self.animojiView]; + + [self.animojiView size:CGSizeMake(self.view.frame.size.width/2-30, 160)]; + [self.animojiView top:self.containerView.topAnchor padding:20]; + [self.animojiView trailing:self.containerView.trailingAnchor padding:-20]; + + + self.avimojiView = [[GridView alloc] initWithFrame:CGRectZero bg:[self colorWithHexString:@"E4DBF1"] icon:[UIImage imageNamed:@"avimoji"] iconSize:110 iconPadding:10 titleTop:5 titleFont:[UIFont systemFontOfSize:20 weight:UIFontWeightBold]]; + self.avimojiView.title.text = @"Avimoji"; + [self.containerView addSubview:self.avimojiView]; + + [self.avimojiView size:CGSizeMake(self.view.frame.size.width/2-30, 160)]; + [self.avimojiView top:self.memojiView.bottomAnchor padding:20]; + [self.avimojiView leading:self.containerView.leadingAnchor padding:20]; + + + self.libraryView = [[GridView alloc] initWithFrame:CGRectZero bg:[self colorWithHexString:@"DBEDC1"] icon:[UIImage imageNamed:@"library"] iconSize:120 iconPadding:20 titleTop:20 titleFont:[UIFont systemFontOfSize:22 weight:UIFontWeightBold]]; + self.libraryView.title.text = @"Library"; + [self.containerView addSubview:self.libraryView]; + + [self.libraryView size:CGSizeMake(self.view.frame.size.width/2-30, 200)]; + [self.libraryView top:self.animojiView.bottomAnchor padding:20]; + [self.libraryView trailing:self.containerView.trailingAnchor padding:-20]; + + + self.utilitiesLabel = [[UILabel alloc] init]; + self.utilitiesLabel.text = @"Utilities"; + self.utilitiesLabel.font = [UIFont systemFontOfSize:28 weight:UIFontWeightHeavy]; + self.utilitiesLabel.textColor = UIColor.labelColor; + self.utilitiesLabel.textAlignment = NSTextAlignmentLeft; + [self.containerView addSubview:self.utilitiesLabel]; + + [self.utilitiesLabel top:self.libraryView.bottomAnchor padding:25]; + [self.utilitiesLabel leading:self.containerView.leadingAnchor padding:20]; + + + self.settingView = [[UtilitiesView alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"gear"]]; + self.settingView.title.text = @"Settings"; + self.settingView.iconView.backgroundColor = UIColor.systemIndigoColor; + [self.containerView addSubview:self.settingView]; + + [self.settingView size:CGSizeMake(self.view.frame.size.width-40, 70)]; + [self.settingView x:self.containerView.centerXAnchor]; + [self.settingView top:self.utilitiesLabel.bottomAnchor padding:10]; + + + self.tutorialView = [[UtilitiesView alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"questionmark"]]; + self.tutorialView.title.text = @"Tutorial"; + self.tutorialView.iconView.backgroundColor = UIColor.systemRedColor; + [self.containerView addSubview:self.tutorialView]; + + [self.tutorialView size:CGSizeMake(self.view.frame.size.width-40, 70)]; + [self.tutorialView x:self.containerView.centerXAnchor]; + [self.tutorialView top:self.settingView.bottomAnchor padding:10]; + + + self.footerView = [[UIView alloc] init]; + [self.scrollView addSubview:self.footerView]; + + [self.footerView size:CGSizeMake(self.view.frame.size.width, 20)]; + [self.footerView x:self.scrollView.centerXAnchor]; + [self.footerView bottom:self.scrollView.bottomAnchor padding:0]; + [self.footerView top:self.containerView.bottomAnchor padding:0]; + +} + + +-(void)initGestures { + + [self.avatarImage addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentProfileAvatarPickerVC)]]; + [self.memojiView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentMemojiVC)]]; + [self.animojiView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentAnimojiVC)]]; + [self.avimojiView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentAvimojiVC)]]; + [self.libraryView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentLibraryVC)]]; + [self.settingView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentSettingsVC)]]; + [self.tutorialView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentTutorialVC)]]; +} + + +-(void)presentProfileAvatarPickerVC { + + TDAvatarIdentityPickerViewController *vc = [[TDAvatarIdentityPickerViewController alloc] initWithTitle:@"Avatar" showDefaultAvatar:NO avatarImage:self.avatarImage.image accent:UIColor.systemBlueColor]; + vc.delegate = self; + [self presentViewController:vc animated:YES completion:nil]; +} + + +-(void)didCreatedAvatar:(UIImage *)avatar { + self.avatarImage.image = avatar; + NSData *imageData = UIImageJPEGRepresentation(self.avatarImage.image, 1.0); + [[SettingManager sharedInstance] setObject:imageData forKey:@"profileAvatar"]; +} + + +-(void)didDismissedAvatarPicker { + NSLog(@"Avatar picker dismissed"); +} + + +-(void)presentMemojiVC { + AVTAvatarStore *store = [[ASAvatarStore alloc] initWithDomainIdentifier:[NSBundle mainBundle].bundleIdentifier]; + self.memojiViewController = [[ASAvatarLibraryViewController alloc] initWithAvatarStore:store]; + [self presentViewController:self.memojiViewController animated:YES completion:nil]; +} + + +-(void)presentAnimojiVC { + AnimojiPickerViewController *vc = [[AnimojiPickerViewController alloc] init]; + vc.delegate = self; + [self presentViewController:vc animated:YES completion:nil]; +} + + +-(void)presentAvimojiVC { + AvimojiViewController *vc = [[AvimojiViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +-(void)presentLibraryVC { + LibraryViewController *vc = [[LibraryViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +-(void)presentSettingsVC { + SettingsViewController *vc = [[SettingsViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +-(void)presentTutorialVC { + TutorialViewController *vc = [[TutorialViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +- (void)didSelectAnimojiWithName:(NSString *)animojiName { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + RecordingStudioViewController *vc = [[RecordingStudioViewController alloc] init]; + vc.puppetName = animojiName; + [self.navigationController pushViewController:vc animated:YES]; + }); +} + + +- (void)didSelectMemojiAvatarNotification:(NSNotification *)notification { + + NSData *memojiData = (NSData *)notification.object; + if (![memojiData isKindOfClass:[NSData class]]) return; + + NSError *error; + id avatar = [AVTAvatar avatarWithDataRepresentation:memojiData error:&error]; + + if (error) { + return; + } + + [self.memojiViewController dismissViewControllerAnimated:YES completion:nil]; + + BOOL isMemoji = [avatar isKindOfClass:[ASAnimoji class]]; + [self pushRecordingControllerWithAvatarInstance:avatar isMemoji:isMemoji]; +} + + +- (void)pushRecordingControllerWithAvatarInstance:(AVTAvatarInstance *)instance isMemoji:(BOOL)isMemoji { + + RecordingStudioViewController *recording = [RecordingStudioViewController new]; + [self.navigationController pushViewController:recording animated:YES]; + recording.avatar = instance; +} + + +-(void)presentDefaultMemojiVC { + DefaultMemojiViewController *vc = [[DefaultMemojiViewController alloc] init]; + vc.modalInPresentation = YES; + [self presentViewController:vc animated:YES completion:nil]; +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + +@end diff --git a/Avatar/App/Avatar/Info.plist b/Avatar/App/Avatar/Info.plist new file mode 100644 index 0000000..c557a8f --- /dev/null +++ b/Avatar/App/Avatar/Info.plist @@ -0,0 +1,25 @@ + + + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + SceneDelegate + + + + + UIFileSharingEnabled + + + diff --git a/Avatar/App/Avatar/Library/LibraryCell.h b/Avatar/App/Avatar/Library/LibraryCell.h new file mode 100644 index 0000000..fc67d25 --- /dev/null +++ b/Avatar/App/Avatar/Library/LibraryCell.h @@ -0,0 +1,9 @@ +#import +#import "ConstraintExtension.h" + +@interface LibraryCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *thumbnailImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIImageView *iconImage; +@end diff --git a/Avatar/App/Avatar/Library/LibraryCell.m b/Avatar/App/Avatar/Library/LibraryCell.m new file mode 100644 index 0000000..c443386 --- /dev/null +++ b/Avatar/App/Avatar/Library/LibraryCell.m @@ -0,0 +1,76 @@ +#import "LibraryCell.h" + +@implementation LibraryCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 15; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = true; + + + self.baseView = [[UIView alloc] init]; + self.baseView.layer.cornerRadius = 15; + self.baseView.backgroundColor = [UIColor colorNamed:@"Secondary"]; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.thumbnailImage = [[UIImageView alloc] init]; + self.thumbnailImage.layer.cornerRadius = 15; + self.thumbnailImage.layer.cornerCurve = kCACornerCurveContinuous; + self.thumbnailImage.clipsToBounds = YES; + self.thumbnailImage.contentMode = UIViewContentModeScaleAspectFill; + [self.baseView addSubview:self.thumbnailImage]; + + [self.thumbnailImage size:CGSizeMake(100, 70)]; + [self.thumbnailImage y:self.baseView.centerYAnchor]; + [self.thumbnailImage leading:self.baseView.leadingAnchor padding:15]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.tintColor = UIColor.systemBlueColor; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + self.iconImage.image = [UIImage systemImageNamed:@"play.rectangle.fill"]; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(40, 40)]; + [self.iconImage y:self.baseView.centerYAnchor]; + [self.iconImage trailing:self.baseView.trailingAnchor padding:-15]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.textColor = UIColor.labelColor; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel y:self.baseView.centerYAnchor]; + [self.titleLabel leading:self.thumbnailImage.trailingAnchor padding:10]; + [self.titleLabel trailing:self.iconImage.leadingAnchor padding:-8]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.thumbnailImage.image = nil; + self.titleLabel.text = nil; +} + + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.backgroundColor = UIColor.clearColor; + self.contentView.backgroundColor = UIColor.clearColor; +} + +@end diff --git a/Avatar/App/Avatar/Library/LibraryDataSource.h b/Avatar/App/Avatar/Library/LibraryDataSource.h new file mode 100644 index 0000000..41a2bae --- /dev/null +++ b/Avatar/App/Avatar/Library/LibraryDataSource.h @@ -0,0 +1,9 @@ +#import +#import + +@interface LibraryDataSource : NSObject ++(instancetype)sharedInstance; +-(id)init; + +-(NSMutableArray*)thumbnailData; +@end diff --git a/Avatar/App/Avatar/Library/LibraryDataSource.m b/Avatar/App/Avatar/Library/LibraryDataSource.m new file mode 100644 index 0000000..78d67dc --- /dev/null +++ b/Avatar/App/Avatar/Library/LibraryDataSource.m @@ -0,0 +1,65 @@ +#import "LibraryDataSource.h" + +@implementation LibraryDataSource + ++(instancetype)sharedInstance { + static LibraryDataSource*sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[LibraryDataSource alloc] init]; + }); + return sharedInstance; +} + + +-(id)init { + return self; +} + + +-(NSMutableArray*)thumbnailData { + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *thumbnailPath = [documentsDirectory stringByAppendingPathComponent:@"/Thumbnails/"]; + + NSMutableArray *folders = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:thumbnailPath error:nil] mutableCopy]; + + for (int i = 0; i < folders.count; i++) { + + NSString *path = [folders objectAtIndex:i]; + if ([path hasSuffix:@".png"]){ + [array addObject:path]; + } + } + + [array sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + + return array; +} + + +@end + + + + + + + + + + + + + + + + + + + + + diff --git a/Avatar/App/Avatar/Library/LibraryViewController.h b/Avatar/App/Avatar/Library/LibraryViewController.h new file mode 100644 index 0000000..be90314 --- /dev/null +++ b/Avatar/App/Avatar/Library/LibraryViewController.h @@ -0,0 +1,15 @@ +#import +#import +#import +#import +#import "ConstraintExtension.h" +#import "LibraryCell.h" +#import "TDHeaderView.h" +#import "LibraryDataSource.h" + +@interface LibraryViewController : UIViewController +@property (nonatomic, retain) TDHeaderView *headerView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *videoArray; +@property (nonatomic, retain) UILabel *messageLabel; +@end diff --git a/Avatar/App/Avatar/Library/LibraryViewController.m b/Avatar/App/Avatar/Library/LibraryViewController.m new file mode 100644 index 0000000..fa4fb58 --- /dev/null +++ b/Avatar/App/Avatar/Library/LibraryViewController.m @@ -0,0 +1,307 @@ +#import "LibraryViewController.h" + +@implementation LibraryViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Primary"]; + + self.videoArray = [[LibraryDataSource sharedInstance] thumbnailData]; + + [self layoutHeaderView]; + [self layoutCollectionView]; + [self checkVideoCount]; +} + + +-(void)layoutHeaderView { + + self.headerView = [[TDHeaderView alloc] initWithTitle:@"Library" accent:UIColor.systemBlueColor leftIcon:@"chevron.left" leftAction:@selector(dismissVC)]; + self.headerView.grabberView.alpha = 0; + self.headerView.leftButton.backgroundColor = [UIColor colorNamed:@"Secondary"]; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 55)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.safeAreaLayoutGuide.topAnchor padding:0]; + + + self.messageLabel = [[UILabel alloc] init]; + self.messageLabel.textAlignment = NSTextAlignmentCenter; + self.messageLabel.font = [UIFont systemFontOfSize:24 weight:UIFontWeightBold]; + self.messageLabel.textColor = UIColor.tertiaryLabelColor; + self.messageLabel.numberOfLines = 2; + self.messageLabel.text = @"You don't have any \nvideo available"; + self.messageLabel.alpha = 0; + [self.view addSubview:self.messageLabel]; + + [self.messageLabel x:self.view.centerXAnchor y:self.view.centerYAnchor]; + [self.messageLabel leading:self.view.leadingAnchor padding:20]; + [self.messageLabel trailing:self.view.trailingAnchor padding:-20]; +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[LibraryCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.view addSubview:self.collectionView]; + + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + [self.collectionView top:self.headerView.bottomAnchor padding:15]; + [self.collectionView bottom:self.view.bottomAnchor padding:0]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.videoArray.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + LibraryCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + NSString *thumbnailFile = [self.videoArray objectAtIndex:indexPath.row]; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *finalPath = [NSString stringWithFormat:@"/Thumbnails/%@", thumbnailFile]; + NSString *thumbnailPath = [documentsDirectory stringByAppendingPathComponent:finalPath]; + + cell.thumbnailImage.image = [UIImage imageWithContentsOfFile:thumbnailPath]; + cell.titleLabel.text = [NSString stringWithFormat:@"Video %li", indexPath.row +1]; + + return cell; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + return CGSizeMake(self.view.frame.size.width-40, 90); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + NSString *videoFile = [self.videoArray objectAtIndex:indexPath.row]; + NSString *videoName = [videoFile stringByReplacingOccurrencesOfString:@".png" withString:@""]; + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *finalPath = [NSString stringWithFormat:@"/Recordings/%@", videoName]; + NSString *thumbnailPath = [documentsDirectory stringByAppendingPathComponent:finalPath]; + + NSURL *videoURL = [NSURL fileURLWithPath:thumbnailPath]; + + AVPlayer *player = [AVPlayer playerWithURL:videoURL]; + AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init]; + playerViewController.player = player; + [self presentViewController:playerViewController animated:YES completion:nil]; + [playerViewController.player play]; + +} + + +- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath { + + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; + +} + + +- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath { + + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; + +} + + +- (UIContextMenuConfiguration *)collectionView:(UICollectionView *)collectionView contextMenuConfigurationForItemAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point { + + UIContextMenuConfiguration* config = [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil actionProvider:^UIMenu* _Nullable(NSArray* _Nonnull suggestedActions) { + + UIAction *saveAction = [UIAction actionWithTitle:@"Save Video" image:[UIImage systemImageNamed:@"icloud.and.arrow.down.fill"] identifier:nil handler:^(UIAction *action) { + + NSString *videoFile = [self.videoArray objectAtIndex:indexPath.row]; + NSString *videoName = [videoFile stringByReplacingOccurrencesOfString:@".png" withString:@""]; + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + + NSString *finalVideoPath = [NSString stringWithFormat:@"/Recordings/%@", videoName]; + NSString *videoPath = [documentsDirectory stringByAppendingPathComponent:finalVideoPath]; + + [self saveVideoWithString:videoPath]; + + }]; + + + UIAction *shareAction = [UIAction actionWithTitle:@"Share Video" image:[UIImage systemImageNamed:@"square.and.arrow.up.fill"] identifier:nil handler:^(UIAction *action) { + + NSString *videoFile = [self.videoArray objectAtIndex:indexPath.row]; + NSString *videoName = [videoFile stringByReplacingOccurrencesOfString:@".png" withString:@""]; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *finalPath = [NSString stringWithFormat:@"/Recordings/%@", videoName]; + NSString *videoPath = [documentsDirectory stringByAppendingPathComponent:finalPath]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self shareVideoWithString:videoPath]; + }); + + }]; + + + UIAction *deleteAction = [UIAction actionWithTitle:@"Delete Video" image:[UIImage systemImageNamed:@"trash.fill"] identifier:nil handler:^(UIAction *action) { + + NSString *videoFile = [self.videoArray objectAtIndex:indexPath.row]; + NSString *videoName = [videoFile stringByReplacingOccurrencesOfString:@".png" withString:@""]; + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + + NSString *finalVideoPath = [NSString stringWithFormat:@"/Recordings/%@", videoName]; + NSString *videoPath = [documentsDirectory stringByAppendingPathComponent:finalVideoPath]; + + + NSString *thumbnailFile = [self.videoArray objectAtIndex:indexPath.row]; + NSString *documentsDirectory2 = [paths objectAtIndex:0]; + NSString *finalThumbnailPath = [NSString stringWithFormat:@"/Thumbnails/%@", thumbnailFile]; + NSString *thumbnailPath = [documentsDirectory2 stringByAppendingPathComponent:finalThumbnailPath]; + + [self deleteVideoWithString:videoPath]; + [self deleteThumbnailWithString:thumbnailPath]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self refreshData]; + }); + + }]; + deleteAction.attributes = UIMenuElementAttributesDestructive; + + return [UIMenu menuWithTitle:@"" children:@[saveAction, shareAction, deleteAction]]; + + }]; + + return config; + +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,10,0,10); +} + + +-(void)shareVideoWithString:(NSString *)video { + + NSURL *videoURL = [NSURL fileURLWithPath:video]; + + UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:@[videoURL] applicationActivities:nil]; + + [activityController setCompletionWithItemsHandler:^(UIActivityType _Nullable activityType, BOOL completed, NSArray * _Nullable returnedItems, NSError * _Nullable activityError) { + if (!completed || !activityType) return; + }]; + [self presentViewController:activityController animated:YES completion:nil]; + +} + + +-(void)saveVideoWithString:(NSString *)video { + + NSURL *url = [NSURL URLWithString:video]; + + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^ { + [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url]; + } completionHandler:^(BOOL success, NSError *error) { + if (success) { + NSLog(@"Movie saved to camera roll."); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self showAlertWithTitle:@"Successful!" subtitle:@"The video was saved to your photo library."]; + }); + } else { + NSLog(@"Could not save movie to camera roll. Error: %@", error); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self showAlertWithTitle:@"Failed!" subtitle:@"The video failed to save to your photo library."]; + }); + } + }]; + +} + + +-(void)deleteVideoWithString:(NSString *)video { + NSError *error = nil; + [[NSFileManager defaultManager] removeItemAtPath:video error:&error]; +} + + +-(void)deleteThumbnailWithString:(NSString *)thumbnail { + NSError *error = nil; + [[NSFileManager defaultManager] removeItemAtPath:thumbnail error:&error]; +} + + +-(void)refreshData { + + self.videoArray = [[LibraryDataSource sharedInstance] thumbnailData]; + [self.collectionView reloadData]; + [self checkVideoCount]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + + +-(void)checkVideoCount { + if (self.videoArray.count == 0) { + self.messageLabel.alpha = 1; + } else { + self.messageLabel.alpha = 0; + } +} + + +-(void)dismissVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + +@end diff --git a/Avatar/App/Avatar/Manager/ARConfiguration+Overrides.h b/Avatar/App/Avatar/Manager/ARConfiguration+Overrides.h new file mode 100644 index 0000000..39d6edc --- /dev/null +++ b/Avatar/App/Avatar/Manager/ARConfiguration+Overrides.h @@ -0,0 +1,4 @@ +#import + +@interface ARConfiguration (Overrides) +@end diff --git a/Avatar/App/Avatar/Manager/ARConfiguration+Overrides.m b/Avatar/App/Avatar/Manager/ARConfiguration+Overrides.m new file mode 100644 index 0000000..b10ad55 --- /dev/null +++ b/Avatar/App/Avatar/Manager/ARConfiguration+Overrides.m @@ -0,0 +1,10 @@ +#import "ARConfiguration+Overrides.h" + +@implementation ARConfiguration (Overrides) + +- (void)setProvidesAudioData:(BOOL)providesAudioData { + // prevent this from working, we never want audio data from ARKit + return; +} + +@end diff --git a/Avatar/App/Avatar/Manager/AvatarManager.h b/Avatar/App/Avatar/Manager/AvatarManager.h new file mode 100644 index 0000000..935e8b8 --- /dev/null +++ b/Avatar/App/Avatar/Manager/AvatarManager.h @@ -0,0 +1,12 @@ +#import +#import +#import "SettingManager.h" + +//extern const NSNotificationName DidSelectMemoji; + +@interface AvatarManager : NSObject + ++ (void)prepareMemojiRuntime; ++ (BOOL)deviceSupportsMemoji; + +@end diff --git a/Avatar/App/Avatar/Manager/AvatarManager.m b/Avatar/App/Avatar/Manager/AvatarManager.m new file mode 100644 index 0000000..ce2420d --- /dev/null +++ b/Avatar/App/Avatar/Manager/AvatarManager.m @@ -0,0 +1,243 @@ +#import "AvatarManager.h" + +NSURL *animojiStudioStoreLocation(void); + +@interface AVTCoreDataCloudKitMirroringConfiguration: NSObject ++ (BOOL)cloudKitMirroringEnabled; +@end + + +@interface AVTCoreDataPersistentStoreConfiguration: NSObject ++ (instancetype)localConfigurationWithStoreLocation:(id)location environment:(id)environment; +@end + + +@interface AVTUIEnvironment: NSObject ++ (instancetype)defaultEnvironment; +@end + + +@import os.log; + + +@interface AvatarManager () +@property (readonly) NSArray *mutableLibraryItems; +@property (assign) BOOL memojiRuntimeInitializedSuccessfully; +@end + + +@implementation AvatarManager { + os_log_t _log; +} + + ++ (instancetype)sharedInstance { + static AvatarManager *_shared; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _shared = [AvatarManager new]; + }); + return _shared; +} + + +- (instancetype)init { + self = [super init]; + + _log = os_log_create("AnimojiStudio", "MemojiSupport"); + + return self; +} + + ++ (void)prepareMemojiRuntime { + [AvatarManager sharedInstance].memojiRuntimeInitializedSuccessfully = [[AvatarManager sharedInstance] _initializeMemojiRuntime]; +} + + +- (BOOL)_initializeMemojiRuntime { + + if (![[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/AvatarUI.framework"] load]) { + os_log_error(_log, "Failed to load AvatarUI framework. Memoji support disabled."); + return NO; + } + + Class AVTArchiverBasedStoreBackend = NSClassFromString(@"AVTArchiverBasedStoreBackend"); + if (!AVTArchiverBasedStoreBackend) { + os_log_error(_log, "Class AVTArchiverBasedStoreBackend not found. Memoji support disabled."); + return NO; + } + + Class AVTUIEnvironment = NSClassFromString(@"AVTUIEnvironment"); + if (!AVTUIEnvironment) { + os_log_error(_log, "Class AVTUIEnvironment not found. Memoji support disabled."); + return NO; + } + + Method m1 = class_getClassMethod(AVTArchiverBasedStoreBackend, NSSelectorFromString(@"storeLocationForDomainIdentifier:environment:")); + if (!m1) { + os_log_error(_log, "Method storeLocationForDomainIdentifier:environment: not found on class AVTArchiverBasedStoreBackend. Memoji support disabled."); + return NO; + } + + Method m2 = class_getClassMethod([self class], @selector(storeLocationForDomainIdentifier:environment:)); + + method_exchangeImplementations(m1, m2); + + Method m3 = class_getInstanceMethod(AVTUIEnvironment, NSSelectorFromString(@"storeLocation")); + if (!m3) { + os_log_error(_log, "Method storeLocation not found on class AVTUIEnvironment. Memoji support disabled."); + return NO; + } + + Method m4 = class_getClassMethod([self class], @selector(storeLocation)); + + method_exchangeImplementations(m3, m4); + + Method m5 = class_getInstanceMethod(AVTUIEnvironment, NSSelectorFromString(@"imageStoreLocation")); + if (!m5) { + os_log_error(_log, "Method imageStoreLocation not found on class AVTUIEnvironment. Memoji support disabled."); + return NO; + } + + Method m6 = class_getClassMethod([self class], @selector(imageStoreLocation)); + + method_exchangeImplementations(m5, m6); + + Class AVTAvatarLibraryModel = NSClassFromString(@"AVTAvatarLibraryModel"); + if (!AVTAvatarLibraryModel) { + os_log_error(_log, "Class AVTAvatarLibraryModel not found. Memoji support disabled."); + return NO; + } + + Method m7 = class_getInstanceMethod(AVTAvatarLibraryModel, NSSelectorFromString(@"performActionOnItemAtIndex:")); + if (!m7) { + os_log_error(_log, "Method performActionOnItemAtIndex: not found on class AVTAvatarLibraryModel. Memoji support disabled."); + return NO; + } + + class_addMethod(AVTAvatarLibraryModel, @selector(original_performActionOnItemAtIndex:), method_getImplementation(m7), method_getTypeEncoding(m7)); + + Method m8 = class_getInstanceMethod([self class], @selector(performActionOnItemAtIndex:)); + method_exchangeImplementations(m7, m8); + + if (!NSClassFromString(@"AVTCoreDataPersistentStoreConfiguration")) { + os_log_error(_log, "Class AVTCoreDataPersistentStoreConfiguration not found. Memoji support disabled."); + return NO; + } + + Method m9 = class_getClassMethod(NSClassFromString(@"AVTCoreDataPersistentStoreConfiguration"), NSSelectorFromString(@"remoteConfigurationWithDaemonClient:environment:")); + Method m10 = class_getClassMethod([self class], @selector(localConfigurationWithStoreLocation:environment:)); + method_exchangeImplementations(m9, m10); + + if (!NSClassFromString(@"AVTCoreDataCloudKitMirroringConfiguration")) { + os_log_error(_log, "Class AVTCoreDataCloudKitMirroringConfiguration not found. Memoji support disabled."); + return NO; + } + + Method m11 = class_getClassMethod(NSClassFromString(@"AVTCoreDataCloudKitMirroringConfiguration"), @selector(cloudKitMirroringEnabled)); + Method m12 = class_getClassMethod([self class], @selector(cloudKitMirroringEnabled)); + method_exchangeImplementations(m11, m12); + + os_log_info(_log, "Memoji runtime initialized successfully"); + + return YES; +} + + ++ (BOOL)cloudKitMirroringEnabled { + return NO; +} + + ++ (id)localConfigurationWithStoreLocation:(id)location environment:(id)environment { + return [NSClassFromString(@"AVTCoreDataPersistentStoreConfiguration") localConfigurationWithStoreLocation:animojiStudioStoreLocation() environment:[NSClassFromString(@"AVTUIEnvironment") defaultEnvironment]]; +} + + ++ (NSURL *)storeLocationForDomainIdentifier:(id)identifier environment:(id)environment { + return animojiStudioStoreLocation(); +} + + ++ (NSURL *)storeLocation { + NSString *path; + + BOOL useDefaultMemoji = [[SettingManager sharedInstance] boolForKey:@"useDefaultMemoji" defaultValue:NO]; + + if (useDefaultMemoji) { + path = @"/var/mobile/Library/Avatar/"; + } else { + path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; + path = [path stringByAppendingPathComponent:@"MemojiStore"]; + } + + return [NSURL fileURLWithPath:path]; +} + + ++ (NSURL *)imageStoreLocation { + NSString *path; + + BOOL useDefaultMemoji = [[SettingManager sharedInstance] boolForKey:@"useDefaultMemoji" defaultValue:NO]; + + if (useDefaultMemoji) { + path = @"/var/mobile/Library/Avatar/"; + } else { + path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; + path = [path stringByAppendingPathComponent:@"MemojiStore"]; + } + return [NSURL fileURLWithPath:path]; +} + + +- (void)original_performActionOnItemAtIndex:(NSUInteger)index { + // implementation replaced at runtime + return; +} + + +- (void)performActionOnItemAtIndex:(NSUInteger)index { + if (index >= self.mutableLibraryItems.count) return; + + id item = self.mutableLibraryItems[index]; + + if ([item isKindOfClass:NSClassFromString(@"AVTAvatarLibraryCreateNewItem")]) { + [self original_performActionOnItemAtIndex:index]; + return; + } + + NSData *memojiData = [[item valueForKey:@"avatarRecord"] valueForKey:@"avatarData"]; + if (!memojiData) return; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"DidSelectMemojiAvatar" object:memojiData]; +} + + ++ (BOOL)deviceSupportsMemoji { + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"ASSimulateMemojiUnsupported"]) return NO; + + return [AvatarManager sharedInstance].memojiRuntimeInitializedSuccessfully; +} + +@end + + +NSURL *animojiStudioStoreLocation(void) { + NSString *path; + + BOOL useDefaultMemoji = [[SettingManager sharedInstance] boolForKey:@"useDefaultMemoji" defaultValue:NO]; + + if (useDefaultMemoji) { + path = @"/var/mobile/Library/Avatar/"; + } else { + path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; + path = [path stringByAppendingPathComponent:@"MemojiStore"]; + } + return [NSURL fileURLWithPath:path]; +} + + +int override_AVTUIIsAvatarSyncEnabled(void) { + return 0; +} diff --git a/Avatar/App/Avatar/Manager/RecordingManager.h b/Avatar/App/Avatar/Manager/RecordingManager.h new file mode 100644 index 0000000..25e6ba7 --- /dev/null +++ b/Avatar/App/Avatar/Manager/RecordingManager.h @@ -0,0 +1,18 @@ +@import UIKit; +@class RecordingManager; +@import ReplayKit; +@import AVFoundation; + +@protocol RecordingManagerDelegate +- (void)recordingManager:(RecordingManager *)coordinator recordingDidFailWithError:(NSError *)error; +- (void)recordingManager:(RecordingManager *)coordinator wantsToPresentRecordingPreviewWithController:(__kindof UIViewController *)previewController; +- (void)recordingManagerDidFinishRecording:(RecordingManager *)coordinator; +@end + +@interface RecordingManager : NSObject +- (void)startRecordingWithAudio:(BOOL)shouldCaptureAudio frontCameraPreview:(BOOL)shouldCaptureFrontCamera; +- (void)stopRecording; +@property (nonatomic, weak) id delegate; +@property (nonatomic, readonly, getter=isRecording) BOOL recording; +@property (nonatomic, readonly) NSURL *videoURL; +@end diff --git a/Avatar/App/Avatar/Manager/RecordingManager.m b/Avatar/App/Avatar/Manager/RecordingManager.m new file mode 100644 index 0000000..bdecc1b --- /dev/null +++ b/Avatar/App/Avatar/Manager/RecordingManager.m @@ -0,0 +1,253 @@ +#import "RecordingManager.h" + +@interface RecordingManager () +@property (nonatomic, strong) RPScreenRecorder *recorder; +@property (nonatomic, assign, getter=isRecording) BOOL recording; +@property (nonatomic, strong) AVAssetWriter *assetWriter; +@property (nonatomic, strong) AVAssetWriterInput *videoInput; +@property (nonatomic, strong) AVAssetWriterInput *micInput; +@property (nonatomic, strong) AVAssetWriterInput *appInput; +@property (nonatomic, assign) BOOL videoSessionStarted; +@property (nonatomic, assign) BOOL micSessionStarted; +@property (nonatomic, assign) BOOL appSessionStarted; +@property (nonatomic, assign) BOOL isMicEnabled; +@end + + +@implementation RecordingManager + ++ (BOOL)shouldUseDumbRecordingMode { + return NO; +} + + +- (void)startRecordingWithAudio:(BOOL)shouldCaptureAudio frontCameraPreview:(BOOL)shouldCaptureFrontCamera { + + self.isMicEnabled = shouldCaptureAudio; + + if (!self.recorder) { + self.recorder = [RPScreenRecorder sharedRecorder]; + self.recorder.microphoneEnabled = shouldCaptureAudio; + self.recorder.cameraEnabled = shouldCaptureFrontCamera; + } + + if ([RecordingManager shouldUseDumbRecordingMode]) { + [self _startDumbRecording]; + } else { + [self _startSmartRecording]; + } +} + + +- (void)stopRecording { + if ([RecordingManager shouldUseDumbRecordingMode]) { + [self _stopDumbRecording]; + } else { + [self _stopSmartRecordingWithError:nil]; + } +} + + +- (void)_startDumbRecording { + + __weak typeof(self) weakSelf = self; + [self.recorder startRecordingWithHandler:^(NSError * _Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (!error) { + weakSelf.recording = YES; + return; + } + + [weakSelf.delegate recordingManager:weakSelf recordingDidFailWithError:error]; + }); + }]; +} + + +- (void)_stopDumbRecording { + + __weak typeof(self) weakSelf = self; + [self.recorder stopRecordingWithHandler:^(RPPreviewViewController * _Nullable previewViewController, NSError * _Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^{ + weakSelf.recording = NO; + + if (error || !previewViewController) { + [weakSelf.delegate recordingManager:weakSelf recordingDidFailWithError:error]; + } else { + previewViewController.previewControllerDelegate = weakSelf; + [weakSelf.delegate recordingManager:weakSelf wantsToPresentRecordingPreviewWithController:previewViewController]; + } + }); + }]; +} + + +- (NSURL *)_recordingURL { + + NSString *basePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; + NSString *path = [basePath stringByAppendingPathComponent:@"Recordings"]; + + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; + } + + NSString *fileName = [NSString stringWithFormat:@"Avatar_%.0f.mp4", [NSDate date].timeIntervalSince1970]; + + NSURL *url = [NSURL fileURLWithPath:[NSString pathWithComponents:@[path, fileName]]]; + + return url; +} + + +- (void)_startSmartRecording { + + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"ASDemoMode"]) { + self.recording = YES; + return; + } + + NSError *writerError; + self.assetWriter = [AVAssetWriter assetWriterWithURL:[self _recordingURL] fileType:AVFileTypeQuickTimeMovie error:&writerError]; + + NSDictionary *aperture = @{AVVideoCleanApertureWidthKey: @(1024), AVVideoCleanApertureHeightKey: @(1024), AVVideoCleanApertureVerticalOffsetKey: @(10), AVVideoCleanApertureHorizontalOffsetKey: @(10)}; + + NSDictionary *aspectRatio = @{AVVideoPixelAspectRatioVerticalSpacingKey: @1, AVVideoPixelAspectRatioHorizontalSpacingKey: @1}; + + NSDictionary *compressionSettings = @{AVVideoPixelAspectRatioKey: aspectRatio, AVVideoCleanApertureKey: aperture}; + + NSDictionary *videoSettings = @{AVVideoCompressionPropertiesKey: compressionSettings, AVVideoCodecKey: AVVideoCodecTypeHEVC, AVVideoWidthKey: @(1024), AVVideoHeightKey: @(1024), AVVideoScalingModeKey: AVVideoScalingModeResizeAspectFill}; + + NSDictionary *micAudioSettings = @{AVFormatIDKey: @(kAudioFormatMPEG4AAC), AVNumberOfChannelsKey: @(2), AVSampleRateKey: @(44100.0), AVEncoderBitRateKey: @(128000)}; + + NSDictionary *appAudioSettings = @{AVFormatIDKey: @(kAudioFormatMPEG4AAC), AVNumberOfChannelsKey: @(2), AVSampleRateKey: @(44100.0),AVEncoderBitRateKey: @(128000)}; + + self.videoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings]; + self.micInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:micAudioSettings]; + self.appInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:appAudioSettings]; + + self.videoInput.expectsMediaDataInRealTime = YES; + self.micInput.expectsMediaDataInRealTime = YES; + self.appInput.expectsMediaDataInRealTime = YES; + + [self.assetWriter addInput:self.videoInput]; + + if (self.isMicEnabled) [self.assetWriter addInput:self.micInput]; + + [self.assetWriter addInput:self.appInput]; + + if (writerError) { + [self.delegate recordingManager:self recordingDidFailWithError:writerError]; + return; + } + + if (![self.assetWriter startWriting]) { + [self _stopSmartRecordingWithError:self.assetWriter.error]; + return; + } + + __weak typeof(self) weakSelf = self; + [self.recorder startCaptureWithHandler:^(CMSampleBufferRef _Nonnull sampleBuffer, RPSampleBufferType bufferType, NSError * _Nullable error) { + if (!CMSampleBufferDataIsReady(sampleBuffer)) return; + + if (self.assetWriter.status != AVAssetWriterStatusWriting) return; + + switch (bufferType) { + case RPSampleBufferTypeVideo: + if (!weakSelf.videoSessionStarted) { + weakSelf.videoSessionStarted = YES; + [self.assetWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)]; + } + + if (weakSelf.videoInput.isReadyForMoreMediaData) { + [weakSelf.videoInput appendSampleBuffer:sampleBuffer]; + } + break; + case RPSampleBufferTypeAudioMic: + if (!weakSelf.isMicEnabled) break; + + if (!weakSelf.micSessionStarted) { + weakSelf.micSessionStarted = YES; + [self.assetWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)]; + } + + if (weakSelf.micInput.isReadyForMoreMediaData) { + [weakSelf.micInput appendSampleBuffer:sampleBuffer]; + } + break; + case RPSampleBufferTypeAudioApp: + if (!weakSelf.appSessionStarted) { + weakSelf.appSessionStarted = YES; + [self.assetWriter startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(sampleBuffer)]; + } + + if (weakSelf.appInput.isReadyForMoreMediaData) { + [weakSelf.appInput appendSampleBuffer:sampleBuffer]; + } + break; + default: break; + } + } completionHandler:^(NSError * _Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (error) { + [weakSelf.delegate recordingManager:weakSelf recordingDidFailWithError:error]; + } else { + weakSelf.recording = YES; + } + }); + }]; +} + + +- (void)_stopSmartRecordingWithError:(NSError *)inputError { + + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"ASDemoMode"]) { + self.recording = NO; + [self.delegate recordingManagerDidFinishRecording:self]; + return; + } + + if (inputError) { + [self.recorder stopCaptureWithHandler:nil]; + [self.delegate recordingManager:self recordingDidFailWithError:inputError]; + return; + } + + __weak typeof(self) weakSelf = self; + [self.recorder stopCaptureWithHandler:^(NSError * _Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^{ + weakSelf.recording = NO; + + if (error) { + [weakSelf.delegate recordingManager:self recordingDidFailWithError:error]; + } + + [weakSelf.assetWriter finishWritingWithCompletionHandler:^{ + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf.delegate recordingManagerDidFinishRecording:weakSelf]; + }); + }]; + }); + }]; +} + + +- (NSURL *)videoURL { + + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"ASDemoMode"]) { + return [[NSBundle mainBundle] URLForResource:@"Foxie" withExtension:@"mov"]; + } + + return self.assetWriter.outputURL; +} + + +- (void)previewControllerDidFinish:(RPPreviewViewController *)previewController { + [previewController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; +} + + +- (void)previewController:(RPPreviewViewController *)previewController didFinishWithActivityTypes:(NSSet *)activityTypes { + [previewController.presentingViewController dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/Avatar/App/Avatar/Manager/SettingManager.h b/Avatar/App/Avatar/Manager/SettingManager.h new file mode 100644 index 0000000..c402150 --- /dev/null +++ b/Avatar/App/Avatar/Manager/SettingManager.h @@ -0,0 +1,20 @@ +#import + +@interface SettingManager : NSObject ++(instancetype)sharedInstance; +-(id)init; + +- (void)setBool:(BOOL)anObject forKey:(id)aKey; +- (void)setObject:(id)anObject forKey:(id)aKey; +- (void)setFloat:(long long)anObject forKey:(id)aKey; +- (void)setInt:(int)anObject forKey:(id)aKey; +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue; +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue; +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue; +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue; +- (bool)boolForKey:(id)aKey; +- (id)objectForKey:(id)aKey; +- (long long)floatForKey:(id)aKey; +- (int)intForKey:(id)aKey; +-(UIColor *)systemColourForKey:(id)aKey defaultColour:(UIColor *)defaultColour; +@end diff --git a/Avatar/App/Avatar/Manager/SettingManager.m b/Avatar/App/Avatar/Manager/SettingManager.m new file mode 100644 index 0000000..01a8bf8 --- /dev/null +++ b/Avatar/App/Avatar/Manager/SettingManager.m @@ -0,0 +1,135 @@ +#import "SettingManager.h" + + +@implementation SettingManager + ++(instancetype)sharedInstance { + static SettingManager *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[SettingManager alloc] init]; + }); + return sharedInstance; +} + +-(id)init { + return self; +} + +- (void)setBool:(BOOL)anObject forKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + [settings setObject:[NSNumber numberWithBool:anObject] forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (void)setObject:(id)anObject forKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + [settings setObject:anObject forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; + NSLog(@"Write image data..."); +} + +- (void)setFloat:(long long)anObject forKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + [settings setObject:@(anObject) forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (void)setInt:(int)anObject forKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + [settings setObject:@(anObject) forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + if([settings objectForKey:aKey] == NULL){ + return defaultValue; + } + return [[settings objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [settings objectForKey:aKey]?:defaultValue; +} + +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [[settings objectForKey:aKey] longLongValue]?:defaultValue; +} + +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [[settings objectForKey:aKey] intValue]?:defaultValue; +} + +- (bool)boolForKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [[settings objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [settings objectForKey:aKey]; +} + +- (long long)floatForKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [[settings objectForKey:aKey] longLongValue]; +} + +- (int)intForKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [[settings objectForKey:aKey] intValue]; +} + + +- (UIColor *)systemColourForKey:(id)aKey defaultColour:(UIColor *)defaultColour { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Settings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + NSData *decodedData = [settings objectForKey:aKey]; + UIColor *color = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]?:defaultColour; + return color; +} + + +@end diff --git a/Avatar/App/Avatar/Onboarding/DefaultMemojiViewController.h b/Avatar/App/Avatar/Onboarding/DefaultMemojiViewController.h new file mode 100644 index 0000000..975fd6d --- /dev/null +++ b/Avatar/App/Avatar/Onboarding/DefaultMemojiViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "SettingManager.h" + +@interface DefaultMemojiViewController : UIViewController +@property (nonatomic, retain) UIView *grabberView; +@property (nonatomic, retain) UIImageView *coverImage; +@property (nonatomic, retain) UITextView *textView; +@property (nonatomic, retain) UIButton *yesButton; +@property (nonatomic, retain) UIButton *noButton; +@end diff --git a/Avatar/App/Avatar/Onboarding/DefaultMemojiViewController.m b/Avatar/App/Avatar/Onboarding/DefaultMemojiViewController.m new file mode 100644 index 0000000..b5472f4 --- /dev/null +++ b/Avatar/App/Avatar/Onboarding/DefaultMemojiViewController.m @@ -0,0 +1,114 @@ +#import "DefaultMemojiViewController.h" + + +@implementation DefaultMemojiViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Primary"]; + + self.grabberView = [[UIView alloc] init]; + self.grabberView.backgroundColor = UIColor.tertiarySystemFillColor; + self.grabberView.layer.cornerRadius = 3; + [self.view addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.view.centerXAnchor]; + [self.grabberView top:self.view.topAnchor padding:10]; + + [self layoutViews]; +} + + +-(void)layoutViews { + + self.coverImage = [[UIImageView alloc] init]; + self.coverImage.image = [UIImage imageNamed:@"cover"]; + [self.view addSubview:self.coverImage]; + + [self.coverImage size:CGSizeMake(300, 147)]; + [self.coverImage x:self.view.centerXAnchor]; + [self.coverImage top:self.grabberView.bottomAnchor padding:20]; + + + self.noButton = [[UIButton alloc] init]; + self.noButton.backgroundColor = [UIColor.systemRedColor colorWithAlphaComponent:0.4]; + self.noButton.layer.cornerRadius = 15; + self.noButton.layer.cornerCurve = kCACornerCurveContinuous; + [self.noButton setTitle:@"NO" forState:UIControlStateNormal]; + [self.noButton addTarget:self action:@selector(dontUseDefaultMemoji) forControlEvents:UIControlEventTouchUpInside]; + [self.noButton setTitleColor:UIColor.systemRedColor forState:UIControlStateNormal]; + [self.view addSubview:self.noButton]; + + [self.noButton size:CGSizeMake(self.view.frame.size.width-100, 50)]; + [self.noButton x:self.view.centerXAnchor]; + [self.noButton bottom:self.view.safeAreaLayoutGuide.bottomAnchor padding:-10]; + + + self.yesButton = [[UIButton alloc] init]; + self.yesButton.backgroundColor = [UIColor.systemBlueColor colorWithAlphaComponent:0.4]; + self.yesButton.layer.cornerRadius = 15; + self.yesButton.layer.cornerCurve = kCACornerCurveContinuous; + [self.yesButton setTitle:@"YES" forState:UIControlStateNormal]; + [self.yesButton addTarget:self action:@selector(useDefaultMemoji) forControlEvents:UIControlEventTouchUpInside]; + [self.yesButton setTitleColor:UIColor.systemBlueColor forState:UIControlStateNormal]; + [self.view addSubview:self.yesButton]; + + [self.yesButton size:CGSizeMake(self.view.frame.size.width-100, 50)]; + [self.yesButton x:self.view.centerXAnchor]; + [self.yesButton bottom:self.noButton.topAnchor padding:-15]; + + + self.textView = [[UITextView alloc] init]; + self.textView.backgroundColor = [UIColor colorNamed:@"Secondary"]; + self.textView.textColor = UIColor.labelColor; + self.textView.text = @"Do you want to import existing Memoji that you’ve already created in iMessage? If yes then you won’t be able to create new Memoji in the Avatar app but you still can create new Memoji in iMessage then the Avatar app will load the newly created Memoji. If you choose no then you will need to create new Memoji within the app. Don’t worry you can switch between existing or new Memoji in the settings option."; + self.textView.editable = NO; + self.textView.layer.cornerRadius = 20; + self.textView.layer.cornerCurve = kCACornerCurveContinuous; + self.textView.textContainerInset = UIEdgeInsetsMake(10, 10, 10, 10); + self.textView.font = [UIFont systemFontOfSize:22]; + [self.view addSubview:self.textView]; + + [self.textView top:self.coverImage.bottomAnchor padding:25]; + [self.textView leading:self.view.leadingAnchor padding:25]; + [self.textView trailing:self.view.trailingAnchor padding:-25]; + [self.textView bottom:self.yesButton.topAnchor padding:-25]; +} + + +-(void)dontUseDefaultMemoji { + + [[SettingManager sharedInstance] setBool:YES forKey:@"didShowDefaultMemojiOption"]; + [[SettingManager sharedInstance] setBool:NO forKey:@"useDefaultMemoji"]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)useDefaultMemoji { + + [[SettingManager sharedInstance] setBool:YES forKey:@"didShowDefaultMemojiOption"]; + [[SettingManager sharedInstance] setBool:YES forKey:@"useDefaultMemoji"]; + [self showAlertWithTitle:@"Existing Memoji" subtitle:@"Restarting is required, the app will now terminate and you will need to relaunch the Avatar app in order for it to load existing Memoji."]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self dismissViewControllerAnimated:YES completion:nil]; + //exit(0); + UIApplication *app = [UIApplication sharedApplication]; + [app performSelector:@selector(suspend)]; + [NSThread sleepForTimeInterval:1.0]; + exit(0); + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + +@end diff --git a/Avatar/App/Avatar/Onboarding/RecordingOnboardingViewController.h b/Avatar/App/Avatar/Onboarding/RecordingOnboardingViewController.h new file mode 100644 index 0000000..1d7f370 --- /dev/null +++ b/Avatar/App/Avatar/Onboarding/RecordingOnboardingViewController.h @@ -0,0 +1,10 @@ +#import +#import "ConstraintExtension.h" +#import "SettingManager.h" + +@interface RecordingOnboardingViewController : UIViewController +@property (nonatomic, retain) UIView *grabberView; +@property (nonatomic, retain) UIImageView *screenshot; +@property (nonatomic, retain) UITextView *textView; +@property (nonatomic, retain) UIButton *dismissButton; +@end diff --git a/Avatar/App/Avatar/Onboarding/RecordingOnboardingViewController.m b/Avatar/App/Avatar/Onboarding/RecordingOnboardingViewController.m new file mode 100644 index 0000000..60b13e9 --- /dev/null +++ b/Avatar/App/Avatar/Onboarding/RecordingOnboardingViewController.m @@ -0,0 +1,71 @@ +#import "RecordingOnboardingViewController.h" + +@implementation RecordingOnboardingViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Primary"]; + + self.grabberView = [[UIView alloc] init]; + self.grabberView.backgroundColor = UIColor.tertiarySystemFillColor; + self.grabberView.layer.cornerRadius = 3; + [self.view addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.view.centerXAnchor]; + [self.grabberView top:self.view.topAnchor padding:10]; + + [self layoutScreenshotView]; +} + + +-(void)layoutScreenshotView { + + self.screenshot = [[UIImageView alloc] init]; + self.screenshot.image = [UIImage imageNamed:@"recording-tutorial"]; + [self.view addSubview:self.screenshot]; + + [self.screenshot size:CGSizeMake(self.view.frame.size.width-70, self.view.frame.size.width-70)]; + [self.screenshot x:self.view.centerXAnchor]; + [self.screenshot top:self.grabberView.bottomAnchor padding:20]; + + + self.dismissButton = [[UIButton alloc] init]; + self.dismissButton.backgroundColor = [UIColor.systemBlueColor colorWithAlphaComponent:0.4]; + self.dismissButton.layer.cornerRadius = 15; + self.dismissButton.layer.cornerCurve = kCACornerCurveContinuous; + [self.dismissButton setTitle:@"Continue" forState:UIControlStateNormal]; + [self.dismissButton addTarget:self action:@selector(dismissVC) forControlEvents:UIControlEventTouchUpInside]; + [self.dismissButton setTitleColor:UIColor.systemBlueColor forState:UIControlStateNormal]; + [self.view addSubview:self.dismissButton]; + + [self.dismissButton size:CGSizeMake(self.view.frame.size.width-100, 50)]; + [self.dismissButton x:self.view.centerXAnchor]; + [self.dismissButton bottom:self.view.safeAreaLayoutGuide.bottomAnchor padding:-10]; + + + self.textView = [[UITextView alloc] init]; + self.textView.backgroundColor = [UIColor colorNamed:@"Secondary"]; + self.textView.textColor = UIColor.labelColor; + self.textView.text = @"The red border line is your recording area. Don’t put stickers or objects out of bounds otherwise they will not be in the actual video."; + self.textView.editable = NO; + self.textView.layer.cornerRadius = 20; + self.textView.layer.cornerCurve = kCACornerCurveContinuous; + self.textView.textContainerInset = UIEdgeInsetsMake(10, 10, 10, 10); + self.textView.font = [UIFont systemFontOfSize:22]; + [self.view addSubview:self.textView]; + + [self.textView top:self.screenshot.bottomAnchor padding:25]; + [self.textView leading:self.view.leadingAnchor padding:25]; + [self.textView trailing:self.view.trailingAnchor padding:-25]; + [self.textView bottom:self.dismissButton.topAnchor padding:-25]; +} + + +-(void)dismissVC { + [[SettingManager sharedInstance] setBool:YES forKey:@"didShowRecordingOnboarding"]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/Avatar/App/Avatar/Preview/AvatarVideoPreviewViewController.h b/Avatar/App/Avatar/Preview/AvatarVideoPreviewViewController.h new file mode 100644 index 0000000..52454f8 --- /dev/null +++ b/Avatar/App/Avatar/Preview/AvatarVideoPreviewViewController.h @@ -0,0 +1,20 @@ +#import +#import +#import +#import "ConstraintExtension.h" +#import "TDHeaderView.h" +#import "RecordingButton.h" + +@interface AvatarVideoPreviewViewController : UIViewController +@property (nonatomic, retain) TDHeaderView *headerView; +@property (nonatomic, retain) NSURL *previouslyLoadedVideo; +@property (nonatomic, strong) AVPlayer *player; +@property (nonatomic, strong) AVPlayerLayer *videoLayer; +@property (nonatomic, strong) UIView *videoView; +@property (nonatomic, retain) NSURL *videoURL; +@property (nonatomic, retain) NSString *videoName; +@property (nonatomic, retain) UIButton *saveButton; +@property (nonatomic, retain) UIButton *shareButton; +@property (nonatomic, retain) RecordingButton *replayButton; +@end + diff --git a/Avatar/App/Avatar/Preview/AvatarVideoPreviewViewController.m b/Avatar/App/Avatar/Preview/AvatarVideoPreviewViewController.m new file mode 100644 index 0000000..baa206c --- /dev/null +++ b/Avatar/App/Avatar/Preview/AvatarVideoPreviewViewController.m @@ -0,0 +1,232 @@ +#import "AvatarVideoPreviewViewController.h" + +@implementation AvatarVideoPreviewViewController + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + [self _loadVideoIfNeeded]; + [self generateThumbnail]; +} + + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [self.player pause]; + [self.player cancelPendingPrerolls]; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Primary"]; + + [self layoutHeaderView]; + [self layoutVideoView]; + [self layoutActionButton]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player]; +} + + +-(void)layoutHeaderView { + + self.headerView = [[TDHeaderView alloc] initWithTitle:@"Preview" accent:UIColor.systemBlueColor leftIcon:@"xmark" leftAction:@selector(dismissVC)]; + self.headerView.leftButton.backgroundColor = [UIColor colorNamed:@"Secondary"]; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.safeAreaLayoutGuide.topAnchor padding:0]; +} + + +- (void)layoutVideoView { + + self.videoView = [UIView new]; + self.videoView.layer.cornerRadius = 25; + self.videoView.layer.cornerCurve = kCACornerCurveContinuous; + self.videoView.clipsToBounds = YES; + [self.view addSubview:self.videoView]; + + [self.videoView size:CGSizeMake(self.view.frame.size.width-40, self.view.frame.size.width-40)]; + [self.videoView x:self.view.centerXAnchor]; + [self.videoView top:self.headerView.bottomAnchor padding:30]; +} + + +-(void)layoutActionButton { + + self.saveButton = [[UIButton alloc] init]; + self.saveButton.backgroundColor = [UIColor.systemBlueColor colorWithAlphaComponent:0.4]; + self.saveButton.layer.cornerRadius = 15; + self.saveButton.layer.cornerCurve = kCACornerCurveContinuous; + [self.saveButton setTitle:@"Save Video" forState:UIControlStateNormal]; + [self.saveButton addTarget:self action:@selector(saveAvatarVideo) forControlEvents:UIControlEventTouchUpInside]; + [self.saveButton setTitleColor:UIColor.systemBlueColor forState:UIControlStateNormal]; + [self.view addSubview:self.saveButton]; + + [self.saveButton size:CGSizeMake(self.view.frame.size.width-100, 50)]; + [self.saveButton x:self.view.centerXAnchor]; + [self.saveButton top:self.videoView.bottomAnchor padding:25]; + + + self.shareButton = [[UIButton alloc] init]; + self.shareButton.backgroundColor = [UIColor.systemBlueColor colorWithAlphaComponent:0.4]; + self.shareButton.layer.cornerRadius = 15; + self.shareButton.layer.cornerCurve = kCACornerCurveContinuous; + [self.shareButton setTitle:@"Share Video" forState:UIControlStateNormal]; + [self.shareButton addTarget:self action:@selector(shareAvatarVideo) forControlEvents:UIControlEventTouchUpInside]; + [self.shareButton setTitleColor:UIColor.systemBlueColor forState:UIControlStateNormal]; + [self.view addSubview:self.shareButton]; + + [self.shareButton size:CGSizeMake(self.view.frame.size.width-100, 50)]; + [self.shareButton x:self.view.centerXAnchor]; + [self.shareButton top:self.saveButton.bottomAnchor padding:15]; + + + self.replayButton = [[RecordingButton alloc] initWithIcon:@"play.fill" accent:[UIColor.systemBlueColor colorWithAlphaComponent:0.6] action:@selector(togglePlaying)]; + self.replayButton.layer.cornerRadius = 35; + self.replayButton.alpha = 0; + [self.view addSubview:self.replayButton]; + + [self.replayButton size:CGSizeMake(70, 70)]; + [self.replayButton x:self.videoView.centerXAnchor y:self.videoView.centerYAnchor]; +} + + +- (void)_loadVideoIfNeeded { + + if (!self.videoURL || !self.isViewLoaded) return; + + if ([self.previouslyLoadedVideo isEqual:self.videoURL]) return; + + self.previouslyLoadedVideo = self.videoURL; + + [self.videoLayer removeFromSuperlayer]; + [self.player pause]; + [self.player cancelPendingPrerolls]; + + self.player = [AVPlayer playerWithURL:self.videoURL]; + self.videoLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; + + self.videoLayer.frame = self.videoView.bounds; + [self.videoView.layer addSublayer:self.videoLayer]; + + [self.player play]; +} + + +-(void)togglePlaying { + + [self.player play]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + self.replayButton.alpha = 0; + }); + +} + + +-(void)saveAvatarVideo { + + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^ { + [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:self.videoURL]; + } completionHandler:^(BOOL success, NSError *error) { + if (success) { + NSLog(@"Movie saved to camera roll."); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self showAlertWithTitle:@"Successful!" subtitle:@"The video was saved to your photo library."]; + }); + } else { + NSLog(@"Could not save movie to camera roll. Error: %@", error); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self showAlertWithTitle:@"Failed!" subtitle:@"The video failed to save to your photo library."]; + }); + } + }]; + +} + + +-(void)shareAvatarVideo { + + if (!self.videoURL) return; + + UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:@[self.videoURL] applicationActivities:nil]; + + [activityController setCompletionWithItemsHandler:^(UIActivityType _Nullable activityType, BOOL completed, NSArray * _Nullable returnedItems, NSError * _Nullable activityError) { + if (!completed || !activityType) return; + }]; + [self presentViewController:activityController animated:YES completion:nil]; +} + + +-(void)generateThumbnail { + + NSArray *existingPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, + YES); + NSString *documentsPath = [existingPath objectAtIndex:0]; + NSString *myPath = [documentsPath stringByAppendingPathComponent:@"/Thumbnails"]; + + if (![[NSFileManager defaultManager] fileExistsAtPath:myPath]) { + [[NSFileManager defaultManager] createDirectoryAtPath:myPath withIntermediateDirectories:NO + attributes:nil error:NULL]; + } + + + NSString *videoURLString = self.videoURL.absoluteString; + + self.videoName = videoURLString.lastPathComponent; + + NSURL *videoURL = [NSURL fileURLWithPath:videoURLString]; + + AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoURL options:nil]; + AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset]; + generator.appliesPreferredTrackTransform = YES; + + NSError *err = NULL; + CMTime thumbTime = CMTimeMakeWithSeconds(0,02); + CGSize maxSize = CGSizeMake(425,425); + generator.maximumSize = maxSize; + + CGImageRef imgRef = [generator copyCGImageAtTime:thumbTime actualTime:NULL error:&err]; + UIImage *thumbnail = [[UIImage alloc] initWithCGImage:imgRef]; + + NSData *data = UIImagePNGRepresentation(thumbnail); + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsDirectory = [paths objectAtIndex:0]; + NSString *newFileName = [NSString stringWithFormat:@"/Thumbnails/%@.png", self.videoName]; + + NSString *dirs = [documentsDirectory stringByAppendingPathComponent:newFileName]; + + [data writeToFile:dirs atomically:YES]; + +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + + +-(void)itemDidFinishPlaying:(NSNotification *) notification { + [self.player seekToTime:kCMTimeZero]; + self.replayButton.alpha = 1; +} + +@end diff --git a/Avatar/App/Avatar/Recording/RecordingActionMenuCell.h b/Avatar/App/Avatar/Recording/RecordingActionMenuCell.h new file mode 100644 index 0000000..19f356f --- /dev/null +++ b/Avatar/App/Avatar/Recording/RecordingActionMenuCell.h @@ -0,0 +1,10 @@ +#import +#import "ConstraintExtension.h" + +@interface RecordingActionMenuCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@end + diff --git a/Avatar/App/Avatar/Recording/RecordingActionMenuCell.m b/Avatar/App/Avatar/Recording/RecordingActionMenuCell.m new file mode 100644 index 0000000..cf1c8a3 --- /dev/null +++ b/Avatar/App/Avatar/Recording/RecordingActionMenuCell.m @@ -0,0 +1,59 @@ +#import "RecordingActionMenuCell.h" + +@implementation RecordingActionMenuCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = UIColor.clearColor; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:0]; + [self.baseView leading:self.leadingAnchor padding:0]; + [self.baseView trailing:self.trailingAnchor padding:0]; + [self.baseView bottom:self.bottomAnchor padding:0]; + + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 10; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + [self.baseView addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(50, 50)]; + [self.iconView x:self.baseView.centerXAnchor]; + [self.iconView top:self.baseView.topAnchor padding:0]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.iconView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(30, 30)]; + [self.iconImage x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.font = [UIFont systemFontOfSize:9 weight:UIFontWeightRegular]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel top:self.iconView.bottomAnchor padding:3]; + [self.titleLabel x:self.baseView.centerXAnchor]; + + } + + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.iconImage.image = nil; + self.titleLabel.text = nil; +} + +@end diff --git a/Avatar/App/Avatar/Recording/RecordingStudioViewController.h b/Avatar/App/Avatar/Recording/RecordingStudioViewController.h new file mode 100644 index 0000000..af4355e --- /dev/null +++ b/Avatar/App/Avatar/Recording/RecordingStudioViewController.h @@ -0,0 +1,31 @@ +#import +#import "RecordingManager.h" +#import "AVTAnimoji.h" +#import "AvatarMotionView.h" +#import "AvatarVideoPreviewViewController.h" +#import "ConstraintExtension.h" +#import "TDHeaderView.h" +#import "RecordingActionMenuCell.h" +#import "RecordingButton.h" +#import "TDStickerPickerViewController.h" +#import "StickerView.h" +#import "SettingManager.h" +#import "RecordingOnboardingViewController.h" + +@interface RecordingStudioViewController : UIViewController +@property (nonatomic, copy) NSString *puppetName; +@property (nonatomic, strong) id avatar; +@property (nonatomic, strong) RecordingManager *recordingManager; +@property (nonatomic, strong) AvatarMotionView *avatarMotionView; +@property (nonatomic, strong) AVTAnimoji *puppet; +@property (nonatomic, strong) AVTAvatarInstance *avatarInstance; +@property (nonatomic, retain) UIImageView *wallpaper; +@property (nonatomic, retain) TDHeaderView *headerView; +@property (nonatomic, retain) UIView *actionView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSTimer *timer; +@property (nonatomic, retain) RecordingButton *stopButton; +@property (strong, nonatomic) StickerView *selectedSticker; +@property (strong,nonatomic) UIDynamicAnimator *animator; +@property (nonatomic) NSInteger numberOfStickers; +@end diff --git a/Avatar/App/Avatar/Recording/RecordingStudioViewController.m b/Avatar/App/Avatar/Recording/RecordingStudioViewController.m new file mode 100755 index 0000000..bc931a3 --- /dev/null +++ b/Avatar/App/Avatar/Recording/RecordingStudioViewController.m @@ -0,0 +1,526 @@ +#import "RecordingStudioViewController.h" + + +@implementation RecordingStudioViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Primary"]; + + [self layoutWallpaper]; + [self layoutAvatarMotionView]; + [self layoutHeaderView]; + [self layoutActionView]; + [self layoutStickerTools]; + [self layoutCollectionView]; + + BOOL showOnboarding = [[SettingManager sharedInstance] boolForKey:@"didShowRecordingOnboarding" defaultValue:NO]; + + if (!showOnboarding) { + [self presentOnboarding]; + } +} + + +-(void)layoutWallpaper { + + self.wallpaper = [[UIImageView alloc] init]; + self.wallpaper.contentMode = UIViewContentModeScaleAspectFill; + self.wallpaper.clipsToBounds = YES; + self.wallpaper.alpha = 0; + [self.view addSubview:self.wallpaper]; + + [self.wallpaper fill]; +} + + +- (void)layoutAvatarMotionView { + + if (self.avatarMotionView) return; + + self.avatarMotionView = [[AvatarMotionView alloc] init]; + self.avatarMotionView.alpha = 0; + self.avatarMotionView.frame = self.view.bounds; + self.avatarMotionView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + self.avatarMotionView.backgroundColor = [UIColor colorNamed:@"Primary"]; + [self.view addSubview:self.avatarMotionView]; + + + if (self.avatarInstance) [self.avatarMotionView setAvatar:self.avatarInstance]; + + [self.avatarMotionView resetTracking]; + + [UIView animateWithDuration:0.3 animations:^{ + self.avatarMotionView.alpha = 1; + }]; + +} + + +- (void)setPuppetName:(NSString *)puppetName { + _puppetName = [puppetName copy]; + self.avatarInstance = (AVTAvatarInstance *)[AVTAnimoji animojiNamed:_puppetName]; +} + + +- (void)setAvatar:(id)avatar { + self.avatarInstance = (AVTAvatarInstance *)avatar; +} + + +- (void)setAvatarInstance:(AVTAvatarInstance *)avatarInstance { + _avatarInstance = avatarInstance; + [self.avatarMotionView setAvatar:_avatarInstance]; +} + + +-(void)layoutHeaderView { + + self.headerView = [[TDHeaderView alloc] initWithTitle:@"Studio" accent:UIColor.systemBlueColor leftIcon:@"chevron.left" leftAction:@selector(dismissVC)]; + self.headerView.grabberView.alpha = 0; + self.headerView.leftButton.backgroundColor = [UIColor colorNamed:@"Secondary"]; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 55)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.safeAreaLayoutGuide.topAnchor padding:0]; +} + +-(void)layoutActionView { + + self.actionView = [[UIView alloc] init]; + self.actionView.backgroundColor = [UIColor colorNamed:@"Secondary"]; + self.actionView.layer.cornerRadius = 25; + self.actionView.layer.cornerCurve = kCACornerCurveContinuous; + self.actionView.layer.maskedCorners = 3; + [self.view addSubview:self.actionView]; + + [self.actionView size:CGSizeMake(self.view.frame.size.width, 130)]; + [self.actionView x:self.view.centerXAnchor]; + [self.actionView bottom:self.view.bottomAnchor padding:0]; + + + self.stopButton = [[RecordingButton alloc] initWithIcon:@"stop.fill" accent:UIColor.systemRedColor action:@selector(stopRecording)]; + self.stopButton.layer.cornerRadius = 35; + self.stopButton.alpha = 0; + [self.actionView addSubview:self.stopButton]; + + [self.stopButton size:CGSizeMake(70, 70)]; + [self.stopButton x:self.actionView.centerXAnchor y:self.actionView.centerYAnchor]; + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[RecordingActionMenuCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.actionView addSubview:self.collectionView]; + + [self.collectionView height:80]; + [self.collectionView width:300]; + [self.collectionView x:self.actionView.centerXAnchor]; + [self.collectionView top:self.actionView.topAnchor padding:15]; + + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return 5; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + RecordingActionMenuCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + if (indexPath.row == 0) { + + cell.iconView.backgroundColor = [UIColor.systemRedColor colorWithAlphaComponent:0.3]; + cell.iconImage.image = [UIImage systemImageNamed:@"record.circle"]; + cell.iconImage.tintColor = UIColor.systemRedColor; + cell.titleLabel.text = @"Record"; + + } else if (indexPath.row == 1) { + + cell.iconView.backgroundColor = [UIColor.systemYellowColor colorWithAlphaComponent:0.3]; + cell.iconImage.image = [UIImage systemImageNamed:@"photo.fill"]; + cell.iconImage.tintColor = UIColor.systemYellowColor; + cell.titleLabel.text = @"Wallpaper"; + + } else if (indexPath.row == 2) { + + cell.iconView.backgroundColor = [UIColor.systemOrangeColor colorWithAlphaComponent:0.3]; + cell.iconImage.image = [UIImage systemImageNamed:@"paintpalette.fill"]; + cell.iconImage.tintColor = UIColor.systemOrangeColor; + cell.titleLabel.text = @"Colour"; + + } else if (indexPath.row == 3) { + + cell.iconView.backgroundColor = [UIColor.systemIndigoColor colorWithAlphaComponent:0.3]; + cell.iconImage.image = [UIImage systemImageNamed:@"face.smiling.fill"]; + cell.iconImage.tintColor = UIColor.systemIndigoColor; + cell.titleLabel.text = @"Stickers"; + + } else if (indexPath.row == 4) { + + cell.iconView.backgroundColor = [UIColor.systemRedColor colorWithAlphaComponent:0.3]; + cell.iconImage.image = [UIImage systemImageNamed:@"trash.fill"]; + cell.iconImage.tintColor = UIColor.systemRedColor; + cell.titleLabel.text = @"Reset"; + + } + + return cell; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + return CGSizeMake(50, 80); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + if (indexPath.row == 0) { + [self prepareRecording]; + } else if (indexPath.row == 1) { + [self presentImagePickerVC]; + } else if (indexPath.row == 2) { + [self presentColourPickerVC]; + } else if (indexPath.row == 3) { + [self presentStickersPickerVC]; + } else if (indexPath.row == 4) { + [self reset]; + } +} + + +-(void)layoutStickerTools { + + self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; + + UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapBackground:)]; + [tapRecognizer setNumberOfTapsRequired:1]; + [self.avatarMotionView addGestureRecognizer:tapRecognizer]; +} + + +-(void)prepareRecording { + + [self.avatarMotionView resetTracking]; + + if (self.recordingManager.isRecording) { + [self stopRecording]; + } else { + [self startRecording]; + } + + if (!self.timer) { + self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(checkRecordingStatus) userInfo:nil repeats:YES]; + } + +} + + +-(void)checkRecordingStatus { + + if (self.recordingManager.isRecording) { + self.collectionView.alpha = 0; + self.stopButton.alpha = 1; + } else { + self.collectionView.alpha = 1; + self.stopButton.alpha = 0; + } + +} + + +- (void)startRecording { + + self.recordingManager = [RecordingManager new]; + self.recordingManager.delegate = self; + + [RPScreenRecorder sharedRecorder].microphoneEnabled = YES; + + if (![[NSUserDefaults standardUserDefaults] boolForKey:@"ASDemoMode"]) { + [self.recordingManager startRecordingWithAudio:YES frontCameraPreview:NO]; + } + + [[UIApplication sharedApplication] setIdleTimerDisabled:YES]; +} + + +- (void)stopRecording { + + [self.recordingManager stopRecording]; + + [[UIApplication sharedApplication] setIdleTimerDisabled:NO]; + + [self.timer invalidate]; + self.timer = nil; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [UIView animateWithDuration:0.2f animations:^{ + self.collectionView.alpha = 1; + self.stopButton.alpha = 0; + }]; + }); +} + + +- (void)recordingManager:(RecordingManager *)coordinator recordingDidFailWithError:(NSError *)error { + NSString *errorMessage = (error.localizedDescription) ? error.localizedDescription : @"Unknown error"; + NSString *message = [NSString stringWithFormat:@"Sorry, the recording failed.\n%@", errorMessage]; + NSLog(@"%@%@", errorMessage, message); +} + + +- (void)recordingManager:(RecordingManager *)coordinator wantsToPresentRecordingPreviewWithController:(__kindof UIViewController *)previewController { +} + + +- (void)recordingManagerDidFinishRecording:(RecordingManager *)coordinator { + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + AvatarVideoPreviewViewController *vc = [[AvatarVideoPreviewViewController alloc] init]; + vc.videoURL = self.recordingManager.videoURL; + [self.navigationController presentViewController:vc animated:YES completion:nil]; + }); + +} + + +-(void)presentImagePickerVC { + UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init]; + imagePickerController.delegate = self; + imagePickerController.allowsEditing = false; + imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [self presentViewController:imagePickerController animated:YES completion:nil]; +} + + +-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(nonnull NSDictionary *)info { + + self.avatarMotionView.backgroundColor = UIColor.clearColor; + self.wallpaper.alpha = 1; + self.wallpaper.image = info[UIImagePickerControllerOriginalImage]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentColourPickerVC { + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + colourPickerVC.selectedColor = self.avatarMotionView.backgroundColor; + colourPickerVC.supportsAlpha = NO; + [self presentViewController:colourPickerVC animated:YES completion:nil]; +} + + +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + self.wallpaper.alpha = 0; + UIColor *cpSelectedColour = viewController.selectedColor; + self.avatarMotionView.backgroundColor = cpSelectedColour; +} + + +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + self.wallpaper.alpha = 0; + UIColor *cpSelectedColour = viewController.selectedColor; + self.avatarMotionView.backgroundColor = cpSelectedColour; +} + + +-(void)presentStickersPickerVC { + + if (self.numberOfStickers == 5) { + [self showAlertWithTitle:@"Sorry!" subtitle:@"You can only use up to 5 stickers 🙁"]; + } else { + + TDStickerPickerViewController *vc = [[TDStickerPickerViewController alloc] init]; + vc.delegate = self; + [self presentViewController:vc animated:YES completion:nil]; + + } + +} + + +- (void)didDismissedStickersPicker { +} + + +- (void)didSelectSticker:(NSString *)sticker { + + NSInteger add = self.numberOfStickers+1; + self.numberOfStickers = add; + + StickerView *stickerView = [[StickerView alloc] initWithContentFrame:CGRectMake(0, 0, 150, 150) contentImage:[UIImage imageNamed:sticker]]; + stickerView.center = self.view.center; + stickerView.enabledControl = NO; + stickerView.enabledBorder = NO; + stickerView.delegate = self; + stickerView.tag = self.numberOfStickers; + [self.view addSubview:stickerView]; +} + + +- (void)stickerViewDidTapDeleteControl:(StickerView *)stickerView { + NSInteger sub = self.numberOfStickers-1; + self.numberOfStickers = sub; +} + + +- (void)stickerViewDidTapContentView:(StickerView *)stickerView { + + if (self.selectedSticker) { + self.selectedSticker.enabledBorder = NO; + self.selectedSticker.enabledControl = NO; + } + self.selectedSticker = stickerView; + self.selectedSticker.enabledBorder = YES; + self.selectedSticker.enabledControl = YES; +} + + +- (void)tapBackground:(UITapGestureRecognizer *)recognizer { + if (self.selectedSticker) { + self.selectedSticker.enabledControl = NO; + self.selectedSticker.enabledBorder = NO; + self.selectedSticker = nil; + } +} + + +- (UIImage *)stickerView:(StickerView *)stickerView imageForRightTopControl:(CGSize)recommendedSize { + return [UIImage imageNamed:@"btn_smile"]; +} + + +- (UIImage *)stickerView:(StickerView *)stickerView imageForLeftBottomControl:(CGSize)recommendedSize { + return [UIImage imageNamed:@"btn_flip"]; +} + + +- (void)stickerViewDidTapLeftBottomControl:(StickerView *)stickerView { + UIImageOrientation targetOrientation = (stickerView.contentImage.imageOrientation == UIImageOrientationUp ? UIImageOrientationUpMirrored : UIImageOrientationUp); + UIImage *invertImage = [UIImage imageWithCGImage:stickerView.contentImage.CGImage scale:1.0 orientation:targetOrientation]; + stickerView.contentImage = invertImage; +} + + +- (void)stickerViewDidTapRightTopControl:(StickerView *)stickerView { + [_animator removeAllBehaviors]; + UISnapBehavior * snapbehavior = [[UISnapBehavior alloc] initWithItem:stickerView snapToPoint:self.view.center]; + snapbehavior.damping = 0.65; + [self.animator addBehavior:snapbehavior]; +} + + +-(void)reset { + + self.wallpaper.alpha = 0; + [self.avatarMotionView resetTracking]; + self.avatarMotionView.backgroundColor = [UIColor colorNamed:@"Primary"]; + + for (UIView *subView in self.view.subviews) { + if ([subView isKindOfClass:[StickerView class]]) { + [subView removeFromSuperview]; + } + } + + self.numberOfStickers = 0; + +} + + +-(void)dismissVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + + +-(void)presentOnboarding { + RecordingOnboardingViewController *vc = [[RecordingOnboardingViewController alloc] init]; + vc.modalInPresentation = YES; + [self presentViewController:vc animated:YES completion:nil]; +} + + +//-(void)testMethod { +// +//// CGRect frames = CGRectMake(0, 0, 200, 200); +// +// CGRect frames = CGRectMake(0, 90, self.view.frame.size.width, self.view.frame.size.height-90); +// +// UIViewController *vc = [[UIViewController alloc] init]; +// +// vc.view.backgroundColor = UIColor.whiteColor; +// +// UIImageView *img = [[UIImageView alloc] initWithFrame:frames]; +// //img.image = [self getScreenShot:frames]; +// +// UIImage *image2 = [self.avatarMotionView snapshot]; +// img.image = image2; +// +// [vc.view addSubview:img]; +// +// [self presentViewController:vc animated:YES completion:nil]; +// +//} + + +//- (UIImage *)getScreenShot:(CGRect)captureFrame { +// //UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow]; +// CGRect rect = captureFrame; +// //UIGraphicsBeginImageContextWithOptions(rect.size, self.view.opaque, 0.0); +// //UIGraphicsBeginImageContext(rect.size); +// UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [UIScreen mainScreen].scale); +// CGContextRef context = UIGraphicsGetCurrentContext(); +// [self.view.layer renderInContext:context]; +// UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); +// UIGraphicsEndImageContext(); +// return img; +//} + +@end diff --git a/Avatar/App/Avatar/Settings/SettingsViewController.h b/Avatar/App/Avatar/Settings/SettingsViewController.h new file mode 100644 index 0000000..9a16d8f --- /dev/null +++ b/Avatar/App/Avatar/Settings/SettingsViewController.h @@ -0,0 +1,10 @@ +#import +#import "ConstraintExtension.h" +#import "TDHeaderView.h" +#import "SocialCell.h" +#import "SwitchCell.h" + +@interface SettingsViewController : UIViewController +@property (nonatomic, retain) TDHeaderView *headerView; +@property (nonatomic, retain) UITableView *tableView; +@end diff --git a/Avatar/App/Avatar/Settings/SettingsViewController.m b/Avatar/App/Avatar/Settings/SettingsViewController.m new file mode 100644 index 0000000..2b8061b --- /dev/null +++ b/Avatar/App/Avatar/Settings/SettingsViewController.m @@ -0,0 +1,194 @@ +#import "SettingsViewController.h" + + +@implementation SettingsViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Primary"]; + [self layoutHeaderView]; + [self layoutTableView]; +} + + +-(void)layoutHeaderView { + + self.headerView = [[TDHeaderView alloc] initWithTitle:@"Settings" accent:UIColor.systemBlueColor leftIcon:@"chevron.left" leftAction:@selector(dismissVC)]; + self.headerView.grabberView.alpha = 0; + self.headerView.leftButton.backgroundColor = [UIColor colorNamed:@"Secondary"]; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 55)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.safeAreaLayoutGuide.topAnchor padding:0]; +} + + +-(void)layoutTableView { + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleInsetGrouped]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + [self.tableView top:self.headerView.bottomAnchor padding:20]; + [self.tableView leading:self.view.leadingAnchor padding:0]; + [self.tableView trailing:self.view.trailingAnchor padding:0]; + [self.tableView bottom:self.view.bottomAnchor padding:0]; +} + + +-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 2; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + if (section == 0) { + return 1; + } else { + return 3; + } +} + + +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + return 35.0f; +} + + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { + + UIView *sectionHeaderView = [[UIView alloc] initWithFrame:CGRectMake(15, 0, tableView.frame.size.width -15, 45)]; + sectionHeaderView.backgroundColor = UIColor.clearColor; + sectionHeaderView.layer.cornerRadius = 15; + sectionHeaderView.clipsToBounds = true; + + UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, sectionHeaderView.frame.size.height /2 -9, 200, 18)]; + headerLabel.backgroundColor = [UIColor clearColor]; + headerLabel.textColor = UIColor.tertiaryLabelColor; + headerLabel.textAlignment = NSTextAlignmentLeft; + headerLabel.font = [UIFont boldSystemFontOfSize:16]; + [sectionHeaderView addSubview:headerLabel]; + + if (section == 0) { + headerLabel.text = @"General"; + } else { + headerLabel.text = @"Social"; + } + + return sectionHeaderView; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + if (indexPath.section == 0) { + + SwitchCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[SwitchCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + + cell.iconView.backgroundColor = [UIColor.systemIndigoColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [UIImage systemImageNamed:@"face.smiling.fill"]; + cell.iconImage.tintColor = UIColor.systemIndigoColor; + cell.titleLabel.text = @"Memoji"; + cell.subtitleLabel.text = @"Import existing Memoji"; + + + return cell; + + } else { + + SocialCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[SocialCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + + if (indexPath.row == 0) { + + cell.iconView.backgroundColor = [UIColor.systemTealColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [[UIImage imageNamed:@"twitter"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + cell.iconImage.tintColor = UIColor.systemTealColor; + cell.titleLabel.text = @"Twitter"; + cell.subtitleLabel.text = @"Follow us on Twitter"; + + } else if (indexPath.row == 1) { + + cell.iconView.backgroundColor = [UIColor.systemYellowColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [[UIImage imageNamed:@"discord"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + cell.iconImage.tintColor = UIColor.systemYellowColor; + cell.titleLabel.text = @"Discord"; + cell.subtitleLabel.text = @"Chat with us"; + + } else if (indexPath.row == 2) { + + cell.iconView.backgroundColor = [UIColor.systemOrangeColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [[UIImage imageNamed:@"paypal"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + cell.iconImage.tintColor = UIColor.systemOrangeColor; + cell.titleLabel.text = @"PayPal"; + cell.subtitleLabel.text = @"Any donation is greatly appreciated"; + + } + + return cell; + } + +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 75; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + + UIApplication *application = [UIApplication sharedApplication]; + + if (indexPath.section == 1) { + + if (indexPath.row == 0) { + NSURL *URL = [NSURL URLWithString:@"https://twitter.com/D3vTitan"]; + [application openURL:URL options:@{} completionHandler:nil]; + } else if (indexPath.row == 1) { + NSURL *URL = [NSURL URLWithString:@"https://discord.gg/Kk4KYpZ528"]; + [application openURL:URL options:@{} completionHandler:nil]; + } else if (indexPath.row == 2) { + NSURL *URL = [NSURL URLWithString:@"https://paypal.me/southerngirlwhocode"]; + [application openURL:URL options:@{} completionHandler:nil]; + } + + } +} + + +-(void)dismissVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + +@end diff --git a/Avatar/App/Avatar/Settings/SocialCell.h b/Avatar/App/Avatar/Settings/SocialCell.h new file mode 100644 index 0000000..9263615 --- /dev/null +++ b/Avatar/App/Avatar/Settings/SocialCell.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" + +@interface SocialCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@end + diff --git a/Avatar/App/Avatar/Settings/SocialCell.m b/Avatar/App/Avatar/Settings/SocialCell.m new file mode 100644 index 0000000..abbf4d6 --- /dev/null +++ b/Avatar/App/Avatar/Settings/SocialCell.m @@ -0,0 +1,77 @@ +#import "SocialCell.h" + +@implementation SocialCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor colorNamed:@"Secondary"]; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:5]; + [self.baseView leading:self.leadingAnchor padding:5]; + [self.baseView trailing:self.trailingAnchor padding:-5]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 10; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + self.iconView.clipsToBounds = YES; + [self.baseView addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(40, 40)]; + [self.iconView y:self.baseView.centerYAnchor]; + [self.iconView leading:self.baseView.leadingAnchor padding:10]; + + + self.iconImage = [[UIImageView alloc] init]; + [self.iconView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(30, 30)]; + [self.iconImage x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.textColor = UIColor.labelColor; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.titleLabel top:self.iconView.topAnchor padding:2]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.subtitleLabel = [[UILabel alloc] init]; + self.subtitleLabel.textAlignment = NSTextAlignmentLeft; + self.subtitleLabel.font = [UIFont systemFontOfSize:13]; + self.subtitleLabel.textColor = UIColor.tertiaryLabelColor; + [self.baseView addSubview:self.subtitleLabel]; + + [self.subtitleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.subtitleLabel bottom:self.iconView.bottomAnchor padding:-2]; + [self.subtitleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + } + + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + + self.iconImage.image = nil; + self.titleLabel.text = nil; + self.subtitleLabel.text = nil; +} + +@end diff --git a/Avatar/App/Avatar/Settings/SwitchCell.h b/Avatar/App/Avatar/Settings/SwitchCell.h new file mode 100644 index 0000000..3d70f4b --- /dev/null +++ b/Avatar/App/Avatar/Settings/SwitchCell.h @@ -0,0 +1,13 @@ +#import +#import "ConstraintExtension.h" +#import "SettingManager.h" + +@interface SwitchCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UISwitch *toggleSwitch; +@end + diff --git a/Avatar/App/Avatar/Settings/SwitchCell.m b/Avatar/App/Avatar/Settings/SwitchCell.m new file mode 100644 index 0000000..afa559c --- /dev/null +++ b/Avatar/App/Avatar/Settings/SwitchCell.m @@ -0,0 +1,98 @@ +#import "SwitchCell.h" + +@implementation SwitchCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + BOOL useDefaultMemoji = [[SettingManager sharedInstance] boolForKey:@"useDefaultMemoji" defaultValue:NO]; + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor colorNamed:@"Secondary"]; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:5]; + [self.baseView leading:self.leadingAnchor padding:5]; + [self.baseView trailing:self.trailingAnchor padding:-5]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 10; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + self.iconView.clipsToBounds = YES; + [self.baseView addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(40, 40)]; + [self.iconView y:self.baseView.centerYAnchor]; + [self.iconView leading:self.baseView.leadingAnchor padding:10]; + + + self.iconImage = [[UIImageView alloc] init]; + [self.iconView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(30, 30)]; + [self.iconImage x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.toggleSwitch = [[UISwitch alloc] init]; + [self.toggleSwitch addTarget:self action:@selector(switchChangedState:) forControlEvents:UIControlEventValueChanged]; + [self.toggleSwitch setOn:useDefaultMemoji animated:NO]; + self.toggleSwitch.onTintColor = UIColor.systemIndigoColor; + self.toggleSwitch.thumbTintColor = [UIColor colorNamed:@"Secondary"]; + [self.contentView addSubview:self.toggleSwitch]; + + [self.toggleSwitch y:self.baseView.centerYAnchor]; + [self.toggleSwitch trailing:self.baseView.trailingAnchor padding:-10]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.textColor = UIColor.labelColor; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.titleLabel top:self.iconView.topAnchor padding:2]; + [self.titleLabel trailing:self.toggleSwitch.leadingAnchor padding:-10]; + + + self.subtitleLabel = [[UILabel alloc] init]; + self.subtitleLabel.textAlignment = NSTextAlignmentLeft; + self.subtitleLabel.font = [UIFont systemFontOfSize:13]; + self.subtitleLabel.textColor = UIColor.tertiaryLabelColor; + [self.baseView addSubview:self.subtitleLabel]; + + [self.subtitleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.subtitleLabel bottom:self.iconView.bottomAnchor padding:-2]; + [self.subtitleLabel trailing:self.toggleSwitch.leadingAnchor padding:-10]; + + } + + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + + self.iconImage.image = nil; + self.titleLabel.text = nil; + self.subtitleLabel.text = nil; +} + + +- (void)switchChangedState:(UISwitch *)sender { + [[SettingManager sharedInstance] setBool:sender.on forKey:@"useDefaultMemoji"]; +// if ([sender isOn]) { +// } else { +// } +} + +@end diff --git a/Avatar/App/Avatar/StickerPicker/SingleHandGestureRecognizer.h b/Avatar/App/Avatar/StickerPicker/SingleHandGestureRecognizer.h new file mode 100644 index 0000000..00da453 --- /dev/null +++ b/Avatar/App/Avatar/StickerPicker/SingleHandGestureRecognizer.h @@ -0,0 +1,8 @@ +#import + +@interface SingleHandGestureRecognizer : UIGestureRecognizer +@property (assign, nonatomic) CGFloat scale; +@property (assign, nonatomic) CGFloat rotation; +- (nonnull instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action anchorView:(nonnull UIView *)anchorView; +- (void)reset; +@end diff --git a/Avatar/App/Avatar/StickerPicker/SingleHandGestureRecognizer.m b/Avatar/App/Avatar/StickerPicker/SingleHandGestureRecognizer.m new file mode 100644 index 0000000..9468d19 --- /dev/null +++ b/Avatar/App/Avatar/StickerPicker/SingleHandGestureRecognizer.m @@ -0,0 +1,69 @@ +#import "SingleHandGestureRecognizer.h" +#import + +@interface SingleHandGestureRecognizer () +@property (strong, nonatomic) UIView *anchorView; +@end + +@implementation SingleHandGestureRecognizer + +- (nonnull instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action anchorView:(nonnull UIView *)anchorView { + SingleHandGestureRecognizer *gesture = [[SingleHandGestureRecognizer alloc] initWithTarget:target action:action]; + gesture.anchorView = anchorView; + return gesture; +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + // Only support single hand. + if ([[event touchesForGestureRecognizer:self] count] > 1) { + self.state = UIGestureRecognizerStateFailed; + } +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + if (self.state == UIGestureRecognizerStatePossible) { + self.state = UIGestureRecognizerStateBegan; + } else { + self.state = UIGestureRecognizerStateChanged; + } + + UITouch *touch = [touches anyObject]; + CGPoint anchorViewCenter = self.anchorView.center; + CGPoint currentPoint = [touch locationInView:self.anchorView.superview]; + CGPoint previousPoint = [touch previousLocationInView:self.anchorView.superview]; + + CGFloat currentRotation = atan2f((currentPoint.y - anchorViewCenter.y), (currentPoint.x - anchorViewCenter.x)); + CGFloat previousRotation = atan2f((previousPoint.y - anchorViewCenter.y), (previousPoint.x - anchorViewCenter.x)); + + CGFloat currentRadius = [self distanceBetweenFirstPoint:currentPoint secondPoint:anchorViewCenter]; + CGFloat previousRadius = [self distanceBetweenFirstPoint:previousPoint secondPoint:anchorViewCenter]; + CGFloat scale = currentRadius / previousRadius; + + [self setRotation:(currentRotation - previousRotation)]; + [self setScale:scale]; +} + +- (CGFloat)distanceBetweenFirstPoint:(CGPoint)first secondPoint:(CGPoint)second { + CGFloat deltaX = second.x - first.x; + CGFloat deltaY = second.y - first.y; + return sqrt(deltaX * deltaX + deltaY * deltaY); +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + if (self.state == UIGestureRecognizerStateChanged) { + self.state = UIGestureRecognizerStateEnded; + } else { + self.state = UIGestureRecognizerStateFailed; + } +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + self.state = UIGestureRecognizerStateFailed; +} + +- (void)reset { + self.rotation = 0; + self.scale = 1; +} + +@end diff --git a/Avatar/App/Avatar/StickerPicker/StickerView.h b/Avatar/App/Avatar/StickerPicker/StickerView.h new file mode 100644 index 0000000..1b8bfb7 --- /dev/null +++ b/Avatar/App/Avatar/StickerPicker/StickerView.h @@ -0,0 +1,25 @@ +#import + +@protocol StickerViewDelegate; + +@interface StickerView : UIView +@property (assign, nonatomic) BOOL enabledControl; +@property (assign, nonatomic) BOOL enabledDeleteControl; +@property (assign, nonatomic) BOOL enabledShakeAnimation; +@property (assign, nonatomic) BOOL enabledBorder; +@property (strong, nonatomic) UIImage *contentImage; +@property (assign, nonatomic) id delegate; +- (instancetype)initWithContentFrame:(CGRect)frame contentImage:(UIImage *)contentImage; +- (void)performTapOperation; +@end + + +@protocol StickerViewDelegate +@optional +- (void)stickerViewDidTapContentView:(StickerView *)stickerView; +- (void)stickerViewDidTapDeleteControl:(StickerView *)stickerView; +- (UIImage *)stickerView:(StickerView *)stickerView imageForRightTopControl:(CGSize)recommendedSize; +- (void)stickerViewDidTapRightTopControl:(StickerView *)stickerView; +- (UIImage *)stickerView:(StickerView *)stickerView imageForLeftBottomControl:(CGSize)recommendedSize; +- (void)stickerViewDidTapLeftBottomControl:(StickerView *)stickerView; +@end diff --git a/Avatar/App/Avatar/StickerPicker/StickerView.m b/Avatar/App/Avatar/StickerPicker/StickerView.m new file mode 100644 index 0000000..4408f6c --- /dev/null +++ b/Avatar/App/Avatar/StickerPicker/StickerView.m @@ -0,0 +1,353 @@ +#import "StickerView.h" +#import "SingleHandGestureRecognizer.h" + +#define kStickerControlViewSize 30 +#define kStickerHalfControlViewSize 15 +#define kStickerMinScale 0.5f +#define kStickerMaxScale 2.0f + + +@interface StickerView () +@property (strong, nonatomic) UIImageView *contentView; +@property (strong, nonatomic) UIImageView *deleteControl; +@property (strong, nonatomic) UIImageView *resizeControl; +@property (strong, nonatomic) UIImageView *rightTopControl; +@property (strong, nonatomic) UIImageView *leftBottomControl; +@property (strong, nonatomic) CAShapeLayer *shapeLayer; +@property (assign, nonatomic) BOOL enableRightTopControl; +@property (assign, nonatomic) BOOL enableLeftBottomControl; +@end + + +@implementation StickerView + + +- (instancetype)initWithContentFrame:(CGRect)frame contentImage:(UIImage *)contentImage { + self = [super initWithFrame:CGRectMake(frame.origin.x - kStickerHalfControlViewSize, frame.origin.y - kStickerHalfControlViewSize, frame.size.width + kStickerControlViewSize, frame.size.height + kStickerControlViewSize)]; + if (self) { + self.contentView = [[UIImageView alloc] initWithFrame:CGRectMake(kStickerHalfControlViewSize, kStickerHalfControlViewSize, frame.size.width, frame.size.height)]; + self.contentImage = contentImage; + [self addSubview:self.contentView]; + + self.resizeControl = [[UIImageView alloc] initWithFrame:CGRectMake(self.contentView.center.x + self.contentView.bounds.size.width / 2 - kStickerHalfControlViewSize, self.contentView.center.y + self.contentView.bounds.size.height / 2 - kStickerHalfControlViewSize, kStickerControlViewSize, kStickerControlViewSize)]; + self.resizeControl.image = [UIImage imageNamed:@"btn_resize"]; + [self addSubview:self.resizeControl]; + + self.deleteControl = [[UIImageView alloc] initWithFrame:CGRectMake(self.contentView.center.x - self.contentView.bounds.size.width / 2 - kStickerHalfControlViewSize, self.contentView.center.y - self.contentView.bounds.size.height / 2 - kStickerHalfControlViewSize, kStickerControlViewSize, kStickerControlViewSize)]; + self.deleteControl.image = [UIImage imageNamed:@"btn_delete"]; + [self addSubview:self.deleteControl]; + + self.rightTopControl = [[UIImageView alloc] initWithFrame:CGRectMake(self.contentView.center.x + self.contentView.bounds.size.width / 2 - kStickerHalfControlViewSize, self.contentView.center.y - self.contentView.bounds.size.height / 2 - kStickerHalfControlViewSize, kStickerControlViewSize, kStickerControlViewSize)]; + [self addSubview:self.rightTopControl]; + + self.leftBottomControl = [[UIImageView alloc] initWithFrame:CGRectMake(self.contentView.center.x - self.contentView.bounds.size.width / 2 - kStickerHalfControlViewSize, self.contentView.center.y + self.contentView.bounds.size.height / 2 - kStickerHalfControlViewSize, kStickerControlViewSize, kStickerControlViewSize)]; + [self addSubview:self.leftBottomControl]; + + [self initShapeLayer]; + [self setupConfig]; + [self attachGestures]; + } + return self; +} + + +- (void)initShapeLayer { + _shapeLayer = [CAShapeLayer layer]; + CGRect shapeRect = self.contentView.frame; + [_shapeLayer setBounds:shapeRect]; + [_shapeLayer setPosition:CGPointMake(self.contentView.frame.size.width / 2, self.contentView.frame.size.height / 2)]; + [_shapeLayer setFillColor:[[UIColor clearColor] CGColor]]; + [_shapeLayer setStrokeColor:[[UIColor systemBlueColor] CGColor]]; + [_shapeLayer setLineWidth:2.0f]; + [_shapeLayer setLineJoin:kCALineJoinRound]; + _shapeLayer.allowsEdgeAntialiasing = YES; + [_shapeLayer setLineDashPattern:[NSArray arrayWithObjects:[NSNumber numberWithInt:5], [NSNumber numberWithInt:3], nil]]; + + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddRect(path, NULL, shapeRect); + [_shapeLayer setPath:path]; + CGPathRelease(path); +} + + +- (void)setupConfig { + self.exclusiveTouch = YES; + + self.userInteractionEnabled = YES; + self.contentView.userInteractionEnabled = YES; + self.resizeControl.userInteractionEnabled = YES; + self.deleteControl.userInteractionEnabled = YES; + self.rightTopControl.userInteractionEnabled = YES; + self.leftBottomControl.userInteractionEnabled = YES; + + _enableRightTopControl = NO; + _enableLeftBottomControl = NO; + + _enabledShakeAnimation = YES; + self.enabledBorder = YES; + + self.enabledDeleteControl = YES; + self.enabledControl = YES; +} + + +- (void)attachGestures { + + UIRotationGestureRecognizer *rotateGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotate:)]; + [rotateGesture setDelegate:self]; + [self.contentView addGestureRecognizer:rotateGesture]; + + UIPinchGestureRecognizer *pinGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleScale:)]; + [pinGesture setDelegate:self]; + [self.contentView addGestureRecognizer:pinGesture]; + + UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMove:)]; + [panGesture setMinimumNumberOfTouches:1]; + [panGesture setMaximumNumberOfTouches:2]; + [panGesture setDelegate:self]; + [self.contentView addGestureRecognizer:panGesture]; + + UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; + [tapRecognizer setNumberOfTapsRequired:1]; + [tapRecognizer setDelegate:self]; + [self.contentView addGestureRecognizer:tapRecognizer]; + + + SingleHandGestureRecognizer *singleHandGesture = [[SingleHandGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleHandAction:) anchorView:self.contentView]; + [self.resizeControl addGestureRecognizer:singleHandGesture]; + + + UITapGestureRecognizer *tapRecognizer2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; + [tapRecognizer2 setNumberOfTapsRequired:1]; + [tapRecognizer2 setDelegate:self]; + [self.deleteControl addGestureRecognizer:tapRecognizer2]; + + + UITapGestureRecognizer *tapRecognizer3 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; + [tapRecognizer3 setNumberOfTapsRequired:1]; + [tapRecognizer3 setDelegate:self]; + [self.rightTopControl addGestureRecognizer:tapRecognizer3]; + + + UITapGestureRecognizer *tapRecognizer4 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; + [tapRecognizer4 setNumberOfTapsRequired:1]; + [tapRecognizer4 setDelegate:self]; + [self.leftBottomControl addGestureRecognizer:tapRecognizer4]; +} + + +- (void)handleTap:(UITapGestureRecognizer *)gesture { + if (gesture.view == self.contentView) { + [self handleTapContentView]; + } else if (gesture.view == self.deleteControl) { + if (_enabledDeleteControl) { + // Default : remove from super view. + [self removeFromSuperview]; + if (_delegate && [_delegate respondsToSelector:@selector(stickerViewDidTapDeleteControl:)]) { + [_delegate stickerViewDidTapDeleteControl:self]; + } + } + } else if (gesture.view == self.rightTopControl) { + if (_enableRightTopControl) { + if (_delegate && [_delegate respondsToSelector:@selector(stickerViewDidTapRightTopControl:)]) { + [_delegate stickerViewDidTapRightTopControl:self]; + } + } + } else if (gesture.view == self.leftBottomControl) { + if (_enableLeftBottomControl) { + if (_delegate && [_delegate respondsToSelector:@selector(stickerViewDidTapLeftBottomControl:)]) { + [_delegate stickerViewDidTapLeftBottomControl:self]; + } + } + } +} + + +- (void)handleTapContentView { + [self.superview bringSubviewToFront:self]; + if (_enabledShakeAnimation) { + [self performShakeAnimation:self]; + } + if (_delegate && [_delegate respondsToSelector:@selector(stickerViewDidTapContentView:)]) { + [_delegate stickerViewDidTapContentView:self]; + } +} + + +- (void)handleMove:(UIPanGestureRecognizer *)gesture { + CGPoint translation = [gesture translationInView:[self superview]]; + CGPoint targetPoint = CGPointMake(self.center.x + translation.x, self.center.y + translation.y); + targetPoint.x = MAX(0, targetPoint.x); + targetPoint.y = MAX(0, targetPoint.y); + targetPoint.x = MIN(self.superview.bounds.size.width, targetPoint.x); + targetPoint.y = MIN(self.superview.bounds.size.height, targetPoint.y); + + [self setCenter:targetPoint]; + [gesture setTranslation:CGPointZero inView:[self superview]]; +} + + +- (void)handleScale:(UIPinchGestureRecognizer *)gesture { + CGFloat scale = gesture.scale; + CGFloat currentScale = [[self.contentView.layer valueForKeyPath:@"transform.scale"] floatValue]; + if (scale * currentScale <= kStickerMinScale) { + scale = kStickerMinScale / currentScale; + } else if (scale * currentScale >= kStickerMaxScale) { + scale = kStickerMaxScale / currentScale; + } + + self.contentView.transform = CGAffineTransformScale(self.contentView.transform, scale, scale); + gesture.scale = 1; + + [self relocalControlView]; +} + + +- (void)handleRotate:(UIRotationGestureRecognizer *)gesture { + self.contentView.transform = CGAffineTransformRotate(self.contentView.transform, gesture.rotation); + gesture.rotation = 0; + + [self relocalControlView]; +} + + +- (void)handleSingleHandAction:(SingleHandGestureRecognizer *)gesture { + CGFloat scale = gesture.scale; + + CGFloat currentScale = [[self.contentView.layer valueForKeyPath:@"transform.scale"] floatValue]; + if (scale * currentScale <= kStickerMinScale) { + scale = kStickerMinScale / currentScale; + } else if (scale * currentScale >= kStickerMaxScale) { + scale = kStickerMaxScale / currentScale; + } + + self.contentView.transform = CGAffineTransformScale(self.contentView.transform, scale, scale); + self.contentView.transform = CGAffineTransformRotate(self.contentView.transform, gesture.rotation); + [gesture reset]; + + [self relocalControlView]; +} + + +- (void)relocalControlView { + CGPoint originalCenter = CGPointApplyAffineTransform(self.contentView.center, CGAffineTransformInvert(self.contentView.transform)); + self.resizeControl.center = CGPointApplyAffineTransform(CGPointMake(originalCenter.x + self.contentView.bounds.size.width / 2.0f, originalCenter.y + self.contentView.bounds.size.height / 2.0f), self.contentView.transform); + self.deleteControl.center = CGPointApplyAffineTransform(CGPointMake(originalCenter.x - self.contentView.bounds.size.width / 2.0f, originalCenter.y - self.contentView.bounds.size.height / 2.0f), self.contentView.transform); + self.rightTopControl.center = CGPointApplyAffineTransform(CGPointMake(originalCenter.x + self.contentView.bounds.size.width / 2.0f, originalCenter.y - self.contentView.bounds.size.height / 2.0f), self.contentView.transform); + self.leftBottomControl.center = CGPointApplyAffineTransform(CGPointMake(originalCenter.x - self.contentView.bounds.size.width / 2.0f, originalCenter.y + self.contentView.bounds.size.height / 2.0f), self.contentView.transform); +} + + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { + if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) { + return NO; + } else { + return YES; + } +} + + +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { + if (self.hidden || !self.userInteractionEnabled || self.alpha < 0.01) { + return nil; + } + if (_enabledControl) { + if ([self.resizeControl pointInside:[self convertPoint:point toView:self.resizeControl] withEvent:event]) { + return self.resizeControl; + } + if (_enabledDeleteControl && [self.deleteControl pointInside:[self convertPoint:point toView:self.deleteControl] withEvent:event]) { + return self.deleteControl; + } + if (_enableRightTopControl && [self.rightTopControl pointInside:[self convertPoint:point toView:self.rightTopControl] withEvent:event]) { + return self.rightTopControl; + } + if (_enableLeftBottomControl && [self.leftBottomControl pointInside:[self convertPoint:point toView:self.leftBottomControl] withEvent:event]) { + return self.leftBottomControl; + } + } + if ([self.contentView pointInside:[self convertPoint:point toView:self.contentView] withEvent:event]) { + return self.contentView; + } + + return nil; +} + + +- (void)performShakeAnimation:(UIView *)targetView { + [targetView.layer removeAnimationForKey:@"anim"]; + CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + animation.duration = 0.5f; + animation.values = @[[NSValue valueWithCATransform3D:targetView.layer.transform], + [NSValue valueWithCATransform3D:CATransform3DScale(targetView.layer.transform, 1.05, 1.05, 1.0)], + [NSValue valueWithCATransform3D:CATransform3DScale(targetView.layer.transform, 0.95, 0.95, 1.0)], + [NSValue valueWithCATransform3D:targetView.layer.transform] + ]; + animation.removedOnCompletion = YES; + [targetView.layer addAnimation:animation forKey:@"anim"]; +} + + +- (void)performTapOperation { + [self handleTapContentView]; +} + + +- (void)setDelegate:(id)delegate { + if (delegate == nil) { + NSAssert(delegate, @"Delegate shounldn't be nil!"); + return; + } + _delegate = delegate; + + if ([_delegate respondsToSelector:@selector(stickerView:imageForRightTopControl:)]) { + UIImage *rightTopImage = [_delegate stickerView:self imageForRightTopControl:CGSizeMake(kStickerControlViewSize, kStickerControlViewSize)]; + if (rightTopImage) { + self.rightTopControl.image = rightTopImage; + _enableRightTopControl = YES; + } + } + if ([_delegate respondsToSelector:@selector(stickerView:imageForLeftBottomControl:)]) { + UIImage *leftBottomImage = [_delegate stickerView:self imageForLeftBottomControl:CGSizeMake(kStickerControlViewSize, kStickerControlViewSize)]; + if (leftBottomImage) { + self.leftBottomControl.image = leftBottomImage; + _enableLeftBottomControl = YES; + } + } +} + + +- (void)setEnabledDeleteControl:(BOOL)enabledDeleteControl { + _enabledDeleteControl = enabledDeleteControl; + if (_enabledControl && _enabledDeleteControl) { + self.deleteControl.hidden = NO; + } else { + self.deleteControl.hidden = YES; + } +} + + +- (void)setEnabledControl:(BOOL)enabledControl { + _enabledControl = enabledControl; + self.deleteControl.hidden = _enabledControl ? !_enabledDeleteControl : YES; + self.resizeControl.hidden = !_enabledControl; + self.rightTopControl.hidden = !_enabledControl; + self.leftBottomControl.hidden = !_enabledControl; +} + + +- (void)setEnabledBorder:(BOOL)enabledBorder { + _enabledBorder = enabledBorder; + if (_enabledBorder) { + [self.contentView.layer addSublayer:self.shapeLayer]; + } else { + [self.shapeLayer removeFromSuperlayer]; + } +} + + +- (void)setContentImage:(UIImage *)contentImage { + _contentImage = contentImage; + self.contentView.image = _contentImage; +} + +@end diff --git a/Avatar/App/Avatar/StickerPicker/TDStickerPickerCell.h b/Avatar/App/Avatar/StickerPicker/TDStickerPickerCell.h new file mode 100644 index 0000000..895d0b9 --- /dev/null +++ b/Avatar/App/Avatar/StickerPicker/TDStickerPickerCell.h @@ -0,0 +1,7 @@ +#import +#import "ConstraintExtension.h" + +@interface TDStickerPickerCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@end diff --git a/Avatar/App/Avatar/StickerPicker/TDStickerPickerCell.m b/Avatar/App/Avatar/StickerPicker/TDStickerPickerCell.m new file mode 100644 index 0000000..c44ce04 --- /dev/null +++ b/Avatar/App/Avatar/StickerPicker/TDStickerPickerCell.m @@ -0,0 +1,32 @@ +#import "TDStickerPickerCell.h" + +@implementation TDStickerPickerCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + + self.baseView = [[UIView alloc] initWithFrame:self.contentView.bounds]; + [self.contentView addSubview:self.baseView]; + + + self.iconImage = [[UIImageView alloc] init]; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(self.frame.size.width, self.frame.size.width)]; + [self.iconImage x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.iconImage.image = nil; +} + + +@end diff --git a/Avatar/App/Avatar/StickerPicker/TDStickerPickerCellHeaderView.h b/Avatar/App/Avatar/StickerPicker/TDStickerPickerCellHeaderView.h new file mode 100644 index 0000000..161cae1 --- /dev/null +++ b/Avatar/App/Avatar/StickerPicker/TDStickerPickerCellHeaderView.h @@ -0,0 +1,8 @@ +#import + +@interface TDStickerPickerCellHeaderView : UICollectionReusableView +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *headerLabel; +@end + + diff --git a/Avatar/App/Avatar/StickerPicker/TDStickerPickerCellHeaderView.m b/Avatar/App/Avatar/StickerPicker/TDStickerPickerCellHeaderView.m new file mode 100644 index 0000000..48174e0 --- /dev/null +++ b/Avatar/App/Avatar/StickerPicker/TDStickerPickerCellHeaderView.m @@ -0,0 +1,28 @@ +#import "TDStickerPickerCellHeaderView.h" + +@implementation TDStickerPickerCellHeaderView + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] initWithFrame:self.bounds]; + self.baseView.clipsToBounds = YES; + [self addSubview:self.baseView]; + + + self.headerLabel = [[UILabel alloc] init]; + self.headerLabel.textColor = UIColor.tertiaryLabelColor; + self.headerLabel.font = [UIFont boldSystemFontOfSize:18]; + [self.baseView addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = YES; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:20].active = YES; + + } + return self; +} + +@end diff --git a/Avatar/App/Avatar/StickerPicker/TDStickerPickerViewController.h b/Avatar/App/Avatar/StickerPicker/TDStickerPickerViewController.h new file mode 100644 index 0000000..99fdef3 --- /dev/null +++ b/Avatar/App/Avatar/StickerPicker/TDStickerPickerViewController.h @@ -0,0 +1,21 @@ +#import +#import "ConstraintExtension.h" +#import "TDStickerPickerCell.h" +#import "TDStickerPickerCellHeaderView.h" +#import "PrivateBlurEffect.h" + +@protocol TDStickersPickerProtocol +@required +-(void)didSelectSticker:(NSString *)sticker; +-(void)didDismissedStickersPicker; +@end + +@interface TDStickerPickerViewController : UIViewController +@property (nonatomic, strong) _UIBackdropViewSettings *blurSetting; +@property (nonatomic, strong) _UIBackdropView *blurView; +@property (nonatomic, retain) UIVisualEffectView *grabberView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *stickerArray; +@property(nonatomic,assign)id delegate; +@property (nonatomic) BOOL didSelectSticker; +@end diff --git a/Avatar/App/Avatar/StickerPicker/TDStickerPickerViewController.m b/Avatar/App/Avatar/StickerPicker/TDStickerPickerViewController.m new file mode 100644 index 0000000..543ab95 --- /dev/null +++ b/Avatar/App/Avatar/StickerPicker/TDStickerPickerViewController.m @@ -0,0 +1,135 @@ +#import "TDStickerPickerViewController.h" + +@implementation TDStickerPickerViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.clearColor; + + self.blurSetting = [_UIBackdropViewSettings settingsForStyle:2]; + self.blurView = [[_UIBackdropView alloc] initWithSettings:self.blurSetting]; + self.blurView.frame = self.view.bounds; + [self.view insertSubview:self.blurView atIndex:0]; + + + NSString *myFile = [[NSBundle mainBundle]pathForResource:@"Stickers" ofType:@"plist"]; + self.stickerArray = [[NSMutableArray alloc] initWithContentsOfFile:myFile]; + + [self layoutGrabberView]; + [self layoutCollectionView]; +} + + +-(void)layoutGrabberView { + + self.grabberView = [[UIVisualEffectView alloc] init]; + self.grabberView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemMaterial]; + self.grabberView.layer.cornerRadius = 3; + self.grabberView.clipsToBounds = YES; + [self.view addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.view.centerXAnchor]; + [self.grabberView top:self.view.topAnchor padding:10]; +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[TDStickerPickerCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.collectionView registerClass:[TDStickerPickerCellHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; + [self.view addSubview:self.collectionView]; + + [self.collectionView top:self.grabberView.bottomAnchor padding:20]; + [self.collectionView bottom:self.view.bottomAnchor padding:-20]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView { + return self.stickerArray.count; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { + return CGSizeMake(self.view.frame.size.width, 45); +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return [[[self.stickerArray objectAtIndex: section] objectForKey:@"Stickers"] count]; +} + + +-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + UICollectionReusableView *reusableview = nil; + + if (kind == UICollectionElementKindSectionHeader) { + + TDStickerPickerCellHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; + headerView.headerLabel.text = [[self.stickerArray objectAtIndex:indexPath.section] objectForKey: @"Title"]; + reusableview = headerView; + } + + return reusableview; + +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + TDStickerPickerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + NSString *imageString = [[[self.stickerArray objectAtIndex: indexPath.section] objectForKey: @"Stickers"] objectAtIndex: indexPath.row]; + cell.iconImage.image = [UIImage imageNamed:imageString]; + return cell; + +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ + return CGSizeMake(self.view.frame.size.width/4-20, self.view.frame.size.width/4-20); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + self.didSelectSticker = YES; + [self.delegate didSelectSticker:[[[self.stickerArray objectAtIndex: indexPath.section] objectForKey: @"Stickers"] objectAtIndex: indexPath.row]]; + [self dismissVC]; +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + + if (!self.didSelectSticker) { + [self.delegate didDismissedStickersPicker]; + } +} + +@end diff --git a/Avatar/App/Avatar/Swift/Avatar-Bridging-Header.h b/Avatar/App/Avatar/Swift/Avatar-Bridging-Header.h new file mode 100644 index 0000000..1b2cb5d --- /dev/null +++ b/Avatar/App/Avatar/Swift/Avatar-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + diff --git a/Avatar/App/Avatar/Swift/Constraints.swift b/Avatar/App/Avatar/Swift/Constraints.swift new file mode 100644 index 0000000..1a16d1e --- /dev/null +++ b/Avatar/App/Avatar/Swift/Constraints.swift @@ -0,0 +1,158 @@ +import Foundation +import UIKit + +extension UIView { + + public func top(_ top: NSLayoutAnchor?, padding size: CGFloat) { + translatesAutoresizingMaskIntoConstraints = false + if let top = top { + topAnchor.constraint(equalTo: top, constant: size).isActive = true + } + } + + + public func top(_ top: NSLayoutAnchor?) { + translatesAutoresizingMaskIntoConstraints = false + if let top = top { + topAnchor.constraint(equalTo: top).isActive = true + } + } + + + public func leading(_ leading: NSLayoutAnchor?, padding size: CGFloat) { + translatesAutoresizingMaskIntoConstraints = false + if let leading = leading { + leadingAnchor.constraint(equalTo: leading, constant: size).isActive = true + } + } + + + public func leading(_ leading: NSLayoutAnchor?) { + translatesAutoresizingMaskIntoConstraints = false + if let leading = leading { + leadingAnchor.constraint(equalTo: leading).isActive = true + } + } + + + public func trailing(_ trailing: NSLayoutAnchor?, padding size: CGFloat) { + translatesAutoresizingMaskIntoConstraints = false + if let trailing = trailing { + trailingAnchor.constraint(equalTo: trailing, constant: size).isActive = true + } + } + + + public func trailing(_ trailing: NSLayoutAnchor?) { + translatesAutoresizingMaskIntoConstraints = false + if let trailing = trailing { + trailingAnchor.constraint(equalTo: trailing).isActive = true + } + } + + + public func bottom(_ bottom: NSLayoutAnchor?, padding size: CGFloat) { + translatesAutoresizingMaskIntoConstraints = false + if let bottom = bottom { + bottomAnchor.constraint(equalTo: bottom, constant: size).isActive = true + } + } + + + public func bottom(_ bottom: NSLayoutAnchor?) { + translatesAutoresizingMaskIntoConstraints = false + if let bottom = bottom { + bottomAnchor.constraint(equalTo: bottom).isActive = true + } + } + + + public func size(_ size: CGSize) { + + translatesAutoresizingMaskIntoConstraints = false + + if size.width != 0 { + widthAnchor.constraint(equalToConstant: size.width).isActive = true + } + + if size.height != 0 { + heightAnchor.constraint(equalToConstant: size.height).isActive = true + } + + } + + + public func width(_ size: CGFloat) { + translatesAutoresizingMaskIntoConstraints = false + widthAnchor.constraint(equalToConstant: size).isActive = true + } + + + public func height(_ size: CGFloat) { + translatesAutoresizingMaskIntoConstraints = false + heightAnchor.constraint(equalToConstant: size).isActive = true + } + + + public func x(_ centerX: NSLayoutAnchor?, y centerY: NSLayoutAnchor?) { + translatesAutoresizingMaskIntoConstraints = false + centerXAnchor.constraint(equalTo: centerX!).isActive = true + centerYAnchor.constraint(equalTo: centerY!).isActive = true + } + + + public func x(_ centerX: NSLayoutAnchor?) { + translatesAutoresizingMaskIntoConstraints = false + centerXAnchor.constraint(equalTo: centerX!).isActive = true + } + + + public func y(_ centerY: NSLayoutAnchor?) { + translatesAutoresizingMaskIntoConstraints = false + centerYAnchor.constraint(equalTo: centerY!).isActive = true + } + + + public func x(_ centerX: NSLayoutAnchor?, padding size: CGFloat) { + translatesAutoresizingMaskIntoConstraints = false + centerXAnchor.constraint(equalTo: centerX!, constant: size).isActive = true + } + + + public func y(_ centerY: NSLayoutAnchor?, padding size: CGFloat) { + translatesAutoresizingMaskIntoConstraints = false + centerYAnchor.constraint(equalTo: centerY!, constant: size).isActive = true + } + + + public func fill() { + + translatesAutoresizingMaskIntoConstraints = false + topAnchor.constraint(equalTo: self.superview!.topAnchor).isActive = true + leadingAnchor.constraint(equalTo: self.superview!.leadingAnchor).isActive = true + trailingAnchor.constraint(equalTo: self.superview!.trailingAnchor).isActive = true + bottomAnchor.constraint(equalTo: self.superview!.bottomAnchor).isActive = true + } + + + public func fill(padding: CGFloat) { + + translatesAutoresizingMaskIntoConstraints = false + topAnchor.constraint(equalTo: self.superview!.topAnchor, constant: padding).isActive = true + leadingAnchor.constraint(equalTo: self.superview!.leadingAnchor, constant: padding).isActive = true + trailingAnchor.constraint(equalTo: self.superview!.trailingAnchor, constant: -padding).isActive = true + bottomAnchor.constraint(equalTo: self.superview!.bottomAnchor, constant: -padding).isActive = true + } + + + public func fill(top: CGFloat, left: CGFloat, right: CGFloat, bottom: CGFloat) { + + translatesAutoresizingMaskIntoConstraints = false + topAnchor.constraint(equalTo: self.superview!.topAnchor, constant: top).isActive = true + leadingAnchor.constraint(equalTo: self.superview!.leadingAnchor, constant: left).isActive = true + trailingAnchor.constraint(equalTo: self.superview!.trailingAnchor, constant: right).isActive = true + bottomAnchor.constraint(equalTo: self.superview!.bottomAnchor, constant: bottom).isActive = true + } + + +} diff --git a/Avatar/App/Avatar/Swift/TutorialViewController.swift b/Avatar/App/Avatar/Swift/TutorialViewController.swift new file mode 100644 index 0000000..77ece53 --- /dev/null +++ b/Avatar/App/Avatar/Swift/TutorialViewController.swift @@ -0,0 +1,78 @@ +import UIKit + +class TutorialViewController: UIViewController { + + var whatsnewView: WhatsNewBaseView! + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .init(named: "Primary") + + let contents = createOnboardingContents() + whatsnewView = WhatsNewBaseView(content: contents) + view.addSubview(whatsnewView) + + whatsnewView.fill() + + } + + + func createOnboardingContents() -> WhatsNewContent.Base { + let color: UIColor = .systemBlue + let title = WhatsNewContent.Title(format: .multiline(welcomeText: "Welcome to Avatar"), text: "Tutorial") + + let items = [ + + WhatsNewContent.Card(title: "Hello", + resume: "Thank you for purchasing Avatar, have an amazing time creating awesome videos and sharing them.", + icon: UIImage(systemName: "hand.wave.fill"), + iconTintColor: .systemIndigo), + + WhatsNewContent.Card(title: "Avatar Profile", + resume: "Tap on your profile icon from the home page to customise your profile avatar.", + icon: UIImage(systemName: "1.circle.fill"), + iconTintColor: .systemGreen), + + WhatsNewContent.Card(title: "Memoji", + resume: "Choose your Memoji from the home page Memoji section, once you have selected your Memoji then it will take you to the recording studio where you can either add a wallpaper or background colour, add stickers and record your Memoji.", + icon: UIImage(systemName: "2.circle.fill"), + iconTintColor: .systemBlue), + + WhatsNewContent.Card(title: "Animoji", + resume: "Choose your Animoji from home page Animoji section, once you have selected your Animoji then it will take you to recording studio where you can either add wallpaper or background colour, add stickers and record your Animoji.", + icon: UIImage(systemName: "3.circle.fill"), + iconTintColor: .systemPink), + + WhatsNewContent.Card(title: "Avimoji", + resume: "Avimoji is a studio where you can customise any avatar, add a background image or colour, Emojis, Memoji stickers or text and change the mask shape then you can that save avatar to your photo library to share them via social media.", + icon: UIImage(systemName: "4.circle.fill"), + iconTintColor: .systemYellow), + + WhatsNewContent.Card(title: "Library", + resume: "Every time you record Memoji or Animoji, the video will be saved to your photo library automatically so you can watch the video, save them to your photo library, share them or delete the video from your photo library by long pressing on the cells.", + icon: UIImage(systemName: "5.circle.fill"), + iconTintColor: .systemTeal), + + WhatsNewContent.Card(title: "Existing Memoji", + resume: "If you don’t want to create Memojis from scratch, you can toggle to import existing Memoji from the settings so it will load existing Memojis that you created from the iMessage app but you won’t be able to create new Memoji in the Avatar app but you still can create new Memoji in iMessage then the Avatar app will load the newly created Memoji. If you disable being able to import existing Memojis then you will need to create new Memoji within the app. Don’t worry you can switch between existing or new Memoji in the settings option.", + icon: UIImage(systemName: "6.circle.fill"), + iconTintColor: .systemOrange), + + WhatsNewContent.Card(title: "Social", + resume: "If you need any help or are having troubling to use the Avatar app please don’t hesitate to contact us via the Social media section from settings.", + icon: UIImage(systemName: "7.circle.fill"), + iconTintColor: .systemRed) + + ] + + let startBtn = WhatsNewContent.Button(text: "Go Back", backgroundColor: .systemBlue) { [weak self] in + self?.navigationController?.popToRootViewController(animated: true) + } + + + return WhatsNewContent.Base(backgroundColor: .init(named: "Primary")!, title: title, cards: items, button: startBtn) + } + + +} diff --git a/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContent.swift b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContent.swift new file mode 100644 index 0000000..f8fc617 --- /dev/null +++ b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContent.swift @@ -0,0 +1,5 @@ +import UIKit + +public enum WhatsNewContent { + +} diff --git a/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentBase.swift b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentBase.swift new file mode 100644 index 0000000..c82e55c --- /dev/null +++ b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentBase.swift @@ -0,0 +1,20 @@ +import UIKit + +public extension WhatsNewContent { + struct Base { + public let backgroundColor: UIColor + public let title: WhatsNewContent.Title + public let cards: [WhatsNewContent.Card] + public let button: WhatsNewContent.Button + + public init(backgroundColor: UIColor, + title: WhatsNewContent.Title, + cards: [WhatsNewContent.Card], + button: WhatsNewContent.Button) { + self.backgroundColor = backgroundColor + self.title = title + self.cards = cards + self.button = button + } + } +} diff --git a/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentButton.swift b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentButton.swift new file mode 100644 index 0000000..42800f2 --- /dev/null +++ b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentButton.swift @@ -0,0 +1,17 @@ +import UIKit + +public extension WhatsNewContent { + struct Button { + public let text: String + public let backgroundColor: UIColor + public let action: (() -> Void)? + + public init(text: String, + backgroundColor: UIColor = .lightGray, + action: (() -> Void)? = nil) { + self.text = text + self.backgroundColor = backgroundColor + self.action = action + } + } +} diff --git a/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentCard.swift b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentCard.swift new file mode 100644 index 0000000..eace4b0 --- /dev/null +++ b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentCard.swift @@ -0,0 +1,26 @@ +import UIKit + +public extension WhatsNewContent { + struct Card { + public let title: String + public let titleFont: UIFont + public let resume: String + public let resumeFont: UIFont + public let icon: UIImage? + public let iconTintColor: UIColor? + + public init(title: String, + titleFont: UIFont = .systemFont(ofSize: 18, weight: .bold), + resume: String, + resumeFont: UIFont = .systemFont(ofSize: 16, weight: .semibold), + icon: UIImage?, + iconTintColor: UIColor = .black) { + self.title = title + self.titleFont = titleFont + self.resume = resume + self.resumeFont = resumeFont + self.icon = icon + self.iconTintColor = iconTintColor + } + } +} diff --git a/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentTitle.swift b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentTitle.swift new file mode 100644 index 0000000..4b128c1 --- /dev/null +++ b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentTitle.swift @@ -0,0 +1,13 @@ +import UIKit + +public extension WhatsNewContent { + struct Title { + public let format: WhatsNewContent.Title.Format + public let text: String + + public init(format: WhatsNewContent.Title.Format, text: String) { + self.format = format + self.text = text + } + } +} diff --git a/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentTitleFormat.swift b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentTitleFormat.swift new file mode 100644 index 0000000..ac6f420 --- /dev/null +++ b/Avatar/App/Avatar/Swift/What's New/Content/WhatsNewContentTitleFormat.swift @@ -0,0 +1,22 @@ +import UIKit + +public extension WhatsNewContent.Title { + enum Format: Equatable { + case oneline + case multiline(welcomeText: String) + + var textAlignment: NSTextAlignment { + switch self { + case .oneline: return .center + case .multiline: return .left + } + } + + var font: UIFont { + switch self { + case .oneline: return .systemFont(ofSize: 32, weight: .bold) + case .multiline: return .systemFont(ofSize: 32, weight: .heavy) + } + } + } +} diff --git a/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewBaseView.swift b/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewBaseView.swift new file mode 100644 index 0000000..4b983c3 --- /dev/null +++ b/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewBaseView.swift @@ -0,0 +1,125 @@ +import UIKit + +public class WhatsNewBaseView: UIView { + public init(content: WhatsNewContent.Base) { + viewContent = content + super.init(frame: .zero) + setup() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + var viewContent: WhatsNewContent.Base + + private lazy var welcomeTitleLabel: UILabel = { + let label = UILabel() + label.numberOfLines = 0 + label.textAlignment = viewContent.title.format.textAlignment + label.font = .systemFont(ofSize: 36, weight: .bold) + label.translatesAutoresizingMaskIntoConstraints = false + label.textColor = .label + if case let .multiline(welcomeText) = viewContent.title.format { + label.text = welcomeText + } + + return label + }() + + private lazy var nameTitleLabel: UILabel = { + let label = UILabel() + label.text = viewContent.title.text + label.textColor = viewContent.button.backgroundColor + label.textAlignment = viewContent.title.format.textAlignment + label.font = viewContent.title.format.font + label.translatesAutoresizingMaskIntoConstraints = false + label.adjustsFontSizeToFitWidth = true + label.minimumScaleFactor = 0.2 + return label + }() + + private var scrollView: UIScrollView = { + let scrollView = UIScrollView() + scrollView.contentInsetAdjustmentBehavior = .never + scrollView.showsVerticalScrollIndicator = false + scrollView.translatesAutoresizingMaskIntoConstraints = false + return scrollView + }() + + private var contentView: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + private lazy var cardsListView: WhatsNewCardsListView = { + let view = WhatsNewCardsListView(items: viewContent.cards) + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + private lazy var continueButton: WhatsNewPrimaryButton = { + let button = WhatsNewPrimaryButton() + button.setTitle(viewContent.button.text, for: .normal) + button.backgroundColor = viewContent.button.backgroundColor + button.translatesAutoresizingMaskIntoConstraints = false + return button + }() + + private func setup() { + setupViewsHierarchy() + setupViewsContraints() + setupAdditionalSettings() + } + + private func setupViewsHierarchy() { + addSubview(welcomeTitleLabel) + addSubview(nameTitleLabel) + + addSubview(scrollView) + scrollView.addSubview(contentView) + contentView.addSubview(cardsListView) + + addSubview(continueButton) + } + + private func setupViewsContraints() { + welcomeTitleLabel.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 60).isActive = true + welcomeTitleLabel.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 40).isActive = true + welcomeTitleLabel.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -40).isActive = true + + nameTitleLabel.topAnchor.constraint(equalTo: welcomeTitleLabel.bottomAnchor, constant: -4).isActive = true + nameTitleLabel.leadingAnchor.constraint(equalTo: welcomeTitleLabel.leadingAnchor).isActive = true + nameTitleLabel.trailingAnchor.constraint(equalTo: welcomeTitleLabel.trailingAnchor).isActive = true + + continueButton.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -5).isActive = true + continueButton.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 24).isActive = true + continueButton.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -24).isActive = true + + scrollView.topAnchor.constraint(equalTo: nameTitleLabel.bottomAnchor, constant: 50).isActive = true + scrollView.leadingAnchor.constraint(equalTo: nameTitleLabel.leadingAnchor).isActive = true + scrollView.trailingAnchor.constraint(equalTo: nameTitleLabel.trailingAnchor).isActive = true + scrollView.bottomAnchor.constraint(equalTo: continueButton.topAnchor, constant: -15).isActive = true + + contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true + contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true + contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true + contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true + contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true + + cardsListView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true + cardsListView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true + cardsListView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true + cardsListView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true + } + + private func setupAdditionalSettings() { + backgroundColor = viewContent.backgroundColor + continueButton.addTarget(self, action: #selector(didPressedButton), for: .touchUpInside) + } + + @objc private func didPressedButton() { + viewContent.button.action?() + } +} diff --git a/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewCardView.swift b/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewCardView.swift new file mode 100644 index 0000000..1c5be61 --- /dev/null +++ b/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewCardView.swift @@ -0,0 +1,87 @@ +import UIKit + +class WhatsNewCardView: UIView { + private let titleText: String + private let titleFont: UIFont + private let descriptionText: String + private let descriptionFont: UIFont + private let icon: UIImage? + private let iconTintColor: UIColor? + + init(titleText: String, + titleFont: UIFont, + descriptionText: String, + descriptionFont: UIFont, + icon: UIImage?, + iconTintColor: UIColor?) { + self.titleText = titleText + self.titleFont = titleFont + self.descriptionText = descriptionText + self.descriptionFont = descriptionFont + self.icon = icon + self.iconTintColor = iconTintColor + + super.init(frame: .zero) + setup() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private lazy var iconImageView: UIImageView = { + let imageView = UIImageView() + imageView.image = icon + imageView.tintColor = iconTintColor + imageView.contentMode = .scaleAspectFit + imageView.translatesAutoresizingMaskIntoConstraints = false + return imageView + }() + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.text = titleText + label.numberOfLines = 0 + label.textColor = .label + label.font = titleFont + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + private lazy var descriptionLabel: UILabel = { + let label = UILabel() + label.text = descriptionText + label.numberOfLines = 0 + label.textColor = .tertiaryLabel + label.font = descriptionFont + label.translatesAutoresizingMaskIntoConstraints = false + return label + }() + + private func setup() { + setupViewsHierarchy() + setupViewsContraints() + } + + private func setupViewsHierarchy() { + addSubview(iconImageView) + addSubview(titleLabel) + addSubview(descriptionLabel) + } + + private func setupViewsContraints() { + iconImageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + iconImageView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true + iconImageView.widthAnchor.constraint(equalToConstant: 36).isActive = true + iconImageView.heightAnchor.constraint(equalToConstant: 36).isActive = true + + titleLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true + titleLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 16).isActive = true + titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true + + descriptionLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 2).isActive = true + descriptionLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor).isActive = true + descriptionLabel.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor).isActive = true + descriptionLabel.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + } +} diff --git a/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewCardsListView.swift b/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewCardsListView.swift new file mode 100644 index 0000000..7a7e4de --- /dev/null +++ b/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewCardsListView.swift @@ -0,0 +1,51 @@ +import UIKit + +class WhatsNewCardsListView: UIView { + init(items: [WhatsNewContent.Card]) { + self.items = items + super.init(frame: .zero) + setup() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + var items: [WhatsNewContent.Card] + + private var listStackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.spacing = 30 + stackView.translatesAutoresizingMaskIntoConstraints = false + return stackView + }() + + private lazy var cards: [WhatsNewCardView] = { + return items.reduce([WhatsNewCardView]()) { createdViews, item in + return createdViews + [WhatsNewCardView(titleText: item.title, + titleFont: item.titleFont, + descriptionText: item.resume, + descriptionFont: item.resumeFont, + icon: item.icon, + iconTintColor: item.iconTintColor)] + } + }() + + private func setup() { + setupViewsHierarchy() + setupViewsContraints() + } + + private func setupViewsHierarchy() { + addSubview(listStackView) + cards.forEach { listStackView.addArrangedSubview($0) } + } + + private func setupViewsContraints() { + listStackView.topAnchor.constraint(equalTo: topAnchor).isActive = true + listStackView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true + listStackView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true + listStackView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true + } +} diff --git a/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewPrimaryButton.swift b/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewPrimaryButton.swift new file mode 100644 index 0000000..e1363b8 --- /dev/null +++ b/Avatar/App/Avatar/Swift/What's New/Views/WhatsNewPrimaryButton.swift @@ -0,0 +1,25 @@ +import UIKit + +class WhatsNewPrimaryButton: UIButton { + init() { + super.init(frame: .zero) + setup() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override var isHighlighted: Bool { + didSet { + alpha = self.isHighlighted ? 0.75 : 1 + } + } + + private func setup() { + setTitleColor(.white, for: .normal) + contentEdgeInsets = UIEdgeInsets(top: 15, left: 8, bottom: 15, right: 8) + titleLabel?.font = .systemFont(ofSize: 16, weight: .semibold) + layer.cornerRadius = 14 + } +} diff --git a/Avatar/App/Avatar/Theme.xcassets/Contents.json b/Avatar/App/Avatar/Theme.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Avatar/App/Avatar/Theme.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Theme.xcassets/Primary.colorset/Contents.json b/Avatar/App/Avatar/Theme.xcassets/Primary.colorset/Contents.json new file mode 100644 index 0000000..ca11ee7 --- /dev/null +++ b/Avatar/App/Avatar/Theme.xcassets/Primary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.118", + "green" : "0.110", + "red" : "0.110" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/Theme.xcassets/Secondary.colorset/Contents.json b/Avatar/App/Avatar/Theme.xcassets/Secondary.colorset/Contents.json new file mode 100644 index 0000000..d8782a9 --- /dev/null +++ b/Avatar/App/Avatar/Theme.xcassets/Secondary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.965", + "green" : "0.949", + "red" : "0.949" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.180", + "green" : "0.173", + "red" : "0.173" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Avatar/App/Avatar/main.m b/Avatar/App/Avatar/main.m new file mode 100644 index 0000000..dba295e --- /dev/null +++ b/Avatar/App/Avatar/main.m @@ -0,0 +1,11 @@ +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + NSString * appDelegateClassName; + @autoreleasepool { + // Setup code that might create autoreleased objects goes here. + appDelegateClassName = NSStringFromClass([AppDelegate class]); + } + return UIApplicationMain(argc, argv, nil, appDelegateClassName); +} diff --git a/Avatar/App/Makefile b/Avatar/App/Makefile new file mode 100644 index 0000000..bd559bf --- /dev/null +++ b/Avatar/App/Makefile @@ -0,0 +1,19 @@ +TARGET = iphone:clang:latest:14.4 +INSTALL_TARGET_PROCESSES = Avatar +ARCHS = arm64 arm64e + +FINALPACKAGE = 1 +DEBUG = 0 + +include $(THEOS)/makefiles/common.mk + +XCODEPROJ_NAME = Avatar +Avatar_XCODE_SCHEME = Avatar +Avatar_CODESIGN_FLAGS = -SAvatar.entitlements +Avatar_XCODE_PROJECT = Avatar.xcodeproj + +include $(THEOS_MAKE_PATH)/xcodeproj.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete diff --git a/Avatar/App/layout/DEBIAN/postinst b/Avatar/App/layout/DEBIAN/postinst new file mode 100755 index 0000000..bfe9126 --- /dev/null +++ b/Avatar/App/layout/DEBIAN/postinst @@ -0,0 +1,2 @@ +#!/bin/bash +uicache -p /Applications/Avatar.app diff --git a/Avatar/Makefile b/Avatar/Makefile new file mode 100644 index 0000000..f302e0c --- /dev/null +++ b/Avatar/Makefile @@ -0,0 +1,16 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.4 + +export CFLAGS = -include $(realpath NCCenter.h) + +FINALPACKAGE = 1 +DEBUG = 0 + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += App + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Avatar/NCCenter.h b/Avatar/NCCenter.h new file mode 100644 index 0000000..0b2feb1 --- /dev/null +++ b/Avatar/NCCenter.h @@ -0,0 +1,9 @@ +#import + +@interface NSDistributedNotificationCenter : NSNotificationCenter ++ (instancetype)defaultCenter; +-(void)postNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3 deliverImmediately:(BOOL)arg4 ; +- (void)postNotificationName:(NSString *)name object:(NSString *)object userInfo:(NSDictionary *)userInfo; +-(id)addObserverForName:(id)arg1 object:(id)arg2 queue:(id)arg3 usingBlock:(/*^block*/id)arg4 ; +-(void)addObserver:(id)arg1 selector:(SEL)arg2 name:(id)arg3 object:(id)arg4 ; +@end \ No newline at end of file diff --git a/Avatar/control b/Avatar/control new file mode 100644 index 0000000..5675048 --- /dev/null +++ b/Avatar/control @@ -0,0 +1,11 @@ +Package: com.titand3v.avatar +Name: Avatar +Architecture: iphoneos-arm +Depends: mobilesubstrate, firmware (>= 14.0) +Version: 1.0 +Section: Tweaks +Description: Avatar studio for Memoji and Animoji +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/avatar/index.html +Icon: https://titand3v.github.io/depictions/avatar/assets/icon.png diff --git a/Avatar/layout/DEBIAN/postinst b/Avatar/layout/DEBIAN/postinst new file mode 100755 index 0000000..37db9c6 --- /dev/null +++ b/Avatar/layout/DEBIAN/postinst @@ -0,0 +1,3 @@ +#!/bin/bash +su mobile -c uicache &>/dev/null +uicache -p /Applications/Avatar.app diff --git a/Breezy/.DS_Store b/Breezy/.DS_Store new file mode 100644 index 0000000..5ffa0ed Binary files /dev/null and b/Breezy/.DS_Store differ diff --git a/Breezy/Makefile b/Breezy/Makefile new file mode 100644 index 0000000..1b574ab --- /dev/null +++ b/Breezy/Makefile @@ -0,0 +1,15 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0:13.0 +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +FINALPACKAGE = 1 +DEBUG = 0 + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak Prefs + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Breezy/Prefs/BZYPrimraryListController.h b/Breezy/Prefs/BZYPrimraryListController.h new file mode 100644 index 0000000..2fbc41c --- /dev/null +++ b/Breezy/Prefs/BZYPrimraryListController.h @@ -0,0 +1,29 @@ +#import +#import + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1;; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + + +@interface BZYPrimraryListController : TDPrimraryController { + OBWelcomeController *onboardingController; + OBWelcomeController *updateController; +} + +@end diff --git a/Breezy/Prefs/BZYPrimraryListController.m b/Breezy/Prefs/BZYPrimraryListController.m new file mode 100644 index 0000000..85ce87c --- /dev/null +++ b/Breezy/Prefs/BZYPrimraryListController.m @@ -0,0 +1,120 @@ +#include "BZYPrimraryListController.h" + +static NSString *BID = @"com.TitanD3v.BreezyPrefs"; +static NSString *tweakName = @"Breezy"; + +@implementation BZYPrimraryListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Primrary" target:self]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[TDPrefsManager sharedInstance] initWithBundleID:@"com.TitanD3v.BreezyPrefs" tweakName:@"Breezy" prefsBundle:@"BreezyPrefs.bundle"]; + + [[TDPrefsManager sharedInstance] bannerTitle:@"Breezy" subtitle:@"Coded with 🤍" devName:@"TitanD3v" coverImagePath:@"/Assets/Banner/cover-image.png" showCoverImage:YES iconPath:@"" iconTint:NO]; + + [[TDPrefsManager sharedInstance] changelogPlistPath:@"/Assets/Changelog/changelog.plist" currentVersion:@"Version 1.0"]; + + [[TDPrefsManager sharedInstance] useAssetsFromLibrary:YES]; + +} + + +-(void)presentTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + onboardingController = [[OBWelcomeController alloc] initWithTitle:@"User Guide" detailText:@"A walk through tutorial how to use Breezy" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/BreezyPrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]]; + + [onboardingController addBulletedListItemWithTitle:@"Your time" description:@"Please take a few minutes of your time to read through to get started." image:[UIImage systemImageNamed:@"timer"]]; + + [onboardingController addBulletedListItemWithTitle:@"Main page" description:@"On the main page, there's menu icon on the navigation bar it will present the drawer when tapped. You will find the social media details, changelog, backup/restore, themes, tweak list, profile and crew list." image:[UIImage systemImageNamed:@"square.stack.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Report a bug" description:@"If you are experiencing a bug or any other issues, you can report a bug from this page below the close button, it will bring up the Bug Report page. You can select the categories, write description about a bug, attach a .txt file, photo, provide URL link for the pastebin or any pasteboard website also you can attach all of them if you want. Once you submit a bug report and our team will be in touch with you within 48 hours. If you haven't heard anything from us and please don't hesitate to get in touch with us through social media." image:[UIImage systemImageNamed:@"ant.circle.fill"]]; + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [onboardingController.buttonTray addButton:dismissButton]; + + onboardingController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:onboardingController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [onboardingController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + onboardingController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [onboardingController.buttonTray addCaptionText:@"Thank you for installing Breezy"]; + + onboardingController.modalPresentationStyle = UIModalPresentationPageSheet; + onboardingController.modalInPresentation = YES; + [self presentViewController:onboardingController animated:YES completion:nil]; + + UIView *reportView = [[UIView alloc] init]; + reportView.backgroundColor = UIColor.clearColor; + [onboardingController.buttonTray addSubview:reportView]; + + reportView.translatesAutoresizingMaskIntoConstraints = NO; + [reportView.topAnchor constraintEqualToAnchor:dismissButton.bottomAnchor constant:10].active = YES; + [[reportView centerXAnchor] constraintEqualToAnchor:onboardingController.buttonTray.centerXAnchor].active = true; + [reportView.widthAnchor constraintEqualToConstant:140].active = YES; + [reportView.heightAnchor constraintEqualToConstant:40].active = YES; + + + UIImageView *bugImage = [[UIImageView alloc] init]; + bugImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + bugImage.tintColor = [[TDAppearance sharedInstance] tintColour]; + [reportView addSubview:bugImage]; + + bugImage.translatesAutoresizingMaskIntoConstraints = NO; + [bugImage.leadingAnchor constraintEqualToAnchor:reportView.leadingAnchor constant:10].active = YES; + [[bugImage centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + [bugImage.widthAnchor constraintEqualToConstant:30].active = YES; + [bugImage.heightAnchor constraintEqualToConstant:30].active = YES; + + + UILabel *reportLabel = [[UILabel alloc] init]; + reportLabel.text = @"Report a bug"; + reportLabel.textColor = [[TDAppearance sharedInstance] tintColour]; + reportLabel.textAlignment = NSTextAlignmentLeft; + [reportView addSubview:reportLabel]; + + reportLabel.translatesAutoresizingMaskIntoConstraints = NO; + [reportLabel.leadingAnchor constraintEqualToAnchor:bugImage.trailingAnchor constant:5].active = YES; + [[reportLabel centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + + [reportView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentReportBugVC)]]; + +} + + +-(void)dismissTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentReportBugVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; + + TDReportBugViewController *bugVC = [[TDReportBugViewController alloc] init]; + bugVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [self presentViewController:bugVC animated:YES completion:nil]; +} + + +@end diff --git a/Breezy/Prefs/BZYSecondaryListController.h b/Breezy/Prefs/BZYSecondaryListController.h new file mode 100644 index 0000000..553707a --- /dev/null +++ b/Breezy/Prefs/BZYSecondaryListController.h @@ -0,0 +1,6 @@ +#import +#import + +@interface BZYGestureController : TDSecondaryController +@end + diff --git a/Breezy/Prefs/BZYSecondaryListController.m b/Breezy/Prefs/BZYSecondaryListController.m new file mode 100644 index 0000000..e96c3c7 --- /dev/null +++ b/Breezy/Prefs/BZYSecondaryListController.m @@ -0,0 +1,13 @@ +#include "BZYSecondaryListController.h" + +@implementation BZYGestureController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Gesture" target:self]; + } + + return _specifiers; +} + +@end diff --git a/Breezy/Prefs/Makefile b/Breezy/Prefs/Makefile new file mode 100644 index 0000000..a539df4 --- /dev/null +++ b/Breezy/Prefs/Makefile @@ -0,0 +1,15 @@ +BUNDLE_NAME = BreezyPrefs + +$(BUNDLE_NAME)_FILES = $(wildcard *.m) +$(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles +$(BUNDLE_NAME)_FRAMEWORKS = UIKit +$(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences OnBoardingKit +$(BUNDLE_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(BUNDLE_NAME)_LIBRARIES = TitanD3vUniversal + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/bundle.mk + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) + $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/BreezyPrefs.plist$(ECHO_END) diff --git a/Breezy/Prefs/Resources/Assets/Banner/banner-icon.png b/Breezy/Prefs/Resources/Assets/Banner/banner-icon.png new file mode 100644 index 0000000..171819f Binary files /dev/null and b/Breezy/Prefs/Resources/Assets/Banner/banner-icon.png differ diff --git a/Breezy/Prefs/Resources/Assets/Banner/cover-image.png b/Breezy/Prefs/Resources/Assets/Banner/cover-image.png new file mode 100644 index 0000000..c3eead0 Binary files /dev/null and b/Breezy/Prefs/Resources/Assets/Banner/cover-image.png differ diff --git a/Breezy/Prefs/Resources/Assets/Cell/prefs-icon@2x.png b/Breezy/Prefs/Resources/Assets/Cell/prefs-icon@2x.png new file mode 100644 index 0000000..d406d84 Binary files /dev/null and b/Breezy/Prefs/Resources/Assets/Cell/prefs-icon@2x.png differ diff --git a/Breezy/Prefs/Resources/Assets/Cell/prefs-icon@3x.png b/Breezy/Prefs/Resources/Assets/Cell/prefs-icon@3x.png new file mode 100644 index 0000000..d104402 Binary files /dev/null and b/Breezy/Prefs/Resources/Assets/Cell/prefs-icon@3x.png differ diff --git a/Breezy/Prefs/Resources/Assets/Changelog/changelog.plist b/Breezy/Prefs/Resources/Assets/Changelog/changelog.plist new file mode 100644 index 0000000..2cfe6e4 --- /dev/null +++ b/Breezy/Prefs/Resources/Assets/Changelog/changelog.plist @@ -0,0 +1,22 @@ + + + + + + + Date + 12th June 2021 + Version + v1.0 + ChangelogDescription + + Initial Release... + + updateCategories + + 0 + + + + + \ No newline at end of file diff --git a/Breezy/Prefs/Resources/Gesture.plist b/Breezy/Prefs/Resources/Gesture.plist new file mode 100644 index 0000000..60788a8 --- /dev/null +++ b/Breezy/Prefs/Resources/Gesture.plist @@ -0,0 +1,163 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Stausbar + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleStatusbarGesture + title + Enable + subtitle + Double tap + iconName + switch + showTips + + defaults + com.TitanD3v.BreezyPrefs + PostNotification + com.TitanD3v.BreezyPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Dock + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleDockGesture + title + Enable + subtitle + Double tap + iconName + switch + showTips + + defaults + com.TitanD3v.BreezyPrefs + PostNotification + com.TitanD3v.BreezyPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Volume + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleVolumeUpGesture + title + Enable + subtitle + Volume Up Button + iconName + switch + showTips + + defaults + com.TitanD3v.BreezyPrefs + PostNotification + com.TitanD3v.BreezyPrefs.settingschanged + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleVolumeDownGesture + title + Enable + subtitle + Volume Down Button + iconName + switch + showTips + + defaults + com.TitanD3v.BreezyPrefs + PostNotification + com.TitanD3v.BreezyPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Shake + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleShakeGesture + title + Enable + subtitle + Shake Motion + iconName + switch + showTips + + defaults + com.TitanD3v.BreezyPrefs + PostNotification + com.TitanD3v.BreezyPrefs.settingschanged + + + + title + + + diff --git a/Breezy/Prefs/Resources/Info.plist b/Breezy/Prefs/Resources/Info.plist new file mode 100644 index 0000000..910409e --- /dev/null +++ b/Breezy/Prefs/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + BreezyPrefs + CFBundleIdentifier + com.TitanD3v.breezyprefs + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + BZYPrimraryListController + + diff --git a/Breezy/Prefs/Resources/Primrary.plist b/Breezy/Prefs/Resources/Primrary.plist new file mode 100644 index 0000000..0c42f7c --- /dev/null +++ b/Breezy/Prefs/Resources/Primrary.plist @@ -0,0 +1,174 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable + + + + cellClass + TDEnableCell + default + + key + toggleBreezy + disabledTitle + Disable Breezy + enabledTitle + Enable Breezy + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + disabledIconPath + Assets/example-icon.png + enabledIconPath + Assets/example-icon.png + defaults + com.TitanD3v.BreezyPrefs + PostNotification + com.TitanD3v.BreezyPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Title + + + + cellClass + TDEditCell + title + Set + subtitle + Title + objectKey + breezyTitle + placeholderText + Hello + default + Hello + iconName + edit + keyboardType + keyboard + defaults + com.TitanD3v.BreezyPrefs + PostNotification + com.TitanD3v.BreezyPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Message + + + + cell + PSDefaultCell + cellClass + TDTextViewCell + title + Set Message + key + breezyMessage + default + How are you? + iconName + textview + defaults + com.TitanD3v.BreezyPrefs + PostNotification + com.TitanD3v.BreezyPrefs.settingschanged + height + 130 + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + App + + + + cell + PSLinkCell + cellClass + TDAppLinkCell + detail + TDAppListController + isController + + title + Choose app + subtitle + To show notification from + key + notificationBundleID + appList + allapps + limitApps + + appsCapacity + 1 + iconName + applist + defaults + com.TitanD3v.BreezyPrefs + postNotification + com.TitanD3v.BreezyPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Gesture + + + + cell + PSLinkCell + cellClass + TDLinkCell + detail + BZYGestureController + isController + + title + Choose + subtitle + Gesture recognizer + iconName + button + + + + title + + + diff --git a/Breezy/Prefs/entry.plist b/Breezy/Prefs/entry.plist new file mode 100644 index 0000000..dd59884 --- /dev/null +++ b/Breezy/Prefs/entry.plist @@ -0,0 +1,21 @@ + + + + + entry + + bundle + BreezyPrefs + cell + PSLinkCell + detail + BZYPrimraryListController + icon + Assets/Cell/prefs-icon.png + isController + + label + Breezy + + + diff --git a/Breezy/Tweak/Breezy.plist b/Breezy/Tweak/Breezy.plist new file mode 100644 index 0000000..10dc654 --- /dev/null +++ b/Breezy/Tweak/Breezy.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard" ); }; } diff --git a/Breezy/Tweak/Breezy.xm b/Breezy/Tweak/Breezy.xm new file mode 100644 index 0000000..d6aba32 --- /dev/null +++ b/Breezy/Tweak/Breezy.xm @@ -0,0 +1,267 @@ +#import +#import +#import "Headers.h" + +static NSString *BID = @"com.TitanD3v.BreezyPrefs"; +static BOOL toggleBreezy; +static NSString *breezyTitle; +static NSString *breezyMessage; +static BOOL toggleStatusbarGesture; +static BOOL toggleDockGesture; +static BOOL toggleVolumeUpGesture; +static BOOL toggleVolumeDownGesture; +static BOOL toggleShakeGesture; +static BBServer *bbServer = nil; + + +static dispatch_queue_t getBBServerQueue() { + + static dispatch_queue_t queue; + static dispatch_once_t predicate; + + dispatch_once(&predicate, ^{ + void* handle = dlopen(NULL, RTLD_GLOBAL); + if (handle) { + dispatch_queue_t __weak *pointer = (__weak dispatch_queue_t *) dlsym(handle, "__BBServerQueue"); + if (pointer) queue = *pointer; + dlclose(handle); + } + }); + + return queue; + +} + + +static void breezyFakeNotification() { + + NSArray *notificationBundleID = [[TDTweakManager sharedInstance] objectForKey:@"notificationBundleID" ID:@"com.TitanD3v.BreezyPrefs"]; + NSString *bundleID = [notificationBundleID objectAtIndex:0]; + + BBBulletin* bulletin = [[%c(BBBulletin) alloc] init]; + + bulletin.title = breezyTitle; + bulletin.message = breezyMessage; + bulletin.sectionID = bundleID; + bulletin.bulletinID = [[NSProcessInfo processInfo] globallyUniqueString]; + bulletin.recordID = [[NSProcessInfo processInfo] globallyUniqueString]; + bulletin.publisherBulletinID = [[NSProcessInfo processInfo] globallyUniqueString]; + bulletin.date = [NSDate date]; + bulletin.defaultAction = [%c(BBAction) actionWithLaunchBundleID:bundleID callblock:nil]; + bulletin.clearable = YES; + bulletin.showsMessagePreview = YES; + bulletin.publicationDate = [NSDate date]; + bulletin.lastInterruptDate = [NSDate date]; + + if ([bbServer respondsToSelector:@selector(publishBulletin:destinations:)]) { + dispatch_sync(getBBServerQueue(), ^{ + [bbServer publishBulletin:bulletin destinations:15]; + }); + } +} + + +%group BreezyStatusbar +%hook _UIStatusBar + +-(void)willMoveToSuperview:(UIView *)newSuperview { + %orig(newSuperview); + + UITapGestureRecognizer *tapGesture1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(invokeFakeNotification)]; + tapGesture1.numberOfTapsRequired = 2; + [self addGestureRecognizer:tapGesture1]; + +} + +%new +-(void)invokeFakeNotification { + breezyFakeNotification(); + NSLog(@"BREEZY title: %@", breezyTitle); +} + +%end +%end + + +%group BreezyVolumeUp +%hook SpringBoard +%property (nonatomic, assign) BOOL didPressed; + +-(BOOL)_handlePhysicalButtonEvent:(UIPressesEvent *)arg1 { + + UIPress *touch = [arg1.allPresses anyObject]; + + if (touch.type == 102) { // 102 up, 103 down + + if (touch.force == 1) { + + self.didPressed = YES; + [self performSelector:@selector(monitorGesturePressed) withObject:nil afterDelay:0.25f]; + + } else { + + self.didPressed = NO; + } + } + + return %orig; +} + +%new +-(void)monitorGesturePressed { + + if (self.didPressed) + [self performSelector:@selector(invokeFakeNotification)]; +} + +%new +-(void)invokeFakeNotification { + breezyFakeNotification(); +} + +%end +%end + + +%group BreezyVolumeDown +%hook SpringBoard +%property (nonatomic, assign) BOOL didPressed; + +-(BOOL)_handlePhysicalButtonEvent:(UIPressesEvent *)arg1 { + + UIPress *touch = [arg1.allPresses anyObject]; + + if (touch.type == 103) { // 102 up, 103 down + + if (touch.force == 1) { + + self.didPressed = YES; + [self performSelector:@selector(monitorGesturePressed) withObject:nil afterDelay:0.25f]; + + } else { + + self.didPressed = NO; + } + } + + return %orig; +} + +%new +-(void)monitorGesturePressed { + + if (self.didPressed) + [self performSelector:@selector(invokeFakeNotification)]; +} + +%new +-(void)invokeFakeNotification { + breezyFakeNotification(); +} + +%end +%end + + +%group BreezyDock +%hook SBDockView +-(void)layoutSubviews { + %orig; + + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(invokeFakeNotification)]; + tapGesture.numberOfTapsRequired = 2; + [self addGestureRecognizer:tapGesture]; + +} + +%new +-(void)invokeFakeNotification { + breezyFakeNotification(); +} + +%end +%end + + +%group BreezyShake +%hook UIWindow + +- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { + %orig; + if(event.type == UIEventSubtypeMotionShake && self == [[UIApplication sharedApplication] keyWindow]) { + breezyFakeNotification(); + } +} + +%end +%end + + +%group BBServerHooks +%hook BBServer + +- (id)initWithQueue:(id)arg1 { + bbServer = %orig; + return bbServer; +} + +- (id)initWithQueue:(id)arg1 dataProviderManager:(id)arg2 syncService:(id)arg3 dismissalSyncCache:(id)arg4 observerListener:(id)arg5 utilitiesListener:(id)arg6 conduitListener:(id)arg7 systemStateListener:(id)arg8 settingsListener:(id)arg9 { + bbServer = %orig; + return bbServer; +} + +- (void)dealloc { + if (bbServer == self) bbServer = nil; + %orig; +} + +%end +%end + + +void SettingsChanged() { + + toggleBreezy = [[TDTweakManager sharedInstance] boolForKey:@"toggleBreezy" defaultValue:NO ID:BID]; + breezyTitle = [[TDTweakManager sharedInstance] objectForKey:@"breezyTitle" defaultValue:@"Hello" ID:BID]; + breezyMessage = [[TDTweakManager sharedInstance] objectForKey:@"breezyMessage" defaultValue:@"How are you?" ID:BID]; + toggleStatusbarGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleStatusbarGesture" defaultValue:YES ID:BID]; + toggleDockGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleDockGesture" defaultValue:NO ID:BID]; + toggleVolumeUpGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleVolumeUpGesture" defaultValue:NO ID:BID]; + toggleVolumeDownGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleVolumeDownGesture" defaultValue:NO ID:BID]; + toggleShakeGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleShakeGesture" defaultValue:NO ID:BID]; + +} + +%ctor { + + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)SettingsChanged, CFSTR("com.TitanD3v.BreezyPrefs.settingschanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + SettingsChanged(); + + if (toggleBreezy) { + + if (toggleStatusbarGesture) { + %init(BreezyStatusbar); + } + + if (toggleVolumeUpGesture) { + %init(BreezyVolumeUp); + } + + if (toggleVolumeDownGesture) { + %init(BreezyVolumeDown); + } + + if (toggleDockGesture) { + %init(BreezyDock); + } + + if (toggleShakeGesture) { + %init(BreezyShake); + } + + %init(BBServerHooks); + + } + + } + diff --git a/Breezy/Tweak/Headers.h b/Breezy/Tweak/Headers.h new file mode 100644 index 0000000..9f535e3 --- /dev/null +++ b/Breezy/Tweak/Headers.h @@ -0,0 +1,37 @@ +@interface BBAction : NSObject ++ (id)actionWithLaunchBundleID:(id)arg1 callblock:(id)arg2; +@end + +@interface BBBulletin : NSObject +@property(nonatomic, copy)NSString* sectionID; +@property(nonatomic, copy)NSString* recordID; +@property(nonatomic, copy)NSString* publisherBulletinID; +@property(nonatomic, copy)NSString* title; +@property(nonatomic, copy)NSString* message; +@property(nonatomic, retain)NSDate* date; +@property(assign, nonatomic)BOOL clearable; +@property(nonatomic)BOOL showsMessagePreview; +@property(nonatomic, copy)BBAction* defaultAction; +@property(nonatomic, copy)NSString* bulletinID; +@property(nonatomic, retain)NSDate* lastInterruptDate; +@property(nonatomic, retain)NSDate* publicationDate; +@end + +@interface BBServer : NSObject +- (void)publishBulletin:(BBBulletin *)arg1 destinations:(NSUInteger)arg2 alwaysToLockScreen:(BOOL)arg3; +- (void)publishBulletin:(id)arg1 destinations:(unsigned long long)arg2; +-(void)_removeBulletins:(id)arg1 forSectionID:(id)arg2 shouldSync:(BOOL)arg3 ; +-(id)_bulletinsForIDs:(id)arg1 ; +-(id)allBulletinIDsForSectionID:(id)arg1 ; +-(void)_removeActiveSectionID:(id)arg1 ; +@end + +@interface _UIStatusBar : UIView +@end + +@interface SpringBoard : NSObject +@property (nonatomic, assign) BOOL didPressed; +@end + +@interface SBDockView : UIView +@end \ No newline at end of file diff --git a/Breezy/Tweak/Makefile b/Breezy/Tweak/Makefile new file mode 100644 index 0000000..be9d41d --- /dev/null +++ b/Breezy/Tweak/Makefile @@ -0,0 +1,13 @@ +TWEAK_NAME = Breezy + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Breezy/control b/Breezy/control new file mode 100644 index 0000000..54d044a --- /dev/null +++ b/Breezy/control @@ -0,0 +1,11 @@ +Package: com.titand3v.breezy +Name: Breezy +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal +Version: 1.0 +Section: Tweaks +Description: Fake notifications +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/breezy/index.html +Icon: https://titand3v.github.io/depictions/breezy/assets/icon.png diff --git a/ColourMyDock/.DS_Store b/ColourMyDock/.DS_Store new file mode 100644 index 0000000..b19d12d Binary files /dev/null and b/ColourMyDock/.DS_Store differ diff --git a/ColourMyDock/Makefile b/ColourMyDock/Makefile new file mode 100644 index 0000000..30f14ba --- /dev/null +++ b/ColourMyDock/Makefile @@ -0,0 +1,15 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0 +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +FINALPACKAGE = 1 +DEBUG = 0 + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak Prefs + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/ColourMyDock/Prefs/CMDPrimraryListController.h b/ColourMyDock/Prefs/CMDPrimraryListController.h new file mode 100644 index 0000000..51c6141 --- /dev/null +++ b/ColourMyDock/Prefs/CMDPrimraryListController.h @@ -0,0 +1,29 @@ +#import +#import + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1;; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + + +@interface CMDPrimraryListController : TDPrimraryController { + OBWelcomeController *onboardingController; + OBWelcomeController *updateController; +} + +@end diff --git a/ColourMyDock/Prefs/CMDPrimraryListController.m b/ColourMyDock/Prefs/CMDPrimraryListController.m new file mode 100644 index 0000000..c25045b --- /dev/null +++ b/ColourMyDock/Prefs/CMDPrimraryListController.m @@ -0,0 +1,120 @@ +#include "CMDPrimraryListController.h" + +@implementation CMDPrimraryListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Primrary" target:self]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[TDPrefsManager sharedInstance] initWithBundleID:@"com.TitanD3v.ColourMyDockPrefs" tweakName:@"ColourMyDock" prefsBundle:@"ColourMyDockPrefs.bundle"]; + + [[TDPrefsManager sharedInstance] bannerTitle:@"ColourMyDock" subtitle:@"Coded with 🤍" devName:@"TitanD3v" coverImagePath:@"/Assets/Banner/cover-image.png" showCoverImage:YES iconPath:@"" iconTint:YES]; + + [[TDPrefsManager sharedInstance] changelogPlistPath:@"/Assets/Changelog/changelog.plist" currentVersion:@"Version 2.0"]; + + [[TDPrefsManager sharedInstance] useAssetsFromLibrary:YES]; + +} + + +-(void)presentTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + onboardingController = [[OBWelcomeController alloc] initWithTitle:@"User Guide" detailText:@"A walk through tutorial how to use ColourMyDock" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ColourMyDockPrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]]; + + [onboardingController addBulletedListItemWithTitle:@"Your time" description:@"Please take a few minutes of your time to read through to get started." image:[UIImage systemImageNamed:@"timer"]]; + + [onboardingController addBulletedListItemWithTitle:@"Main page" description:@"On the main page, there's menu icon on the navigation bar it will present the drawer when tapped. You will find the social media details, changelog, backup/restore, themes, tweak list, profile and crew list." image:[UIImage systemImageNamed:@"square.stack.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Report a bug" description:@"If you are experiencing a bug or any other issues, you can report a bug from this page below the close button, it will bring up the Bug Report page. You can select the categories, write description about a bug, attach a .txt file, photo, provide URL link for the pastebin or any pasteboard website also you can attach all of them if you want. Once you submit a bug report and our team will be in touch with you within 48 hours. If you haven't heard anything from us and please don't hesitate to get in touch with us through social media." image:[UIImage systemImageNamed:@"ant.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Gesture" description:@"Choose your preferred gesture on the Dock to present dock settings menu." image:[UIImage systemImageNamed:@"hand.tap.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Border" description:@"Change the border width however you like." image:[UIImage systemImageNamed:@"line.horizontal.3.decrease"]]; + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [onboardingController.buttonTray addButton:dismissButton]; + + onboardingController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:onboardingController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [onboardingController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + onboardingController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [onboardingController.buttonTray addCaptionText:@"Thank you for installing ColourMyDock"]; + + onboardingController.modalPresentationStyle = UIModalPresentationPageSheet; + onboardingController.modalInPresentation = YES; + [self presentViewController:onboardingController animated:YES completion:nil]; + + UIView *reportView = [[UIView alloc] init]; + reportView.backgroundColor = UIColor.clearColor; + [onboardingController.buttonTray addSubview:reportView]; + + reportView.translatesAutoresizingMaskIntoConstraints = NO; + [reportView.topAnchor constraintEqualToAnchor:dismissButton.bottomAnchor constant:10].active = YES; + [[reportView centerXAnchor] constraintEqualToAnchor:onboardingController.buttonTray.centerXAnchor].active = true; + [reportView.widthAnchor constraintEqualToConstant:140].active = YES; + [reportView.heightAnchor constraintEqualToConstant:40].active = YES; + + + UIImageView *bugImage = [[UIImageView alloc] init]; + bugImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + bugImage.tintColor = [[TDAppearance sharedInstance] tintColour]; + [reportView addSubview:bugImage]; + + bugImage.translatesAutoresizingMaskIntoConstraints = NO; + [bugImage.leadingAnchor constraintEqualToAnchor:reportView.leadingAnchor constant:10].active = YES; + [[bugImage centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + [bugImage.widthAnchor constraintEqualToConstant:30].active = YES; + [bugImage.heightAnchor constraintEqualToConstant:30].active = YES; + + + UILabel *reportLabel = [[UILabel alloc] init]; + reportLabel.text = @"Report a bug"; + reportLabel.textColor = [[TDAppearance sharedInstance] tintColour]; + reportLabel.textAlignment = NSTextAlignmentLeft; + [reportView addSubview:reportLabel]; + + reportLabel.translatesAutoresizingMaskIntoConstraints = NO; + [reportLabel.leadingAnchor constraintEqualToAnchor:bugImage.trailingAnchor constant:5].active = YES; + [[reportLabel centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + + [reportView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentReportBugVC)]]; + +} + + +-(void)dismissTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentReportBugVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; + + TDReportBugViewController *bugVC = [[TDReportBugViewController alloc] init]; + bugVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [self presentViewController:bugVC animated:YES completion:nil]; +} + +@end diff --git a/ColourMyDock/Prefs/Makefile b/ColourMyDock/Prefs/Makefile new file mode 100644 index 0000000..c744ec9 --- /dev/null +++ b/ColourMyDock/Prefs/Makefile @@ -0,0 +1,15 @@ +BUNDLE_NAME = ColourMyDockPrefs + +$(BUNDLE_NAME)_FILES = $(wildcard *.m) +$(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles +$(BUNDLE_NAME)_FRAMEWORKS = UIKit +$(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences OnBoardingKit +$(BUNDLE_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(BUNDLE_NAME)_LIBRARIES = TitanD3vUniversal + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/bundle.mk + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) + $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/ColourMyDockPrefs.plist$(ECHO_END) diff --git a/ColourMyDock/Prefs/Resources/Assets/Banner/banner-icon.png b/ColourMyDock/Prefs/Resources/Assets/Banner/banner-icon.png new file mode 100644 index 0000000..2164e04 Binary files /dev/null and b/ColourMyDock/Prefs/Resources/Assets/Banner/banner-icon.png differ diff --git a/ColourMyDock/Prefs/Resources/Assets/Banner/cover-image.png b/ColourMyDock/Prefs/Resources/Assets/Banner/cover-image.png new file mode 100644 index 0000000..67f24fc Binary files /dev/null and b/ColourMyDock/Prefs/Resources/Assets/Banner/cover-image.png differ diff --git a/ColourMyDock/Prefs/Resources/Assets/Cell/cell-banner.png b/ColourMyDock/Prefs/Resources/Assets/Cell/cell-banner.png new file mode 100644 index 0000000..67f24fc Binary files /dev/null and b/ColourMyDock/Prefs/Resources/Assets/Cell/cell-banner.png differ diff --git a/ColourMyDock/Prefs/Resources/Assets/Cell/prefs-icon@2x.png b/ColourMyDock/Prefs/Resources/Assets/Cell/prefs-icon@2x.png new file mode 100644 index 0000000..2bc5231 Binary files /dev/null and b/ColourMyDock/Prefs/Resources/Assets/Cell/prefs-icon@2x.png differ diff --git a/ColourMyDock/Prefs/Resources/Assets/Cell/prefs-icon@3x.png b/ColourMyDock/Prefs/Resources/Assets/Cell/prefs-icon@3x.png new file mode 100644 index 0000000..a06a682 Binary files /dev/null and b/ColourMyDock/Prefs/Resources/Assets/Cell/prefs-icon@3x.png differ diff --git a/ColourMyDock/Prefs/Resources/Assets/Changelog/changelog.plist b/ColourMyDock/Prefs/Resources/Assets/Changelog/changelog.plist new file mode 100644 index 0000000..39fa035 --- /dev/null +++ b/ColourMyDock/Prefs/Resources/Assets/Changelog/changelog.plist @@ -0,0 +1,45 @@ + + + + + + + Date + 22nd May 2021 + Version + v2.0 + ChangelogDescription + + Added border width + Added background image + Added border colour + Added gesture options on dock - double tap, triple tap, swipe left or right + Fixed blur effect when change system appearance light or dark mode + + updateCategories + + 3 + 3 + 3 + 3 + 1 + + + + + Date + 26th Feb 2021 + Version + v1.0 + ChangelogDescription + + Initial Release... + + updateCategories + + 0 + + + + + \ No newline at end of file diff --git a/ColourMyDock/Prefs/Resources/Info.plist b/ColourMyDock/Prefs/Resources/Info.plist new file mode 100644 index 0000000..2066e10 --- /dev/null +++ b/ColourMyDock/Prefs/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ColourMyDockPrefs + CFBundleIdentifier + com.titand3v.colourmydockprefs + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + CMDPrimraryListController + + diff --git a/ColourMyDock/Prefs/Resources/Primrary.plist b/ColourMyDock/Prefs/Resources/Primrary.plist new file mode 100644 index 0000000..4c93d76 --- /dev/null +++ b/ColourMyDock/Prefs/Resources/Primrary.plist @@ -0,0 +1,128 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable + + + + cellClass + TDEnableCell + default + + key + toggleColourMyDock + disabledTitle + Disable ColourMyDock + enabledTitle + Enable ColourMyDock + disabledColour + B92F2F + enabledColour + 43EB1F + disabledIconPath + Assets/example-icon.png + enabledIconPath + Assets/example-icon.png + defaults + com.TitanD3v.ColourMyDockPrefs + PostNotification + com.TitanD3v.ColourMyDockPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Gesture + + + + cell + PSLinkListCell + cellClass + TDListCell + title + Dock + subtitle + Gesture + default + 0 + detail + TDListController + key + dockGesture + validValues + + 0 + 1 + 2 + 3 + + validTitles + + Double Tap + Triple Tap + Swipe Left + Swipe Right + + iconName + button + defaults + com.TitanD3v.ColourMyDockPrefs + PostNotification + com.TitanD3v.ColourMyDockPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Border + + + + cell + PSSliderCell + cellClass + TDSliderCell + title + Border Width + default + 1 + key + dockBorderWidth + min + 0 + max + 5 + showValue + + isSegmented + + showTips + + defaults + com.TitanD3v.ColourMyDockPrefs + PostNotification + com.TitanD3v.ColourMyDockPrefs.settingschanged + + + + title + + + diff --git a/ColourMyDock/Prefs/entry.plist b/ColourMyDock/Prefs/entry.plist new file mode 100644 index 0000000..0d16d01 --- /dev/null +++ b/ColourMyDock/Prefs/entry.plist @@ -0,0 +1,21 @@ + + + + + entry + + bundle + ColourMyDockPrefs + cell + PSLinkCell + detail + CMDPrimraryListController + icon + Assets/Cell/prefs-icon.png + isController + + label + ColourMyDock + + + diff --git a/ColourMyDock/Tweak/ColourMyDock.plist b/ColourMyDock/Tweak/ColourMyDock.plist new file mode 100644 index 0000000..10dc654 --- /dev/null +++ b/ColourMyDock/Tweak/ColourMyDock.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard" ); }; } diff --git a/ColourMyDock/Tweak/ColourMyDock.xm b/ColourMyDock/Tweak/ColourMyDock.xm new file mode 100644 index 0000000..8e598a1 --- /dev/null +++ b/ColourMyDock/Tweak/ColourMyDock.xm @@ -0,0 +1,573 @@ +#import +#import "Headers.h" + +static NSString *BID = @"com.TitanD3v.ColourMyDockPrefs"; +static BOOL toggleColourMyDock; + +SBFloatingDockPlatterView *floatingDockView; +SBDockView *stockDockView; +UIView *dockView; +UIImageView *backgroundImage; +NSInteger colourPickerIndex = 0; +NSInteger dockGesture; +CGFloat dockBorderWidth; + + +%group DockHooks +%hook SBDockView + +- (void)traitCollectionDidChange:(UITraitCollection *)old { + %orig(old); + [self performSelector:@selector(removeBlurView) withObject:nil afterDelay:0.0]; +} + + +%new +-(void)removeBlurView { + + UIView *backgroundView = [self valueForKey:@"backgroundView"]; + if([backgroundView respondsToSelector:@selector(_materialLayer)]) { + ((MTMaterialView *)backgroundView).weighting = 0; + } + if([backgroundView respondsToSelector:@selector(blurView)]) { + ((SBWallpaperEffectView *)backgroundView).blurView.hidden = YES; + } + +} + + +-(id)initWithDockListView:(id)arg1 forSnapshot:(BOOL)arg2 { + + if (dockGesture == 0) { + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureFired)]; + tapGesture.numberOfTapsRequired = 2; + [self addGestureRecognizer:tapGesture]; + } else if (dockGesture == 1) { + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureFired)]; + tapGesture.numberOfTapsRequired = 3; + [self addGestureRecognizer:tapGesture]; + } else if (dockGesture == 2) { + UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureFired)]; + swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; + [self addGestureRecognizer:swipeLeft]; + } else if (dockGesture == 3) { + UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureFired)]; + swipeRight.direction = UISwipeGestureRecognizerDirectionRight; + [self addGestureRecognizer:swipeRight]; + } + + return stockDockView = %orig; +} + + +-(void)didMoveToWindow { + %orig; + + if(!dockView) { + UIView *backgroundView = [self valueForKey:@"backgroundView"]; + + dockView = [[UIView alloc] init]; + dockView.clipsToBounds = true; + NSData *decodedData = [[TDTweakManager sharedInstance] objectForKey:@"dockBackgroundColour" ID:BID]; + UIColor *dockBGColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + + NSData *decodedData2 = [[TDTweakManager sharedInstance] objectForKey:@"dockBorderColour" ID:BID]; + UIColor *dockBorderColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData2]; + + if (decodedData) { + dockView.backgroundColor = dockBGColour; + } else { + dockView.backgroundColor = UIColor.whiteColor; + } + + dockView.layer.borderWidth = dockBorderWidth; + + if (decodedData2) { + + dockView.layer.borderColor = dockBorderColour.CGColor; + } else { + UIColor *defaultColour = UIColor.clearColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:defaultColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBorderColour" ID:BID]; + dockView.layer.borderColor = UIColor.clearColor.CGColor; + } + + [backgroundView addSubview:dockView]; + + NSData *dockBackgroundImage = [[TDTweakManager sharedInstance] objectForKey:@"dockBackgroundImage" ID:BID]; + backgroundImage = [[UIImageView alloc] init]; + if (dockBackgroundImage != nil) { + backgroundImage.image = [UIImage imageWithData:dockBackgroundImage]; + } + backgroundImage.contentMode = UIViewContentModeScaleAspectFill; + [dockView addSubview:backgroundImage]; + + + + } + +} + + +-(void)layoutSubviews { + %orig; + + UIView *backgroundView = [self valueForKey:@"backgroundView"]; + if([backgroundView respondsToSelector:@selector(_materialLayer)]) { + ((MTMaterialView *)backgroundView).weighting = 0; + dockView.layer.cornerRadius = ((MTMaterialView *)backgroundView).materialLayer.cornerRadius; + } + if([backgroundView respondsToSelector:@selector(blurView)]) { + ((SBWallpaperEffectView *)backgroundView).blurView.hidden = YES; + } + + dockView.frame = backgroundView.bounds; + backgroundImage.frame = dockView.bounds; + +} + + +%new +-(void)tapGestureFired { + + +UIAlertController *settingsAlert = [UIAlertController alertControllerWithTitle:@"Dock Settings" message:@"" preferredStyle:UIAlertControllerStyleActionSheet]; + +UIAlertAction *backgroundAction = [UIAlertAction actionWithTitle:@"Background Colour" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + +backgroundImage.image = nil; +NSString *prefPath = @"/var/mobile/Library/Preferences/com.TitanD3v.ColourMyDockPrefs.plist"; +NSMutableDictionary *settings = [NSMutableDictionary dictionary]; +[settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; +[settings removeObjectForKey:@"dockBackgroundImage"]; +[settings writeToFile:prefPath atomically:YES]; + +colourPickerIndex = 0; +[self presentColourPickerVC]; +}]; + +UIAlertAction *borderAction = [UIAlertAction actionWithTitle:@"Border Colour" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { +colourPickerIndex = 1; +[self presentColourPickerVC]; +}]; + +UIAlertAction *imageAction = [UIAlertAction actionWithTitle:@"Background Image" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { +[self presentImagePickerVC]; +}]; + +UIAlertAction *resetBackgroundAction = [UIAlertAction actionWithTitle:@"Reset Background Colour" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + + UIColor *resetColour = UIColor.whiteColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:resetColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBackgroundColour" ID:BID]; + dockView.backgroundColor = resetColour; + +}]; + +UIAlertAction *resetBorderAction = [UIAlertAction actionWithTitle:@"Reset Border Colour" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + + UIColor *resetColour = UIColor.clearColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:resetColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBorderColour" ID:BID]; + dockView.layer.borderColor = resetColour.CGColor; + +}]; + +UIAlertAction *resetImageAction = [UIAlertAction actionWithTitle:@"Reset Background Image" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + +backgroundImage.image = nil; +NSString *prefPath = @"/var/mobile/Library/Preferences/com.TitanD3v.ColourMyDockPrefs.plist"; +NSMutableDictionary *settings = [NSMutableDictionary dictionary]; +[settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; +[settings removeObjectForKey:@"dockBackgroundImage"]; +[settings writeToFile:prefPath atomically:YES]; + +}]; + +UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { + +}]; + +[backgroundAction setValue:[[UIImage systemImageNamed:@"drop.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; +[borderAction setValue:[[UIImage systemImageNamed:@"drop.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; +[imageAction setValue:[[UIImage systemImageNamed:@"photo.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; +[resetBackgroundAction setValue:[[UIImage systemImageNamed:@"arrow.uturn.backward.circle.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; +[resetBorderAction setValue:[[UIImage systemImageNamed:@"arrow.uturn.backward.circle.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; +[resetImageAction setValue:[[UIImage systemImageNamed:@"arrow.uturn.backward.circle.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; + + +[settingsAlert addAction:backgroundAction]; +[settingsAlert addAction:borderAction]; +[settingsAlert addAction:imageAction]; +[settingsAlert addAction:resetBackgroundAction]; +[settingsAlert addAction:resetBorderAction]; +[settingsAlert addAction:resetImageAction]; +[settingsAlert addAction:cancelAction]; +[[%c(SBIconController) sharedInstance] presentViewController:settingsAlert animated:YES completion:nil]; + +} + + +%new +-(void)presentColourPickerVC { + + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + if (colourPickerIndex == 0) { + colourPickerVC.selectedColor = dockView.backgroundColor; + } else if (colourPickerIndex == 1) { + NSData *decodedData = [[TDTweakManager sharedInstance] objectForKey:@"dockBorderColour" ID:BID]; + UIColor *dockBorderColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + colourPickerVC.selectedColor = dockBorderColour; + } + [[%c(SBIconController) sharedInstance] presentViewController:colourPickerVC animated:YES completion:nil]; +} + + +%new +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + + UIColor *dockSelectedColour = viewController.selectedColor; + +if (colourPickerIndex == 0) { + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:dockSelectedColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBackgroundColour" ID:BID]; + dockView.backgroundColor = dockSelectedColour; +} else if (colourPickerIndex == 1) { + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:dockSelectedColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBorderColour" ID:BID]; + dockView.layer.borderColor = dockSelectedColour.CGColor; +} + + +} + + +%new +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + + UIColor *dockSelectedColour = viewController.selectedColor; + +if (colourPickerIndex == 0) { + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:dockSelectedColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBackgroundColour" ID:BID]; + dockView.backgroundColor = dockSelectedColour; +} else if (colourPickerIndex == 1) { + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:dockSelectedColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBorderColour" ID:BID]; + dockView.layer.borderColor = dockSelectedColour.CGColor; +} + +} + + +%new +-(void)presentImagePickerVC { + + UIImagePickerController *picker = [[UIImagePickerController alloc] init]; + picker.delegate = self; + picker.allowsEditing = YES; + picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + + [[%c(SBIconController) sharedInstance] presentViewController:picker animated:YES completion:nil]; + +} + + +%new +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { + + UIImage *chosenImage = info[UIImagePickerControllerEditedImage]; + NSData *imageData = UIImageJPEGRepresentation(chosenImage, 1.0); + [[TDTweakManager sharedInstance] setObject:imageData forKey:@"dockBackgroundImage" ID:BID]; + backgroundImage.image = chosenImage; + [picker dismissViewControllerAnimated:YES completion:nil]; +} + +%end + + +%hook SBFloatingDockPlatterView + +- (void)traitCollectionDidChange:(UITraitCollection *)old { + %orig(old); + [self performSelector:@selector(removeBlurView) withObject:nil afterDelay:0.0]; +} + + +%new +-(void)removeBlurView { + + UIView *backgroundView = [self valueForKey:@"backgroundView"]; + if([backgroundView respondsToSelector:@selector(_materialLayer)]) { + ((MTMaterialView *)backgroundView).weighting = 0; + } + if([backgroundView respondsToSelector:@selector(blurView)]) { + ((SBWallpaperEffectView *)backgroundView).blurView.hidden = YES; + } + +} + + +-(id)initWithFrame:(CGRect)arg1 { + + if (dockGesture == 0) { + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureFired)]; + tapGesture.numberOfTapsRequired = 2; + [self addGestureRecognizer:tapGesture]; + } else if (dockGesture == 1) { + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureFired)]; + tapGesture.numberOfTapsRequired = 3; + [self addGestureRecognizer:tapGesture]; + } else if (dockGesture == 2) { + UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureFired)]; + swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; + [self addGestureRecognizer:swipeLeft]; + } else if (dockGesture == 3) { + UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureFired)]; + swipeRight.direction = UISwipeGestureRecognizerDirectionRight; + [self addGestureRecognizer:swipeRight]; + } + + return floatingDockView = %orig; +} + + +-(void)layoutSubviews { + %orig; + + _UIBackdropView *backgroundView = [self valueForKey:@"_backgroundView"]; + if(![[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){13, 0, 0}]) { + backgroundView.backdropEffectView.hidden = YES; + } + + if(!dockView) { + + dockView = [[UIView alloc] init]; + dockView.clipsToBounds = true; + NSData *decodedData = [[TDTweakManager sharedInstance] objectForKey:@"dockBackgroundColour" ID:BID]; + UIColor *dockBGColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + + NSData *decodedData2 = [[TDTweakManager sharedInstance] objectForKey:@"dockBorderColour" ID:BID]; + UIColor *dockBorderColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData2]; + + if (decodedData) { + dockView.backgroundColor = dockBGColour; + } else { + dockView.backgroundColor = UIColor.whiteColor; + } + + dockView.layer.borderWidth = dockBorderWidth; + + if (decodedData2) { + + dockView.layer.borderColor = dockBorderColour.CGColor; + } else { + UIColor *defaultColour = UIColor.clearColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:defaultColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBorderColour" ID:BID]; + dockView.layer.borderColor = UIColor.clearColor.CGColor; + } + + [backgroundView addSubview:dockView]; + + NSData *dockBackgroundImage = [[TDTweakManager sharedInstance] objectForKey:@"dockBackgroundImage" ID:BID]; + backgroundImage = [[UIImageView alloc] init]; + if (dockBackgroundImage != nil) { + backgroundImage.image = [UIImage imageWithData:dockBackgroundImage]; + } + backgroundImage.contentMode = UIViewContentModeScaleAspectFill; + [dockView addSubview:backgroundImage]; + + } + + dockView.frame = backgroundView.bounds; + backgroundImage.frame = dockView.bounds; + +} + + +%new +-(void)tapGestureFired { + + +UIAlertController *settingsAlert = [UIAlertController alertControllerWithTitle:@"Dock Settings" message:@"" preferredStyle:UIAlertControllerStyleActionSheet]; + +UIAlertAction *backgroundAction = [UIAlertAction actionWithTitle:@"Background Colour" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + +backgroundImage.image = nil; +NSString *prefPath = @"/var/mobile/Library/Preferences/com.TitanD3v.ColourMyDockPrefs.plist"; +NSMutableDictionary *settings = [NSMutableDictionary dictionary]; +[settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; +[settings removeObjectForKey:@"dockBackgroundImage"]; +[settings writeToFile:prefPath atomically:YES]; + +colourPickerIndex = 0; +[self presentColourPickerVC]; +}]; + +UIAlertAction *borderAction = [UIAlertAction actionWithTitle:@"Border Colour" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { +colourPickerIndex = 1; +[self presentColourPickerVC]; +}]; + +UIAlertAction *imageAction = [UIAlertAction actionWithTitle:@"Background Image" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { +[self presentImagePickerVC]; +}]; + +UIAlertAction *resetBackgroundAction = [UIAlertAction actionWithTitle:@"Reset Background Colour" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + + UIColor *resetColour = UIColor.whiteColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:resetColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBackgroundColour" ID:BID]; + dockView.backgroundColor = resetColour; + +}]; + +UIAlertAction *resetBorderAction = [UIAlertAction actionWithTitle:@"Reset Border Colour" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + + UIColor *resetColour = UIColor.clearColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:resetColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBorderColour" ID:BID]; + dockView.layer.borderColor = resetColour.CGColor; + +}]; + +UIAlertAction *resetImageAction = [UIAlertAction actionWithTitle:@"Reset Background Image" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + +backgroundImage.image = nil; +NSString *prefPath = @"/var/mobile/Library/Preferences/com.TitanD3v.ColourMyDockPrefs.plist"; +NSMutableDictionary *settings = [NSMutableDictionary dictionary]; +[settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; +[settings removeObjectForKey:@"dockBackgroundImage"]; +[settings writeToFile:prefPath atomically:YES]; + +}]; + +UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { + +}]; + +[backgroundAction setValue:[[UIImage systemImageNamed:@"drop.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; +[borderAction setValue:[[UIImage systemImageNamed:@"drop.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; +[imageAction setValue:[[UIImage systemImageNamed:@"photo.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; +[resetBackgroundAction setValue:[[UIImage systemImageNamed:@"arrow.uturn.backward.circle.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; +[resetBorderAction setValue:[[UIImage systemImageNamed:@"arrow.uturn.backward.circle.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; +[resetImageAction setValue:[[UIImage systemImageNamed:@"arrow.uturn.backward.circle.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; + + +[settingsAlert addAction:backgroundAction]; +[settingsAlert addAction:borderAction]; +[settingsAlert addAction:imageAction]; +[settingsAlert addAction:resetBackgroundAction]; +[settingsAlert addAction:resetBorderAction]; +[settingsAlert addAction:resetImageAction]; +[settingsAlert addAction:cancelAction]; +[[%c(SBIconController) sharedInstance] presentViewController:settingsAlert animated:YES completion:nil]; + +} + + +%new +-(void)presentColourPickerVC { + + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + if (colourPickerIndex == 0) { + colourPickerVC.selectedColor = dockView.backgroundColor; + } else if (colourPickerIndex == 1) { + NSData *decodedData = [[TDTweakManager sharedInstance] objectForKey:@"dockBorderColour" ID:BID]; + UIColor *dockBorderColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + colourPickerVC.selectedColor = dockBorderColour; + } + [[%c(SBIconController) sharedInstance] presentViewController:colourPickerVC animated:YES completion:nil]; +} + + +%new +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + + UIColor *dockSelectedColour = viewController.selectedColor; + +if (colourPickerIndex == 0) { + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:dockSelectedColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBackgroundColour" ID:BID]; + dockView.backgroundColor = dockSelectedColour; +} else if (colourPickerIndex == 1) { + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:dockSelectedColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBorderColour" ID:BID]; + dockView.layer.borderColor = dockSelectedColour.CGColor; +} + + +} + + +%new +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + + UIColor *dockSelectedColour = viewController.selectedColor; + +if (colourPickerIndex == 0) { + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:dockSelectedColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBackgroundColour" ID:BID]; + dockView.backgroundColor = dockSelectedColour; +} else if (colourPickerIndex == 1) { + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:dockSelectedColour]; + [[TDTweakManager sharedInstance] setObject:encodedData forKey:@"dockBorderColour" ID:BID]; + dockView.layer.borderColor = dockSelectedColour.CGColor; +} + +} + + +%new +-(void)presentImagePickerVC { + + UIImagePickerController *picker = [[UIImagePickerController alloc] init]; + picker.delegate = self; + picker.allowsEditing = YES; + picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + + [[%c(SBIconController) sharedInstance] presentViewController:picker animated:YES completion:nil]; + +} + + +%new +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { + + UIImage *chosenImage = info[UIImagePickerControllerEditedImage]; + NSData *imageData = UIImageJPEGRepresentation(chosenImage, 1.0); + [[TDTweakManager sharedInstance] setObject:imageData forKey:@"dockBackgroundImage" ID:BID]; + backgroundImage.image = chosenImage; + [picker dismissViewControllerAnimated:YES completion:nil]; +} + +%end +%end + + + +void SettingsChanged() { + + toggleColourMyDock = [[TDTweakManager sharedInstance] boolForKey:@"toggleColourMyDock" defaultValue:NO ID:BID]; + dockBorderWidth = [[TDTweakManager sharedInstance] floatForKey:@"dockBorderWidth" defaultValue:1 ID:BID]; + dockGesture = [[TDTweakManager sharedInstance] intForKey:@"dockGesture" defaultValue:0 ID:BID]; + +} + +%ctor { + + NSString * path = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0]; + if ([path containsString:@"/Application"] || [path containsString:@"SpringBoard.app"]) { + + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)SettingsChanged, CFSTR("com.TitanD3v.ColourMyDockPrefs.settingschanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + SettingsChanged(); + + if (toggleColourMyDock) { + %init(DockHooks); + } + + } +} diff --git a/ColourMyDock/Tweak/Headers.h b/ColourMyDock/Tweak/Headers.h new file mode 100644 index 0000000..5acded7 --- /dev/null +++ b/ColourMyDock/Tweak/Headers.h @@ -0,0 +1,34 @@ +@interface SBDockView : UIView +-(void)presentColourPickerVC; +-(void)presentImagePickerVC; +@end + +@interface SBFloatingDockPlatterView : UIView +-(double)maximumContinuousCornerRadius; +-(void)presentColourPickerVC; +-(void)presentImagePickerVC; +@end + +@interface SBWallpaperEffectView : UIView +@property (nonatomic,retain) UIView * blurView; +@end + +@interface MTMaterialLayer : CALayer +@end + +@interface MTMaterialView : UIView +@property (getter=_materialLayer,nonatomic,readonly) MTMaterialLayer *materialLayer; +@property (assign, nonatomic) double weighting; +@end + +@interface _UIBackdropEffectView : UIView +@end + +@interface _UIBackdropView () +@property (nonatomic, retain) _UIBackdropEffectView * backdropEffectView; +-(double)_cornerRadius; +@end + +@interface SBIconController : UIViewController ++(id)sharedInstance; +@end \ No newline at end of file diff --git a/ColourMyDock/Tweak/Makefile b/ColourMyDock/Tweak/Makefile new file mode 100644 index 0000000..f160e5f --- /dev/null +++ b/ColourMyDock/Tweak/Makefile @@ -0,0 +1,13 @@ +TWEAK_NAME = ColourMyDock + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/ColourMyDock/control b/ColourMyDock/control new file mode 100644 index 0000000..4c83aeb --- /dev/null +++ b/ColourMyDock/control @@ -0,0 +1,11 @@ +Package: com.titand3v.colourmydock +Name: ColourMyDock +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal +Version: 2.0 +Section: Tweaks +Description: Colour your dock +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/colourmydock/index.html +Icon: https://titand3v.github.io/depictions/colourmydock/icon.png diff --git a/ColourMyDock/layout/DEBIAN/postinst b/ColourMyDock/layout/DEBIAN/postinst new file mode 100755 index 0000000..0731f49 --- /dev/null +++ b/ColourMyDock/layout/DEBIAN/postinst @@ -0,0 +1,8 @@ +echo "" +echo "" +echo "Thank you for installing ColourMyDock 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/Digitnetic/.DS_Store b/Digitnetic/.DS_Store new file mode 100644 index 0000000..3713f71 Binary files /dev/null and b/Digitnetic/.DS_Store differ diff --git a/Digitnetic/Makefile b/Digitnetic/Makefile new file mode 100644 index 0000000..8e489d3 --- /dev/null +++ b/Digitnetic/Makefile @@ -0,0 +1,17 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0:13.0 +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +FINALPACKAGE = 1 +DEBUG = 0 + +export CFLAGS = -include $(realpath NCCenter.h) + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak Prefs + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Digitnetic/NCCenter.h b/Digitnetic/NCCenter.h new file mode 100644 index 0000000..0b2feb1 --- /dev/null +++ b/Digitnetic/NCCenter.h @@ -0,0 +1,9 @@ +#import + +@interface NSDistributedNotificationCenter : NSNotificationCenter ++ (instancetype)defaultCenter; +-(void)postNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3 deliverImmediately:(BOOL)arg4 ; +- (void)postNotificationName:(NSString *)name object:(NSString *)object userInfo:(NSDictionary *)userInfo; +-(id)addObserverForName:(id)arg1 object:(id)arg2 queue:(id)arg3 usingBlock:(/*^block*/id)arg4 ; +-(void)addObserver:(id)arg1 selector:(SEL)arg2 name:(id)arg3 object:(id)arg4 ; +@end \ No newline at end of file diff --git a/Digitnetic/Prefs/DGTPrimraryListController.h b/Digitnetic/Prefs/DGTPrimraryListController.h new file mode 100644 index 0000000..ec81b50 --- /dev/null +++ b/Digitnetic/Prefs/DGTPrimraryListController.h @@ -0,0 +1,29 @@ +#import +#import + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1;; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + + +@interface DGTPrimraryListController : TDPrimraryController { + OBWelcomeController *onboardingController; + OBWelcomeController *updateController; +} + +@end diff --git a/Digitnetic/Prefs/DGTPrimraryListController.m b/Digitnetic/Prefs/DGTPrimraryListController.m new file mode 100644 index 0000000..abfb676 --- /dev/null +++ b/Digitnetic/Prefs/DGTPrimraryListController.m @@ -0,0 +1,122 @@ +#include "DGTPrimraryListController.h" + +@implementation DGTPrimraryListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Primrary" target:self]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[TDPrefsManager sharedInstance] initWithBundleID:@"com.TitanD3v.DigitneticPrefs" tweakName:@"Digitnetic" prefsBundle:@"DigitneticPrefs.bundle"]; + + [[TDPrefsManager sharedInstance] bannerTitle:@"Digitnetic" subtitle:@"Coded with 🤍" devName:@"TitanD3v" coverImagePath:@"/Assets/Banner/cover-image.png" showCoverImage:YES iconPath:@"" iconTint:YES]; + + [[TDPrefsManager sharedInstance] changelogPlistPath:@"/Assets/Changelog/changelog.plist" currentVersion:@"Version 1.1"]; + + [[TDPrefsManager sharedInstance] useAssetsFromLibrary:YES]; + +} + + +-(void)presentTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + onboardingController = [[OBWelcomeController alloc] initWithTitle:@"User Guide" detailText:@"A walk through tutorial how to use Digitnetic" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/DigitneticPrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]]; + + [onboardingController addBulletedListItemWithTitle:@"Your time" description:@"Please take a few minutes of your time to read through to get started." image:[UIImage systemImageNamed:@"timer"]]; + + [onboardingController addBulletedListItemWithTitle:@"Main page" description:@"On the main page, there's menu icon on the navigation bar it will present the drawer when tapped. You will find the social media details, changelog, backup/restore, tweak list, profile and crew list." image:[UIImage systemImageNamed:@"square.stack.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Report a bug" description:@"If you are experiencing a bug or any other issues, you can report a bug from this page below the close button, it will bring up the Bug Report page. You can select the categories, write description about a bug, attach a .txt file, photo, provide URL link for the pastebin or any pasteboard website also you can attach all of them if you want. Once you submit a bug report and our team will be in touch with you within 48 hours. If you haven't heard anything from us and please don't hesitate to get in touch with us through social media." image:[UIImage systemImageNamed:@"ant.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Enable Digitnetic" description:@"Enable Digitnetic then choose your prefered appearance." image:[UIImage systemImageNamed:@"1.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Colour" description:@"You can colour digitnetic if you don't want to use light or dark mode." image:[UIImage systemImageNamed:@"2.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Miscellaneous" description:@"You can set the calculator as primrary if you don't want it to show keypad first, change the corner radius and choose haptic feedback strength." image:[UIImage systemImageNamed:@"3.circle.fill"]]; + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [onboardingController.buttonTray addButton:dismissButton]; + + onboardingController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:onboardingController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [onboardingController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + onboardingController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [onboardingController.buttonTray addCaptionText:@"Thank you for installing Digitnetic"]; + + onboardingController.modalPresentationStyle = UIModalPresentationPageSheet; + onboardingController.modalInPresentation = YES; + [self presentViewController:onboardingController animated:YES completion:nil]; + + UIView *reportView = [[UIView alloc] init]; + reportView.backgroundColor = UIColor.clearColor; + [onboardingController.buttonTray addSubview:reportView]; + + reportView.translatesAutoresizingMaskIntoConstraints = NO; + [reportView.topAnchor constraintEqualToAnchor:dismissButton.bottomAnchor constant:10].active = YES; + [[reportView centerXAnchor] constraintEqualToAnchor:onboardingController.buttonTray.centerXAnchor].active = true; + [reportView.widthAnchor constraintEqualToConstant:140].active = YES; + [reportView.heightAnchor constraintEqualToConstant:40].active = YES; + + + UIImageView *bugImage = [[UIImageView alloc] init]; + bugImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + bugImage.tintColor = [[TDAppearance sharedInstance] tintColour]; + [reportView addSubview:bugImage]; + + bugImage.translatesAutoresizingMaskIntoConstraints = NO; + [bugImage.leadingAnchor constraintEqualToAnchor:reportView.leadingAnchor constant:10].active = YES; + [[bugImage centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + [bugImage.widthAnchor constraintEqualToConstant:30].active = YES; + [bugImage.heightAnchor constraintEqualToConstant:30].active = YES; + + + UILabel *reportLabel = [[UILabel alloc] init]; + reportLabel.text = @"Report a bug"; + reportLabel.textColor = [[TDAppearance sharedInstance] tintColour]; + reportLabel.textAlignment = NSTextAlignmentLeft; + [reportView addSubview:reportLabel]; + + reportLabel.translatesAutoresizingMaskIntoConstraints = NO; + [reportLabel.leadingAnchor constraintEqualToAnchor:bugImage.trailingAnchor constant:5].active = YES; + [[reportLabel centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + + [reportView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentReportBugVC)]]; + +} + + +-(void)dismissTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentReportBugVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; + + TDReportBugViewController *bugVC = [[TDReportBugViewController alloc] init]; + bugVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [self presentViewController:bugVC animated:YES completion:nil]; +} + +@end diff --git a/Digitnetic/Prefs/DGTSecondaryListController.h b/Digitnetic/Prefs/DGTSecondaryListController.h new file mode 100644 index 0000000..db55ede --- /dev/null +++ b/Digitnetic/Prefs/DGTSecondaryListController.h @@ -0,0 +1,12 @@ +#import +#import + +@interface DGTAppearanceController : TDSecondaryController +@end + +@interface DGTColourController : TDSecondaryController +@end + +@interface DGTMiscellaneousController : TDSecondaryController +@end + diff --git a/Digitnetic/Prefs/DGTSecondaryListController.m b/Digitnetic/Prefs/DGTSecondaryListController.m new file mode 100644 index 0000000..ac68a48 --- /dev/null +++ b/Digitnetic/Prefs/DGTSecondaryListController.m @@ -0,0 +1,39 @@ +#include "DGTSecondaryListController.h" + +@implementation DGTAppearanceController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Appearance" target:self]; + } + + return _specifiers; +} + +@end + + +@implementation DGTColourController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Colour" target:self]; + } + + return _specifiers; +} + +@end + + +@implementation DGTMiscellaneousController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Miscellaneous" target:self]; + } + + return _specifiers; +} + +@end diff --git a/Digitnetic/Prefs/Makefile b/Digitnetic/Prefs/Makefile new file mode 100644 index 0000000..85dd5ce --- /dev/null +++ b/Digitnetic/Prefs/Makefile @@ -0,0 +1,15 @@ +BUNDLE_NAME = DigitneticPrefs + +$(BUNDLE_NAME)_FILES = $(wildcard *.m Purchase/*.m) +$(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles +$(BUNDLE_NAME)_FRAMEWORKS = UIKit +$(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences OnBoardingKit +$(BUNDLE_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(BUNDLE_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/bundle.mk + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) + $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/DigitneticPrefs.plist$(ECHO_END) diff --git a/Digitnetic/Prefs/Resources/Appearance.plist b/Digitnetic/Prefs/Resources/Appearance.plist new file mode 100644 index 0000000..6cdfe86 --- /dev/null +++ b/Digitnetic/Prefs/Resources/Appearance.plist @@ -0,0 +1,184 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Appearance + + + + cellClass + TDAppearanceCell + key + digitneticAppearance + default + digitneticLight + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + options + + light + + appearanceOption + digitneticLight + title + Light + imageName + appearance-light + arrangement + 1 + + dark + + appearanceOption + digitneticDark + title + Dark + imageName + appearance-dark + arrangement + 2 + + dynamic + + appearanceOption + digitneticDynamic + title + Dynamic + imageName + appearance-dynamic + arrangement + 2 + + + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Keypad Wallpaper + + + + cellClass + TDEnableCell + default + + key + toggleKeypadBackgroundImage + disabledTitle + Disable Wallpaper + enabledTitle + Enable Wallpaper + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDImagePickerCell + title + Choose + subtitle + Wallpaper Image + action + chooseImage + key + keypadBackgroundImage + usesJPEG + + compressionQuality + 1.0 + iconName + photo + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Calculator Wallpaper + + + + cellClass + TDEnableCell + default + + key + toggleCalculatorBackgroundImage + disabledTitle + Disable Wallpaper + enabledTitle + Enable Wallpaper + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDImagePickerCell + title + Choose + subtitle + Wallpaper Image + action + chooseImage + key + calculatorBackgroundImage + usesJPEG + + compressionQuality + 1.0 + iconName + photo + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + title + + + diff --git a/Digitnetic/Prefs/Resources/Assets/Banner/banner-icon.png b/Digitnetic/Prefs/Resources/Assets/Banner/banner-icon.png new file mode 100644 index 0000000..11acc4c Binary files /dev/null and b/Digitnetic/Prefs/Resources/Assets/Banner/banner-icon.png differ diff --git a/Digitnetic/Prefs/Resources/Assets/Banner/cover-image.png b/Digitnetic/Prefs/Resources/Assets/Banner/cover-image.png new file mode 100644 index 0000000..67f24fc Binary files /dev/null and b/Digitnetic/Prefs/Resources/Assets/Banner/cover-image.png differ diff --git a/Digitnetic/Prefs/Resources/Assets/Cell/prefs-icon@2x.png b/Digitnetic/Prefs/Resources/Assets/Cell/prefs-icon@2x.png new file mode 100644 index 0000000..2c91220 Binary files /dev/null and b/Digitnetic/Prefs/Resources/Assets/Cell/prefs-icon@2x.png differ diff --git a/Digitnetic/Prefs/Resources/Assets/Cell/prefs-icon@3x.png b/Digitnetic/Prefs/Resources/Assets/Cell/prefs-icon@3x.png new file mode 100644 index 0000000..f95ceaa Binary files /dev/null and b/Digitnetic/Prefs/Resources/Assets/Cell/prefs-icon@3x.png differ diff --git a/Digitnetic/Prefs/Resources/Assets/Changelog/changelog.plist b/Digitnetic/Prefs/Resources/Assets/Changelog/changelog.plist new file mode 100644 index 0000000..58b925f --- /dev/null +++ b/Digitnetic/Prefs/Resources/Assets/Changelog/changelog.plist @@ -0,0 +1,41 @@ + + + + + + + Date + 22nd June 2021 + Version + v1.0 + ChangelogDescription + + Added highlighting button when pressed on phone leypad or calculator buttons + Added activator gesture to show or hide Digitnetic + Fixed decimal for calculator isn't showing the result when adding decimal. + + updateCategories + + 3 + 3 + 1 + + + + + Date + 19th June 2021 + Version + v1.0 + ChangelogDescription + + Initial Release... + + updateCategories + + 0 + + + + + diff --git a/Digitnetic/Prefs/Resources/Assets/Payment/ss1.png b/Digitnetic/Prefs/Resources/Assets/Payment/ss1.png new file mode 100644 index 0000000..957a389 Binary files /dev/null and b/Digitnetic/Prefs/Resources/Assets/Payment/ss1.png differ diff --git a/Digitnetic/Prefs/Resources/Assets/Payment/ss2.png b/Digitnetic/Prefs/Resources/Assets/Payment/ss2.png new file mode 100644 index 0000000..1b903bd Binary files /dev/null and b/Digitnetic/Prefs/Resources/Assets/Payment/ss2.png differ diff --git a/Digitnetic/Prefs/Resources/Assets/Payment/ss3.png b/Digitnetic/Prefs/Resources/Assets/Payment/ss3.png new file mode 100644 index 0000000..50564b6 Binary files /dev/null and b/Digitnetic/Prefs/Resources/Assets/Payment/ss3.png differ diff --git a/Digitnetic/Prefs/Resources/Assets/Payment/ss4.png b/Digitnetic/Prefs/Resources/Assets/Payment/ss4.png new file mode 100644 index 0000000..b8adebb Binary files /dev/null and b/Digitnetic/Prefs/Resources/Assets/Payment/ss4.png differ diff --git a/Digitnetic/Prefs/Resources/Assets/Payment/ss5.png b/Digitnetic/Prefs/Resources/Assets/Payment/ss5.png new file mode 100644 index 0000000..dee0e59 Binary files /dev/null and b/Digitnetic/Prefs/Resources/Assets/Payment/ss5.png differ diff --git a/Digitnetic/Prefs/Resources/Assets/Payment/ss6.png b/Digitnetic/Prefs/Resources/Assets/Payment/ss6.png new file mode 100644 index 0000000..ed047d6 Binary files /dev/null and b/Digitnetic/Prefs/Resources/Assets/Payment/ss6.png differ diff --git a/Digitnetic/Prefs/Resources/Assets/Payment/ss7.png b/Digitnetic/Prefs/Resources/Assets/Payment/ss7.png new file mode 100644 index 0000000..c1a349e Binary files /dev/null and b/Digitnetic/Prefs/Resources/Assets/Payment/ss7.png differ diff --git a/Digitnetic/Prefs/Resources/Colour.plist b/Digitnetic/Prefs/Resources/Colour.plist new file mode 100644 index 0000000..81e5428 --- /dev/null +++ b/Digitnetic/Prefs/Resources/Colour.plist @@ -0,0 +1,391 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Calculator Colours + + + + cellClass + TDEnableCell + default + + key + toggleCalculatorColour + disabledTitle + Disable Colour + enabledTitle + Enable Colour + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Background + subtitle + Colour + default + FFFFFF + key + calculatorBackgroundColour + iconName + colour + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Number KeyPad + subtitle + Colour + default + FFFFFF + key + calculatorButtonColour + iconName + colour + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Arithmetic KeyPad + subtitle + Colour + default + FFFFFF + key + calculatorArithmeticColour + iconName + colour + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Delete KeyPad + subtitle + Colour + default + FFFFFF + key + calculatorDeleteColour + iconName + colour + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Font + subtitle + Colour + default + FFFFFF + key + calculatorFontColour + iconName + colour + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + + + + + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Keypad Colours + + + + cellClass + TDEnableCell + default + + key + toggleKeypadColour + disabledTitle + Disable Colour + enabledTitle + Enable Colour + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Background + subtitle + Colour + default + FFFFFF + key + keypadBackgroundColour + iconName + colour + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Number Keypad + subtitle + Colour + default + FFFFFF + key + keypadButtonColour + iconName + colour + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Call Button + subtitle + Colour + default + FFFFFF + key + keypadCallButtonColour + iconName + colour + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Call Icon + subtitle + Colour + default + FFFFFF + key + keypadCallIconColour + iconName + colour + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Delete Button + subtitle + Colour + default + FFFFFF + key + keypadDeleteColour + iconName + colour + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Font + subtitle + Colour + default + FFFFFF + key + keypadFontColour + iconName + colour + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + title + + + diff --git a/Digitnetic/Prefs/Resources/Info.plist b/Digitnetic/Prefs/Resources/Info.plist new file mode 100644 index 0000000..0347aa4 --- /dev/null +++ b/Digitnetic/Prefs/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + DigitneticPrefs + CFBundleIdentifier + com.titand3v.digitneticprefs + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + DGTPrimraryListController + + diff --git a/Digitnetic/Prefs/Resources/Miscellaneous.plist b/Digitnetic/Prefs/Resources/Miscellaneous.plist new file mode 100644 index 0000000..7aa2546 --- /dev/null +++ b/Digitnetic/Prefs/Resources/Miscellaneous.plist @@ -0,0 +1,147 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Haptic + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleHaptic + title + Enable + subtitle + Haptic Feedback + iconName + switch + showTips + + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + hapticStrength + default + 0 + validTitles + + Light + Medium + Heavy + + validValues + + 0 + 1 + 2 + + title + Type + showTips + + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Primrary + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleCalculatorAsPrimrary + title + Set Calculator + subtitle + As primrary + customIcon + + iconTint + + iconName + switch + showTips + + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Corner Radius + + + + cell + PSSliderCell + cellClass + TDSliderCell + title + Digitnetic Corner Radius + default + 15 + key + cornerRadius + min + 1 + max + 30 + showValue + + isSegmented + + showTips + + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + title + + + diff --git a/Digitnetic/Prefs/Resources/Primrary.plist b/Digitnetic/Prefs/Resources/Primrary.plist new file mode 100644 index 0000000..ead96e1 --- /dev/null +++ b/Digitnetic/Prefs/Resources/Primrary.plist @@ -0,0 +1,82 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable + + + + cellClass + TDEnableCell + default + + key + toggleDigitnetic + disabledTitle + Disable Digitnetic + enabledTitle + Enable Digitnetic + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + disabledIconPath + Assets/example-icon.png + enabledIconPath + Assets/example-icon.png + defaults + com.TitanD3v.DigitneticPrefs + PostNotification + com.TitanD3v.DigitneticPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Categories + + + + cellClass + TDGridCell + leftTitle + Appearance + leftIconName + appearance + leftClass + DGTAppearanceController + middleTitle + Colour + middleIconName + colour + middleClass + DGTColourController + rightTitle + Miscellaneous + rightIconName + misc + rightClass + DGTMiscellaneousController + classID + primrary + + + + title + + + diff --git a/Digitnetic/Prefs/entry.plist b/Digitnetic/Prefs/entry.plist new file mode 100644 index 0000000..bc42ddf --- /dev/null +++ b/Digitnetic/Prefs/entry.plist @@ -0,0 +1,21 @@ + + + + + entry + + bundle + DigitneticPrefs + cell + PSLinkCell + detail + DGTPrimraryListController + icon + Assets/Cell/prefs-icon.png + isController + + label + Digitnetic + + + diff --git a/Digitnetic/Tweak/DIGITNETIC/CalculatorView.h b/Digitnetic/Tweak/DIGITNETIC/CalculatorView.h new file mode 100644 index 0000000..51c580b --- /dev/null +++ b/Digitnetic/Tweak/DIGITNETIC/CalculatorView.h @@ -0,0 +1,30 @@ +#import +#import "GlobalPreferences.h" + +@interface CalculatorView : UIView + +@property (nonatomic, strong) UIImageView *backgroundImage; +@property (nonatomic, strong) UIButton *keypadOne; +@property (nonatomic, strong) UIButton *keypadTwo; +@property (nonatomic, strong) UIButton *keypadThree; +@property (nonatomic, strong) UIButton *keypadFour; +@property (nonatomic, strong) UIButton *keypadFive; +@property (nonatomic, strong) UIButton *keypadSix; +@property (nonatomic, strong) UIButton *keypadSeven; +@property (nonatomic, strong) UIButton *keypadEight; +@property (nonatomic, strong) UIButton *keypadNine; +@property (nonatomic, strong) UIButton *keypadPunctuation; +@property (nonatomic, strong) UIButton *keypadZero; +@property (nonatomic, strong) UIButton *keypadDelete; +@property (nonatomic, strong) UIButton *keypadPlus; +@property (nonatomic, strong) UIButton *keypadTimes; +@property (nonatomic, strong) UIButton *keypadMinus; +@property (nonatomic, strong) UIButton *keypadDivide; +@property (nonatomic, strong) UIButton *keypadTotal; +@property (nonatomic, strong) UIButton *keypadClearall; +@property (strong, nonatomic) UIView *fieldView; +@property (strong, nonatomic) UILabel *calculatorLabel; +@property (strong, nonatomic) UILabel *resultLabel; + +@end + diff --git a/Digitnetic/Tweak/DIGITNETIC/CalculatorView.m b/Digitnetic/Tweak/DIGITNETIC/CalculatorView.m new file mode 100644 index 0000000..6095610 --- /dev/null +++ b/Digitnetic/Tweak/DIGITNETIC/CalculatorView.m @@ -0,0 +1,766 @@ +#import "CalculatorView.h" + +@implementation CalculatorView + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + loadPrefs(); + + if (toggleCalculatorBackgroundImage) { + self.backgroundImage = [[UIImageView alloc] initWithFrame:self.bounds]; + self.backgroundImage.image = [UIImage imageWithData:calculatorBackgroundImage]; + self.backgroundImage.contentMode = UIViewContentModeScaleAspectFill; + [self addSubview:self.backgroundImage]; + } + + + self.keypadZero = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadZero setTitle:@"0" forState:UIControlStateNormal]; + self.keypadZero.layer.cornerRadius = 20; + self.keypadZero.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadZero.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadZero addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadZero]; + + [self.keypadZero size:CGSizeMake(115, 40)]; + [self.keypadZero leading:self.leadingAnchor padding:5]; + [self.keypadZero bottom:self.bottomAnchor padding:-5]; + + + self.keypadPunctuation = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadPunctuation setTitle:@"." forState:UIControlStateNormal]; + self.keypadPunctuation.layer.cornerRadius = 20; + self.keypadPunctuation.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadPunctuation.titleLabel.font = [UIFont boldSystemFontOfSize:24]; + [self.keypadPunctuation addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadPunctuation]; + + [self.keypadPunctuation size:CGSizeMake(55, 40)]; + [self.keypadPunctuation leading:self.keypadZero.trailingAnchor padding:5]; + [self.keypadPunctuation bottom:self.bottomAnchor padding:-5]; + + + self.keypadTotal = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadTotal setTitle:@"=" forState:UIControlStateNormal]; + self.keypadTotal.layer.cornerRadius = 20; + self.keypadTotal.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadTotal.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadTotal addTarget:self action:@selector(resultPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadTotal]; + + [self.keypadTotal size:CGSizeMake(55, 40)]; + [self.keypadTotal leading:self.keypadPunctuation.trailingAnchor padding:5]; + [self.keypadTotal bottom:self.bottomAnchor padding:-5]; + + + self.keypadOne = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadOne setTitle:@"1" forState:UIControlStateNormal]; + self.keypadOne.layer.cornerRadius = 20; + self.keypadOne.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadOne.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadOne addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadOne]; + + [self.keypadOne size:CGSizeMake(55, 40)]; + [self.keypadOne leading:self.leadingAnchor padding:5]; + [self.keypadOne bottom:self.keypadZero.topAnchor padding:-5]; + + + self.keypadTwo = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadTwo setTitle:@"2" forState:UIControlStateNormal]; + self.keypadTwo.layer.cornerRadius = 20; + self.keypadTwo.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadTwo.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadTwo addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadTwo]; + + [self.keypadTwo size:CGSizeMake(55, 40)]; + [self.keypadTwo leading:self.keypadOne.trailingAnchor padding:5]; + [self.keypadTwo bottom:self.keypadZero.topAnchor padding:-5]; + + + self.keypadThree = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadThree setTitle:@"3" forState:UIControlStateNormal]; + self.keypadThree.layer.cornerRadius = 20; + self.keypadThree.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadThree.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadThree addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadThree]; + + [self.keypadThree size:CGSizeMake(55, 40)]; + [self.keypadThree leading:self.keypadTwo.trailingAnchor padding:5]; + [self.keypadThree bottom:self.keypadPunctuation.topAnchor padding:-5]; + + + self.keypadPlus = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadPlus setTitle:@"+" forState:UIControlStateNormal]; + self.keypadPlus.layer.cornerRadius = 20; + self.keypadPlus.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadPlus.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadPlus addTarget:self action:@selector(arithmeticPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadPlus]; + + [self.keypadPlus size:CGSizeMake(55, 40)]; + [self.keypadPlus leading:self.keypadThree.trailingAnchor padding:5]; + [self.keypadPlus bottom:self.keypadTotal.topAnchor padding:-5]; + + + self.keypadFour = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadFour setTitle:@"4" forState:UIControlStateNormal]; + self.keypadFour.layer.cornerRadius = 20; + self.keypadFour.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadFour.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadFour addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadFour]; + + [self.keypadFour size:CGSizeMake(55, 40)]; + [self.keypadFour leading:self.leadingAnchor padding:5]; + [self.keypadFour bottom:self.keypadOne.topAnchor padding:-5]; + + + self.keypadFive = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadFive setTitle:@"5" forState:UIControlStateNormal]; + self.keypadFive.layer.cornerRadius = 20; + self.keypadFive.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadFive.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadFive addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadFive]; + + [self.keypadFive size:CGSizeMake(55, 40)]; + [self.keypadFive leading:self.keypadFour.trailingAnchor padding:5]; + [self.keypadFive bottom:self.keypadTwo.topAnchor padding:-5]; + + // Six button + self.keypadSix = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadSix setTitle:@"6" forState:UIControlStateNormal]; + self.keypadSix.layer.cornerRadius = 20; + self.keypadSix.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadSix.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadSix addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadSix]; + + [self.keypadSix size:CGSizeMake(55, 40)]; + [self.keypadSix leading:self.keypadFive.trailingAnchor padding:5]; + [self.keypadSix bottom:self.keypadThree.topAnchor padding:-5]; + + + self.keypadMinus = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadMinus setTitle:@"-" forState:UIControlStateNormal]; + self.keypadMinus.layer.cornerRadius = 20; + self.keypadMinus.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadMinus.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadMinus addTarget:self action:@selector(arithmeticPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadMinus]; + + [self.keypadMinus size:CGSizeMake(55, 40)]; + [self.keypadMinus leading:self.keypadSix.trailingAnchor padding:5]; + [self.keypadMinus bottom:self.keypadPlus.topAnchor padding:-5]; + + + self.keypadSeven = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadSeven setTitle:@"7" forState:UIControlStateNormal]; + self.keypadSeven.layer.cornerRadius = 20; + self.keypadSeven.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadSeven.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadSeven addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadSeven]; + + [self.keypadSeven size:CGSizeMake(55, 40)]; + [self.keypadSeven leading:self.leadingAnchor padding:5]; + [self.keypadSeven bottom:self.keypadFour.topAnchor padding:-5]; + + + self.keypadEight = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadEight setTitle:@"8" forState:UIControlStateNormal]; + self.keypadEight.layer.cornerRadius = 20; + self.keypadEight.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadEight.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadEight addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadEight]; + + [self.keypadEight size:CGSizeMake(55, 40)]; + [self.keypadEight leading:self.keypadSeven.trailingAnchor padding:5]; + [self.keypadEight bottom:self.keypadFive.topAnchor padding:-5]; + + + self.keypadNine = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadNine setTitle:@"9" forState:UIControlStateNormal]; + self.keypadNine.layer.cornerRadius = 20; + self.keypadNine.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadNine.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadNine addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadNine]; + + [self.keypadNine size:CGSizeMake(55, 40)]; + [self.keypadNine leading:self.keypadEight.trailingAnchor padding:5]; + [self.keypadNine bottom:self.keypadSix.topAnchor padding:-5]; + + + self.keypadTimes = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadTimes setTitle:@"x" forState:UIControlStateNormal]; + self.keypadTimes.layer.cornerRadius = 20; + self.keypadTimes.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadTimes.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadTimes addTarget:self action:@selector(arithmeticPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadTimes]; + + [self.keypadTimes size:CGSizeMake(55, 40)]; + [self.keypadTimes leading:self.keypadNine.trailingAnchor padding:5]; + [self.keypadTimes bottom:self.keypadMinus.topAnchor padding:-5]; + + + self.keypadClearall = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadClearall setTitle:@"AC" forState:UIControlStateNormal]; + self.keypadClearall.layer.cornerRadius = 20; + self.keypadClearall.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadClearall.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadClearall addTarget:self action:@selector(clearallPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadClearall]; + + [self.keypadClearall size:CGSizeMake(115, 40)]; + [self.keypadClearall leading:self.leadingAnchor padding:5]; + [self.keypadClearall bottom:self.keypadSeven.topAnchor padding:-5]; + + + self.keypadDelete = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadDelete setTitle:@"<" forState:UIControlStateNormal]; + self.keypadDelete.layer.cornerRadius = 20; + self.keypadDelete.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadDelete.titleLabel.font = [UIFont boldSystemFontOfSize:22]; + [self.keypadDelete addTarget:self action:@selector(deletePressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadDelete]; + + [self.keypadDelete size:CGSizeMake(55, 40)]; + [self.keypadDelete leading:self.keypadClearall.trailingAnchor padding:5]; + [self.keypadDelete bottom:self.keypadEight.topAnchor padding:-5]; + + + self.keypadDivide = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadDivide setTitle:@"÷" forState:UIControlStateNormal]; + self.keypadDivide.layer.cornerRadius = 20; + self.keypadDivide.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadDivide.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadDivide addTarget:self action:@selector(arithmeticPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadDivide]; + + [self.keypadDivide size:CGSizeMake(55, 40)]; + [self.keypadDivide x:self.keypadTimes.centerXAnchor]; + [self.keypadDivide bottom:self.keypadTimes.topAnchor padding:-5]; + + + self.fieldView = [[UIView alloc] init]; + self.fieldView.backgroundColor = UIColor.clearColor; + [self addSubview:self.fieldView]; + + [self.fieldView top:self.topAnchor padding:0]; + [self.fieldView leading:self.leadingAnchor padding:0]; + [self.fieldView trailing:self.trailingAnchor padding:0]; + [self.fieldView bottom:self.keypadClearall.topAnchor padding:0]; + + + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(copyResultPressed)]; + tapGesture.numberOfTapsRequired = 2; + [self.fieldView addGestureRecognizer:tapGesture]; + + + self.calculatorLabel = [[UILabel alloc] init]; + self.calculatorLabel.backgroundColor = [UIColor clearColor]; + self.calculatorLabel.userInteractionEnabled = NO; + self.calculatorLabel.text = @""; + self.calculatorLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold]; + self.calculatorLabel.textAlignment = NSTextAlignmentRight; + [self addSubview:self.calculatorLabel]; + + [self.calculatorLabel top:self.topAnchor padding:10]; + [self.calculatorLabel trailing:self.trailingAnchor padding:-10]; + + + self.resultLabel = [[UILabel alloc] init]; + self.resultLabel.backgroundColor = [UIColor clearColor]; + self.resultLabel.userInteractionEnabled = NO; + self.resultLabel.text = @""; + self.resultLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold]; + self.resultLabel.textAlignment = NSTextAlignmentRight; + [self addSubview:self.resultLabel]; + + [self.resultLabel bottom:self.keypadDivide.topAnchor padding:-10]; + [self.resultLabel trailing:self.trailingAnchor padding:-10]; + + + if (!toggleCalculatorColour) { + + self.keypadTotal.backgroundColor = [UIColor systemOrangeColor]; + self.keypadPlus.backgroundColor = [UIColor systemOrangeColor]; + self.keypadMinus.backgroundColor = [UIColor systemOrangeColor]; + self.keypadTimes.backgroundColor = [UIColor systemOrangeColor]; + self.keypadDelete.backgroundColor = [UIColor systemRedColor]; + self.keypadDivide.backgroundColor = [UIColor systemOrangeColor]; + + + if ([digitneticAppearance isEqualToString:@"digitneticLight"]) { + + self.backgroundColor = UIColor.whiteColor; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadPunctuation.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadClearall.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + + [self.keypadZero setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadPunctuation setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTotal setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadPlus setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadMinus setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTimes setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadClearall setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadDelete setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadDivide setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + self.calculatorLabel.textColor = [UIColor blackColor]; + self.resultLabel.textColor = [UIColor blackColor]; + + } else if ([digitneticAppearance isEqualToString:@"digitneticDark"]) { + + self.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.12 alpha: 1.00]; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadPunctuation.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadClearall.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + + [self.keypadZero setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadPunctuation setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTotal setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadPlus setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadMinus setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTimes setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadClearall setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadDelete setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadDivide setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + self.calculatorLabel.textColor = [UIColor whiteColor]; + self.resultLabel.textColor = [UIColor whiteColor]; + + } else if ([digitneticAppearance isEqualToString:@"digitneticDynamic"]) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + + self.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.12 alpha: 1.00]; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadPunctuation.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadClearall.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + + [self.keypadZero setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadPunctuation setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTotal setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadPlus setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadMinus setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTimes setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadClearall setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadDelete setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadDivide setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + self.calculatorLabel.textColor = [UIColor whiteColor]; + self.resultLabel.textColor = [UIColor whiteColor]; + + } else { + + self.backgroundColor = UIColor.whiteColor; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadPunctuation.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadClearall.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + + [self.keypadZero setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadPunctuation setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTotal setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadPlus setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadMinus setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTimes setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadClearall setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadDelete setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadDivide setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + self.calculatorLabel.textColor = [UIColor blackColor]; + self.resultLabel.textColor = [UIColor blackColor]; + + } + + } + + } else { + + self.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorBackgroundColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadZero.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadPunctuation.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadOne.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadTwo.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadThree.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadFour.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadFive.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadSix.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadSeven.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadEight.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadNine.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadClearall.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadTotal.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorArithmeticColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadPlus.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorArithmeticColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadMinus.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorArithmeticColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadTimes.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorArithmeticColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadDelete.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorDeleteColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadDivide.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorArithmeticColour" defaultValue:@"FFFFFF" ID:BID]; + + [self.keypadZero setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadPunctuation setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadTotal setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadPlus setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadMinus setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadTimes setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadClearall setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadDelete setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadDivide setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + self.calculatorLabel.textColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID]; + self.resultLabel.textColor = [[TDTweakManager sharedInstance] colourForKey:@"calculatorFontColour" defaultValue:@"FFFFFF" ID:BID]; + + } + + } + return self; +} + + +- (void)arithmeticPressed:(UIButton *)sender { + + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^ { + sender.alpha = 0.4; + } + completion:^(BOOL finished) { + sender.alpha = 1.0; + }]; + + [self invokeHapticFeedback]; + + if(self.calculatorLabel.text.length == 0){ + return; + } + + NSString *mul = @"x"; + NSString *div = @"/"; + + + if ([sender.titleLabel.text isEqualToString:mul] || [sender.titleLabel.text isEqualToString:div]) { + + NSString *expression = [NSString stringWithFormat:@"(%@)%@",self.calculatorLabel.text,sender.titleLabel.text]; + self.calculatorLabel.text = expression; + + } else { + + NSString *expression = [NSString stringWithFormat:@"%@%@",self.calculatorLabel.text,sender.titleLabel.text]; + self.calculatorLabel.text = expression; + } + + self.resultLabel.text = @""; + +} + + +- (void)resultPressed:(UIButton *)sender { + + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^ { + sender.alpha = 0.4; + } + completion:^(BOOL finished) { + sender.alpha = 1.0; + }]; + + [self invokeHapticFeedback]; + + if(self.calculatorLabel.text.length == 0){ + return; + } + + @try { + + NSString *numericExpression = [NSString stringWithFormat:@"%@", self.calculatorLabel.text]; + + numericExpression = [numericExpression stringByReplacingOccurrencesOfString:@"x" withString:@"*"]; + + numericExpression = [numericExpression stringByReplacingOccurrencesOfString:@"÷" withString:@"/"]; + + NSExpression *expression = [NSExpression expressionWithFormat:numericExpression]; + + NSNumber *result = [expression expressionValueWithObject:nil context:nil]; + + NSLog(@"Total result = %@", [NSString stringWithFormat:@"%@", result]); + + self.resultLabel.text = [NSString stringWithFormat:@"= %@", result]; + + } @catch (NSException *exception) { + NSLog(@"%@", exception.reason); + } @finally { + + } + + +} + + +- (void)deletePressed:(UIButton *)sender { + + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^ { + sender.alpha = 0.4; + } + completion:^(BOOL finished) { + sender.alpha = 1.0; + }]; + + [self invokeHapticFeedback]; + + if (self.calculatorLabel.text.length == 0) { + return; + } + + NSString *numericExpression = self.calculatorLabel.text; + + NSString *lastChar = [numericExpression substringFromIndex:[numericExpression length] - 1]; + + if([lastChar isEqualToString:@")"]){ + + NSString *Prefix = @"("; + NSString *Suffix = @")"; + NSRange needleRange = NSMakeRange(Prefix.length, numericExpression.length - Prefix.length - Suffix.length); + numericExpression = [numericExpression substringWithRange:needleRange]; + + } else { + numericExpression = [numericExpression substringToIndex:[numericExpression length]-1]; + } + + self.calculatorLabel.text = numericExpression; + self.resultLabel.text = @""; +} + + +- (void)clearallPressed:(UIButton *)sender { + + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^ { + sender.alpha = 0.4; + } + completion:^(BOOL finished) { + sender.alpha = 1.0; + }]; + + [self invokeHapticFeedback]; + self.resultLabel.text = @""; + self.calculatorLabel.text = @""; +} + + +- (void)keypadNumbersPressed:(UIButton *)sender { + + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^ { + sender.alpha = 0.4; + } + completion:^(BOOL finished) { + sender.alpha = 1.0; + }]; + + [self invokeHapticFeedback]; + + // if (self.calculatorLabel.text.length != 0) { + + // NSString *lastChar = [self.calculatorLabel.text substringFromIndex:[self.calculatorLabel.text length] - 1]; + + // if ([lastChar isEqualToString:@"."] && [sender.titleLabel.text isEqualToString:@"."]) { + // return; + // } + // } + + NSString *expression = [NSString stringWithFormat:@"%@%@", self.calculatorLabel.text, sender.titleLabel.text]; + + self.calculatorLabel.text = expression; + self.resultLabel.text = @""; + +} + + +- (void)traitCollectionDidChange:(UITraitCollection *) previousTraitCollection { + + if ([digitneticAppearance isEqualToString:@"digitneticDynamic"]) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + + self.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.12 alpha: 1.00]; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadPunctuation.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadClearall.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + + [self.keypadZero setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadPunctuation setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTotal setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadPlus setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadMinus setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTimes setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadClearall setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadDelete setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadDivide setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + self.calculatorLabel.textColor = [UIColor whiteColor]; + self.resultLabel.textColor = [UIColor whiteColor]; + + } else { + + self.backgroundColor = UIColor.whiteColor; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadPunctuation.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadClearall.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + + [self.keypadZero setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadPunctuation setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTotal setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadPlus setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadMinus setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTimes setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadClearall setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadDelete setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadDivide setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + self.calculatorLabel.textColor = [UIColor blackColor]; + self.resultLabel.textColor = [UIColor blackColor]; + + } + + } + +} + + +-(void)invokeHapticFeedback { + if (toggleHaptic) { + + if (hapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (hapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (hapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + + } +} + + +-(void)copyResultPressed { + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = self.resultLabel.text; +} + +@end diff --git a/Digitnetic/Tweak/DIGITNETIC/DialerView.h b/Digitnetic/Tweak/DIGITNETIC/DialerView.h new file mode 100644 index 0000000..40a49e7 --- /dev/null +++ b/Digitnetic/Tweak/DIGITNETIC/DialerView.h @@ -0,0 +1,27 @@ +#import +#import "GlobalPreferences.h" + +@interface DialerView : UIView + +@property (nonatomic, strong) UIImageView *backgroundImage; +@property (nonatomic, strong) UIButton *keypadCall; +@property (nonatomic, strong) UIImageView *phoneImage; +@property (nonatomic, strong) UIButton *keypadAsterisk; +@property (nonatomic, strong) UIButton *keypadZero; +@property (nonatomic, strong) UIButton *keypadHash; +@property (nonatomic, strong) UIButton *keypadDelete; +@property (nonatomic, strong) UIImageView *deleteImage; +@property (nonatomic, strong) UIButton *keypadOne; +@property (nonatomic, strong) UIButton *keypadTwo; +@property (nonatomic, strong) UIButton *keypadThree; +@property (nonatomic, strong) UIButton *keypadFour; +@property (nonatomic, strong) UIButton *keypadFive; +@property (nonatomic, strong) UIButton *keypadSix; +@property (nonatomic, strong) UIButton *keypadSeven; +@property (nonatomic, strong) UIButton *keypadEight; +@property (nonatomic, strong) UIButton *keypadNine; +@property (strong, nonatomic) UIView *fieldView; +@property (nonatomic, retain) UILabel *numberLabel; + +@end + diff --git a/Digitnetic/Tweak/DIGITNETIC/DialerView.m b/Digitnetic/Tweak/DIGITNETIC/DialerView.m new file mode 100644 index 0000000..1d27f2e --- /dev/null +++ b/Digitnetic/Tweak/DIGITNETIC/DialerView.m @@ -0,0 +1,594 @@ +#import "DialerView.h" + +@implementation DialerView + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + loadPrefs(); + + if (toggleKeypadBackgroundImage) { + self.backgroundImage = [[UIImageView alloc] initWithFrame:self.bounds]; + self.backgroundImage.image = [UIImage imageWithData:keypadBackgroundImage]; + self.backgroundImage.contentMode = UIViewContentModeScaleAspectFill; + [self addSubview:self.backgroundImage]; + } + + + self.keypadCall = [[UIButton alloc] initWithFrame:CGRectZero]; + self.keypadCall.layer.cornerRadius = 20; + [self.keypadCall addTarget:self action:@selector(callPressed) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadCall]; + + [self.keypadCall size:CGSizeMake(115, 40)]; + [self.keypadCall x:self.centerXAnchor]; + [self.keypadCall bottom:self.bottomAnchor padding:-5]; + + + self.phoneImage = [[UIImageView alloc] init]; + self.phoneImage.userInteractionEnabled = true; + self.phoneImage.image = [[UIImage systemImageNamed:@"phone.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.phoneImage.contentMode = UIViewContentModeScaleAspectFit; + [self.keypadCall addSubview:self.phoneImage]; + + [self.phoneImage size:CGSizeMake(30, 30)]; + [self.phoneImage x:self.keypadCall.centerXAnchor y:self.keypadCall.centerYAnchor]; + + [self.phoneImage addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(callPressed)]]; + + + self.keypadDelete = [[UIButton alloc] initWithFrame:CGRectZero]; + self.keypadDelete.backgroundColor = [UIColor clearColor]; + [self.keypadDelete addTarget:self action:@selector(deletePressed) forControlEvents:UIControlEventTouchUpInside]; + self.keypadDelete.hidden = YES; + [self addSubview:self.keypadDelete]; + + [self.keypadDelete leading:self.keypadCall.trailingAnchor padding:0]; + [self.keypadDelete trailing:self.trailingAnchor padding:0]; + [self.keypadDelete y:self.keypadCall.centerYAnchor]; + [self.keypadDelete height:40]; + + + self.deleteImage = [[UIImageView alloc] init]; + self.deleteImage.userInteractionEnabled = true; + self.deleteImage.image = [[UIImage systemImageNamed:@"delete.left.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.deleteImage.contentMode = UIViewContentModeScaleAspectFit; + [self.keypadDelete addSubview:self.deleteImage]; + + [self.deleteImage size:CGSizeMake(30, 30)]; + [self.deleteImage x:self.keypadDelete.centerXAnchor y:self.keypadDelete.centerYAnchor]; + + [self.deleteImage addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(deletePressed)]]; + + + self.keypadAsterisk = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadAsterisk setTitle:@"*" forState:UIControlStateNormal]; + self.keypadAsterisk.layer.cornerRadius = 22.5; + self.keypadAsterisk.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadAsterisk.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadAsterisk addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadAsterisk]; + + [self.keypadAsterisk size:CGSizeMake(45, 45)]; + [self.keypadAsterisk leading:self.leadingAnchor padding:30]; + [self.keypadAsterisk bottom:self.keypadCall.topAnchor padding:-7]; + + + self.keypadZero = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadZero setTitle:@"0" forState:UIControlStateNormal]; + self.keypadZero.layer.cornerRadius = 22.5; + self.keypadZero.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadZero.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadZero addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadZero]; + + [self.keypadZero size:CGSizeMake(45, 45)]; + [self.keypadZero x:self.centerXAnchor]; + [self.keypadZero bottom:self.keypadCall.topAnchor padding:-7]; + + + self.keypadHash = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadHash setTitle:@"#" forState:UIControlStateNormal]; + self.keypadHash.layer.cornerRadius = 22.5; + self.keypadHash.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadHash.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadHash addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadHash]; + + [self.keypadHash size:CGSizeMake(45, 45)]; + [self.keypadHash trailing:self.trailingAnchor padding:-30]; + [self.keypadHash bottom:self.keypadCall.topAnchor padding:-7]; + + + self.keypadSeven = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadSeven setTitle:@"7" forState:UIControlStateNormal]; + self.keypadSeven.layer.cornerRadius = 22.5; + self.keypadSeven.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadSeven.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadSeven addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadSeven]; + + [self.keypadSeven size:CGSizeMake(45, 45)]; + [self.keypadSeven leading:self.leadingAnchor padding:30]; + [self.keypadSeven bottom:self.keypadAsterisk.topAnchor padding:-4]; + + + self.keypadEight = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadEight setTitle:@"8" forState:UIControlStateNormal]; + self.keypadEight.layer.cornerRadius = 22.5; + self.keypadEight.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadEight.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadEight addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadEight]; + + [self.keypadEight size:CGSizeMake(45, 45)]; + [self.keypadEight x:self.keypadZero.centerXAnchor]; + [self.keypadEight bottom:self.keypadZero.topAnchor padding:-4]; + + + self.keypadNine = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadNine setTitle:@"9" forState:UIControlStateNormal]; + self.keypadNine.layer.cornerRadius = 22.5; + self.keypadNine.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadNine.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadNine addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadNine]; + + [self.keypadNine size:CGSizeMake(45, 45)]; + [self.keypadNine trailing:self.trailingAnchor padding:-30]; + [self.keypadNine bottom:self.keypadHash.topAnchor padding:-4]; + + + self.keypadFour = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadFour setTitle:@"4" forState:UIControlStateNormal]; + self.keypadFour.layer.cornerRadius = 22.5; + self.keypadFour.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadFour.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadFour addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadFour]; + + [self.keypadFour size:CGSizeMake(45, 45)]; + [self.keypadFour leading:self.leadingAnchor padding:30]; + [self.keypadFour bottom:self.keypadSeven.topAnchor padding:-4]; + + + self.keypadFive = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadFive setTitle:@"5" forState:UIControlStateNormal]; + self.keypadFive.layer.cornerRadius = 22.5; + self.keypadFive.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadFive.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadFive addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadFive]; + + [self.keypadFive size:CGSizeMake(45, 45)]; + [self.keypadFive x:self.centerXAnchor]; + [self.keypadFive bottom:self.keypadEight.topAnchor padding:-4]; + + + self.keypadSix = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadSix setTitle:@"6" forState:UIControlStateNormal]; + self.keypadSix.layer.cornerRadius = 22.5; + self.keypadSix.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadSix.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadSix addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadSix]; + + [self.keypadSix size:CGSizeMake(45, 45)]; + [self.keypadSix trailing:self.trailingAnchor padding:-30]; + [self.keypadSix bottom:self.keypadNine.topAnchor padding:-4]; + + + self.keypadOne = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadOne setTitle:@"1" forState:UIControlStateNormal]; + self.keypadOne.layer.cornerRadius = 22.5; + self.keypadOne.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadOne.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadOne addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadOne]; + + [self.keypadOne size:CGSizeMake(45, 45)]; + [self.keypadOne leading:self.leadingAnchor padding:30]; + [self.keypadOne bottom:self.keypadFour.topAnchor padding:-4]; + + + self.keypadTwo = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadTwo setTitle:@"2" forState:UIControlStateNormal]; + self.keypadTwo.layer.cornerRadius = 22.5; + self.keypadTwo.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadTwo.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadTwo addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadTwo]; + + [self.keypadTwo size:CGSizeMake(45, 45)]; + [self.keypadTwo x:self.centerXAnchor]; + [self.keypadTwo bottom:self.keypadFive.topAnchor padding:-4]; + + + self.keypadThree = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.keypadThree setTitle:@"3" forState:UIControlStateNormal]; + self.keypadThree.layer.cornerRadius = 22.5; + self.keypadThree.titleLabel.textAlignment = NSTextAlignmentCenter; + self.keypadThree.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + [self.keypadThree addTarget:self action:@selector(keypadNumbersPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:self.keypadThree]; + + [self.keypadThree size:CGSizeMake(45, 45)]; + [self.keypadThree trailing:self.trailingAnchor padding:-30]; + [self.keypadThree bottom:self.keypadSix.topAnchor padding:-4]; + + + self.fieldView = [[UIView alloc] init]; + self.fieldView.backgroundColor = UIColor.clearColor; + [self addSubview:self.fieldView]; + + [self.fieldView top:self.topAnchor padding:0]; + [self.fieldView leading:self.leadingAnchor padding:0]; + [self.fieldView trailing:self.trailingAnchor padding:0]; + [self.fieldView bottom:self.keypadOne.topAnchor padding:0]; + + + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pastePhoneNumber)]; + tapGesture.numberOfTapsRequired = 2; + [self.fieldView addGestureRecognizer:tapGesture]; + + + self.numberLabel = [[UILabel alloc] init]; + self.numberLabel.text = @""; + self.numberLabel.textAlignment = NSTextAlignmentCenter; + self.numberLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold]; + [self addSubview:self.numberLabel]; + + [self.numberLabel top:self.topAnchor padding:20]; + [self.numberLabel x:self.centerXAnchor]; + + if (!toggleKeypadColour) { + + self.keypadCall.backgroundColor = UIColor.systemGreenColor; + self.phoneImage.tintColor = UIColor.whiteColor; + self.deleteImage.tintColor = UIColor.systemRedColor; + + if ([digitneticAppearance isEqualToString:@"digitneticLight"]) { + + self.backgroundColor = UIColor.whiteColor; + self.keypadAsterisk.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadHash.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + + [self.keypadAsterisk setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadZero setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadHash setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + self.numberLabel.textColor = UIColor.blackColor; + + } else if ([digitneticAppearance isEqualToString:@"digitneticDark"]) { + + self.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.12 alpha: 1.00]; + self.keypadAsterisk.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadHash.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + + [self.keypadAsterisk setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadZero setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadHash setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + self.numberLabel.textColor = UIColor.whiteColor; + + } else if ([digitneticAppearance isEqualToString:@"digitneticDynamic"]) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + + self.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.12 alpha: 1.00]; + self.keypadAsterisk.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadHash.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + + [self.keypadAsterisk setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadZero setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadHash setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + self.numberLabel.textColor = UIColor.whiteColor; + + } else { + + self.backgroundColor = UIColor.whiteColor; + self.keypadAsterisk.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadHash.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + + [self.keypadAsterisk setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadZero setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadHash setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + self.numberLabel.textColor = UIColor.blackColor; + + } + + } + + } else { + + self.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadBackgroundColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadCall.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadCallButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.phoneImage.tintColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadCallIconColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadAsterisk.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadZero.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadHash.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadSeven.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadEight.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadNine.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadFour.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadFive.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadSix.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadOne.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadTwo.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + self.keypadThree.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadButtonColour" defaultValue:@"FFFFFF" ID:BID]; + + [self.keypadAsterisk setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadZero setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadHash setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID] forState:UIControlStateNormal]; + self.numberLabel.textColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadFontColour" defaultValue:@"FFFFFF" ID:BID]; + self.deleteImage.tintColor = [[TDTweakManager sharedInstance] colourForKey:@"keypadDeleteColour" defaultValue:@"FFFFFF" ID:BID]; + + } + + + } + return self; +} + + +- (void)keypadNumbersPressed:(UIButton *)sender { + + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^ { + sender.alpha = 0.4; + } + completion:^(BOOL finished) { + sender.alpha = 1.0; + }]; + + [self invokeHapticFeedback]; + + NSString *expression = [NSString stringWithFormat:@"%@%@", self.numberLabel.text, sender.titleLabel.text]; + + self.numberLabel.text = expression; + + if (self.numberLabel.text.length > 0) { + self.keypadDelete.hidden = NO; + } else { + self.keypadDelete.hidden = YES; + } + +} + + +- (void)deletePressed { + + [UIView animateWithDuration:0.1 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^ { + self.keypadDelete.alpha = 0.4; + } + completion:^(BOOL finished) { + self.keypadDelete.alpha = 1.0; + }]; + + [self invokeHapticFeedback]; + + if (self.numberLabel.text.length == 0) { + return; + } + + NSString *numericExpression = self.numberLabel.text; + numericExpression = [numericExpression substringToIndex:[numericExpression length]-1]; + self.numberLabel.text = numericExpression; + + if (self.numberLabel.text.length > 0) { + self.keypadDelete.hidden = NO; + } else { + self.keypadDelete.hidden = YES; + } +} + + +- (void)callPressed { + + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^ { + self.keypadCall.alpha = 0.4; + } + completion:^(BOOL finished) { + self.keypadCall.alpha = 1.0; + }]; + + [self invokeHapticFeedback]; + + NSString *phoneNumber = [NSString stringWithFormat:@"tel:%@", self.numberLabel.text]; + UIApplication *application = [UIApplication sharedApplication]; + [application openURL:[NSURL URLWithString:phoneNumber] options:@{} completionHandler:nil]; + + // NSURL *phoneNumber = [NSURL URLWithString:@"telprompt://13232222222"]; + // [[UIApplication sharedApplication] openURL:phoneNumber]; + + self.keypadDelete.hidden = YES; + self.numberLabel.text = @""; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"HideDigitneticNotification" object:self]; +} + + +-(void)pastePhoneNumber { + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + NSString *pasteNumber = pasteboard.string; + self.numberLabel.text = pasteNumber; + + if (self.numberLabel.text.length > 0) { + self.keypadDelete.hidden = NO; + } else { + self.keypadDelete.hidden = YES; + } + [self invokeHapticFeedback]; +} + + +- (void)traitCollectionDidChange:(UITraitCollection *) previousTraitCollection { + + if ([digitneticAppearance isEqualToString:@"digitneticDynamic"]) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + + self.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.12 alpha: 1.00]; + self.keypadAsterisk.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadHash.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + + [self.keypadAsterisk setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadZero setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadHash setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + self.numberLabel.textColor = UIColor.whiteColor; + + } else { + + self.backgroundColor = UIColor.whiteColor; + self.keypadAsterisk.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadZero.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadHash.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSeven.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadEight.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadNine.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFour.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadFive.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadSix.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadOne.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadTwo.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.keypadThree.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + + [self.keypadAsterisk setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadZero setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadThree setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadTwo setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadOne setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSix setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFive setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadFour setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadNine setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadEight setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadHash setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [self.keypadSeven setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + self.numberLabel.textColor = UIColor.blackColor; + + } + + } + +} + + +-(void)invokeHapticFeedback { + if (toggleHaptic) { + + if (hapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (hapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (hapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + + } +} + +@end diff --git a/Digitnetic/Tweak/DIGITNETIC/DigitneticFloatingView.h b/Digitnetic/Tweak/DIGITNETIC/DigitneticFloatingView.h new file mode 100644 index 0000000..7565e7b --- /dev/null +++ b/Digitnetic/Tweak/DIGITNETIC/DigitneticFloatingView.h @@ -0,0 +1,6 @@ +#import + +@interface DigitneticFloatingView : UIView +@property(nonatomic,assign,getter = isDragEnable) BOOL dragEnable; +@property(nonatomic,assign,getter = isAdsorbEnable) BOOL adsorbEnable; +@end diff --git a/Digitnetic/Tweak/DIGITNETIC/DigitneticFloatingView.m b/Digitnetic/Tweak/DIGITNETIC/DigitneticFloatingView.m new file mode 100644 index 0000000..d99e4e1 --- /dev/null +++ b/Digitnetic/Tweak/DIGITNETIC/DigitneticFloatingView.m @@ -0,0 +1,114 @@ +#import "DigitneticFloatingView.h" +#import +#define PADDING 5 +#define KScreenWidth [UIScreen mainScreen].bounds.size.width +#define KScreenHeight [UIScreen mainScreen].bounds.size.height + +static void *DragEnableKey = &DragEnableKey; +static void *AdsorbEnableKey = &AdsorbEnableKey; + + +@implementation DigitneticFloatingView + +-(void)setDragEnable:(BOOL)dragEnable +{ + objc_setAssociatedObject(self, DragEnableKey,@(dragEnable), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +-(BOOL)isDragEnable +{ + return [objc_getAssociatedObject(self, DragEnableKey) boolValue]; +} + +-(void)setAdsorbEnable:(BOOL)adsorbEnable +{ + objc_setAssociatedObject(self, AdsorbEnableKey,@(adsorbEnable), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +-(BOOL)isAdsorbEnable +{ + return [objc_getAssociatedObject(self, AdsorbEnableKey) boolValue]; +} + +CGPoint beginPoint; + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + //self.highlighted = YES; + if (![objc_getAssociatedObject(self, DragEnableKey) boolValue]) { + return; + } + + UITouch *touch = [touches anyObject]; + + beginPoint = [touch locationInView:self]; +} + + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + //self.highlighted = NO; + if (![objc_getAssociatedObject(self, DragEnableKey) boolValue]) { + return; + } + + UITouch *touch = [touches anyObject]; + + CGPoint nowPoint = [touch locationInView:self]; + + float offsetX = nowPoint.x - beginPoint.x; + float offsetY = nowPoint.y - beginPoint.y; + + CGFloat btnCenterX = self.center.x + offsetX; + CGFloat btnCenterY = self.center.y + offsetY; + + if (btnCenterX < 0) { + btnCenterX = 0; + }else if(btnCenterX > KScreenWidth){ + btnCenterX = KScreenWidth; + } + + if (btnCenterY < 0) { + btnCenterY = 0; + }else if (btnCenterY > KScreenHeight){ + btnCenterY = KScreenHeight; + } + + self.center = CGPointMake(btnCenterX, btnCenterY); + +} + +-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + + if (self.superview && [objc_getAssociatedObject(self,AdsorbEnableKey) boolValue] ) { + float marginLeft = self.frame.origin.x; + float marginRight = self.superview.frame.size.width - self.frame.origin.x - self.frame.size.width; + float marginTop = self.frame.origin.y; + float marginBottom = self.superview.frame.size.height - self.frame.origin.y - self.frame.size.height; + [UIView animateWithDuration:0.125 animations:^(void){ + if (marginTop<60) { + self.frame = CGRectMake(marginLeft +#import + +@interface DraggableWindow : UIWindow +@end \ No newline at end of file diff --git a/Digitnetic/Tweak/DIGITNETIC/DraggableWindow.m b/Digitnetic/Tweak/DIGITNETIC/DraggableWindow.m new file mode 100644 index 0000000..22f008d --- /dev/null +++ b/Digitnetic/Tweak/DIGITNETIC/DraggableWindow.m @@ -0,0 +1,36 @@ +#import "DraggableWindow.h" + +@implementation DraggableWindow +- (id)initWithFrame:(CGRect)frame { + + + self = [super initWithFrame:frame]; + self.clipsToBounds = YES; + self.backgroundColor = UIColor.clearColor; + self.layer.masksToBounds = YES; + self.windowLevel = 3000; + //self.windowLevel = UIWindowLevelStatusBar; + self.alpha = 1; + self.opaque = NO; + self.userInteractionEnabled = YES; + + return self; +} + + +- (bool)_shouldCreateContextAsSecure{ + return YES; +} + + +-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { + + for (UIView* subview in self.subviews ) { + if ( [subview hitTest:[self convertPoint:point toView:subview] withEvent:event] != nil ) { + return YES; + } + } + return NO; +} + +@end diff --git a/Digitnetic/Tweak/DIGITNETIC/GlobalPrefs/GlobalPreferences.h b/Digitnetic/Tweak/DIGITNETIC/GlobalPrefs/GlobalPreferences.h new file mode 100644 index 0000000..f0d192e --- /dev/null +++ b/Digitnetic/Tweak/DIGITNETIC/GlobalPrefs/GlobalPreferences.h @@ -0,0 +1,30 @@ +#import + +static NSString *BID = @"com.TitanD3v.DigitneticPrefs"; + +static BOOL toggleDigitnetic; +static NSString *digitneticAppearance; +static BOOL toggleCalculatorColour; +static BOOL toggleKeypadColour; +static BOOL toggleHaptic; +static NSInteger hapticStrength; +static BOOL toggleKeypadBackgroundImage; +static BOOL toggleCalculatorBackgroundImage; +static NSData *keypadBackgroundImage = nil; +static NSData *calculatorBackgroundImage = nil; +static BOOL showSBTutorial; + +static void loadPrefs() { + + toggleDigitnetic = [[TDTweakManager sharedInstance] boolForKey:@"toggleDigitnetic" defaultValue:NO ID:BID]; + digitneticAppearance = [[TDTweakManager sharedInstance] objectForKey:@"digitneticAppearance" defaultValue:@"digitneticLight" ID:BID]; + toggleCalculatorColour = [[TDTweakManager sharedInstance] boolForKey:@"toggleCalculatorColour" defaultValue:NO ID:BID]; + toggleKeypadColour = [[TDTweakManager sharedInstance] boolForKey:@"toggleKeypadColour" defaultValue:NO ID:BID]; + toggleKeypadBackgroundImage = [[TDTweakManager sharedInstance] boolForKey:@"toggleKeypadBackgroundImage" defaultValue:NO ID:BID]; + toggleCalculatorBackgroundImage = [[TDTweakManager sharedInstance] boolForKey:@"toggleCalculatorBackgroundImage" defaultValue:NO ID:BID]; + keypadBackgroundImage = [[TDTweakManager sharedInstance] objectForKey:@"keypadBackgroundImage" ID:BID]; + calculatorBackgroundImage = [[TDTweakManager sharedInstance] objectForKey:@"calculatorBackgroundImage" ID:BID]; + toggleHaptic = [[TDTweakManager sharedInstance] boolForKey:@"toggleHaptic" defaultValue:YES ID:BID]; + hapticStrength = [[TDTweakManager sharedInstance] intForKey:@"hapticStrength" defaultValue:0 ID:BID]; + showSBTutorial = [[TDTweakManager sharedInstance] boolForKey:@"showSBTutorial" defaultValue:YES ID:BID]; +} diff --git a/Digitnetic/Tweak/Digitnetic.plist b/Digitnetic/Tweak/Digitnetic.plist new file mode 100644 index 0000000..10dc654 --- /dev/null +++ b/Digitnetic/Tweak/Digitnetic.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard" ); }; } diff --git a/Digitnetic/Tweak/Digitnetic.xm b/Digitnetic/Tweak/Digitnetic.xm new file mode 100644 index 0000000..e489d5b --- /dev/null +++ b/Digitnetic/Tweak/Digitnetic.xm @@ -0,0 +1,270 @@ +#import +#import "./DIGITNETIC/DraggableWindow.h" +#import "./DIGITNETIC/DigitneticFloatingView.h" +#import "./DIGITNETIC/CalculatorView.h" +#import "./DIGITNETIC/DialerView.h" +#import + +static BOOL toggleCalculatorAsPrimrary = NO; +static float cornerRadius; + +@interface SpringBoard : UIView +-(void)layoutWindow; +-(void)showKeypad; +-(void)showCalculator; +-(void)hideDigitnetic; +-(void)showDigitnetic; +-(void)showAlertWithSettings; +@end + + +@interface ShowDigitnetic : NSObject +@end + +@interface HideDigitnetic : NSObject +@end + + +static DraggableWindow *draggableWindow = nil; +static DigitneticFloatingView *digitneticFloatingView; +static UIViewController *baseVC; +static DialerView *dialerView; +static CalculatorView *calculatorView; + +%group Digitnetic +%hook SpringBoard + +- (void)applicationDidFinishLaunching:(id)application { + + %orig; + [self layoutWindow]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveDigitneticNotification:) name:@"HideDigitneticNotification" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveDigitneticNotification:) name:@"ShowDigitneticNotification" object:nil]; +} + +%new +- (void)receiveDigitneticNotification:(NSNotification *) notification { + + if ([[notification name] isEqualToString:@"HideDigitneticNotification"]) { + [self hideDigitnetic]; + } + if ([[notification name] isEqualToString:@"ShowDigitneticNotification"]) { + [self showDigitnetic]; + } +} + +%new +-(void)layoutWindow { + + + if (!draggableWindow) { + + draggableWindow = [[DraggableWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + draggableWindow.hidden = NO; + + + digitneticFloatingView = [[DigitneticFloatingView alloc] initWithFrame:CGRectMake(5, 100, 245, 300)]; + digitneticFloatingView.layer.cornerRadius = cornerRadius; + digitneticFloatingView.layer.cornerCurve = kCACornerCurveContinuous; + digitneticFloatingView.backgroundColor = UIColor.clearColor; + digitneticFloatingView.clipsToBounds = true; + digitneticFloatingView.alpha = 0; + [digitneticFloatingView setDragEnable:YES]; + [digitneticFloatingView setAdsorbEnable:YES]; + [draggableWindow addSubview:digitneticFloatingView]; + + + baseVC = [[UIViewController alloc] init]; + baseVC.view.frame = digitneticFloatingView.bounds; + [digitneticFloatingView addSubview:baseVC.view]; + + + dialerView = [[DialerView alloc] initWithFrame:baseVC.view.bounds]; + [baseVC.view addSubview:dialerView]; + + + calculatorView = [[CalculatorView alloc] initWithFrame:baseVC.view.bounds]; + [baseVC.view addSubview:calculatorView]; + + + if (toggleCalculatorAsPrimrary) { + calculatorView.alpha = 1; + dialerView.alpha = 0; + } else { + calculatorView.alpha = 0; + dialerView.alpha = 1; + } + + + UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc] init]; + gestureRecognizer.minimumPressDuration = 0.5; + [gestureRecognizer addTarget:self action:@selector(longPressedFired:)]; + [baseVC.view addGestureRecognizer:gestureRecognizer]; + + } + +} + +%new +-(void)longPressedFired:(UILongPressGestureRecognizer*)sender { + + if (sender.state == UIGestureRecognizerStateChanged) { + [self showAlertWithSettings]; + } + +} + +%new +-(void)showAlertWithSettings { + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Digitnetic" message:@"" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *keypadAction = [UIAlertAction actionWithTitle:@"Keypad" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self showKeypad]; + }]; + + UIAlertAction *calculatorAction = [UIAlertAction actionWithTitle:@"Calculator" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self showCalculator]; + }]; + + UIAlertAction *hideAction = [UIAlertAction actionWithTitle:@"Hide Digitnetic" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self hideDigitnetic]; + }]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + + }]; + + + [alertController addAction:keypadAction]; + [alertController addAction:calculatorAction]; + [alertController addAction:hideAction]; + [alertController addAction:cancelAction]; + [baseVC presentViewController:alertController animated:YES completion:nil]; +} + +%new +-(void)showKeypad { + + dialerView.alpha = 1; + calculatorView.alpha = 0; + +} + + +%new +-(void)showCalculator { + + dialerView.alpha = 0; + calculatorView.alpha = 1; + +} + + +%new +-(void)showDigitnetic { + + [UIView animateWithDuration:0.2 animations:^ { + digitneticFloatingView.alpha = 1; + }]; +} + + +%new +-(void)hideDigitnetic { + + [UIView animateWithDuration:0.2 animations:^ { + digitneticFloatingView.alpha = 0; + }]; +} + +%end +%end + + +static NSBundle *iconPath = [NSBundle bundleWithPath:@"/Library/PreferenceBundles/DigitneticPrefs.bundle/Assets/Cell/"]; + +@implementation ShowDigitnetic + +-(void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)digitnetic1 { + + [UIView animateWithDuration:0.2 animations:^ { + digitneticFloatingView.alpha = 1; + }]; + [digitnetic1 setHandled:YES]; + +} + + ++(void)load { + + [[LAActivator sharedInstance] registerListener:[self new] forName:@"Toggle Show Digitnetic"]; + +} + + +- (NSArray *)activator:(LAActivator *)activator requiresCompatibleEventModesForListenerWithName:(NSString *)listenerName { + return [NSArray arrayWithObjects:@"springboard", @"lockscreen", @"application", nil]; +} + + +- (UIImage *)activator:(LAActivator *)activator requiresSmallIconForListenerName:(NSString *)listenerName scale:(CGFloat)scale{ + return [UIImage imageNamed:@"prefs-icon" inBundle:iconPath compatibleWithTraitCollection:nil]; + +} + + +@end + + +@implementation HideDigitnetic + +-(void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)digitnetic2 { + + [UIView animateWithDuration:0.2 animations:^ { + digitneticFloatingView.alpha = 0; + }]; + [digitnetic2 setHandled:YES]; + +} + + ++(void)load { + + [[LAActivator sharedInstance] registerListener:[self new] forName:@"Toggle Hide Digitnetic"]; + +} + + +- (NSArray *)activator:(LAActivator *)activator requiresCompatibleEventModesForListenerWithName:(NSString *)listenerName { + return [NSArray arrayWithObjects:@"springboard", @"lockscreen", @"application", nil]; +} + + +- (UIImage *)activator:(LAActivator *)activator requiresSmallIconForListenerName:(NSString *)listenerName scale:(CGFloat)scale{ + return [UIImage imageNamed:@"prefs-icon" inBundle:iconPath compatibleWithTraitCollection:nil]; + +} + + +@end + + +void SettingsChanged() { + + toggleDigitnetic = [[TDTweakManager sharedInstance] boolForKey:@"toggleDigitnetic" defaultValue:NO ID:BID]; + toggleCalculatorAsPrimrary = [[TDTweakManager sharedInstance] boolForKey:@"toggleCalculatorAsPrimrary" defaultValue:NO ID:BID]; + cornerRadius = [[TDTweakManager sharedInstance] floatForKey:@"cornerRadius" defaultValue:15 ID:BID]; + +} + + +%ctor { + + SettingsChanged(); + + if (toggleDigitnetic) { + %init(Digitnetic); + } +} diff --git a/Digitnetic/Tweak/Makefile b/Digitnetic/Tweak/Makefile new file mode 100644 index 0000000..2deeb67 --- /dev/null +++ b/Digitnetic/Tweak/Makefile @@ -0,0 +1,23 @@ +TWEAK_NAME = Digitnetic + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +dtoim = $(foreach d,$(1),-I$(d)) +_IMPORTS = $(shell /bin/ls -d ./*/) +_IMPORTS = $(shell /bin/ls -d ./DIGITNETIC/) +_IMPORTS = $(shell /bin/ls -d ./DIGITNETIC/*/) +_IMPORTS += $(shell /bin/ls -d ./DIGITNETIC/*/*/) +_IMPORTS += $(shell /bin/ls -d ./DIGITNETIC/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./DIGITNETIC/*/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./) +IMPORTS = -I$./DIGITNETIC $(call dtoim, $(_IMPORTS)) + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations $(IMPORTS) +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt activator +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Digitnetic/control b/Digitnetic/control new file mode 100644 index 0000000..9b6a1d3 --- /dev/null +++ b/Digitnetic/control @@ -0,0 +1,11 @@ +Package: com.titand3v.digitnetic +Name: Digitnetic +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal, libactivator +Version: 1.1 +Section: Tweaks +Description: Floating phone keypad and calculator +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/digitnetic/index.html +Icon: https://titand3v.github.io/depictions/digitnetic/assets/icon.png diff --git a/Digitnetic/layout/DEBIAN/postinst b/Digitnetic/layout/DEBIAN/postinst new file mode 100755 index 0000000..fb691e3 --- /dev/null +++ b/Digitnetic/layout/DEBIAN/postinst @@ -0,0 +1,8 @@ +echo "" +echo "" +echo "Thank you for installing Digitnetic 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/Flowing/.DS_Store b/Flowing/.DS_Store new file mode 100644 index 0000000..af78a4e Binary files /dev/null and b/Flowing/.DS_Store differ diff --git a/Flowing/Makefile b/Flowing/Makefile new file mode 100644 index 0000000..2c9082a --- /dev/null +++ b/Flowing/Makefile @@ -0,0 +1,15 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0:13.0 +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +FINALPACKAGE = 1 +DEBUG = 0 + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Flowing/Tweak/Flowing.plist b/Flowing/Tweak/Flowing.plist new file mode 100644 index 0000000..10dc654 --- /dev/null +++ b/Flowing/Tweak/Flowing.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard" ); }; } diff --git a/Flowing/Tweak/Flowing.xm b/Flowing/Tweak/Flowing.xm new file mode 100644 index 0000000..763dd5b --- /dev/null +++ b/Flowing/Tweak/Flowing.xm @@ -0,0 +1,21 @@ +#import + +@interface BSUIScrollView : UIScrollView +@end + +%group Flowing +%hook BSUIScrollView +-(void)layoutSubviews { + %orig; + self.pagingEnabled = NO; +} +%end +%end + +%ctor { + + NSString * path = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0]; + if ([path containsString:@"/Application"] || [path containsString:@"SpringBoard.app"]) { + %init(Flowing); + } +} diff --git a/Flowing/Tweak/Makefile b/Flowing/Tweak/Makefile new file mode 100644 index 0000000..4a8fcc2 --- /dev/null +++ b/Flowing/Tweak/Makefile @@ -0,0 +1,12 @@ +TWEAK_NAME = Flowing + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Flowing/control b/Flowing/control new file mode 100644 index 0000000..d93b560 --- /dev/null +++ b/Flowing/control @@ -0,0 +1,11 @@ +Package: com.titand3v.flowing +Name: Flowing +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal +Version: 1.0 +Section: Tweaks +Description: Disable paging scrolling on SpringBoard +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/flowing/index.html +Icon: https://titand3v.github.io/depictions/nova/flowing/icon.png diff --git a/Flowing/layout/DEBIAN/postinst b/Flowing/layout/DEBIAN/postinst new file mode 100755 index 0000000..a32c87d --- /dev/null +++ b/Flowing/layout/DEBIAN/postinst @@ -0,0 +1,8 @@ +echo "" +echo "" +echo "Thank you for installing Flowing 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Luv/.DS_Store b/Luv/.DS_Store new file mode 100644 index 0000000..2f1c457 Binary files /dev/null and b/Luv/.DS_Store differ diff --git a/Luv/Makefile b/Luv/Makefile new file mode 100644 index 0000000..1b574ab --- /dev/null +++ b/Luv/Makefile @@ -0,0 +1,15 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0:13.0 +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +FINALPACKAGE = 1 +DEBUG = 0 + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak Prefs + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Luv/Prefs/LUVPrimraryListController.h b/Luv/Prefs/LUVPrimraryListController.h new file mode 100644 index 0000000..20b5b25 --- /dev/null +++ b/Luv/Prefs/LUVPrimraryListController.h @@ -0,0 +1,29 @@ +#import +#import + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1;; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + + +@interface LUVPrimraryListController : TDPrimraryController { + OBWelcomeController *onboardingController; + OBWelcomeController *updateController; +} + +@end diff --git a/Luv/Prefs/LUVPrimraryListController.m b/Luv/Prefs/LUVPrimraryListController.m new file mode 100644 index 0000000..20baa54 --- /dev/null +++ b/Luv/Prefs/LUVPrimraryListController.m @@ -0,0 +1,115 @@ +#include "LUVPrimraryListController.h" + +@implementation LUVPrimraryListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Primrary" target:self]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[TDPrefsManager sharedInstance] initWithBundleID:@"com.TitanD3v.LuvPrefs" tweakName:@"Luv" prefsBundle:@"LuvPrefs.bundle"]; + + [[TDPrefsManager sharedInstance] bannerTitle:@"Luv" subtitle:@"Coded with 🤍" devName:@"TitanD3v" coverImagePath:@"/Assets/Banner/cover-image.png" showCoverImage:YES iconPath:@"" iconTint:YES]; + + [[TDPrefsManager sharedInstance] changelogPlistPath:@"/Assets/Changelog/changelog.plist" currentVersion:@"Version 1.1"]; + + [[TDPrefsManager sharedInstance] useAssetsFromLibrary:YES]; +} + + +-(void)presentTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + onboardingController = [[OBWelcomeController alloc] initWithTitle:@"User Guide" detailText:@"A walk through tutorial how to use Luv" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/LuvPrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]]; + + [onboardingController addBulletedListItemWithTitle:@"Your time" description:@"Please take a few minutes of your time to read through to get started." image:[UIImage systemImageNamed:@"timer"]]; + + [onboardingController addBulletedListItemWithTitle:@"Main page" description:@"On the main page, there's menu icon on the navigation bar it will present the drawer when tapped. You will find the social media details, changelog, backup/restore, tweak list, profile and crew list." image:[UIImage systemImageNamed:@"square.stack.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Report a bug" description:@"If you are experiencing a bug or any other issues, you can report a bug from this page below the close button, it will bring up the Bug Report page. You can select the categories, write description about a bug, attach a .txt file, photo, provide URL link for the pastebin or any pasteboard website also you can attach all of them if you want. Once you submit a bug report and our team will be in touch with you within 48 hours. If you haven't heard anything from us and please don't hesitate to get in touch with us through social media." image:[UIImage systemImageNamed:@"ant.circle.fill"]]; + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [onboardingController.buttonTray addButton:dismissButton]; + + onboardingController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:onboardingController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [onboardingController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + onboardingController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [onboardingController.buttonTray addCaptionText:@"Thank you for installing Luv"]; + + onboardingController.modalPresentationStyle = UIModalPresentationPageSheet; + onboardingController.modalInPresentation = YES; + [self presentViewController:onboardingController animated:YES completion:nil]; + + UIView *reportView = [[UIView alloc] init]; + reportView.backgroundColor = UIColor.clearColor; + [onboardingController.buttonTray addSubview:reportView]; + + reportView.translatesAutoresizingMaskIntoConstraints = NO; + [reportView.topAnchor constraintEqualToAnchor:dismissButton.bottomAnchor constant:10].active = YES; + [[reportView centerXAnchor] constraintEqualToAnchor:onboardingController.buttonTray.centerXAnchor].active = true; + [reportView.widthAnchor constraintEqualToConstant:140].active = YES; + [reportView.heightAnchor constraintEqualToConstant:40].active = YES; + + + UIImageView *bugImage = [[UIImageView alloc] init]; + bugImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + bugImage.tintColor = [[TDAppearance sharedInstance] tintColour]; + [reportView addSubview:bugImage]; + + bugImage.translatesAutoresizingMaskIntoConstraints = NO; + [bugImage.leadingAnchor constraintEqualToAnchor:reportView.leadingAnchor constant:10].active = YES; + [[bugImage centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + [bugImage.widthAnchor constraintEqualToConstant:30].active = YES; + [bugImage.heightAnchor constraintEqualToConstant:30].active = YES; + + + UILabel *reportLabel = [[UILabel alloc] init]; + reportLabel.text = @"Report a bug"; + reportLabel.textColor = [[TDAppearance sharedInstance] tintColour]; + reportLabel.textAlignment = NSTextAlignmentLeft; + [reportView addSubview:reportLabel]; + + reportLabel.translatesAutoresizingMaskIntoConstraints = NO; + [reportLabel.leadingAnchor constraintEqualToAnchor:bugImage.trailingAnchor constant:5].active = YES; + [[reportLabel centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + + [reportView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentReportBugVC)]]; + +} + + +-(void)dismissTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentReportBugVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; + + TDReportBugViewController *bugVC = [[TDReportBugViewController alloc] init]; + bugVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [self presentViewController:bugVC animated:YES completion:nil]; +} + +@end diff --git a/Luv/Prefs/LUVSecondaryListController.h b/Luv/Prefs/LUVSecondaryListController.h new file mode 100644 index 0000000..1b781fa --- /dev/null +++ b/Luv/Prefs/LUVSecondaryListController.h @@ -0,0 +1,12 @@ +#import +#import + +@interface LUVAppearanceController : TDSecondaryController +@end + +@interface LUVColourController : TDSecondaryController +@end + +@interface LUVMiscellaneousController : TDSecondaryController +@end + diff --git a/Luv/Prefs/LUVSecondaryListController.m b/Luv/Prefs/LUVSecondaryListController.m new file mode 100644 index 0000000..841a98c --- /dev/null +++ b/Luv/Prefs/LUVSecondaryListController.m @@ -0,0 +1,37 @@ +#include "LUVSecondaryListController.h" + +@implementation LUVAppearanceController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Appearance" target:self]; + } + + return _specifiers; +} + +@end + +@implementation LUVColourController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Colour" target:self]; + } + + return _specifiers; +} + +@end + +@implementation LUVMiscellaneousController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Miscellaneous" target:self]; + } + + return _specifiers; +} + +@end diff --git a/Luv/Prefs/Makefile b/Luv/Prefs/Makefile new file mode 100644 index 0000000..3fc9e74 --- /dev/null +++ b/Luv/Prefs/Makefile @@ -0,0 +1,15 @@ +BUNDLE_NAME = LuvPrefs + +$(BUNDLE_NAME)_FILES = $(wildcard *.m) +$(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles +$(BUNDLE_NAME)_FRAMEWORKS = UIKit +$(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences OnBoardingKit +$(BUNDLE_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(BUNDLE_NAME)_LIBRARIES = TitanD3vUniversal + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/bundle.mk + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) + $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/LuvPrefs.plist$(ECHO_END) diff --git a/Luv/Prefs/Resources/Appearance.plist b/Luv/Prefs/Resources/Appearance.plist new file mode 100644 index 0000000..8fa20b7 --- /dev/null +++ b/Luv/Prefs/Resources/Appearance.plist @@ -0,0 +1,186 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Appearance + + + + cellClass + TDAppearanceCell + key + luvAppearance + default + luvDark + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + options + + light + + appearanceOption + luvLight + title + Light + imageName + appearance-light + arrangement + 1 + + dark + + appearanceOption + luvDark + title + Dark + imageName + appearance-dark + arrangement + 2 + + dynamic + + appearanceOption + luvDynamic + title + Dynamic + imageName + appearance-dynamic + arrangement + 3 + + + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Style + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + floatingButtonStyles + default + 0 + validTitles + + Circle + Rounded + + validValues + + 0 + 1 + + title + Floating Button Style + showTips + + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Size + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + floatingButtonSize + default + 0 + validTitles + + Small + Medium + Large + + validValues + + 0 + 1 + 2 + + title + Floating Button Size + showTips + + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Icon + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + floatingIconStyle + default + 0 + validTitles + + Fill + Outline + + validValues + + 0 + 1 + + title + Icon Style + showTips + + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + + + + title + + + diff --git a/Luv/Prefs/Resources/Assets/Banner/banner-icon.png b/Luv/Prefs/Resources/Assets/Banner/banner-icon.png new file mode 100644 index 0000000..74d98d5 Binary files /dev/null and b/Luv/Prefs/Resources/Assets/Banner/banner-icon.png differ diff --git a/Luv/Prefs/Resources/Assets/Banner/cover-image.png b/Luv/Prefs/Resources/Assets/Banner/cover-image.png new file mode 100644 index 0000000..de13d25 Binary files /dev/null and b/Luv/Prefs/Resources/Assets/Banner/cover-image.png differ diff --git a/Luv/Prefs/Resources/Assets/Cell/prefs-icon@2x.png b/Luv/Prefs/Resources/Assets/Cell/prefs-icon@2x.png new file mode 100644 index 0000000..914225b Binary files /dev/null and b/Luv/Prefs/Resources/Assets/Cell/prefs-icon@2x.png differ diff --git a/Luv/Prefs/Resources/Assets/Cell/prefs-icon@3x.png b/Luv/Prefs/Resources/Assets/Cell/prefs-icon@3x.png new file mode 100644 index 0000000..b5707ae Binary files /dev/null and b/Luv/Prefs/Resources/Assets/Cell/prefs-icon@3x.png differ diff --git a/Luv/Prefs/Resources/Assets/Changelog/changelog.plist b/Luv/Prefs/Resources/Assets/Changelog/changelog.plist new file mode 100644 index 0000000..ee80a30 --- /dev/null +++ b/Luv/Prefs/Resources/Assets/Changelog/changelog.plist @@ -0,0 +1,37 @@ + + + + + + + Date + 13th June 2021 + Version + v1.1 + ChangelogDescription + + Added long press on Luv button to hide it and shake your device to unhide it. + + updateCategories + + 3 + + + + + Date + 26th May 2021 + Version + v1.0 + ChangelogDescription + + Initial Release... + + updateCategories + + 0 + + + + + \ No newline at end of file diff --git a/Luv/Prefs/Resources/Colour.plist b/Luv/Prefs/Resources/Colour.plist new file mode 100644 index 0000000..d710d56 --- /dev/null +++ b/Luv/Prefs/Resources/Colour.plist @@ -0,0 +1,105 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Custom Colour + + + + cellClass + TDEnableCell + default + + key + toggleColour + disabledTitle + Disable Colour + enabledTitle + Enable Colour + disabledColour + B92F2F + enabledColour + 43EB1F + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Background + subtitle + Colour + default + FFFFFF + key + luvBackgroundColour + iconName + colour + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Like + subtitle + Colour + default + FFFFFF + key + luvLikeColour + iconName + colour + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Dislike + subtitle + Colour + default + FFFFFF + key + luvDislikeColour + iconName + colour + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + + + + title + + + diff --git a/Luv/Prefs/Resources/Info.plist b/Luv/Prefs/Resources/Info.plist new file mode 100644 index 0000000..b32bcbc --- /dev/null +++ b/Luv/Prefs/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + LuvPrefs + CFBundleIdentifier + com.titand3v.luvprefs + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + LUVPrimraryListController + + diff --git a/Luv/Prefs/Resources/Miscellaneous.plist b/Luv/Prefs/Resources/Miscellaneous.plist new file mode 100644 index 0000000..8234e75 --- /dev/null +++ b/Luv/Prefs/Resources/Miscellaneous.plist @@ -0,0 +1,107 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Notification + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + showNotification + title + Show Notification + subtitle + When you like the song + iconName + switch + showTips + + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Haptic + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleHaptic + title + Enable + subtitle + Haptic Feedback + iconName + switch + showTips + + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + hapticType + default + 0 + validTitles + + Light + Medium + Heavy + + validValues + + 0 + 1 + 2 + + title + Type + showTips + + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + + + + title + + + diff --git a/Luv/Prefs/Resources/Primrary.plist b/Luv/Prefs/Resources/Primrary.plist new file mode 100644 index 0000000..03145a0 --- /dev/null +++ b/Luv/Prefs/Resources/Primrary.plist @@ -0,0 +1,76 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable + + + + cellClass + TDEnableCell + default + + key + toggleLuv + disabledTitle + Disable Luv + enabledTitle + Enable Luv + disabledColour + B92F2F + enabledColour + 43EB1F + defaults + com.TitanD3v.LuvPrefs + PostNotification + com.TitanD3v.LuvPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Categories + + + + cellClass + TDGridCell + leftTitle + Appearance + leftIconName + appearance + leftClass + LUVAppearanceController + middleTitle + Colour + middleIconName + colour + middleClass + LUVColourController + rightTitle + Miscellaneous + rightIconName + misc + rightClass + LUVMiscellaneousController + classID + primrary + + + + title + + + diff --git a/Luv/Prefs/entry.plist b/Luv/Prefs/entry.plist new file mode 100644 index 0000000..a2fc66d --- /dev/null +++ b/Luv/Prefs/entry.plist @@ -0,0 +1,21 @@ + + + + + entry + + bundle + LuvPrefs + cell + PSLinkCell + detail + LUVPrimraryListController + icon + Assets/Cell/prefs-icon.png + isController + + label + Luv + + + diff --git a/Luv/Tweak/FloatingView.h b/Luv/Tweak/FloatingView.h new file mode 100644 index 0000000..4e9c78a --- /dev/null +++ b/Luv/Tweak/FloatingView.h @@ -0,0 +1,6 @@ +#import + +@interface FloatingView : UIView +@property(nonatomic,assign,getter = isDragEnable) BOOL dragEnable; +@property(nonatomic,assign,getter = isAdsorbEnable) BOOL adsorbEnable; +@end diff --git a/Luv/Tweak/FloatingView.m b/Luv/Tweak/FloatingView.m new file mode 100644 index 0000000..62c2afd --- /dev/null +++ b/Luv/Tweak/FloatingView.m @@ -0,0 +1,114 @@ +#import "FloatingView.h" +#import +#define PADDING 5 +#define KScreenWidth [UIScreen mainScreen].bounds.size.width +#define KScreenHeight [UIScreen mainScreen].bounds.size.height + +static void *DragEnableKey = &DragEnableKey; +static void *AdsorbEnableKey = &AdsorbEnableKey; + + +@implementation FloatingView + +-(void)setDragEnable:(BOOL)dragEnable +{ + objc_setAssociatedObject(self, DragEnableKey,@(dragEnable), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +-(BOOL)isDragEnable +{ + return [objc_getAssociatedObject(self, DragEnableKey) boolValue]; +} + +-(void)setAdsorbEnable:(BOOL)adsorbEnable +{ + objc_setAssociatedObject(self, AdsorbEnableKey,@(adsorbEnable), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +-(BOOL)isAdsorbEnable +{ + return [objc_getAssociatedObject(self, AdsorbEnableKey) boolValue]; +} + +CGPoint beginPoint; + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + //self.highlighted = YES; + if (![objc_getAssociatedObject(self, DragEnableKey) boolValue]) { + return; + } + + UITouch *touch = [touches anyObject]; + + beginPoint = [touch locationInView:self]; +} + + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + //self.highlighted = NO; + if (![objc_getAssociatedObject(self, DragEnableKey) boolValue]) { + return; + } + + UITouch *touch = [touches anyObject]; + + CGPoint nowPoint = [touch locationInView:self]; + + float offsetX = nowPoint.x - beginPoint.x; + float offsetY = nowPoint.y - beginPoint.y; + + CGFloat btnCenterX = self.center.x + offsetX; + CGFloat btnCenterY = self.center.y + offsetY; + + if (btnCenterX < 0) { + btnCenterX = 0; + }else if(btnCenterX > KScreenWidth){ + btnCenterX = KScreenWidth; + } + + if (btnCenterY < 0) { + btnCenterY = 0; + }else if (btnCenterY > KScreenHeight){ + btnCenterY = KScreenHeight; + } + + self.center = CGPointMake(btnCenterX, btnCenterY); + +} + +-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + + if (self.superview && [objc_getAssociatedObject(self,AdsorbEnableKey) boolValue] ) { + float marginLeft = self.frame.origin.x; + float marginRight = self.superview.frame.size.width - self.frame.origin.x - self.frame.size.width; + float marginTop = self.frame.origin.y; + float marginBottom = self.superview.frame.size.height - self.frame.origin.y - self.frame.size.height; + [UIView animateWithDuration:0.125 animations:^(void){ + if (marginTop<60) { + self.frame = CGRectMake(marginLeft +#import +#import "TopWindow.h" +#import "FloatingView.h" +#include + +@interface SBApplication : NSObject +@property (nonatomic,readonly) NSString * bundleIdentifier; +@end + +@interface SBMediaController +@property (nonatomic, weak,readonly) SBApplication * nowPlayingApplication; ++(id)sharedInstance; +- (BOOL)isPlaying; +- (id)nowPlayingApplication; +@end + +@interface BBAction : NSObject ++ (id)actionWithLaunchBundleID:(id)arg1 callblock:(id)arg2; +@end + +@interface BBBulletin : NSObject +@property(nonatomic, copy)NSString* sectionID; +@property(nonatomic, copy)NSString* recordID; +@property(nonatomic, copy)NSString* publisherBulletinID; +@property(nonatomic, copy)NSString* title; +@property(nonatomic, copy)NSString* message; +@property(nonatomic, retain)NSDate* date; +@property(assign, nonatomic)BOOL clearable; +@property(nonatomic)BOOL showsMessagePreview; +@property(nonatomic, copy)BBAction* defaultAction; +@property(nonatomic, copy)NSString* bulletinID; +@property(nonatomic, retain)NSDate* lastInterruptDate; +@property(nonatomic, retain)NSDate* publicationDate; +@end + +@interface BBServer : NSObject +- (void)publishBulletin:(BBBulletin *)arg1 destinations:(NSUInteger)arg2 alwaysToLockScreen:(BOOL)arg3; +- (void)publishBulletin:(id)arg1 destinations:(unsigned long long)arg2; +-(void)_removeBulletins:(id)arg1 forSectionID:(id)arg2 shouldSync:(BOOL)arg3 ; +-(id)_bulletinsForIDs:(id)arg1 ; +-(id)allBulletinIDsForSectionID:(id)arg1 ; +-(void)_removeActiveSectionID:(id)arg1 ; +@end + +@interface SPTNowPlayingFreeTierFeedbackButton : UIButton +@end + +@interface SPTNowPlayingAnimatedLikeButton : UIButton +@end + +@interface UIStatusBarWindow : UIWindow +@end + +@interface NSDistributedNotificationCenter : NSNotificationCenter ++ (instancetype)defaultCenter; +-(void)postNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3 deliverImmediately:(BOOL)arg4 ; +- (void)postNotificationName:(NSString *)name object:(NSString *)object userInfo:(NSDictionary *)userInfo; +@end + +@interface SPTNowPlayingBarHeartViewController +-(id)heartButton; +@end + +@interface SPTNowPlayingHeartButtonViewController +-(id)animatedLikeButton; +@end + +@interface SpringBoard : UIView +-(void)layoutWindow; +@end \ No newline at end of file diff --git a/Luv/Tweak/Luv.plist b/Luv/Tweak/Luv.plist new file mode 100644 index 0000000..66e4a81 --- /dev/null +++ b/Luv/Tweak/Luv.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard", "com.spotify.client" ); }; } diff --git a/Luv/Tweak/Luv.xm b/Luv/Tweak/Luv.xm new file mode 100644 index 0000000..2fa2210 --- /dev/null +++ b/Luv/Tweak/Luv.xm @@ -0,0 +1,474 @@ +#import "Headers.h" + +static NSString *BID = @"com.TitanD3v.LuvPrefs"; +static BOOL toggleLuv; +static BOOL showNotification; +static BOOL toggleHaptic; +static NSUInteger floatingButtonSize; +static NSUInteger floatingButtonStyles; +static NSUInteger hapticType; +static NSUInteger floatingIconStyle; +static NSString *luvAppearance; +static BOOL toggleColour; +static bool isInCollectionLast; +static NSString *songNameFull; +static NSString *lastNotifTitle; +static TopWindow *topWindow = nil; +static FloatingView *floatingView; +static UIImageView *iconImage; +static UIVisualEffectView *blurEffectView; +static BBServer *bbServerSPL; +static SPTNowPlayingAnimatedLikeButton *collectionBtn; +static float buttonSize; +static float buttonCornerRadius; +static float iconSize; + + +static BOOL isSpotifyPlaying(){ + + NSString *nowPlayingID = [[[%c(SBMediaController) sharedInstance] nowPlayingApplication] bundleIdentifier]; + + if ([nowPlayingID length] !=0 && [nowPlayingID rangeOfString:@"com.spotify.client"].location != NSNotFound) + { + return 1; + } + else{ + return 0; + } + +} + + +static dispatch_queue_t getBBServerQueue() { + + static dispatch_queue_t queue; + static dispatch_once_t predicate; + + dispatch_once(&predicate, ^{ + void* handle = dlopen(NULL, RTLD_GLOBAL); + if (handle) { + dispatch_queue_t __weak *pointer = (__weak dispatch_queue_t *) dlsym(handle, "__BBServerQueue"); + if (pointer) queue = *pointer; + dlclose(handle); + } + }); + + return queue; + +} + + +static void SPTLNotification(NSString *msg) { + + BBBulletin* bulletin = [[%c(BBBulletin) alloc] init]; + + bulletin.title = @"Luv"; + bulletin.message = msg; + bulletin.sectionID = @"com.spotify.client"; + bulletin.bulletinID = [[NSProcessInfo processInfo] globallyUniqueString]; + bulletin.recordID = [[NSProcessInfo processInfo] globallyUniqueString]; + bulletin.publisherBulletinID = [[NSProcessInfo processInfo] globallyUniqueString]; + bulletin.date = [NSDate date]; + bulletin.defaultAction = [%c(BBAction) actionWithLaunchBundleID:@"com.spotify.client" callblock:nil]; + bulletin.clearable = YES; + bulletin.showsMessagePreview = YES; + bulletin.publicationDate = [NSDate date]; + bulletin.lastInterruptDate = [NSDate date]; + + if ([bbServerSPL respondsToSelector:@selector(publishBulletin:destinations:)]) { + dispatch_sync(getBBServerQueue(), ^{ + [bbServerSPL publishBulletin:bulletin destinations:15]; + }); + } + +} + + +%group LuvHooks +%hook BBServer + +- (id)initWithQueue:(id)arg1 { + + bbServerSPL = %orig; + return bbServerSPL; + +} + +- (id)initWithQueue:(id)arg1 dataProviderManager:(id)arg2 syncService:(id)arg3 dismissalSyncCache:(id)arg4 observerListener:(id)arg5 utilitiesListener:(id)arg6 conduitListener:(id)arg7 systemStateListener:(id)arg8 settingsListener:(id)arg9 { + + bbServerSPL = %orig; + return bbServerSPL; + +} + +- (void)dealloc { + + if (bbServerSPL == self) bbServerSPL = nil; + %orig; + +} + +%end + + +%hook SpringBoard + +- (void)applicationDidFinishLaunching:(id)application { + + %orig; + if(isSpotifyPlaying()){ + [self layoutWindow]; + } + + [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.SpotiLove/showWindow" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + [self layoutWindow]; + }]; + +} + + +%new +-(void)layoutWindow { + + if(isSpotifyPlaying()) { + + if (!topWindow) { + + topWindow = [[TopWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + topWindow.hidden = NO; + + + if (floatingButtonSize == 0) { + + buttonSize = 60; + iconSize = 40; + + if (floatingButtonStyles == 0) { + buttonCornerRadius = 30; + } else { + buttonCornerRadius = 8; + } + + } else if (floatingButtonSize == 1) { + + buttonSize = 70; + iconSize = 45; + + if (floatingButtonStyles == 0) { + buttonCornerRadius = 35; + } else { + buttonCornerRadius = 10; + } + + } else if (floatingButtonSize == 2) { + + buttonSize = 80; + iconSize = 50; + + if (floatingButtonStyles == 0) { + buttonCornerRadius = 40; + } else { + buttonCornerRadius = 10; + } + + } + + + floatingView = [[FloatingView alloc] initWithFrame:CGRectMake(5, 100, buttonSize, buttonSize)]; + floatingView.layer.cornerRadius = buttonCornerRadius; + floatingView.clipsToBounds = true; + [floatingView setDragEnable:YES]; + [floatingView setAdsorbEnable:YES]; + [topWindow addSubview:floatingView]; + + + blurEffectView = [[UIVisualEffectView alloc] initWithFrame:CGRectMake(0, 0, buttonSize, buttonSize)]; + [floatingView insertSubview:blurEffectView atIndex:0]; + + + if (!toggleColour) { + if([luvAppearance isEqualToString:@"luvLight"]) { + + blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + + } else if([luvAppearance isEqualToString:@"luvDark"]) { + + blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + + } else if([luvAppearance isEqualToString:@"luvDynamic"]) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + } else { + blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + } + + } + + } else { + + blurEffectView.alpha = 0; + floatingView.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"luvBackgroundColour" defaultValue:@"FFFFFF" ID:BID]; + + } + + + iconImage = [[UIImageView alloc] init]; + iconImage.userInteractionEnabled = NO; + if (floatingIconStyle == 0) { + iconImage.image = [[UIImage systemImageNamed:@"heart.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } else { + iconImage.image = [[UIImage systemImageNamed:@"heart"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } + if (toggleColour) { + iconImage.tintColor = [[TDTweakManager sharedInstance] colourForKey:@"luvLikeColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + iconImage.tintColor = UIColor.systemGreenColor; + } + iconImage.contentMode = UIViewContentModeScaleAspectFit; + [floatingView addSubview:iconImage]; + + [iconImage size:CGSizeMake(iconSize, iconSize)]; + [iconImage x:floatingView.centerXAnchor y:floatingView.centerYAnchor]; + + [floatingView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(gestureTapped)]]; + + UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc] init]; + gestureRecognizer.minimumPressDuration = 0.5; + [gestureRecognizer addTarget:self action:@selector(longPressedFired:)]; + [floatingView addGestureRecognizer:gestureRecognizer]; + + } + + [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.SpotiLove/isInCollection" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + bool isInCollection = [[[notification userInfo] objectForKey:@"isInCollection"] boolValue]; + if(isInCollection){ + if (floatingIconStyle == 0) { + iconImage.image = [[UIImage systemImageNamed:@"heart.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } else { + iconImage.image = [[UIImage systemImageNamed:@"heart"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } + if (toggleColour) { + iconImage.tintColor = [[TDTweakManager sharedInstance] colourForKey:@"luvLikeColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + iconImage.tintColor = UIColor.systemGreenColor; + } + } + else{ + if (floatingIconStyle == 0) { + iconImage.image = [[UIImage systemImageNamed:@"heart.slash.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } else { + iconImage.image = [[UIImage systemImageNamed:@"heart.slash"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } + + if (toggleColour) { + iconImage.tintColor = [[TDTweakManager sharedInstance] colourForKey:@"luvDislikeColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + iconImage.tintColor = UIColor.systemRedColor; + } + } + }]; + + [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.SpotiLove/SPTLNotification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + + if(showNotification){ + bool isInCollectionLast = [[[notification userInfo] objectForKey:@"isInCollectionLast"] boolValue]; + + if(!isInCollectionLast){ + NSString *title = [NSString stringWithFormat:@"%@ added to liked collection", songNameFull]; + if(![lastNotifTitle isEqual:title]){ + SPTLNotification(title); + } + NSLog(@"SpotiLove isInCollectionLast NOO title:-%@ lastNotifTitle:-%@", title, lastNotifTitle); + lastNotifTitle = title; + } + else{ + NSString *title = [NSString stringWithFormat:@"%@ removed from liked collection", songNameFull]; + if(![lastNotifTitle isEqual:title]){ + SPTLNotification(title); + } + NSLog(@"SpotiLove isInCollectionLast YESS title:-%@ lastNotifTitle:-%@", title, lastNotifTitle); + lastNotifTitle = title; + } + } + + }]; + + } + +} + + +%new +-(void)longPressedFired:(UILongPressGestureRecognizer*)sender { + + if (sender.state == UIGestureRecognizerStateBegan) { + [UIView animateWithDuration:0.2 animations:^ { + floatingView.alpha = 0; + }]; + } else if (sender.state == UIGestureRecognizerStateChanged) { + [UIView animateWithDuration:0.2 animations:^ { + floatingView.alpha = 0; + }]; + } else if (sender.state == UIGestureRecognizerStateEnded) { + [UIView animateWithDuration:0.2 animations:^ { + floatingView.alpha = 0; + }]; + } + +} + + +%new +-(void)gestureTapped { + + if (toggleHaptic) { + [[TDUtilities sharedInstance] haptic:hapticType]; + } + + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.SpotiLove/addToCollection" object:nil userInfo:nil deliverImmediately:YES]; +} + + +- (void)traitCollectionDidChange:(UITraitCollection *) previousTraitCollection { + + %orig; + + if (!toggleColour) { + if([luvAppearance isEqualToString:@"luvDynamic"]) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + } else { + blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + } + + } + } + +} + +%end + + +%hook UIWindow + +- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { + + %orig; + if(event.type == UIEventSubtypeMotionShake && self == [[UIApplication sharedApplication] keyWindow]) { + + if(isSpotifyPlaying()) { + [UIView animateWithDuration:0.2 animations:^ { + floatingView.alpha = 1; + }]; + } + + } +} + +%end + + +%hook SPTNowPlayingAuxiliaryActionsModel +- (bool)isInCollection{ + //this is where we check if song is already in collection or nahh + bool isInCollection = %orig; + + if(isInCollection != isInCollectionLast){ + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.SpotiLove/isInCollection" object:nil userInfo:@{@"isInCollection" : @(isInCollection)} deliverImmediately:YES]; + } + + return isInCollectionLast = %orig; +} +%end + + +%hook SPTNowPlayingHeartButtonViewController +-(id)initWithModel:(id)arg1 auxiliaryActionsHandler:(id)arg2 testManager:(id)arg3 { + [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.SpotiLove/addToCollection" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + + [collectionBtn sendActionsForControlEvents:UIControlEventTouchUpInside]; + + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.SpotiLove/SPTLNotification" object:nil userInfo:@{@"isInCollectionLast" : @(isInCollectionLast)} deliverImmediately:YES]; + }]; + + return %orig; + +} + +%end + +%hook SPTNowPlayingHeartButtonViewController +-(id)animatedLikeButton { + collectionBtn = %orig; + return %orig; +} +%end + + +%hook SBMediaController + +-(void)setNowPlayingInfo:(id)arg1 { + %orig; + + //here we get current playing songname + MRMediaRemoteGetNowPlayingInfo(dispatch_get_main_queue(), ^(CFDictionaryRef information) { + NSDictionary *dict = (__bridge NSDictionary *)information; + if (dict) { + NSString *songName = [dict objectForKey:(__bridge NSString*)kMRMediaRemoteNowPlayingInfoAlbum]; + NSString *songArtist = [dict objectForKey:(__bridge NSString*)kMRMediaRemoteNowPlayingInfoArtist]; + + if(songArtist != nil && songName != nil) + songNameFull = [NSString stringWithFormat:@"%@ by %@", songName, songArtist]; + + else if(songArtist != nil) + songNameFull = songName; + + else + songNameFull = [NSString stringWithFormat:@"by %@", songArtist]; + + } + }); + + + //Here we hide/show our likke button + if(isSpotifyPlaying()){ + + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.SpotiLove/showWindow" object:nil userInfo:nil deliverImmediately:YES]; + + } else { + topWindow = nil; + } +} +%end +%end + + +void SettingsChanged() { + + toggleLuv = [[TDTweakManager sharedInstance] boolForKey:@"toggleLuv" defaultValue:NO ID:BID]; + showNotification = [[TDTweakManager sharedInstance] boolForKey:@"showNotification" defaultValue:YES ID:BID]; + floatingButtonSize = [[TDTweakManager sharedInstance] intForKey:@"floatingButtonSize" defaultValue:0 ID:BID]; + floatingButtonStyles = [[TDTweakManager sharedInstance] intForKey:@"floatingButtonStyles" defaultValue:0 ID:BID]; + hapticType = [[TDTweakManager sharedInstance] intForKey:@"hapticType" defaultValue:0 ID:BID]; + toggleHaptic = [[TDTweakManager sharedInstance] boolForKey:@"toggleHaptic" defaultValue:YES ID:BID]; + luvAppearance = [[TDTweakManager sharedInstance] objectForKey:@"luvAppearance" defaultValue:@"luvDark" ID:BID]; + toggleColour = [[TDTweakManager sharedInstance] boolForKey:@"toggleColour" defaultValue:NO ID:BID]; + floatingIconStyle = [[TDTweakManager sharedInstance] intForKey:@"floatingIconStyle" defaultValue:0 ID:BID]; +} + +%ctor { + + NSString * path = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0]; + if ([path containsString:@"/Application"] || [path containsString:@"SpringBoard.app"]) { + + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)SettingsChanged, CFSTR("com.TitanD3v.LuvPrefs.settingschanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + SettingsChanged(); + + if (toggleLuv) { + %init(LuvHooks); + } + + } +} diff --git a/Luv/Tweak/Makefile b/Luv/Tweak/Makefile new file mode 100644 index 0000000..9041627 --- /dev/null +++ b/Luv/Tweak/Makefile @@ -0,0 +1,13 @@ +TWEAK_NAME = Luv + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit MediaRemote +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Luv/Tweak/TopWindow.h b/Luv/Tweak/TopWindow.h new file mode 100644 index 0000000..e8d7496 --- /dev/null +++ b/Luv/Tweak/TopWindow.h @@ -0,0 +1,5 @@ +#import +#import + +@interface TopWindow : UIWindow +@end \ No newline at end of file diff --git a/Luv/Tweak/TopWindow.m b/Luv/Tweak/TopWindow.m new file mode 100644 index 0000000..11b6c90 --- /dev/null +++ b/Luv/Tweak/TopWindow.m @@ -0,0 +1,36 @@ +#import "TopWindow.h" + +@implementation TopWindow +- (id)initWithFrame:(CGRect)frame { + + + self = [super initWithFrame:frame]; + self.clipsToBounds = YES; + self.backgroundColor = UIColor.clearColor; + self.layer.masksToBounds = YES; + self.windowLevel = 3000; + //self.windowLevel = UIWindowLevelStatusBar; + self.alpha = 1; + self.opaque = NO; + self.userInteractionEnabled = YES; + + return self; +} + + +- (bool)_shouldCreateContextAsSecure{ + return YES; +} + + +-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { + + for (UIView* subview in self.subviews ) { + if ( [subview hitTest:[self convertPoint:point toView:subview] withEvent:event] != nil ) { + return YES; + } + } + return NO; +} + +@end diff --git a/Luv/control b/Luv/control new file mode 100644 index 0000000..3e49daf --- /dev/null +++ b/Luv/control @@ -0,0 +1,11 @@ +Package: com.titand3v.luv +Name: Luv +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal +Version: 1.1 +Section: Tweaks +Description: TitanD3v Tweaks +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/luv/index.html +Icon: https://titand3v.github.io/depictions/luv/assets/icon.png diff --git a/Luv/layout/DEBIAN/postinst b/Luv/layout/DEBIAN/postinst new file mode 100755 index 0000000..721375c --- /dev/null +++ b/Luv/layout/DEBIAN/postinst @@ -0,0 +1,8 @@ +echo "" +echo "" +echo "Thank you for installing Luv 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/Nova/.DS_Store b/Nova/.DS_Store new file mode 100644 index 0000000..67bde69 Binary files /dev/null and b/Nova/.DS_Store differ diff --git a/Nova/Makefile b/Nova/Makefile new file mode 100644 index 0000000..d2ef0e2 --- /dev/null +++ b/Nova/Makefile @@ -0,0 +1,17 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0 +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +FINALPACKAGE = 1 +DEBUG = 0 + +export CFLAGS = -include $(realpath NCCenter.h) + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak Prefs + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Nova/NCCenter.h b/Nova/NCCenter.h new file mode 100644 index 0000000..0b2feb1 --- /dev/null +++ b/Nova/NCCenter.h @@ -0,0 +1,9 @@ +#import + +@interface NSDistributedNotificationCenter : NSNotificationCenter ++ (instancetype)defaultCenter; +-(void)postNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3 deliverImmediately:(BOOL)arg4 ; +- (void)postNotificationName:(NSString *)name object:(NSString *)object userInfo:(NSDictionary *)userInfo; +-(id)addObserverForName:(id)arg1 object:(id)arg2 queue:(id)arg3 usingBlock:(/*^block*/id)arg4 ; +-(void)addObserver:(id)arg1 selector:(SEL)arg2 name:(id)arg3 object:(id)arg4 ; +@end \ No newline at end of file diff --git a/Nova/Prefs/Makefile b/Nova/Prefs/Makefile new file mode 100644 index 0000000..00978a4 --- /dev/null +++ b/Nova/Prefs/Makefile @@ -0,0 +1,15 @@ +BUNDLE_NAME = NovaPrefs + +$(BUNDLE_NAME)_FILES = $(wildcard *.m Purchase/*.m) +$(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles +$(BUNDLE_NAME)_FRAMEWORKS = UIKit +$(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences OnBoardingKit +$(BUNDLE_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(BUNDLE_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt #mryipc + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/bundle.mk + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) + $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/NovaPrefs.plist$(ECHO_END) diff --git a/Nova/Prefs/NOVPrimraryListController.h b/Nova/Prefs/NOVPrimraryListController.h new file mode 100644 index 0000000..d80f42b --- /dev/null +++ b/Nova/Prefs/NOVPrimraryListController.h @@ -0,0 +1,29 @@ +#import +#import + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1;; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + + +@interface NOVPrimraryListController : TDPrimraryController { + OBWelcomeController *onboardingController; + OBWelcomeController *updateController; +} + +@end diff --git a/Nova/Prefs/NOVPrimraryListController.m b/Nova/Prefs/NOVPrimraryListController.m new file mode 100644 index 0000000..99aebb0 --- /dev/null +++ b/Nova/Prefs/NOVPrimraryListController.m @@ -0,0 +1,127 @@ +#include "NOVPrimraryListController.h" + + +@implementation NOVPrimraryListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Primrary" target:self]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[TDPrefsManager sharedInstance] initWithBundleID:@"com.TitanD3v.NovaPrefs" tweakName:@"Nova" prefsBundle:@"NovaPrefs.bundle"]; + + [[TDPrefsManager sharedInstance] bannerTitle:@"Nova" subtitle:@"Coded with 🤍" devName:@"TitanD3v" coverImagePath:@"/Assets/Banner/cover-image.png" showCoverImage:YES iconPath:@"/Assets/Banner/banner-icon.png" iconTint:NO]; + + [[TDPrefsManager sharedInstance] changelogPlistPath:@"/Assets/Changelog/changelog.plist" currentVersion:@"Version 1.3"]; + + [[TDPrefsManager sharedInstance] useAssetsFromLibrary:YES]; + +} + + +-(void)presentTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + onboardingController = [[OBWelcomeController alloc] initWithTitle:@"User Guide" detailText:@"A walk through tutorial how to use Nova" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/NovaPrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]]; + + [onboardingController addBulletedListItemWithTitle:@"Your time" description:@"Please take a few minutes of your time to read through to get started." image:[UIImage systemImageNamed:@"timer"]]; + + [onboardingController addBulletedListItemWithTitle:@"Main page" description:@"On the main page, there's menu icon on the navigation bar it will present the drawer when tapped. You will find the social media details, changelog, backup/restore, themes, tweak list, profile and crew list." image:[UIImage systemImageNamed:@"square.stack.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Purchase" description:@"Once you activate the 2 day free trial or purchase Nova then you will need to respring, after that you can enable Nova" image:[UIImage systemImageNamed:@"dollarsign.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Compose" description:@"You can change your chat bubble avatar image and name from Compose Settings otherwise it will use the default settings" image:[UIImage systemImageNamed:@"pencil.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Colour" description:@"You can change the colour of Nova user interface if you don’t want it to adapt your system appearance for light or dark mode from the Colour section" image:[UIImage systemImageNamed:@"eyedropper.full"]]; + + [onboardingController addBulletedListItemWithTitle:@"Miscellaneous" description:@"You can configure some settings such as the floating button alignment, haptic feedback, etc from the Miscellaneous section" image:[UIImage systemImageNamed:@"gear"]]; + + [onboardingController addBulletedListItemWithTitle:@"Review" description:@"Please make sure to write a review for Nova, we would love to hear your feedback about Nova so we can improve it for its users." image:[UIImage systemImageNamed:@"star.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Report a bug" description:@"If you are experiencing a bug or any other issues, you can report a bug from this page below the close button, it will bring up the Bug Report page. You can select the categories, write description about a bug, attach a .txt file, photo, provide URL link for the pastebin or any pasteboard website also you can attach all of them if you want. Once you submit a bug report and our team will be in touch with you within 48 hours. If you haven't heard anything from us and please don't hesitate to get in touch with us through social media." image:[UIImage systemImageNamed:@"ant.circle.fill"]]; + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [onboardingController.buttonTray addButton:dismissButton]; + + onboardingController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:onboardingController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [onboardingController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + onboardingController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [onboardingController.buttonTray addCaptionText:@"Thank you for installing Nova"]; + + onboardingController.modalPresentationStyle = UIModalPresentationPageSheet; + onboardingController.modalInPresentation = YES; + [self presentViewController:onboardingController animated:YES completion:nil]; + + UIView *reportView = [[UIView alloc] init]; + reportView.backgroundColor = UIColor.clearColor; + [onboardingController.buttonTray addSubview:reportView]; + + reportView.translatesAutoresizingMaskIntoConstraints = NO; + [reportView.topAnchor constraintEqualToAnchor:dismissButton.bottomAnchor constant:10].active = YES; + [[reportView centerXAnchor] constraintEqualToAnchor:onboardingController.buttonTray.centerXAnchor].active = true; + [reportView.widthAnchor constraintEqualToConstant:140].active = YES; + [reportView.heightAnchor constraintEqualToConstant:40].active = YES; + + + UIImageView *bugImage = [[UIImageView alloc] init]; + bugImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + bugImage.tintColor = [[TDAppearance sharedInstance] tintColour]; + [reportView addSubview:bugImage]; + + bugImage.translatesAutoresizingMaskIntoConstraints = NO; + [bugImage.leadingAnchor constraintEqualToAnchor:reportView.leadingAnchor constant:10].active = YES; + [[bugImage centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + [bugImage.widthAnchor constraintEqualToConstant:30].active = YES; + [bugImage.heightAnchor constraintEqualToConstant:30].active = YES; + + + UILabel *reportLabel = [[UILabel alloc] init]; + reportLabel.text = @"Report a bug"; + reportLabel.textColor = [[TDAppearance sharedInstance] tintColour]; + reportLabel.textAlignment = NSTextAlignmentLeft; + [reportView addSubview:reportLabel]; + + reportLabel.translatesAutoresizingMaskIntoConstraints = NO; + [reportLabel.leadingAnchor constraintEqualToAnchor:bugImage.trailingAnchor constant:5].active = YES; + [[reportLabel centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + + [reportView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentReportBugVC)]]; + +} + + +-(void)dismissTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentReportBugVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; + + TDReportBugViewController *bugVC = [[TDReportBugViewController alloc] init]; + bugVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [self presentViewController:bugVC animated:YES completion:nil]; +} + +@end diff --git a/Nova/Prefs/NOVSecondaryListController.h b/Nova/Prefs/NOVSecondaryListController.h new file mode 100644 index 0000000..09e3e62 --- /dev/null +++ b/Nova/Prefs/NOVSecondaryListController.h @@ -0,0 +1,12 @@ +#import +#import + +@interface NOVComposeListController : TDSecondaryController +@end + +@interface NOVColourListController : TDSecondaryController +@end + +@interface NOVMiscellaneousListController : TDSecondaryController +@end + diff --git a/Nova/Prefs/NOVSecondaryListController.m b/Nova/Prefs/NOVSecondaryListController.m new file mode 100644 index 0000000..acf3dfc --- /dev/null +++ b/Nova/Prefs/NOVSecondaryListController.m @@ -0,0 +1,39 @@ +#include "NOVSecondaryListController.h" + +@implementation NOVComposeListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Compose" target:self]; + } + + return _specifiers; +} + +@end + + +@implementation NOVColourListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Colour" target:self]; + } + + return _specifiers; +} + +@end + + +@implementation NOVMiscellaneousListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Miscellaneous" target:self]; + } + + return _specifiers; +} + +@end diff --git a/Nova/Prefs/Resources/Assets/Banner/banner-icon.png b/Nova/Prefs/Resources/Assets/Banner/banner-icon.png new file mode 100644 index 0000000..61c0aa0 Binary files /dev/null and b/Nova/Prefs/Resources/Assets/Banner/banner-icon.png differ diff --git a/Nova/Prefs/Resources/Assets/Banner/cover-image.png b/Nova/Prefs/Resources/Assets/Banner/cover-image.png new file mode 100644 index 0000000..67f24fc Binary files /dev/null and b/Nova/Prefs/Resources/Assets/Banner/cover-image.png differ diff --git a/Nova/Prefs/Resources/Assets/Cell/prefs-icon@2x.png b/Nova/Prefs/Resources/Assets/Cell/prefs-icon@2x.png new file mode 100644 index 0000000..24089c2 Binary files /dev/null and b/Nova/Prefs/Resources/Assets/Cell/prefs-icon@2x.png differ diff --git a/Nova/Prefs/Resources/Assets/Cell/prefs-icon@3x.png b/Nova/Prefs/Resources/Assets/Cell/prefs-icon@3x.png new file mode 100644 index 0000000..3f4de8c Binary files /dev/null and b/Nova/Prefs/Resources/Assets/Cell/prefs-icon@3x.png differ diff --git a/Nova/Prefs/Resources/Assets/Changelog/changelog.plist b/Nova/Prefs/Resources/Assets/Changelog/changelog.plist new file mode 100644 index 0000000..88f2340 --- /dev/null +++ b/Nova/Prefs/Resources/Assets/Changelog/changelog.plist @@ -0,0 +1,71 @@ + + + + + + + Date + 13th June 2021 + Version + v1.3 + ChangelogDescription + + Fixed licence when purchasing Nova + + updateCategories + + 1 + + + + + Date + 17th May 2021 + Version + v1.2 + ChangelogDescription + + Fixed update alert on springboard + + updateCategories + + 1 + + + + + Date + 17th May 2021 + Version + v1.1 + ChangelogDescription + + Fixed active schedule message avatar image content mode + Now you can send up to 10 photos attachments + You can add wallpaper background image to Nova's background + + updateCategories + + 1 + 3 + 3 + + + + + Date + 14th May 2021 + Version + v1.0 + ChangelogDescription + + Initial Release... + + updateCategories + + 0 + + + + + \ No newline at end of file diff --git a/Nova/Prefs/Resources/Assets/ExtSettings/Colour.plist b/Nova/Prefs/Resources/Assets/ExtSettings/Colour.plist new file mode 100644 index 0000000..a16a7fc --- /dev/null +++ b/Nova/Prefs/Resources/Assets/ExtSettings/Colour.plist @@ -0,0 +1,468 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Custom Colour + + + + cellClass + TDEnableCell + default + + key + toggleCustomColour + disabledTitle + Disable Colour + enabledTitle + Enable Colour + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + disabledIconPath + colour + enabledIconPath + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Background + subtitle + Colour + default + FFFFFF + key + backgroundColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Cell + subtitle + Colour + default + FFFFFF + key + cellColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Font + subtitle + Colour + default + FFFFFF + key + fontColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Accent + subtitle + Colour + default + FFFFFF + key + accentColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Navigation Bar + subtitle + Colour + default + FFFFFF + key + navbarColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Clock Icon + subtitle + Colour + default + FFFFFF + key + clockColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Checkmark Icon + subtitle + Colour + default + FFFFFF + key + checkmarkColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Floating Button + subtitle + Colour + default + FFFFFF + key + floatingButtonColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Floating Icon + subtitle + Colour + default + FFFFFF + key + floatingIconColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Your Bubble Font + subtitle + Colour + default + FFFFFF + key + bubbleFontColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Your Bubble + subtitle + Colour + default + FFFFFF + key + bubbleColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Recipient Bubble Font + subtitle + Colour + default + FFFFFF + key + recipientBubbleFontColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Recipient Bubble + subtitle + Colour + default + FFFFFF + key + recipientBubbleColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Remaining Time Font + subtitle + Colour + default + FFFFFF + key + remainingFontColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Separator Line + subtitle + Colour + default + FFFFFF + key + separatorColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Remaining Background + subtitle + Colour + default + FFFFFF + key + remainingBackgroundColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Sent Background + subtitle + Colour + default + FFFFFF + key + sentBackgroundColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Icons + subtitle + Colour + default + FFFFFF + key + iconColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Photo Button + subtitle + Colour + default + FFFFFF + key + photoButtonColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Tool Bar + subtitle + Colour + default + FFFFFF + key + toolbarColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + title + + + diff --git a/Nova/Prefs/Resources/Assets/ExtSettings/Compose.plist b/Nova/Prefs/Resources/Assets/ExtSettings/Compose.plist new file mode 100644 index 0000000..30d3c55 --- /dev/null +++ b/Nova/Prefs/Resources/Assets/ExtSettings/Compose.plist @@ -0,0 +1,78 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Name + + + + cellClass + TDEditCell + title + Your + subtitle + Name + objectKey + senderName + placeholderText + Your Name + default + You + iconName + edit + keyboardType + keyboard + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Avatar + + + + cell + PSLinkCell + cellClass + TDImagePickerCell + title + Your Avatar + subtitle + Image + action + chooseImage + key + senderAvatarImage + usesJPEG + + compressionQuality + 0.8 + iconName + photo + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + title + + + diff --git a/Nova/Prefs/Resources/Assets/ExtSettings/Miscellaneous.plist b/Nova/Prefs/Resources/Assets/ExtSettings/Miscellaneous.plist new file mode 100644 index 0000000..ca52145 --- /dev/null +++ b/Nova/Prefs/Resources/Assets/ExtSettings/Miscellaneous.plist @@ -0,0 +1,260 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Wallpaper + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleWallpaper + title + Enable + subtitle + Background Wallpaper + iconName + switch + showTips + + tipsTitle + Example Title + tipsMessage + This is an example banner. + tipsImageStyle + 1 + tipsImage + Assets/example-banner.png + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDImagePickerCell + title + Wallpaper + subtitle + Image + action + chooseImage + key + wallpaperImage + usesJPEG + + compressionQuality + 0.8 + iconName + photo + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Hide Floating Button + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleHideFloatingButton + title + Floating Button + subtitle + Hide when scrolling down + iconName + switch + showTips + + tipsTitle + Example Title + tipsMessage + This is an example banner. + tipsImageStyle + 1 + tipsImage + Assets/example-banner.png + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Alignment + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + floatingButtonAlignment + default + 3 + validTitles + + Left + Center + Right + + validValues + + 1 + 2 + 3 + + title + Floating button alignment + showTips + + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Haptic + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleHaptic + title + Enable + subtitle + Haptic Feedback + iconName + switch + showTips + + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + hapticStrength + default + 0 + validTitles + + Light + Medium + Heavy + + validValues + + 0 + 1 + 2 + + title + Type + showTips + + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Smart Airplane Mode + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleSmartAirplaneMode + title + Enable + subtitle + Smart Airplane Mode + iconName + switch + showTips + + tipsTitle + Smart Airplane Mode + tipsMessage + If your airplane mode is enabled before your schedule message are due to send to recipient, it will disable airplane mode for couple of minutes to send the message then enable airplane mode again after sent the message. + tipsImageStyle + 0 + tipsImage + airplane + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + title + + + diff --git a/Nova/Prefs/Resources/Assets/ExtSettings/Root.plist b/Nova/Prefs/Resources/Assets/ExtSettings/Root.plist new file mode 100644 index 0000000..6a1e5ab --- /dev/null +++ b/Nova/Prefs/Resources/Assets/ExtSettings/Root.plist @@ -0,0 +1,46 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Categories + + + + cellClass + TDGridCell + leftTitle + Compose Settings + leftIconName + compose + leftClass + NOVExtComposeListController + middleTitle + Colour + middleIconName + colour + middleClass + NOVExtColourListController + rightTitle + Miscellaneous + rightIconName + misc + rightClass + NOVExtMiscellaneousListController + classID + external + + + + title + + + diff --git a/Nova/Prefs/Resources/Assets/Payment/ss1.png b/Nova/Prefs/Resources/Assets/Payment/ss1.png new file mode 100644 index 0000000..a32f508 Binary files /dev/null and b/Nova/Prefs/Resources/Assets/Payment/ss1.png differ diff --git a/Nova/Prefs/Resources/Assets/Payment/ss2.png b/Nova/Prefs/Resources/Assets/Payment/ss2.png new file mode 100644 index 0000000..7cf21b0 Binary files /dev/null and b/Nova/Prefs/Resources/Assets/Payment/ss2.png differ diff --git a/Nova/Prefs/Resources/Assets/Payment/ss3.png b/Nova/Prefs/Resources/Assets/Payment/ss3.png new file mode 100644 index 0000000..3e61b56 Binary files /dev/null and b/Nova/Prefs/Resources/Assets/Payment/ss3.png differ diff --git a/Nova/Prefs/Resources/Assets/Payment/ss4.png b/Nova/Prefs/Resources/Assets/Payment/ss4.png new file mode 100644 index 0000000..f4a3c33 Binary files /dev/null and b/Nova/Prefs/Resources/Assets/Payment/ss4.png differ diff --git a/Nova/Prefs/Resources/Assets/Payment/ss5.png b/Nova/Prefs/Resources/Assets/Payment/ss5.png new file mode 100644 index 0000000..c9a21f3 Binary files /dev/null and b/Nova/Prefs/Resources/Assets/Payment/ss5.png differ diff --git a/Nova/Prefs/Resources/Colour.plist b/Nova/Prefs/Resources/Colour.plist new file mode 100644 index 0000000..a16a7fc --- /dev/null +++ b/Nova/Prefs/Resources/Colour.plist @@ -0,0 +1,468 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Custom Colour + + + + cellClass + TDEnableCell + default + + key + toggleCustomColour + disabledTitle + Disable Colour + enabledTitle + Enable Colour + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + disabledIconPath + colour + enabledIconPath + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Background + subtitle + Colour + default + FFFFFF + key + backgroundColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Cell + subtitle + Colour + default + FFFFFF + key + cellColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Font + subtitle + Colour + default + FFFFFF + key + fontColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Accent + subtitle + Colour + default + FFFFFF + key + accentColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Navigation Bar + subtitle + Colour + default + FFFFFF + key + navbarColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Clock Icon + subtitle + Colour + default + FFFFFF + key + clockColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Checkmark Icon + subtitle + Colour + default + FFFFFF + key + checkmarkColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Floating Button + subtitle + Colour + default + FFFFFF + key + floatingButtonColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Floating Icon + subtitle + Colour + default + FFFFFF + key + floatingIconColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Your Bubble Font + subtitle + Colour + default + FFFFFF + key + bubbleFontColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Your Bubble + subtitle + Colour + default + FFFFFF + key + bubbleColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Recipient Bubble Font + subtitle + Colour + default + FFFFFF + key + recipientBubbleFontColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Recipient Bubble + subtitle + Colour + default + FFFFFF + key + recipientBubbleColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Remaining Time Font + subtitle + Colour + default + FFFFFF + key + remainingFontColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Separator Line + subtitle + Colour + default + FFFFFF + key + separatorColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Remaining Background + subtitle + Colour + default + FFFFFF + key + remainingBackgroundColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Sent Background + subtitle + Colour + default + FFFFFF + key + sentBackgroundColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Icons + subtitle + Colour + default + FFFFFF + key + iconColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Photo Button + subtitle + Colour + default + FFFFFF + key + photoButtonColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Tool Bar + subtitle + Colour + default + FFFFFF + key + toolbarColour + iconName + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + title + + + diff --git a/Nova/Prefs/Resources/Compose.plist b/Nova/Prefs/Resources/Compose.plist new file mode 100644 index 0000000..30d3c55 --- /dev/null +++ b/Nova/Prefs/Resources/Compose.plist @@ -0,0 +1,78 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Name + + + + cellClass + TDEditCell + title + Your + subtitle + Name + objectKey + senderName + placeholderText + Your Name + default + You + iconName + edit + keyboardType + keyboard + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Avatar + + + + cell + PSLinkCell + cellClass + TDImagePickerCell + title + Your Avatar + subtitle + Image + action + chooseImage + key + senderAvatarImage + usesJPEG + + compressionQuality + 0.8 + iconName + photo + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + title + + + diff --git a/Nova/Prefs/Resources/Info.plist b/Nova/Prefs/Resources/Info.plist new file mode 100644 index 0000000..a3405c5 --- /dev/null +++ b/Nova/Prefs/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + NovaPrefs + CFBundleIdentifier + com.TitanD3v.novaprefs + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + NOVPrimraryListController + + diff --git a/Nova/Prefs/Resources/Miscellaneous.plist b/Nova/Prefs/Resources/Miscellaneous.plist new file mode 100644 index 0000000..d923b4c --- /dev/null +++ b/Nova/Prefs/Resources/Miscellaneous.plist @@ -0,0 +1,220 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Wallpaper + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleWallpaper + title + Enable + subtitle + Background Wallpaper + iconName + switch + showTips + + tipsTitle + Example Title + tipsMessage + This is an example banner. + tipsImageStyle + 1 + tipsImage + Assets/example-banner.png + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDImagePickerCell + title + Wallpaper + subtitle + Image + action + chooseImage + key + wallpaperImage + usesJPEG + + compressionQuality + 0.8 + iconName + photo + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Hide Floating Button + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleHideFloatingButton + title + Floating Button + subtitle + Hide when scrolling down + iconName + switch + showTips + + tipsTitle + Example Title + tipsMessage + This is an example banner. + tipsImageStyle + 1 + tipsImage + Assets/example-banner.png + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Alignment + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + floatingButtonAlignment + default + 3 + validTitles + + Left + Center + Right + + validValues + + 1 + 2 + 3 + + title + Floating button alignment + showTips + + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Haptic + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleHaptic + title + Enable + subtitle + Haptic Feedback + iconName + switch + showTips + + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + hapticStrength + default + 0 + validTitles + + Light + Medium + Heavy + + validValues + + 0 + 1 + 2 + + title + Type + showTips + + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + title + + + diff --git a/Nova/Prefs/Resources/Primrary.plist b/Nova/Prefs/Resources/Primrary.plist new file mode 100644 index 0000000..8e23487 --- /dev/null +++ b/Nova/Prefs/Resources/Primrary.plist @@ -0,0 +1,82 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable + + + + cellClass + TDEnableCell + default + + key + toggleNova + disabledTitle + Disable Nova + enabledTitle + Enable Nova + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + disabledIconPath + colour + enabledIconPath + colour + defaults + com.TitanD3v.NovaPrefs + PostNotification + com.TitanD3v.NovaPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Categories + + + + cellClass + TDGridCell + leftTitle + Compose Settings + leftIconName + compose + leftClass + NOVComposeListController + middleTitle + Colour + middleIconName + colour + middleClass + NOVColourListController + rightTitle + Miscellaneous + rightIconName + misc + rightClass + NOVMiscellaneousListController + classID + primrary + + + + title + + + diff --git a/Nova/Prefs/entry.plist b/Nova/Prefs/entry.plist new file mode 100644 index 0000000..9b3084b --- /dev/null +++ b/Nova/Prefs/entry.plist @@ -0,0 +1,21 @@ + + + + + entry + + bundle + NovaPrefs + cell + PSLinkCell + detail + NOVPrimraryListController + icon + Assets/Cell/prefs-icon.png + isController + + label + Nova + + + diff --git a/Nova/Tweak/Headers.h b/Nova/Tweak/Headers.h new file mode 100644 index 0000000..3e93763 --- /dev/null +++ b/Nova/Tweak/Headers.h @@ -0,0 +1,42 @@ +#import +#import +#import "./NOVA/ColourScheme/Colour-Scheme.h" +#import +#import "./NOVA/Blur/FloatingBlurView.h" +#import "./NOVA/ActiveScheduleVC.h" +#import "ScheduleManager.h" + + +@interface SpringBoard : NSObject +-(void)loadSchedules; +-(void)launchTestView; +@end + +@interface PCSimpleTimer : NSObject { + NSRunLoop* _timerRunLoop; +} +-(id)userInfo; +-(void)scheduleInRunLoop:(id)arg1 ; +-(id)initWithFireDate:(id)arg1 serviceIdentifier:(id)arg2 target:(id)arg3 selector:(SEL)arg4 userInfo:(id)arg5 ; +- (void)invalidate; +@end + +@interface SMSScheuler : NSObject +- (NSNumber *)sendText:(NSDictionary *)vals; +@end + +@interface SSender : NSObject +@property (strong) CPDistributedMessagingCenter * messagingCenter; +- (id)init; +- (BOOL)sendText:(NSString *)body toPhn:(NSString *)address withAttachments:(NSArray*)files; +@end + +@interface UIApplication (NOVA) +- (BOOL)launchApplicationWithIdentifier:(NSString *)identifier suspended:(BOOL)suspend; +@end + +@interface SBAirplaneModeController : NSObject ++(id)sharedInstance; +-(BOOL)isInAirplaneMode; +-(void)setInAirplaneMode:(BOOL)arg1 ; +@end \ No newline at end of file diff --git a/Nova/Tweak/Makefile b/Nova/Tweak/Makefile new file mode 100644 index 0000000..e0e9392 --- /dev/null +++ b/Nova/Tweak/Makefile @@ -0,0 +1,22 @@ +TWEAK_NAME = Nova + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +dtoim = $(foreach d,$(1),-I$(d)) +_IMPORTS = $(shell /bin/ls -d ./NOVA/*/) +_IMPORTS += $(shell /bin/ls -d ./NOVA/*/*/) +_IMPORTS += $(shell /bin/ls -d ./NOVA/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./NOVA/*/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./) +IMPORTS = -I$./NOVA $(call dtoim, $(_IMPORTS)) + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations $(IMPORTS) +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt rocketbootstrap +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit PersistentConnection AppSupport Preferences +$(TWEAK_NAME)_FRAMEWORKS = UIKit Photos PhotosUI + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Nova/Tweak/NOVA/ActiveScheduleVC.h b/Nova/Tweak/NOVA/ActiveScheduleVC.h new file mode 100644 index 0000000..e6b6c8f --- /dev/null +++ b/Nova/Tweak/NOVA/ActiveScheduleVC.h @@ -0,0 +1,9 @@ +#import +#import "CreateScheduleVC.h" +#import "ActiveCell.h" +#import "Colour-Scheme.h" + +@interface ActiveScheduleVC : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@end + diff --git a/Nova/Tweak/NOVA/ActiveScheduleVC.m b/Nova/Tweak/NOVA/ActiveScheduleVC.m new file mode 100644 index 0000000..f1824f9 --- /dev/null +++ b/Nova/Tweak/NOVA/ActiveScheduleVC.m @@ -0,0 +1,296 @@ +#import "ActiveScheduleVC.h" +#import "ScheduleManager.h" + +NSMutableArray *todaysSchedules; +NSMutableArray *futureSchedules; +NSMutableArray *sentSchedules; +NSTimer *tableRefresher; +ScheduleManager *sharedInstance; + +@implementation ActiveScheduleVC + +- (void)viewDidLoad { + [super viewDidLoad]; + + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + + if (toggleWallpaper) { + UIImageView *backgroundImage = [[UIImageView alloc] initWithFrame:self.view.bounds]; + backgroundImage.contentMode = UIViewContentModeScaleAspectFill; + backgroundImage.image = [UIImage imageWithData:wallpaperImage]; + [self.view addSubview:backgroundImage]; + } + + self.title = @"Schedule Messages"; + + if (toggleCustomColour) { + self.navigationController.navigationBar.barTintColor = [[TDTweakManager sharedInstance] colourForKey:@"navbarColour" defaultValue:@"FFFFFF" ID:BID]; + } + self.navigationController.navigationBar.tintColor = [UIColor accentColour]; + [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor fontColour]}]; + + UIBarButtonItem *createButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(createSchedule)]; + self.navigationItem.rightBarButtonItem = createButton; + + UIBarButtonItem *settingButton = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"gear"] style:UIBarButtonItemStylePlain target:self action:@selector(presentSettingVC)]; + self.navigationItem.leftBarButtonItem = settingButton; + + [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.Nova/ActiveScheduleVCReload" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self reloadTableData]; + }); + }]; + + tableRefresher = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(reloadTableData) userInfo:nil repeats:YES]; + + todaysSchedules = [NSMutableArray new]; + [self loadSchedules]; + [self layoutTableView]; +} + + +-(void)loadSchedules{ + sharedInstance = [[ScheduleManager sharedInstance] init]; + todaysSchedules = [sharedInstance getTodaysSchedules]; + futureSchedules = [sharedInstance getFutureSchedules]; + sentSchedules = [sharedInstance getSentSchedules]; +} + +-(void)reloadTableData{ + [self loadSchedules]; + [self.tableView reloadData]; +} + +-(void)layoutTableView { + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 3; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + + if (section == 0) { // Today + return [todaysSchedules count]; + } else if (section == 1) { // Future + return [futureSchedules count]; + } else { // Sent + return [sentSchedules count]; + } + +} + + +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + return 35.0f; +} + + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { + + UIView *sectionHeaderView = [[UIView alloc] initWithFrame:CGRectMake(15, 0, tableView.frame.size.width -15, 45)]; + sectionHeaderView.backgroundColor = UIColor.clearColor; + sectionHeaderView.layer.cornerRadius = 15; + sectionHeaderView.clipsToBounds = true; + + UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, sectionHeaderView.frame.size.height /2 -9, 200, 18)]; + headerLabel.backgroundColor = [UIColor clearColor]; + headerLabel.textColor = [UIColor fontColour]; + headerLabel.textAlignment = NSTextAlignmentLeft; + headerLabel.font = [UIFont boldSystemFontOfSize:16]; + [sectionHeaderView addSubview:headerLabel]; + + if (section == 0) { + headerLabel.text = @"Today"; + } else if (section == 1) { + headerLabel.text = @"Future"; + } else { + headerLabel.text = @"Sent"; + } + + return sectionHeaderView; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ActiveCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[ActiveCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + if (indexPath.section == 0) { // Today + + cell.iconImage.image = [[UIImage systemImageNamed:@"clock.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + cell.iconImage.tintColor = [UIColor clockColour]; + cell.remainingView.backgroundColor = [UIColor remainingBackgroundColour]; + + NSString *remainingLabel = [sharedInstance getTimeLeft:todaysSchedules[indexPath.row][@"scheduleLabel"]]; + + cell.avatarImage.image = [UIImage imageWithContentsOfFile:todaysSchedules[indexPath.row][@"avatarImage"]]; + cell.remainingLabel.text = remainingLabel; + cell.recipientLabel.text = todaysSchedules[indexPath.row][@"recipientLabel"]; + cell.messageLabel.text = todaysSchedules[indexPath.row][@"messageLabel"]; + cell.scheduleLabel.text = [sharedInstance dateToStr:todaysSchedules[indexPath.row][@"scheduleLabel"]]; + + } else if (indexPath.section == 1) { // Future + + cell.iconImage.image = [[UIImage systemImageNamed:@"clock.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + cell.iconImage.tintColor = [UIColor clockColour]; + cell.remainingView.backgroundColor = [UIColor remainingBackgroundColour]; + + NSString *remainingLabel = [sharedInstance getTimeLeft:futureSchedules[indexPath.row][@"scheduleLabel"]]; + + cell.avatarImage.image = [UIImage imageWithContentsOfFile:futureSchedules[indexPath.row][@"avatarImage"]]; + cell.remainingLabel.text = remainingLabel; + cell.recipientLabel.text = futureSchedules[indexPath.row][@"recipientLabel"]; + cell.messageLabel.text = futureSchedules[indexPath.row][@"messageLabel"]; + cell.scheduleLabel.text = [sharedInstance dateToStr:futureSchedules[indexPath.row][@"scheduleLabel"]]; + + + } else if (indexPath.section == 2) { // Sent + + cell.iconImage.image = [[UIImage systemImageNamed:@"checkmark.circle.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + cell.iconImage.tintColor = [UIColor checkmarkColour]; + cell.remainingView.backgroundColor = [UIColor sentBackgroundColour]; + cell.remainingLabel.text = @"SENT"; + + cell.avatarImage.image = [UIImage imageWithContentsOfFile:sentSchedules[indexPath.row][@"avatarImage"]]; + cell.recipientLabel.text = sentSchedules[indexPath.row][@"recipientLabel"]; + cell.messageLabel.text = sentSchedules[indexPath.row][@"messageLabel"]; + cell.scheduleLabel.text = [sharedInstance dateToStr:sentSchedules[indexPath.row][@"scheduleLabel"]]; + + } + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 200; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + +} + + +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { + if (editingStyle == UITableViewCellEditingStyleDelete) { + + } +} + + +- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath { + + UIContextualAction *clearAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:nil handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) { + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + + if (indexPath.section == 0) { // Today + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/deleteScheduleWithId" object:nil userInfo:@{@"withID" : todaysSchedules[indexPath.row][@"id"]} deliverImmediately:YES]; + } else if (indexPath.section == 1) { // Future + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/deleteScheduleWithId" object:nil userInfo:@{@"withID" : futureSchedules[indexPath.row][@"id"]} deliverImmediately:YES]; + } else if (indexPath.section == 2) { // Sent + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/deleteScheduleWithId" object:nil userInfo:@{@"withID" : sentSchedules[indexPath.row][@"id"]} deliverImmediately:YES]; + } + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self reloadTableData]; + }); + + }]; + + UIImage *transparentImage = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Nova.bundle/Assets/transparent.png"]; + UIImage *trashImage = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Nova.bundle/Assets/trash.png"]; + CGSize sacleSize = CGSizeMake(50, 50); + UIGraphicsBeginImageContextWithOptions(sacleSize, NO, 0.0); + [trashImage drawInRect:CGRectMake(0, 0, sacleSize.width, sacleSize.height)]; + UIImage * resizedTrashImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + clearAction.image = resizedTrashImage; + clearAction.backgroundColor = [UIColor colorWithPatternImage:transparentImage]; + + + UISwipeActionsConfiguration *configuration = [UISwipeActionsConfiguration configurationWithActions:@[clearAction]]; + + return configuration; + +} + + +-(void)createSchedule { + +[self invokeHapticFeedback]; + + CreateScheduleVC *nvc = [[CreateScheduleVC alloc] init]; + [self.navigationController pushViewController:nvc animated:YES]; + +} + +-(void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + [tableRefresher invalidate]; + tableRefresher = nil; +} + + +-(void)presentSettingVC { + + [self invokeHapticFeedback]; + + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/PresentSetting" object:nil userInfo:nil deliverImmediately:YES]; + + // SettingViewController *svc = [[SettingViewController alloc] init]; + // svc.modalInPresentation = YES; + // UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:svc]; + // [self presentViewController:navController animated:YES completion:nil]; + +} + + +-(void)invokeHapticFeedback { + if (toggleHaptic) { + if (hapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (hapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (hapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + } +} + +@end diff --git a/Nova/Tweak/NOVA/Blur/FloatingBlurView.h b/Nova/Tweak/NOVA/Blur/FloatingBlurView.h new file mode 100644 index 0000000..7bef4d2 --- /dev/null +++ b/Nova/Tweak/NOVA/Blur/FloatingBlurView.h @@ -0,0 +1,7 @@ +#import +#import "Colour-Scheme.h" + +@interface FloatingBlurView : UIView +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (nonatomic, retain) UIImageView *scheduleImage; +@end diff --git a/Nova/Tweak/NOVA/Blur/FloatingBlurView.m b/Nova/Tweak/NOVA/Blur/FloatingBlurView.m new file mode 100644 index 0000000..a1a078d --- /dev/null +++ b/Nova/Tweak/NOVA/Blur/FloatingBlurView.m @@ -0,0 +1,94 @@ +#import "FloatingBlurView.h" + +@implementation FloatingBlurView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + loadPrefs(); + + self.layer.cornerRadius = 30; + self.clipsToBounds = true; + self.layer.shadowOpacity = 0.5; + self.layer.shadowOffset = CGSizeMake(0.0,0.0); + self.layer.shadowRadius = 3.0; + self.layer.masksToBounds = false; + + + self.blurEffectView = [[UIVisualEffectView alloc] initWithFrame:CGRectZero]; + self.blurEffectView.layer.cornerRadius = 30; + self.blurEffectView.clipsToBounds = true; + [self addSubview:self.blurEffectView]; + + self.blurEffectView.translatesAutoresizingMaskIntoConstraints = false; + [self.blurEffectView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0].active = YES; + [self.blurEffectView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0].active = YES; + [self.blurEffectView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:0].active = YES; + [self.blurEffectView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0].active = YES; + + + self.scheduleImage = [[UIImageView alloc] init]; + self.scheduleImage.image = [[UIImage systemImageNamed:@"clock"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [self addSubview:self.scheduleImage]; + + [self.scheduleImage size:CGSizeMake(40, 40)]; + [self.scheduleImage x:self.centerXAnchor y:self.centerYAnchor]; + + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + self.scheduleImage.tintColor = [UIColor whiteColor]; + self.layer.shadowColor = [UIColor colorWithRed: 0.28 green: 0.28 blue: 0.29 alpha: 1.00].CGColor; + + } else { + + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; + self.scheduleImage.tintColor = [UIColor lightGrayColor]; + self.layer.shadowColor = UIColor.lightGrayColor.CGColor; + + } + + if (toggleCustomColour) { + self.blurEffectView.alpha = 0; + self.backgroundColor = [UIColor buttonColour]; + self.scheduleImage.tintColor = [UIColor iconColour]; + self.layer.shadowColor = UIColor.clearColor.CGColor; + } + + } + + return self; + +} + + +- (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + self.scheduleImage.tintColor = [UIColor whiteColor]; + self.layer.shadowColor = [UIColor colorWithRed: 0.28 green: 0.28 blue: 0.29 alpha: 1.00].CGColor; + + } else { + + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; + self.scheduleImage.tintColor = [UIColor lightGrayColor]; + self.layer.shadowColor = UIColor.lightGrayColor.CGColor; + + } + + if (toggleCustomColour) { + self.blurEffectView.alpha = 0; + self.backgroundColor = [UIColor buttonColour]; + self.scheduleImage.tintColor = [UIColor iconColour]; + self.layer.shadowColor = UIColor.clearColor.CGColor; + } + +} + + +@end diff --git a/Nova/Tweak/NOVA/Cells/ActiveCell.h b/Nova/Tweak/NOVA/Cells/ActiveCell.h new file mode 100644 index 0000000..24ad9f5 --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/ActiveCell.h @@ -0,0 +1,18 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPrefernces.h" + +@interface ActiveCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *remainingLabel; +@property (nonatomic, retain) UIImageView *avatarImage; +@property (nonatomic, retain) UILabel *recipientLabel; +@property (nonatomic, retain) UITextView *messageLabel; +@property (nonatomic, retain) UILabel *scheduleLabel; +@property (nonatomic, retain) UIView *splitView; +@property (nonatomic, retain) UIView *remainingView; + +@end + diff --git a/Nova/Tweak/NOVA/Cells/ActiveCell.m b/Nova/Tweak/NOVA/Cells/ActiveCell.m new file mode 100644 index 0000000..5719e37 --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/ActiveCell.m @@ -0,0 +1,153 @@ +#import "ActiveCell.h" + +@implementation ActiveCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + loadPrefs(); + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor cellColour]; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:5]; + [self.baseView leading:self.leadingAnchor padding:10]; + [self.baseView trailing:self.trailingAnchor padding:-10]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + + self.avatarImage = [[UIImageView alloc] init]; + self.avatarImage.layer.cornerRadius = 35; + self.avatarImage.clipsToBounds = true; + self.avatarImage.contentMode = UIViewContentModeScaleAspectFill; + [self.baseView addSubview:self.avatarImage]; + + [self.avatarImage size:CGSizeMake(70, 70)]; + [self.avatarImage top:self.baseView.topAnchor padding:10]; + [self.avatarImage leading:self.baseView.leadingAnchor padding:10]; + + + self.recipientLabel = [[UILabel alloc] init]; + self.recipientLabel.font = [UIFont boldSystemFontOfSize:20]; + self.recipientLabel.textAlignment = NSTextAlignmentLeft; + self.recipientLabel.textColor = [UIColor fontColour]; + [self.baseView addSubview:self.recipientLabel]; + + [self.recipientLabel top:self.avatarImage.topAnchor padding:5]; + [self.recipientLabel leading:self.avatarImage.trailingAnchor padding:10]; + [self.recipientLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.messageLabel = [[UITextView alloc] init]; + self.messageLabel.font = [UIFont systemFontOfSize:15]; + self.messageLabel.textAlignment = NSTextAlignmentLeft; + self.messageLabel.delegate = self; + self.messageLabel.backgroundColor = [UIColor bubbleColour]; + self.messageLabel.layer.cornerRadius = 20; + self.messageLabel.layer.maskedCorners = 14; + self.messageLabel.textColor = [UIColor bubbleFontColour]; + self.messageLabel.editable = NO; + [self.contentView addSubview:self.messageLabel]; + + [self.messageLabel top:self.recipientLabel.bottomAnchor padding:10]; + [self.messageLabel leading:self.avatarImage.trailingAnchor padding:10]; + [self.messageLabel trailing:self.baseView.trailingAnchor padding:-60]; + [self.messageLabel height:70]; + + + self.splitView = [[UIView alloc] init]; + self.splitView.backgroundColor = [UIColor yellowColor]; + self.splitView.layer.cornerRadius = 1; + [self.baseView addSubview:self.splitView]; + + [self.splitView x:self.baseView.centerXAnchor]; + [self.splitView height:2]; + [self.splitView top:self.messageLabel.bottomAnchor padding:15]; + [self.splitView leading:self.baseView.leadingAnchor padding:20]; + [self.splitView trailing:self.baseView.trailingAnchor padding:-20]; + + + self.remainingView = [[UIView alloc] init]; + self.remainingView.layer.cornerRadius = 8; + self.remainingView.layer.cornerCurve = kCACornerCurveContinuous; + self.remainingView.clipsToBounds = true; + [self.baseView addSubview:self.remainingView]; + + [self.remainingView size:CGSizeMake(120, 35)]; + [self.remainingView top:self.splitView.bottomAnchor padding:12]; + [self.remainingView leading:self.baseView.leadingAnchor padding:20]; + + + self.iconImage = [[UIImageView alloc] init]; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(25, 25)]; + [self.iconImage y:self.remainingView.centerYAnchor]; + [self.iconImage leading:self.remainingView.leadingAnchor padding:5]; + + + self.remainingLabel = [[UILabel alloc] init]; + self.remainingLabel.font = [UIFont boldSystemFontOfSize:12]; + self.remainingLabel.textAlignment = NSTextAlignmentLeft; + self.remainingLabel.textColor = [UIColor remainingFontColour]; + [self.remainingView addSubview:self.remainingLabel]; + + [self.remainingLabel y:self.iconImage.centerYAnchor]; + [self.remainingLabel leading:self.iconImage.trailingAnchor padding:5]; + [self.remainingLabel trailing:self.remainingView.trailingAnchor padding:-5]; + + + self.scheduleLabel = [[UILabel alloc] init]; + self.scheduleLabel.font = [UIFont systemFontOfSize:13]; + self.scheduleLabel.textAlignment = NSTextAlignmentRight; + self.scheduleLabel.numberOfLines = 1; + self.scheduleLabel.textColor = [UIColor fontColour]; + [self.baseView addSubview:self.scheduleLabel]; + + [self.scheduleLabel y:self.remainingView.centerYAnchor]; + [self.scheduleLabel leading:self.remainingView.trailingAnchor padding:10]; + [self.scheduleLabel trailing:self.baseView.trailingAnchor padding:-20]; + + + if (!toggleCustomColour) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.splitView.backgroundColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.1]; + } else { + self.splitView.backgroundColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 1.0]; + } + + } else { + self.splitView.backgroundColor = [UIColor separatorColour]; + } + + } + + return self; +} + + +- (void)traitCollectionDidChange:(UITraitCollection *) previousTraitCollection { + + if (!toggleCustomColour) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.splitView.backgroundColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.1]; + } else { + self.splitView.backgroundColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 1.0]; + } + + } else { + self.splitView.backgroundColor = [UIColor separatorColour]; + } + +} + +@end diff --git a/Nova/Tweak/NOVA/Cells/BubbleCell.h b/Nova/Tweak/NOVA/Cells/BubbleCell.h new file mode 100644 index 0000000..63d2364 --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/BubbleCell.h @@ -0,0 +1,8 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPrefernces.h" + +@interface BubbleCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@end + diff --git a/Nova/Tweak/NOVA/Cells/BubbleCell.m b/Nova/Tweak/NOVA/Cells/BubbleCell.m new file mode 100644 index 0000000..2af602d --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/BubbleCell.m @@ -0,0 +1,26 @@ +#import "BubbleCell.h" + +@implementation BubbleCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = UIColor.clearColor; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:5]; + [self.baseView leading:self.leadingAnchor padding:10]; + [self.baseView trailing:self.trailingAnchor padding:-10]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + } + + return self; +} + +@end diff --git a/Nova/Tweak/NOVA/Cells/ContactCell.h b/Nova/Tweak/NOVA/Cells/ContactCell.h new file mode 100644 index 0000000..e19861b --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/ContactCell.h @@ -0,0 +1,24 @@ +#import +#import "Colour-Scheme.h" + +@protocol ContactButtonDelegate +@optional +- (void)contactButtonTappedForCell:(UITableViewCell *)cell; +@end + +@interface ContactCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIButton *menuButton; +@property (nonatomic, retain) UIImageView *avatarImage; +@property (nonatomic, retain) UIButton *contactButton; +@property (nonatomic, retain) UIImageView *personImage; +@property (nonatomic, retain) UILabel *nameTitleLabel; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UIImageView *phoneImage; +@property (nonatomic, retain) UILabel *phoneTitleLabel; +@property (nonatomic, retain) UILabel *phoneLabel; +@property (nonatomic, retain) UIView *splitView; +@property (nonatomic, weak) id contactDelegate; + +@end + diff --git a/Nova/Tweak/NOVA/Cells/ContactCell.m b/Nova/Tweak/NOVA/Cells/ContactCell.m new file mode 100644 index 0000000..efddcc3 --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/ContactCell.m @@ -0,0 +1,146 @@ +#import "ContactCell.h" + +@implementation ContactCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor cellColour]; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:15]; + [self.baseView leading:self.leadingAnchor padding:10]; + [self.baseView trailing:self.trailingAnchor padding:-10]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + + self.menuButton = [[UIButton alloc] init]; + UIImage *menuImage = [UIImage systemImageNamed:@"ellipsis"]; + [self.menuButton setImage:menuImage forState:UIControlStateNormal]; + self.menuButton.transform = CGAffineTransformMakeRotation(M_PI / 2); + self.menuButton.tintColor = [UIColor accentColour]; + [self.contentView addSubview:self.menuButton]; + + [self.menuButton size:CGSizeMake(40, 40)]; + [self.menuButton top:self.baseView.topAnchor padding:5]; + [self.menuButton trailing:self.baseView.trailingAnchor padding:5]; + + + self.avatarImage = [[UIImageView alloc] init]; + self.avatarImage.layer.cornerRadius = 45; + self.avatarImage.clipsToBounds = true; + self.avatarImage.contentMode = UIViewContentModeScaleAspectFill; + [self.contentView addSubview:self.avatarImage]; + + [self.avatarImage size:CGSizeMake(90, 90)]; + [self.avatarImage x:self.baseView.centerXAnchor]; + [self.avatarImage top:self.baseView.topAnchor padding:10]; + + + self.contactButton = [[UIButton alloc] init]; + [self.contactButton addTarget:self action:@selector(contactButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self.contactButton setTitle:@"Choose Contact" forState:UIControlStateNormal]; + [self.contactButton setTitleColor:[UIColor accentColour] forState:UIControlStateNormal]; + self.contactButton.titleLabel.font = [UIFont systemFontOfSize:14]; + [self.contentView addSubview:self.contactButton]; + + [self.contactButton top:self.avatarImage.bottomAnchor padding:5]; + [self.contactButton x:self.baseView.centerXAnchor]; + [self.contactButton height:13]; + + + self.personImage = [[UIImageView alloc] init]; + self.personImage.image = [UIImage systemImageNamed:@"person.crop.circle"]; + self.personImage.tintColor = [UIColor iconTintColour]; + self.personImage.contentMode = UIViewContentModeScaleAspectFit; + [self.baseView addSubview:self.personImage]; + + [self.personImage size:CGSizeMake(40, 40)]; + [self.personImage top:self.contactButton.bottomAnchor padding:10]; + [self.personImage leading:self.baseView.leadingAnchor padding:10]; + + + self.nameTitleLabel = [[UILabel alloc] init]; + self.nameTitleLabel.textAlignment = NSTextAlignmentLeft; + self.nameTitleLabel.text = @"Name"; + self.nameTitleLabel.font = [UIFont systemFontOfSize:12]; + self.nameTitleLabel.alpha = 0.7; + self.nameTitleLabel.textColor = [UIColor fontColour]; + [self.baseView addSubview:self.nameTitleLabel]; + + [self.nameTitleLabel top:self.personImage.topAnchor padding:2]; + [self.nameTitleLabel leading:self.personImage.trailingAnchor padding:10]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.textAlignment = NSTextAlignmentLeft; + self.nameLabel.font = [UIFont boldSystemFontOfSize:16]; + self.nameLabel.textColor = [UIColor fontColour]; + [self.baseView addSubview:self.nameLabel]; + + [self.nameLabel bottom:self.personImage.bottomAnchor padding:-2]; + [self.nameLabel leading:self.personImage.trailingAnchor padding:10]; + + + self.splitView = [[UIView alloc] init]; + self.splitView.backgroundColor = [UIColor separatorColour]; + self.splitView.layer.cornerRadius = 1; + [self.baseView addSubview:self.splitView]; + + [self.splitView x:self.baseView.centerXAnchor]; + [self.splitView height:2]; + [self.splitView top:self.nameLabel.bottomAnchor padding:10]; + [self.splitView leading:self.baseView.leadingAnchor padding:20]; + [self.splitView trailing:self.baseView.trailingAnchor padding:-20]; + + + self.phoneImage = [[UIImageView alloc] init]; + self.phoneImage.image = [UIImage systemImageNamed:@"phone.circle"]; + self.phoneImage.tintColor = [UIColor iconTintColour]; + self.phoneImage.contentMode = UIViewContentModeScaleAspectFit; + [self.baseView addSubview:self.phoneImage]; + + [self.phoneImage size:CGSizeMake(40, 40)]; + [self.phoneImage top:self.splitView.bottomAnchor padding:10]; + [self.phoneImage leading:self.baseView.leadingAnchor padding:10]; + + + self.phoneTitleLabel = [[UILabel alloc] init]; + self.phoneTitleLabel.textAlignment = NSTextAlignmentLeft; + self.phoneTitleLabel.text = @"Phone"; + self.phoneTitleLabel.font = [UIFont systemFontOfSize:12]; + self.phoneTitleLabel.alpha = 0.7; + self.phoneTitleLabel.textColor = [UIColor fontColour]; + [self.baseView addSubview:self.phoneTitleLabel]; + + [self.phoneTitleLabel top:self.phoneImage.topAnchor padding:2]; + [self.phoneTitleLabel leading:self.phoneImage.trailingAnchor padding:10]; + + + self.phoneLabel = [[UILabel alloc] init]; + self.phoneLabel.textAlignment = NSTextAlignmentLeft; + self.phoneLabel.textColor = [UIColor fontColour]; + self.phoneLabel.font = [UIFont boldSystemFontOfSize:16]; + [self.baseView addSubview:self.phoneLabel]; + + [self.phoneLabel bottom:self.phoneImage.bottomAnchor padding:-2]; + [self.phoneLabel leading:self.phoneImage.trailingAnchor padding:10]; + + } + + return self; +} + + +- (void)contactButtonPressed:(id)sender { + [self.contactDelegate contactButtonTappedForCell:self]; +} + +@end diff --git a/Nova/Tweak/NOVA/Cells/DateCell.h b/Nova/Tweak/NOVA/Cells/DateCell.h new file mode 100644 index 0000000..3b62f4d --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/DateCell.h @@ -0,0 +1,8 @@ +#import +#import "Colour-Scheme.h" + +@interface DateCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *titleLabel; +@end + diff --git a/Nova/Tweak/NOVA/Cells/DateCell.m b/Nova/Tweak/NOVA/Cells/DateCell.m new file mode 100644 index 0000000..67b4376 --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/DateCell.m @@ -0,0 +1,38 @@ +#import "DateCell.h" + +@implementation DateCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor cellColour]; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:5]; + [self.baseView leading:self.leadingAnchor padding:10]; + [self.baseView trailing:self.trailingAnchor padding:-10]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.font = [UIFont systemFontOfSize:14]; + self.titleLabel.textColor = [UIColor fontColour]; + self.titleLabel.text = @"Set date & time"; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.baseView.leadingAnchor padding:10]; + [self.titleLabel y:self.baseView.centerYAnchor]; + } + + return self; +} + +@end diff --git a/Nova/Tweak/NOVA/Cells/PhotoCell.h b/Nova/Tweak/NOVA/Cells/PhotoCell.h new file mode 100644 index 0000000..cf6fe6e --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/PhotoCell.h @@ -0,0 +1,9 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPrefernces.h" + +@interface PhotoCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *photoImages; +@property (nonatomic, retain) UILabel *countLabel; +@end diff --git a/Nova/Tweak/NOVA/Cells/PhotoCell.m b/Nova/Tweak/NOVA/Cells/PhotoCell.m new file mode 100644 index 0000000..1710774 --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/PhotoCell.m @@ -0,0 +1,46 @@ +#import "PhotoCell.h" + +@implementation PhotoCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor clearColor]; + self.baseView.layer.cornerRadius = 8; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + [self.baseView fill]; + + + self.photoImages = [[UIImageView alloc] init]; + self.photoImages.contentMode = UIViewContentModeScaleAspectFill; + self.photoImages.layer.borderWidth = 0.7; + self.photoImages.layer.borderColor = [UIColor accentColour].CGColor; + self.photoImages.clipsToBounds = true; + self.photoImages.layer.cornerRadius = 8; + [self.baseView addSubview:self.photoImages]; + [self.photoImages fill]; + + + self.countLabel = [[UILabel alloc] init]; + self.countLabel.textColor = UIColor.whiteColor; + self.countLabel.font = [UIFont systemFontOfSize:10]; + self.countLabel.layer.cornerRadius = 7.5; + self.countLabel.clipsToBounds = true; + self.countLabel.backgroundColor = [UIColor accentColour]; + self.countLabel.textAlignment = NSTextAlignmentCenter; + [self.baseView addSubview:self.countLabel]; + + [self.countLabel x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + [self.countLabel size:CGSizeMake(15, 15)]; + + + } + return self; +} + +@end diff --git a/Nova/Tweak/NOVA/Cells/RecipientCell.h b/Nova/Tweak/NOVA/Cells/RecipientCell.h new file mode 100644 index 0000000..da5cdcd --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/RecipientCell.h @@ -0,0 +1,15 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPrefernces.h" + +@interface RecipientCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *avatarImage; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UILabel *timeLabel; +@property (nonatomic, retain) UIView *bubbleView; +@property (nonatomic, retain) UILabel *bubbleLabel; + +@end + diff --git a/Nova/Tweak/NOVA/Cells/RecipientCell.m b/Nova/Tweak/NOVA/Cells/RecipientCell.m new file mode 100644 index 0000000..4d763e6 --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/RecipientCell.m @@ -0,0 +1,126 @@ +#import "RecipientCell.h" + +@implementation RecipientCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + loadPrefs(); + + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor clearColor]; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:5]; + [self.baseView leading:self.leadingAnchor padding:5]; + [self.baseView trailing:self.trailingAnchor padding:-5]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + + self.avatarImage = [[UIImageView alloc] init]; + self.avatarImage.contentMode = UIViewContentModeScaleAspectFill; + self.avatarImage.layer.cornerRadius = 20; + self.avatarImage.clipsToBounds = true; + [self.baseView addSubview:self.avatarImage]; + + [self.avatarImage size:CGSizeMake(40, 40)]; + [self.avatarImage top:self.baseView.topAnchor padding:5]; + [self.avatarImage leading:self.baseView.leadingAnchor padding:15]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.textAlignment = NSTextAlignmentLeft; + self.nameLabel.textColor = [UIColor fontColour]; + self.nameLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightSemibold]; + [self.baseView addSubview:self.nameLabel]; + + [self.nameLabel top:self.avatarImage.topAnchor padding:5]; + [self.nameLabel leading:self.avatarImage.trailingAnchor padding:10]; + + + NSDate * now = [NSDate date]; + NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init]; + [outputFormatter setDateFormat:@"HH:mm"]; + + self.timeLabel = [[UILabel alloc] init]; + self.timeLabel.textAlignment = NSTextAlignmentLeft; + self.timeLabel.textColor = [UIColor fontColour]; + self.timeLabel.font = [UIFont systemFontOfSize:12 weight:UIFontWeightRegular]; + self.timeLabel.text = [outputFormatter stringFromDate:now]; + [self.baseView addSubview:self.timeLabel]; + + [self.timeLabel bottom:self.avatarImage.bottomAnchor padding:-5]; + [self.timeLabel leading:self.avatarImage.trailingAnchor padding:10]; + + + self.bubbleView = [[UIView alloc] init]; + self.bubbleView.layer.cornerRadius = 20; + self.bubbleView.layer.maskedCorners = 14; + [self.baseView addSubview:self.bubbleView]; + + [self.bubbleView size:CGSizeMake(200, 90)]; + [self.bubbleView top:self.avatarImage.bottomAnchor padding:10]; + [self.bubbleView leading:self.baseView.leadingAnchor padding:15]; + + + self.bubbleLabel = [[UILabel alloc] init]; + self.bubbleLabel.textAlignment = NSTextAlignmentLeft; + self.bubbleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightRegular]; + self.bubbleLabel.numberOfLines = 3; + self.bubbleLabel.text = @"Write something that \nyou would like to \nsay to me."; + [self.bubbleView addSubview:self.bubbleLabel]; + + [self.bubbleLabel top:self.bubbleView.topAnchor padding:5]; + [self.bubbleLabel leading:self.bubbleView.leadingAnchor padding:10]; + [self.bubbleLabel trailing:self.bubbleView.trailingAnchor padding:-5]; + [self.bubbleLabel bottom:self.bubbleView.bottomAnchor padding:-5]; + + + if (!toggleCustomColour) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.bubbleView.backgroundColor = [UIColor colorWithRed: 0.15 green: 0.15 blue: 0.16 alpha: 1.00]; + self.bubbleLabel.textColor = UIColor.whiteColor; + } else { + self.bubbleView.backgroundColor = [UIColor colorWithRed: 0.91 green: 0.91 blue: 0.92 alpha: 1.00]; + self.bubbleLabel.textColor = UIColor.blackColor; + } + + } else { + self.bubbleView.backgroundColor = [UIColor recipientBubbleColour]; + self.bubbleLabel.textColor = [UIColor recipientBubbleFontColour]; + } + + } + + return self; +} + + +- (void)traitCollectionDidChange:(UITraitCollection *) previousTraitCollection { + + if (!toggleCustomColour) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.bubbleView.backgroundColor = [UIColor colorWithRed: 0.15 green: 0.15 blue: 0.16 alpha: 1.00]; + self.bubbleLabel.textColor = UIColor.whiteColor; + } else { + self.bubbleView.backgroundColor = [UIColor colorWithRed: 0.91 green: 0.91 blue: 0.92 alpha: 1.00]; + self.bubbleLabel.textColor = UIColor.blackColor; + } + + } else { + self.bubbleView.backgroundColor = [UIColor recipientBubbleColour]; + self.bubbleLabel.textColor = [UIColor recipientBubbleFontColour]; + } + +} + +@end diff --git a/Nova/Tweak/NOVA/Cells/SenderCell.h b/Nova/Tweak/NOVA/Cells/SenderCell.h new file mode 100644 index 0000000..d139c4c --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/SenderCell.h @@ -0,0 +1,13 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPrefernces.h" + +@interface SenderCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *avatarImage; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UILabel *timeLabel; + +@end + diff --git a/Nova/Tweak/NOVA/Cells/SenderCell.m b/Nova/Tweak/NOVA/Cells/SenderCell.m new file mode 100644 index 0000000..5bc7185 --- /dev/null +++ b/Nova/Tweak/NOVA/Cells/SenderCell.m @@ -0,0 +1,69 @@ +#import "SenderCell.h" + +@implementation SenderCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + loadPrefs(); + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor clearColor]; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:5]; + [self.baseView leading:self.leadingAnchor padding:5]; + [self.baseView trailing:self.trailingAnchor padding:-5]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + + self.avatarImage = [[UIImageView alloc] init]; + self.avatarImage.contentMode = UIViewContentModeScaleAspectFill; + if (senderAvatarImage != nil) { + self.avatarImage.image = [UIImage imageWithData:senderAvatarImage]; + } else { + self.avatarImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Nova.bundle/Assets/avatar.png"]; + } + self.avatarImage.layer.cornerRadius = 20; + self.avatarImage.clipsToBounds = true; + [self.baseView addSubview:self.avatarImage]; + + [self.avatarImage size:CGSizeMake(40, 40)]; + [self.avatarImage top:self.baseView.topAnchor padding:5]; + [self.avatarImage trailing:self.baseView.trailingAnchor padding:-15]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.textAlignment = NSTextAlignmentLeft; + self.nameLabel.textColor = [UIColor fontColour]; + self.nameLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightSemibold]; + self.nameLabel.text = senderName; + [self.baseView addSubview:self.nameLabel]; + + [self.nameLabel top:self.avatarImage.topAnchor padding:5]; + [self.nameLabel trailing:self.avatarImage.leadingAnchor padding:-10]; + + + self.timeLabel = [[UILabel alloc] init]; + self.timeLabel.textAlignment = NSTextAlignmentLeft; + self.timeLabel.textColor = [UIColor fontColour]; + self.timeLabel.font = [UIFont systemFontOfSize:12 weight:UIFontWeightRegular]; + self.timeLabel.text = @"Just now"; + [self.baseView addSubview:self.timeLabel]; + + [self.timeLabel bottom:self.avatarImage.bottomAnchor padding:-5]; + [self.timeLabel trailing:self.avatarImage.leadingAnchor padding:-10]; + + + } + + return self; +} + +@end diff --git a/Nova/Tweak/NOVA/ColourScheme/Colour-Scheme.h b/Nova/Tweak/NOVA/ColourScheme/Colour-Scheme.h new file mode 100644 index 0000000..8a85372 --- /dev/null +++ b/Nova/Tweak/NOVA/ColourScheme/Colour-Scheme.h @@ -0,0 +1,78 @@ +#import "GlobalPrefernces.h" + +@interface UIColor (BackgroundColour) ++ (UIColor *)backgroundColour; +@end + +@interface UIColor (CellColour) ++ (UIColor *)cellColour; +@end + +@interface UIColor (FontColour) ++ (UIColor *)fontColour; +@end + +@interface UIColor (AccentColour) ++ (UIColor *)accentColour; +@end + +@interface UIColor (ClockColour) ++ (UIColor *)clockColour; +@end + +@interface UIColor (CheckmarkColour) ++ (UIColor *)checkmarkColour; +@end + +@interface UIColor (ButtonColour) ++ (UIColor *)buttonColour; +@end + +@interface UIColor (IconColour) ++ (UIColor *)iconColour; +@end + +@interface UIColor (BubbleFontColour) ++ (UIColor *)bubbleFontColour; +@end + +@interface UIColor (BubbleColour) ++ (UIColor *)bubbleColour; +@end + +@interface UIColor (RemainingFontColour) ++ (UIColor *)remainingFontColour; +@end + +@interface UIColor (SeparatorColour) ++ (UIColor *)separatorColour; +@end + +@interface UIColor (RemainingBackgroundColour) ++ (UIColor *)remainingBackgroundColour; +@end + +@interface UIColor (SentBackgroundColour) ++ (UIColor *)sentBackgroundColour; +@end + +@interface UIColor (IconTintColour) ++ (UIColor *)iconTintColour; +@end + +@interface UIColor (RecipientBubbleFontColour) ++ (UIColor *)recipientBubbleFontColour; +@end + +@interface UIColor (RecipientBubbleColour) ++ (UIColor *)recipientBubbleColour; +@end + +@interface UIColor (PhotoButtonColour) ++ (UIColor *)photoButtonColour; +@end + +@interface UIColor (ToolbarColour) ++ (UIColor *)toolbarColour; +@end + diff --git a/Nova/Tweak/NOVA/ColourScheme/Colour-Scheme.m b/Nova/Tweak/NOVA/ColourScheme/Colour-Scheme.m new file mode 100644 index 0000000..e863524 --- /dev/null +++ b/Nova/Tweak/NOVA/ColourScheme/Colour-Scheme.m @@ -0,0 +1,311 @@ +#import "Colour-Scheme.h" + +@implementation UIColor (BackgroundColour) ++ (UIColor *)backgroundColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"backgroundColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemBackgroundColor; + } + + return customColour; +} +@end + + +@implementation UIColor (CellColour) ++ (UIColor *)cellColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"cellColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.secondarySystemBackgroundColor; + } + + return customColour; +} +@end + + +@implementation UIColor (FontColour) ++ (UIColor *)fontColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"fontColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.labelColor; + } + + return customColour; +} +@end + + +@implementation UIColor (AccentColour) ++ (UIColor *)accentColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"accentColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemBlueColor; + } + + return customColour; +} +@end + + +@implementation UIColor (ClockColour) ++ (UIColor *)clockColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"clockColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.whiteColor; + } + + return customColour; +} +@end + + +@implementation UIColor (CheckmarkColour) ++ (UIColor *)checkmarkColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"checkmarkColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.whiteColor; + } + + return customColour; +} +@end + + +@implementation UIColor (ButtonColour) ++ (UIColor *)buttonColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"floatingButtonColour" defaultValue:@"FFFFFF" ID:BID]; + } + + return customColour; +} +@end + + +@implementation UIColor (IconColour) ++ (UIColor *)iconColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"floatingIconColour" defaultValue:@"FFFFFF" ID:BID]; + } + + return customColour; +} +@end + + +@implementation UIColor (BubbleFontColour) ++ (UIColor *)bubbleFontColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"bubbleFontColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.whiteColor; + } + + return customColour; +} +@end + + +@implementation UIColor (BubbleColour) ++ (UIColor *)bubbleColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"bubbleColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemBlueColor; + } + + return customColour; +} +@end + + +@implementation UIColor (RemainingFontColour) ++ (UIColor *)remainingFontColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"remainingFontColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.whiteColor; + } + + return customColour; +} +@end + + +@implementation UIColor (SeparatorColour) ++ (UIColor *)separatorColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"separatorColour" defaultValue:@"FFFFFF" ID:BID]; + } + + return customColour; +} +@end + + +@implementation UIColor (RemainingBackgroundColour) ++ (UIColor *)remainingBackgroundColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"remainingBackgroundColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = [UIColor colorWithRed: 1.00 green: 0.58 blue: 0.00 alpha: 0.8]; + } + + return customColour; +} +@end + + +@implementation UIColor (SentBackgroundColour) ++ (UIColor *)sentBackgroundColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"remainingBackgroundColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = [UIColor colorWithRed: 0.20 green: 0.78 blue: 0.35 alpha: 0.8]; + } + + return customColour; +} +@end + + +@implementation UIColor (IconTintColour) ++ (UIColor *)iconTintColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"iconColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.labelColor; + } + + return customColour; +} +@end + + +@implementation UIColor (RecipientBubbleFontColour) ++ (UIColor *)recipientBubbleFontColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"recipientBubbleFontColour" defaultValue:@"FFFFFF" ID:BID]; + } + + return customColour; +} +@end + + +@implementation UIColor (RecipientBubbleColour) ++ (UIColor *)recipientBubbleColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"recipientBubbleColour" defaultValue:@"FFFFFF" ID:BID]; + } + + return customColour; +} +@end + + +@implementation UIColor (PhotoButtonColour) ++ (UIColor *)photoButtonColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"photoButtonColour" defaultValue:@"FFFFFF" ID:BID]; + } + + return customColour; +} +@end + + +@implementation UIColor (ToolbarColour) ++ (UIColor *)toolbarColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"toolbarColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemBackgroundColor; + } + + return customColour; +} +@end diff --git a/Nova/Tweak/NOVA/ComposeMessageVC.h b/Nova/Tweak/NOVA/ComposeMessageVC.h new file mode 100644 index 0000000..ca10e3a --- /dev/null +++ b/Nova/Tweak/NOVA/ComposeMessageVC.h @@ -0,0 +1,38 @@ +#import +#import "Colour-Scheme.h" +#import "SenderCell.h" +#import "RecipientCell.h" +#import "PhotoCell.h" +#import +#import +#import "GlobalPrefernces.h" + +@protocol messageDataProtocol +-(void)passDataToCreateVC:(NSMutableArray *)imageArrays message:(NSString *)messageString includedAttachment:(BOOL)didIncludedAttachment; +@end + + +@interface ComposeMessageVC : UIViewController + +@property (nonatomic, retain) UIButton *doneButton; +@property (nonatomic, retain) UIImageView *doneImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, assign) CGFloat defaultChatHeight; +@property (nonatomic, retain) UITextView *senderTextView; +@property (nonatomic, retain) UILabel *placeholderLabel; +@property (nonatomic, retain) UIView *toolbarView; +@property (nonatomic, retain) UIImage *recipientAvatarImage; +@property (nonatomic, retain) NSString *recipientNameString; +@property (nonatomic, retain) NSString *senderTextString; +@property (nonatomic, retain) UIButton *photoButton; +@property (nonatomic, retain) UIImageView *photoImage; +@property (nonatomic) float kbHeight; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *imageArray; +@property(nonatomic,assign)id messageDataDelegate; +@property (nonatomic, assign, getter= didAddedAttachmentImages) BOOL didAddedAttachmentImages; +@property (nonatomic, retain) UIColor *toolbarColour; + +@end + diff --git a/Nova/Tweak/NOVA/ComposeMessageVC.xm b/Nova/Tweak/NOVA/ComposeMessageVC.xm new file mode 100644 index 0000000..c26468a --- /dev/null +++ b/Nova/Tweak/NOVA/ComposeMessageVC.xm @@ -0,0 +1,503 @@ +#import "ComposeMessageVC.h" + +@implementation ComposeMessageVC + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + + if (toggleWallpaper) { + UIImageView *backgroundImage = [[UIImageView alloc] initWithFrame:self.view.bounds]; + backgroundImage.contentMode = UIViewContentModeScaleAspectFill; + backgroundImage.image = [UIImage imageWithData:wallpaperImage]; + [self.view addSubview:backgroundImage]; + } + + self.doneButton = [[UIButton alloc] init]; + [self.doneButton addTarget:self action:@selector(dismissVC) forControlEvents:UIControlEventTouchUpInside]; + self.doneButton.backgroundColor = [UIColor accentColour]; + self.doneButton.layer.cornerRadius = 20; + self.doneButton.clipsToBounds = true; + [self.view addSubview:self.doneButton]; + + [self.doneButton top:self.view.topAnchor padding:10]; + [self.doneButton trailing:self.view.trailingAnchor padding:-10]; + [self.doneButton size:CGSizeMake(60, 40)]; + + + self.doneImage = [[UIImageView alloc] init]; + self.doneImage.image = [[UIImage systemImageNamed:@"checkmark"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + if (toggleCustomColour) { + self.doneImage.tintColor = [UIColor iconTintColour]; + } else { + self.doneImage.tintColor = UIColor.whiteColor; + } + [self.doneButton addSubview:self.doneImage]; + + [self.doneImage size:CGSizeMake(20, 20)]; + [self.doneImage x:self.doneButton.centerXAnchor y:self.doneButton.centerYAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightSemibold]; + self.titleLabel.textColor = [UIColor fontColour]; + self.titleLabel.text = @"Compose Message"; + [self.view addSubview:self.titleLabel]; + + [self.titleLabel y:self.doneButton.centerYAnchor]; + [self.titleLabel leading:self.view.leadingAnchor padding:15]; + + self.defaultChatHeight = 80; + + if (iPhone_6_8) { + self.kbHeight = 260; + } else if (iPhone_6_8_Plus) { + self.kbHeight = 266; + } else if (iPhone_X_XS_11Pro) { + self.kbHeight = 336; + } else if (iPhone_XR_XS_11Pro) { + self.kbHeight = 346; + } else if (iPhone_12_mini) { + self.kbHeight = 336; + } else if (iPhone_12_Pro) { + self.kbHeight = 336; + } else if (iPhone_12_Pro_Max) { + self.kbHeight = 346; + } + + [self layoutTableView]; + [self layoutToolbar]; + [self performSelector:@selector(refreshSenderChatHeight) withObject:nil afterDelay:0.1]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; + + + self.imageArray = [NSMutableArray array]; + + self.toolbarColour = [UIColor toolbarColour]; + + if (!toggleCustomColour) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.photoButton.backgroundColor = [UIColor colorWithRed: 0.15 green: 0.15 blue: 0.16 alpha: 1.00]; + } else { + self.photoButton.backgroundColor = [UIColor colorWithRed: 0.91 green: 0.91 blue: 0.92 alpha: 1.00]; + } + + } else { + self.photoButton.backgroundColor = [UIColor photoButtonColour]; + } + +if (showComposeTips) { +[self performSelector:@selector(showTipsAlert) withObject:nil afterDelay:1.0]; +} + +} + + +-(void)showTipsAlert { + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Tips" message:@"1) Tap on your chat bubble to start typing a message \n\n2) Tap anywhere outside your chat bubble to dismiss the keyboard \n\n3) Press photo button to add images attachment, you can add up to 5 images \n\n4) You can change your chat name and avatar image from the settings." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *dismissButton = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/DisableTipsAlert" object:nil userInfo:nil deliverImmediately:YES]; + }]; + + [alert addAction:dismissButton]; + [self presentViewController:alert animated:YES completion:nil]; + +} + + +-(void)refreshSenderChatHeight { + + [self.tableView beginUpdates]; + [UIView animateWithDuration:.3 animations:^(void) { + CGFloat paddingForTextView = 60; + self.defaultChatHeight = self.senderTextView.contentSize.height + paddingForTextView; + }]; + [self.tableView endUpdates]; + + if (self.senderTextView.text && self.senderTextView.text.length > 0) { + self.placeholderLabel.alpha = 0; + } else { + self.placeholderLabel.alpha = 0.7; + } +} + + + +-(void)layoutTableView { + + self.tableView = [[UITableView alloc] init]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + [self.tableView top:self.doneButton.bottomAnchor padding:10]; + [self.tableView leading:self.view.leadingAnchor padding:0]; + [self.tableView trailing:self.view.trailingAnchor padding:0]; + [self.tableView bottom:self.view.bottomAnchor padding:-70]; + + + UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKB)]; + [self.tableView addGestureRecognizer:gestureRecognizer]; + +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 2; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + + if (indexPath.row == 0) { + + RecipientCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[RecipientCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + cell.backgroundColor = UIColor.clearColor; + cell.avatarImage.image = self.recipientAvatarImage; + cell.nameLabel.text = self.recipientNameString; + + return cell; + + } else { + + SenderCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[SenderCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + cell.backgroundColor = UIColor.clearColor; + + + self.senderTextView = [[UITextView alloc] init]; + self.senderTextView.delegate = self; + self.senderTextView.backgroundColor = [UIColor bubbleColour]; + self.senderTextView.contentInset = UIEdgeInsetsMake(0, 5, 0, 0); + self.senderTextView.font = [UIFont systemFontOfSize:18]; + self.senderTextView.layer.cornerRadius = 20; + self.senderTextView.layer.maskedCorners = 13; + self.senderTextView.text = self.senderTextString; + self.senderTextView.textColor = [UIColor bubbleFontColour]; + [cell.contentView addSubview:self.senderTextView]; + + [self.senderTextView width:250]; + [self.senderTextView trailing:cell.contentView.trailingAnchor padding:-20]; + [self.senderTextView top:cell.avatarImage.bottomAnchor padding:10]; + [self.senderTextView bottom:cell.contentView.bottomAnchor padding:0]; + + + self.placeholderLabel = [[UILabel alloc] init]; + self.placeholderLabel.font = [UIFont systemFontOfSize:18]; + self.placeholderLabel.textAlignment = NSTextAlignmentLeft; + self.placeholderLabel.textColor = [UIColor bubbleFontColour]; + self.placeholderLabel.text = @"Type something..."; + self.placeholderLabel.layer.zPosition = 10; + self.placeholderLabel.alpha = 0.7; + [self.senderTextView addSubview:self.placeholderLabel]; + + [self.placeholderLabel y:self.senderTextView.centerYAnchor]; + [self.placeholderLabel leading:self.senderTextView.leadingAnchor padding:7]; + + return cell; + + } + +} + + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + if (indexPath.row == 0) { + return 170; + } else { + return self.defaultChatHeight; + } +} + + +- (void)textViewDidChange:(UITextView *)textView { + + [self.tableView beginUpdates]; + [UIView animateWithDuration:.3 animations:^(void) { + CGFloat paddingForTextView = 60; + self.defaultChatHeight = textView.contentSize.height + paddingForTextView; + }]; + [self.tableView endUpdates]; + + + [UIView animateWithDuration:0.3 animations:^ { + UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, self.kbHeight , 0.0); + self.tableView.contentInset = contentInsets; + self.tableView.scrollIndicatorInsets = contentInsets; + [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:NO]; + }]; + + + if (textView.text && textView.text.length > 0) { + self.placeholderLabel.alpha = 0; + } else { + self.placeholderLabel.alpha = 0.7; + } + +} + + +-(void)layoutToolbar { + + self.toolbarView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 65, self.view.frame.size.width, 65)]; + if (self.didAddedAttachmentImages) { + self.toolbarView.backgroundColor = self.toolbarColour; + } else { + self.toolbarView.backgroundColor = UIColor.clearColor; + } + self.toolbarView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; + [self.view addSubview:self.toolbarView]; + + + self.photoButton = [[UIButton alloc] init]; + [self.photoButton addTarget:self action:@selector(presentImagePicker) forControlEvents:UIControlEventTouchUpInside]; + self.photoButton.layer.cornerRadius = 22.5; + [self.toolbarView addSubview:self.photoButton]; + + [self.photoButton size:CGSizeMake(45, 45)]; + [self.photoButton y:self.toolbarView.centerYAnchor]; + [self.photoButton leading:self.toolbarView.leadingAnchor padding:13]; + + + self.photoImage = [[UIImageView alloc] init]; + self.photoImage.image = [[UIImage systemImageNamed:@"photo.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.photoImage.tintColor = [UIColor iconTintColour]; + self.photoImage.contentMode = UIViewContentModeScaleAspectFit; + [self.photoButton addSubview:self.photoImage]; + + [self.photoImage size:CGSizeMake(25, 25)]; + [self.photoImage x:self.photoButton.centerXAnchor y:self.photoButton.centerYAnchor]; + + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[PhotoCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.toolbarView addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + [self.collectionView top:self.toolbarView.topAnchor padding:5]; + [self.collectionView leading:self.photoButton.trailingAnchor padding:10]; + [self.collectionView trailing:self.toolbarView.trailingAnchor padding:-5]; + [self.collectionView bottom:self.toolbarView.bottomAnchor padding:-5]; + +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.imageArray.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + PhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.photoImages.image = [self.imageArray objectAtIndex:indexPath.row]; + cell.countLabel.text = [NSString stringWithFormat:@"%li", indexPath.row +1]; + + return cell; + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + return CGSizeMake(50, 50); +} + + +-(void)keyboardWillShow:(NSNotification *)note { + + CGRect keyboardBounds; + [[note.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue: &keyboardBounds]; + NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]; + NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey]; + + keyboardBounds = [self.view convertRect:keyboardBounds toView:nil]; + + CGRect containerFrame = self.toolbarView.frame; + containerFrame.origin.y = self.view.bounds.size.height - (keyboardBounds.size.height + containerFrame.size.height); + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [UIView setAnimationDuration:[duration doubleValue]]; + [UIView setAnimationCurve:[curve intValue]]; + + self.toolbarView.frame = containerFrame; + [UIView commitAnimations]; + + + [UIView animateWithDuration:0.3 animations:^ { + + UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, self.kbHeight , 0.0); + self.tableView.contentInset = contentInsets; + self.tableView.scrollIndicatorInsets = contentInsets; + [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; + + }]; + +} + + +-(void)keyboardWillHide:(NSNotification *)note { + + NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]; + NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey]; + + CGRect containerFrame = self.toolbarView.frame; + containerFrame.origin.y = self.view.bounds.size.height - containerFrame.size.height; + + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [UIView setAnimationDuration:[duration doubleValue]]; + [UIView setAnimationCurve:[curve intValue]]; + + self.toolbarView.frame = containerFrame; + [UIView commitAnimations]; + + + [UIView animateWithDuration:.3 animations:^(void) { + self.tableView.contentInset = UIEdgeInsetsZero; + self.tableView.scrollIndicatorInsets = UIEdgeInsetsZero; + }]; + +} + + +-(void)presentImagePicker { + + [self invokeHapticFeedback]; + + [self.senderTextView resignFirstResponder]; + + PHPickerConfiguration *config = [[PHPickerConfiguration alloc] init]; + config.selectionLimit = 10; + config.filter = [PHPickerFilter imagesFilter]; + + PHPickerViewController *pickerViewController = [[PHPickerViewController alloc] initWithConfiguration:config]; + pickerViewController.delegate = self; + [self presentViewController:pickerViewController animated:YES completion:nil]; + +} + + +-(void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray *)results { + + self.didAddedAttachmentImages = YES; + self.toolbarView.backgroundColor = self.toolbarColour; + [self.imageArray removeAllObjects]; + + [picker dismissViewControllerAnimated:YES completion:nil]; + + for (PHPickerResult *result in results) { + + [result.itemProvider loadObjectOfClass:[UIImage class] completionHandler:^(__kindof id _Nullable object, NSError * _Nullable error) { + + if ([object isKindOfClass:[UIImage class]]) { + dispatch_async(dispatch_get_main_queue(), ^{ + + [self.imageArray addObject:object]; + [self.collectionView reloadData]; + + NSLog(@"%@", self.imageArray); + + }); + } + }]; + + } +} + + +-(void)presentKB { + [self.senderTextView becomeFirstResponder]; +} + +-(void)dismissKB { + [self.senderTextView resignFirstResponder]; +} + + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + + +-(void)dismissVC { + + [self invokeHapticFeedback]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)viewWillDisappear:(BOOL)animated { + [self.messageDataDelegate passDataToCreateVC:self.imageArray message:self.senderTextView.text includedAttachment:self.didAddedAttachmentImages]; +} + + +- (void)traitCollectionDidChange:(UITraitCollection *) previousTraitCollection { + + if (!toggleCustomColour) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.photoButton.backgroundColor = [UIColor colorWithRed: 0.15 green: 0.15 blue: 0.16 alpha: 1.00]; + } else { + self.photoButton.backgroundColor = [UIColor colorWithRed: 0.91 green: 0.91 blue: 0.92 alpha: 1.00]; + } + + } else { + self.photoButton.backgroundColor = [UIColor photoButtonColour]; + } + +} + + +-(void)invokeHapticFeedback { + if (toggleHaptic) { + if (hapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (hapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (hapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + } +} + +@end diff --git a/Nova/Tweak/NOVA/CreateScheduleVC.h b/Nova/Tweak/NOVA/CreateScheduleVC.h new file mode 100644 index 0000000..d446f7f --- /dev/null +++ b/Nova/Tweak/NOVA/CreateScheduleVC.h @@ -0,0 +1,33 @@ +#import +#import +#import +#import "ActiveCell.h" +#import "ContactCell.h" +#import "DateCell.h" +#import "BubbleCell.h" +#import "ComposeMessageVC.h" +#import "Colour-Scheme.h" + +//[Black NewCodeStarts] replace your file with this file's code + +@interface CreateScheduleVC : UIViewController { + + NSString *firstName; + NSString *surnameName; + NSString *mobilePhoneNumber; + NSString *homePhoneNumber; + NSString *iphonePhoneNumber; +} + +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) UIDatePicker *datePicker; +@property (nonatomic, retain) NSString *fullPhoneNumber; +@property (nonatomic, retain) UIImage *contactAvatarImage; +@property (nonatomic, retain) UITextView *senderTextView; +@property (nonatomic, assign) CGFloat defaultChatHeight; +@property (nonatomic, retain) NSMutableArray *savedImageArray; +@property (nonatomic, retain) NSMutableArray *savedImagePathArray; +@property (nonatomic) BOOL includedAttachmentImages; +@property (nonatomic, retain) NSString *contactFullName; +@property (nonatomic) BOOL didAddedContacts; +@end diff --git a/Nova/Tweak/NOVA/CreateScheduleVC.m b/Nova/Tweak/NOVA/CreateScheduleVC.m new file mode 100644 index 0000000..294799d --- /dev/null +++ b/Nova/Tweak/NOVA/CreateScheduleVC.m @@ -0,0 +1,614 @@ +#import "CreateScheduleVC.h" +#import "../Headers.h" +//[Black NewCodeStarts] replace your file with this file's code + +static NSDate *pickedDate; +static NSString *finalPhoneNumber; +static NSString *messageLabel; + +static NSMutableArray *phoneNumbers; + +static NSString *recipientLabel; +ScheduleManager *sharedInstance; + +static NSString *withID; + +@implementation CreateScheduleVC + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + self.title = @"New Schedule"; + + if (toggleWallpaper) { + UIImageView *backgroundImage = [[UIImageView alloc] initWithFrame:self.view.bounds]; + backgroundImage.contentMode = UIViewContentModeScaleAspectFill; + backgroundImage.image = [UIImage imageWithData:wallpaperImage]; + [self.view addSubview:backgroundImage]; + } + + self.contactAvatarImage = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Nova.bundle/Assets/avatar.png"]; + + if (toggleCustomColour) { + self.navigationController.navigationBar.barTintColor = [[TDTweakManager sharedInstance] colourForKey:@"navbarColour" defaultValue:@"FFFFFF" ID:BID]; + } + self.navigationController.navigationBar.tintColor = [UIColor accentColour]; + [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor fontColour]}]; + + UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithTitle:@"Save" style:UIBarButtonItemStylePlain target:self action:@selector(saveScheduleMessage)]; + self.navigationItem.rightBarButtonItem = saveButton; + + + self.defaultChatHeight = 40; + + [self layoutTableView]; + + [self performSelector:@selector(refreshSenderChatHeight) withObject:nil afterDelay:0.1]; + + self.savedImageArray = [NSMutableArray array]; + self.savedImagePathArray = [NSMutableArray array]; + + sharedInstance = [[ScheduleManager sharedInstance] init]; + + withID = [NSString stringWithFormat:@"%lld", (long long)([[NSDate date] timeIntervalSince1970] * 1000.0)]; +} + + +-(void)refreshSenderChatHeight { + + [self.tableView beginUpdates]; + [UIView animateWithDuration:.3 animations:^(void) { + CGFloat paddingForTextView = 10; + self.defaultChatHeight = self.senderTextView.contentSize.height + paddingForTextView; + }]; + [self.tableView endUpdates]; + +} + + +-(void)layoutTableView { + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 3; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + + if (section == 0) { // Contact + return 1; + } else if (section == 1) { // Future + return 1; + } else { // Sent + return 1; + } + +} + + +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + if (section == 0) { + return 0; + } else { + return 35.0f; + } +} + + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { + + UIView *sectionHeaderView = [[UIView alloc] initWithFrame:CGRectMake(15, 0, tableView.frame.size.width -15, 45)]; + sectionHeaderView.backgroundColor = UIColor.clearColor; + sectionHeaderView.layer.cornerRadius = 15; + sectionHeaderView.clipsToBounds = true; + + UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, sectionHeaderView.frame.size.height /2 -9, 200, 18)]; + headerLabel.backgroundColor = [UIColor clearColor]; + headerLabel.textColor = [UIColor fontColour]; + headerLabel.textAlignment = NSTextAlignmentLeft; + headerLabel.font = [UIFont boldSystemFontOfSize:16]; + [sectionHeaderView addSubview:headerLabel]; + + if (section == 0) { + headerLabel.text = @""; + } else if (section == 1) { + headerLabel.text = @"Date & Time"; + } else { + headerLabel.text = @"Message"; + } + + return sectionHeaderView; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + if (indexPath.section == 0) { + + ContactCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ContactCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + cell.avatarImage.image = self.contactAvatarImage; + [cell.avatarImage addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(contactButtonTappedForCell:)]]; + cell.avatarImage.userInteractionEnabled = YES; + + cell.contactDelegate = self; + cell.menuButton.menu = [self contactMenu]; + cell.menuButton.showsMenuAsPrimaryAction = true; + + return cell; + + } else if (indexPath.section == 1) { + + DateCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[DateCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + + self.datePicker = [[UIDatePicker alloc] init]; + [self.datePicker setDatePickerMode:UIDatePickerModeDateAndTime]; + [self.datePicker addTarget:self action:@selector(datePickerChanged:) forControlEvents:UIControlEventValueChanged]; + self.datePicker.preferredDatePickerStyle = UIDatePickerStyleCompact; + [self.datePicker setValue:[UIColor fontColour] forKey:@"textColor"]; + [cell.contentView addSubview:self.datePicker]; + + [self.datePicker size:CGSizeMake(190, 40)]; + [self.datePicker y:cell.baseView.centerYAnchor]; + [self.datePicker trailing:cell.baseView.trailingAnchor padding:-10]; + + + return cell; + + } else { + + BubbleCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[BubbleCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + self.senderTextView = [[UITextView alloc] init]; + self.senderTextView.delegate = self; + self.senderTextView.backgroundColor = UIColor.systemBlueColor; + self.senderTextView.contentInset = UIEdgeInsetsMake(0, 5, 0, 0); + self.senderTextView.font = [UIFont systemFontOfSize:18]; + self.senderTextView.layer.cornerRadius = 20; + self.senderTextView.layer.maskedCorners = 14; + self.senderTextView.text = @"Write a message..."; + self.senderTextView.editable = NO; + self.senderTextView.textColor = [UIColor bubbleFontColour]; + [cell.contentView addSubview:self.senderTextView]; + + [self.senderTextView trailing:cell.baseView.trailingAnchor padding:0]; + [self.senderTextView leading:cell.baseView.leadingAnchor padding:0]; + [self.senderTextView top:cell.baseView.topAnchor padding:0]; + [self.senderTextView bottom:cell.baseView.bottomAnchor padding:0]; + + [self.senderTextView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentMessageVC)]]; + + + return cell; + } + +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + + float heights; + + if (indexPath.section == 0) { + heights = 260; + } else if (indexPath.section == 1) { + heights = 60; + }else { + heights = self.defaultChatHeight; + } + + return heights; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + + if (toggleHaptic) { + + if (hapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (hapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (hapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + + } + + if (indexPath.section == 2) { + [self presentMessageVC]; + } + +} + + +-(void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact { + + self.didAddedContacts = YES; + + phoneNumbers = [[NSMutableArray alloc] init]; + CNContactStore *store = [[CNContactStore alloc] init]; + + [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { + + CNContactPickerViewController *picker = [[CNContactPickerViewController alloc] init]; + picker.delegate = self; + picker.displayedPropertyKeys = @[CNContactGivenNameKey]; + + [self presentViewController:picker animated:YES completion:nil]; + + }]; + + + if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusAuthorized) { + + NSIndexPath *_indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; + ContactCell *cell = (ContactCell *)[self.tableView cellForRowAtIndexPath:_indexPath]; + + if (contact.imageData != nil ) { + UIImage *CIMage = [UIImage imageWithData:(NSData *)contact.imageData]; + cell.avatarImage.image = CIMage; + self.contactAvatarImage = CIMage; + } else { + cell.avatarImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Nova.bundle/Assets/avatar.png"]; + } + + firstName = contact.givenName; + surnameName = contact.familyName; + + recipientLabel = [NSString stringWithFormat:@"%@ %@", firstName, surnameName]; + + cell.nameLabel.text = recipientLabel; + self.contactFullName = recipientLabel; + + for (NSString* phoneNumber in contact.phoneNumbers){ + + NSString * phoneLabel = [phoneNumber valueForKey:@"label"]; + + if ([phoneLabel rangeOfString:@"Home"].location != NSNotFound){ + + homePhoneNumber = [[phoneNumber valueForKey:@"value"] valueForKey:@"digits"]; + mobilePhoneNumber = @""; + iphonePhoneNumber = @""; + + }else{ + + homePhoneNumber = @""; + } + + if ([phoneLabel rangeOfString:@"Mobile"].location != NSNotFound){ // Add iPhone + + mobilePhoneNumber = [[phoneNumber valueForKey:@"value"] valueForKey:@"digits"]; + homePhoneNumber = @""; + iphonePhoneNumber = @""; + + }else{ + + mobilePhoneNumber = @""; + } + + if ([phoneLabel rangeOfString:@"iPhone"].location != NSNotFound){ + + iphonePhoneNumber = [[phoneNumber valueForKey:@"value"] valueForKey:@"digits"]; + homePhoneNumber = @""; + mobilePhoneNumber = @""; + + }else{ + + iphonePhoneNumber = @""; + } + + + // if([mobilePhoneNumber length] != 0) + // finalPhoneNumber = [NSString stringWithFormat:@"%@", mobilePhoneNumber]; + // if([iphonePhoneNumber length] != 0) + // finalPhoneNumber = [NSString stringWithFormat:@"%@", iphonePhoneNumber]; + // else + // finalPhoneNumber = [NSString stringWithFormat:@"%@", homePhoneNumber]; + + // UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Nova" message:@"This contact has multiple phone numbers. Please pick one contact from below." preferredStyle:UIAlertControllerStyleActionSheet]; + // alertController.modalPresentationStyle = UIModalPresentationPopover; + + if([mobilePhoneNumber length] != 0){ + finalPhoneNumber = [NSString stringWithFormat:@"%@", mobilePhoneNumber]; + } + + if([iphonePhoneNumber length] != 0){ + finalPhoneNumber = [NSString stringWithFormat:@"%@", iphonePhoneNumber]; + } + + if([homePhoneNumber length] != 0){ + finalPhoneNumber = [NSString stringWithFormat:@"%@", homePhoneNumber]; + } + + if(![phoneNumbers containsObject:finalPhoneNumber]) + [phoneNumbers addObject:finalPhoneNumber]; + + self.fullPhoneNumber = finalPhoneNumber; + + NSString *lastChr = [finalPhoneNumber substringFromIndex: [finalPhoneNumber length] - 3]; + + NSMutableString *mask = [[NSMutableString alloc]init]; + + for (int i=0; i<[finalPhoneNumber length]-3; i++) { + [mask appendString:@"•"]; + + } + [mask appendString:lastChr]; + + cell.phoneLabel.text = mask; + + + } + } +} + + +- (void)contactPickerDidCancel:(CNContactPickerViewController *)picker { + +} + +- (void)datePickerChanged:(UIDatePicker *)datePicker { + pickedDate = [datePicker date]; +} + + +-(void)presentMessageVC { + + if (self.didAddedContacts) { + ComposeMessageVC *mvc = [[ComposeMessageVC alloc] init]; + mvc.modalInPresentation = YES; + mvc.messageDataDelegate = self; + if (self.includedAttachmentImages){ + [mvc setDidAddedAttachmentImages:YES]; + } + mvc.recipientNameString = self.contactFullName; + mvc.recipientAvatarImage = self.contactAvatarImage; + [self presentViewController:mvc animated:YES completion:nil]; + + + if (![self.senderTextView.text isEqualToString:@"Write a message..."]) { + mvc.senderTextString = self.senderTextView.text; + } + + mvc.imageArray = self.savedImageArray; + + } else { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Sorry!" message:@"Please choose contact before you can compose a message." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + } + +} + + +-(void)saveScheduleMessage { + + if (toggleHaptic) { + + if (hapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (hapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (hapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + } + + + messageLabel = self.senderTextView.text; + + + if([recipientLabel length] == 0 || [messageLabel length] == 0 || pickedDate == nil || [finalPhoneNumber length] == 0){ + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Nova" message:@"Please enter all the required details." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* cnlButton = [UIAlertAction actionWithTitle:@"OK" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + [alert dismissViewControllerAnimated:YES completion:nil]; + }]; + + [alert addAction:cnlButton]; + [self presentViewController:alert animated:YES completion:nil]; + } + else if ([phoneNumbers count] > 1){ + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Nova" message:@"This contact has multiple phone numbers. Please pick one phone number from below." preferredStyle:UIAlertControllerStyleActionSheet]; + alertController.modalPresentationStyle = UIModalPresentationPopover; + + for(NSString *phoneNumber in phoneNumbers){ + [alertController addAction:[UIAlertAction actionWithTitle:phoneNumber style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + finalPhoneNumber = phoneNumber; + NSString *imgName = [NSString stringWithFormat:@"/Library/Application Support/Nova.bundle/Avatars/%@-Avatar.png", withID]; + NSDictionary *data = @{@"id" : withID, @"attachedImages" : self.savedImagePathArray, @"recipientLabel" : recipientLabel, @"messageLabel" : messageLabel, @"scheduleLabel" : pickedDate, @"phoneNumber" : finalPhoneNumber, @"isSent" : @NO, @"avatarImage" : imgName}; + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/addScheduleWithId" object:nil userInfo:@{@"withID" : withID, @"data" : data} deliverImmediately:YES]; + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/ActiveScheduleVCReload" object:nil userInfo:nil deliverImmediately:YES]; + + [self.navigationController popViewControllerAnimated:YES]; + }]]; + } + + [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:NULL]]; + [self presentViewController:alertController animated:YES completion:nil]; + } + else{ + + + NSString *imgName = [NSString stringWithFormat:@"/Library/Application Support/Nova.bundle/Avatars/%@-Avatar.png", withID]; + NSDictionary *data = @{@"id" : withID, @"attachedImages" : self.savedImagePathArray, @"recipientLabel" : recipientLabel, @"messageLabel" : messageLabel, @"scheduleLabel" : pickedDate, @"phoneNumber" : finalPhoneNumber, @"isSent" : @NO, @"avatarImage" : imgName}; + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/addScheduleWithId" object:nil userInfo:@{@"withID" : withID, @"data" : data} deliverImmediately:YES]; + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/ActiveScheduleVCReload" object:nil userInfo:nil deliverImmediately:YES]; + + [self.navigationController popViewControllerAnimated:YES]; + + } + + //[Black NewCodeStarts] this is where we save users Avatar to /tmp/ and will copy from there to App support + if(self.contactAvatarImage){ + NSString *imgName = [NSString stringWithFormat:@"/tmp/%@-Avatar.png", withID]; + [UIImagePNGRepresentation(self.contactAvatarImage) writeToFile:imgName atomically:YES]; + } +} + + +- (void)contactButtonTappedForCell:(UITableViewCell *)cell { + + [self invokeHapticFeedback]; + + CNContactPickerViewController *picker = [[CNContactPickerViewController alloc] init]; + picker.delegate = self; + picker.displayedPropertyKeys = @[CNContactGivenNameKey]; + [self presentViewController:picker animated:YES completion:nil]; +} + + +-(UIMenu *)contactMenu { + + UIAction *photoAction = [UIAction actionWithTitle:@"Choose Contact Photo" image:[UIImage systemImageNamed:@"photo.fill"] identifier:nil handler:^(UIAction *action) { + [self presentPhotoPickerVC]; + [self invokeHapticFeedback]; + }]; + + UIAction *previewAction = [UIAction actionWithTitle:@"Show Phone Number" image:[UIImage systemImageNamed:@"eye.fill"] identifier:nil handler:^(UIAction *action) { + NSIndexPath *_indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; + ContactCell *cell = (ContactCell *)[self.tableView cellForRowAtIndexPath:_indexPath]; + cell.phoneLabel.text = self.fullPhoneNumber; + [self invokeHapticFeedback]; + }]; + + return [UIMenu menuWithTitle:@"Contact Settings" children:@[photoAction, previewAction]]; +} + + +-(void)presentPhotoPickerVC { + + UIImagePickerController *avatarImagePickerController = [[UIImagePickerController alloc] init]; + avatarImagePickerController.delegate = self; + avatarImagePickerController.allowsEditing = false; + avatarImagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [self presentViewController:avatarImagePickerController animated:YES completion:nil]; + +} + + +-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(nonnull NSDictionary *)info { + + NSIndexPath *_indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; + ContactCell *cell = (ContactCell *)[self.tableView cellForRowAtIndexPath:_indexPath]; + cell.avatarImage.image = info[UIImagePickerControllerOriginalImage]; + self.contactAvatarImage = info[UIImagePickerControllerOriginalImage]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)passDataToCreateVC:(NSMutableArray *)imageArrays message:(NSString *)messageString includedAttachment:(BOOL)didIncludedAttachment { + + self.senderTextView.text = messageString; + + if (self.senderTextView.text && self.senderTextView.text.length > 0) { + self.senderTextView.text = messageString; + } else { + self.senderTextView.text = @"Write a message..."; + } + + [self.tableView beginUpdates]; + [UIView animateWithDuration:.3 animations:^(void) { + CGFloat paddingForTextView = 10; + self.defaultChatHeight = self.senderTextView.contentSize.height + paddingForTextView; + }]; + [self.tableView endUpdates]; + + + if (didIncludedAttachment) { + self.includedAttachmentImages = YES; + } + + + if (imageArrays != nil) { + self.savedImageArray = imageArrays; + + long imgCount = 0; + NSString *imgName; + + while(imgCount < self.savedImageArray.count){ + UIImage *image = self.savedImageArray[imgCount]; + imgName = [NSString stringWithFormat:@"/tmp/%@-%ld.png", withID, imgCount]; + [UIImagePNGRepresentation(image) writeToFile:imgName atomically:YES]; + [self.savedImagePathArray addObject:imgName]; + imgCount++; + } + + } + +} + + +-(void)invokeHapticFeedback { + if (toggleHaptic) { + if (hapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (hapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (hapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + } +} + +@end diff --git a/Nova/Tweak/NOVA/GlobalPrefs/GlobalPrefernces.h b/Nova/Tweak/NOVA/GlobalPrefs/GlobalPrefernces.h new file mode 100644 index 0000000..0b71e97 --- /dev/null +++ b/Nova/Tweak/NOVA/GlobalPrefs/GlobalPrefernces.h @@ -0,0 +1,23 @@ +#import + +static NSString *BID = @"com.TitanD3v.NovaPrefs"; +static BOOL toggleCustomColour; +static BOOL toggleHaptic; +static NSInteger hapticStrength; +static NSString *senderName; +static NSData *senderAvatarImage = nil; +static BOOL showComposeTips; +static BOOL toggleWallpaper; +static NSData *wallpaperImage = nil; + +static void loadPrefs() { + + toggleCustomColour = [[TDTweakManager sharedInstance] boolForKey:@"toggleCustomColour" defaultValue:NO ID:BID]; + toggleHaptic = [[TDTweakManager sharedInstance] boolForKey:@"toggleHaptic" defaultValue:YES ID:BID]; + hapticStrength = [[TDTweakManager sharedInstance] intForKey:@"hapticStrength" defaultValue:0 ID:BID]; + senderName = [[TDTweakManager sharedInstance] objectForKey:@"senderName" defaultValue:@"You" ID:BID]; + senderAvatarImage = [[TDTweakManager sharedInstance] objectForKey:@"senderAvatarImage" defaultValue:nil ID:BID]; + showComposeTips = [[TDTweakManager sharedInstance] boolForKey:@"showComposeTips" defaultValue:YES ID:BID]; + toggleWallpaper = [[TDTweakManager sharedInstance] boolForKey:@"toggleWallpaper" defaultValue:NO ID:BID]; + wallpaperImage = [[TDTweakManager sharedInstance] objectForKey:@"wallpaperImage" defaultValue:nil ID:BID]; +} diff --git a/Nova/Tweak/NOVA/ScheduleManager.h b/Nova/Tweak/NOVA/ScheduleManager.h new file mode 100644 index 0000000..b9240e9 --- /dev/null +++ b/Nova/Tweak/NOVA/ScheduleManager.h @@ -0,0 +1,32 @@ +#import +//[Black NewCodeStarts] replace your file with this file's code + +@interface ScheduleManager : NSObject +@property (nonatomic, retain) NSMutableDictionary *scheduleMsgs; ++(instancetype)sharedInstance; +-(id)init; + +-(NSString*)getUDID; + +-(NSDate*)getTodaysDate; +-(NSString*)dateToStr:(NSDate*)date; + +-(void)saveAvatarWithPhn:(NSString*)phoneNumber; + +-(NSMutableDictionary*)getAllSchedules; +-(NSMutableArray*)getSentSchedules; +-(NSMutableArray*)getTodaysSchedules; +-(NSMutableArray*)getFutureSchedules; + +-(void)deleteScheduleWithId:(NSString*)withID; +-(void)addScheduleWithId:(NSString*)withID data:(NSDictionary*)data; + +-(NSString*)getTimeLeft:(NSDate*)date1; +-(NSDate*)strToDate:(NSString*)dateStr; +-(NSMutableArray*)sortedSchedules:(NSMutableArray*)arrayToSort; + +-(void)markMsgAsSentWithId:(NSString*)withID data:(NSDictionary*)data; + +-(void)saveAttachtedImagesWithId:(NSString*)withID attachedImages:(NSArray*)images; +-(NSMutableArray*)arrangeAttachedWithId:(NSString*)withID attachedImages:(NSArray*)images; +@end \ No newline at end of file diff --git a/Nova/Tweak/NOVA/sampleData.plist b/Nova/Tweak/NOVA/sampleData.plist new file mode 100644 index 0000000..a475d16 --- /dev/null +++ b/Nova/Tweak/NOVA/sampleData.plist @@ -0,0 +1,39 @@ + + + + + 0 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat + messageLabel + This is a test Message + scheduleLabel + 13/04/2020 13:00 + + 1 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat 1 + messageLabel + This is a 2nd test Message + scheduleLabel + 13/04/2020 13:10 + + 2 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat 2 + messageLabel + This is a 3rd test Message + scheduleLabel + 13/04/2020 13:20 + + + diff --git a/Nova/Tweak/Nova.plist b/Nova/Tweak/Nova.plist new file mode 100644 index 0000000..905f6a5 --- /dev/null +++ b/Nova/Tweak/Nova.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard", "com.apple.MobileSMS"); }; } diff --git a/Nova/Tweak/Nova.xm b/Nova/Tweak/Nova.xm new file mode 100644 index 0000000..c92d990 --- /dev/null +++ b/Nova/Tweak/Nova.xm @@ -0,0 +1,365 @@ +#import "Headers.h" +#import "SettingViewController.h" + +static BOOL toggleNova; +static BOOL toggleHideFloatingButton; +static NSInteger floatingButtonAlignment; + +static NSMutableArray *todaysSchedules; +static NSMutableArray *futureSchedules; + +static SSender *sender; +static PCSimpleTimer *lastTimer; + +ScheduleManager *SMSharedInstance; +FloatingBlurView *scheduleButton; + +static BBServer *bbServer; +static bool shouldIgnoreAirplaneMode = NO; + + +static UIWindow *settingWindow = nil; + + +@implementation SSender +- (id)init { + if (self = [super init]) { + self.messagingCenter = [CPDistributedMessagingCenter centerNamed:@"com.TitanD3v.SMSScheuler"]; + rocketbootstrap_distributedmessagingcenter_apply(self.messagingCenter); + } + return self; +} + +- (BOOL)sendText:(NSString *)msg toPhn:(NSString *)toPhn withAttachments:(NSArray*)files{ + NSDictionary* args = [NSDictionary new]; + if([files count]==0) + args = @{@"Message": msg, @"Phone": toPhn}; + else + args = @{@"Message": msg, @"Phone": toPhn, @"Attachment" : files}; + + return [self.messagingCenter sendMessageName:@"SMSScheuler" userInfo:args]; +} +@end + +@interface CKConversationListCollectionViewController : UIViewController +@end + + +static dispatch_queue_t getBBServerQueue() { + + static dispatch_queue_t queue; + static dispatch_once_t predicate; + + dispatch_once(&predicate, ^{ + void* handle = dlopen(NULL, RTLD_GLOBAL); + if (handle) { + dispatch_queue_t __weak *pointer = (__weak dispatch_queue_t *) dlsym(handle, "__BBServerQueue"); + if (pointer) queue = *pointer; + dlclose(handle); + } + }); + + return queue; + +} + + +static void NovaNotification(NSString *msg) { + BBBulletin* bulletin = [[%c(BBBulletin) alloc] init]; + + bulletin.title = @"Nova"; + bulletin.message = msg; + bulletin.sectionID = @"com.apple.MobileSMS"; + bulletin.bulletinID = [[NSProcessInfo processInfo] globallyUniqueString]; + bulletin.recordID = [[NSProcessInfo processInfo] globallyUniqueString]; + bulletin.publisherBulletinID = [[NSProcessInfo processInfo] globallyUniqueString]; + bulletin.date = [NSDate date]; + bulletin.defaultAction = [%c(BBAction) actionWithLaunchBundleID:@"com.apple.MobileSMS" callblock:nil]; + bulletin.clearable = YES; + bulletin.showsMessagePreview = YES; + bulletin.publicationDate = [NSDate date]; + bulletin.lastInterruptDate = [NSDate date]; + + if ([bbServer respondsToSelector:@selector(publishBulletin:destinations:)]) { + dispatch_sync(getBBServerQueue(), ^{ + NSLog(@"scheduleMsg will send NovaNotification :-%@.bulletin:-%@", bbServer, bulletin); + [bbServer publishBulletin:bulletin destinations:15]; + }); + } +} + +%group Nova + +%hook BBServer + +- (id)initWithQueue:(id)arg1 { + bbServer = %orig; + return bbServer; +} + +- (id)initWithQueue:(id)arg1 dataProviderManager:(id)arg2 syncService:(id)arg3 dismissalSyncCache:(id)arg4 observerListener:(id)arg5 utilitiesListener:(id)arg6 conduitListener:(id)arg7 systemStateListener:(id)arg8 settingsListener:(id)arg9 { + bbServer = %orig; + return bbServer; +} + +- (void)dealloc { + if (bbServer == self) bbServer = nil; + %orig; +} + +%end + +%hook CKConversationListCollectionViewController +- (void)viewWillAppear:(BOOL)animated { + %orig; + loadPrefs(); + + scheduleButton = [[FloatingBlurView alloc] init]; + scheduleButton.layer.cornerRadius = 30; + scheduleButton.alpha = 1; + [self.view addSubview:scheduleButton]; + + if (floatingButtonAlignment == 1) { + [scheduleButton size:CGSizeMake(60, 60)]; + [scheduleButton leading:self.view.leadingAnchor padding:20]; + [scheduleButton bottom:self.view.bottomAnchor padding:-20]; + } else if (floatingButtonAlignment == 2) { + [scheduleButton size:CGSizeMake(60, 60)]; + [scheduleButton x:self.view.centerXAnchor]; + [scheduleButton bottom:self.view.bottomAnchor padding:-20]; + } else if (floatingButtonAlignment == 3) { + [scheduleButton size:CGSizeMake(60, 60)]; + [scheduleButton trailing:self.view.trailingAnchor padding:-20]; + [scheduleButton bottom:self.view.bottomAnchor padding:-20]; + } + + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(scheduleActionTriggered)]; + [scheduleButton addGestureRecognizer:tap]; + +} + + +%new +-(void)scheduleActionTriggered { + + if (toggleHaptic) { + + if (hapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (hapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (hapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + + } + + + ActiveScheduleVC *svc = [[ActiveScheduleVC alloc] init]; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:svc]; + [self presentViewController:navController animated:YES completion:nil]; + +} + + +- (void)viewWillDisappear:(BOOL)animated { + %orig; + scheduleButton.alpha = 0; +} + + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + + if (toggleHideFloatingButton) { + if (scrollView.contentOffset.y < 0) { + [UIView animateWithDuration:0.2 animations:^{ + scheduleButton.alpha = 1; + }]; + + } else if (scrollView.contentOffset.y >= 40) { + [UIView animateWithDuration:0.2 animations:^{ + scheduleButton.alpha = 0; + }]; + } + } + + %orig; +} + +%end + +%hook SpringBoard + +-(id)init{ + + [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.Nova/deleteScheduleWithId" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + NSString *withID = [[[notification userInfo] objectForKey:@"withID"] stringValue]; + NSLog(@"scheduleMsg got notif deleteScheduleWithId withID:-%@", withID); + [SMSharedInstance deleteScheduleWithId:withID]; + + [lastTimer invalidate]; + lastTimer = nil; + [self loadSchedules]; + }]; + + [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.Nova/addScheduleWithId" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + NSDictionary *data = (NSDictionary*)[[notification userInfo] objectForKey:@"data"]; + NSString *withID = [[[notification userInfo] objectForKey:@"withID"] stringValue]; + [SMSharedInstance addScheduleWithId:withID data:data]; + + [lastTimer invalidate]; + lastTimer = nil; + [self loadSchedules]; + NSLog(@"scheduleMsg got notif addScheduleWithId withID:-%@, scheduleLabel:-%@", withID, data[@"scheduleLabel"]); + }]; + + [self loadSchedules]; + return %orig; +} + +%new +-(void)loadSchedules{ + todaysSchedules = [SMSharedInstance getTodaysSchedules]; + futureSchedules = [SMSharedInstance getFutureSchedules]; + + if([todaysSchedules count] !=0){ + for(int i=0;i<[todaysSchedules count];i++){ + dispatch_async(dispatch_get_main_queue(), ^{ + lastTimer = [[PCSimpleTimer alloc] initWithFireDate:(NSDate*)todaysSchedules[i][@"scheduleLabel"] + serviceIdentifier:@"com.TitanD3v.SMSScheuler.service" + target:self + selector:@selector(messageOperations:) + userInfo:todaysSchedules[i]]; + [lastTimer scheduleInRunLoop:[NSRunLoop mainRunLoop]]; + }); + } + } + + if([futureSchedules count] !=0){ + for(int i=0;i<[futureSchedules count];i++){ + dispatch_async(dispatch_get_main_queue(), ^{ + lastTimer = [[PCSimpleTimer alloc] initWithFireDate:(NSDate*)futureSchedules[i][@"scheduleLabel"] + serviceIdentifier:@"com.TitanD3v.SMSScheuler.service" + target:self + selector:@selector(messageOperations:) + userInfo:futureSchedules[i]]; + [lastTimer scheduleInRunLoop:[NSRunLoop mainRunLoop]]; + }); + } + } +} + +%new +-(void)messageOperations:(id)timer{ + + NSDictionary* userInfo = [(PCSimpleTimer *)timer userInfo]; + NSMutableDictionary *allSchedules = [SMSharedInstance getAllSchedules]; + bool isInAirplaneMode = [[%c(SBAirplaneModeController) sharedInstance ]isInAirplaneMode]; + dispatch_async(dispatch_get_main_queue(), ^{ + if(shouldIgnoreAirplaneMode && isInAirplaneMode){ + [[%c(SBAirplaneModeController) sharedInstance ] setInAirplaneMode:NO]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + if(allSchedules[userInfo[@"id"]] && ![allSchedules[userInfo[@"id"]][@"isSent"] boolValue]){ + NSMutableArray *attachedImages = [SMSharedInstance arrangeAttachedWithId:userInfo[@"id"] attachedImages:userInfo[@"attachedImages"]]; + NSLog(@"scheduleMsg messageOperations attachedImages.count:-%ld", attachedImages.count); + [sender sendText:userInfo[@"messageLabel"] toPhn:userInfo[@"phoneNumber"] withAttachments:attachedImages]; + [SMSharedInstance markMsgAsSentWithId:userInfo[@"id"] data:userInfo]; + NSString *msg = [NSString stringWithFormat:@"Scheduled message has been sent to %@", allSchedules[userInfo[@"id"]][@"recipientLabel"]]; + NovaNotification(msg); + [[%c(SBAirplaneModeController) sharedInstance ] setInAirplaneMode:YES]; + } + }); + } + else{ + if(allSchedules[userInfo[@"id"]] && ![allSchedules[userInfo[@"id"]][@"isSent"] boolValue]){ + NSMutableArray *attachedImages = [SMSharedInstance arrangeAttachedWithId:userInfo[@"id"] attachedImages:userInfo[@"attachedImages"]]; + NSLog(@"scheduleMsg messageOperations attachedImages.count:-%ld", attachedImages.count); + [sender sendText:userInfo[@"messageLabel"] toPhn:userInfo[@"phoneNumber"] withAttachments:attachedImages]; + [SMSharedInstance markMsgAsSentWithId:userInfo[@"id"] data:userInfo]; + NSString *msg = [NSString stringWithFormat:@"Scheduled message has been sent to %@", allSchedules[userInfo[@"id"]][@"recipientLabel"]]; + NovaNotification(msg); + } + } + }); + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/ActiveScheduleVCReload" object:nil userInfo:nil deliverImmediately:YES]; + NSLog(@"scheduleMsg messageOperations isInAirplaneMode:-%d, isSent :-%d, keyData:-%@", isInAirplaneMode, [allSchedules[userInfo[@"id"]][@"isSent"] boolValue], allSchedules[userInfo[@"id"]]); +} +%end + + +%hook SpringBoard +- (void)applicationDidFinishLaunching:(id)application { + + %orig; +[[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.Nova/DisableTipsAlert" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { +[[TDTweakManager sharedInstance] setBool:NO forKey:@"showComposeTips" ID:@"com.TitanD3v.NovaPrefs"]; +}]; + + +if (!settingWindow) { + +settingWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, MAIN_SCREEN_WIDTH, MAIN_SCREEN_HEIGHT)]; +settingWindow.backgroundColor = [UIColor clearColor]; +settingWindow.hidden = YES; +settingWindow.windowLevel = UIWindowLevelStatusBar; +settingWindow.tintColor = [UIColor colorWithRed: 0.95 green: 0.27 blue: 0.17 alpha: 1.00]; +settingWindow.rootViewController = [UIViewController new]; +[settingWindow setUserInteractionEnabled:YES]; + +} + + +[[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.Nova/DismissSetting" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { +dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ +settingWindow.hidden = YES; +settingWindow.tintColor = [UIColor colorWithRed: 0.95 green: 0.27 blue: 0.17 alpha: 1.00]; +}); +}]; + + +[[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.Nova/PresentSetting" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + settingWindow.hidden = NO; + settingWindow.tintColor = [UIColor colorWithRed: 0.95 green: 0.27 blue: 0.17 alpha: 1.00]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + + settingWindow.tintColor = [UIColor colorWithRed: 0.95 green: 0.27 blue: 0.17 alpha: 1.00]; + SettingViewController *svc = [[SettingViewController alloc] init]; + svc.modalInPresentation = YES; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:svc]; + [settingWindow.rootViewController presentViewController:navController animated:YES completion:nil]; + + }); + +}]; + + +} + +%end +%end + + +void SettingsChanged() { + + toggleNova = [[TDTweakManager sharedInstance] boolForKey:@"toggleNova" defaultValue:NO ID:BID]; + toggleHideFloatingButton = [[TDTweakManager sharedInstance] boolForKey:@"toggleHideFloatingButton" defaultValue:YES ID:BID]; + floatingButtonAlignment = [[TDTweakManager sharedInstance] intForKey:@"floatingButtonAlignment" defaultValue:3 ID:BID]; +} + +%ctor { + + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)SettingsChanged, CFSTR("com.TitanD3v.NovaPrefs.settingschanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + SettingsChanged(); + + if (toggleNova) { + %init(Nova); + sender = [[%c(SSender) alloc] init]; + SMSharedInstance = [[ScheduleManager sharedInstance] init]; + sender = [[SSender alloc] init]; + [sender sendText:@"This is test msg by NOVA." toPhn:@"" withAttachments:nil]; + [lastTimer invalidate]; + lastTimer = nil; + } + +} diff --git a/Nova/Tweak/SMSScheuler.h b/Nova/Tweak/SMSScheuler.h new file mode 100644 index 0000000..d1dc1bd --- /dev/null +++ b/Nova/Tweak/SMSScheuler.h @@ -0,0 +1,152 @@ +@interface NSObject (Undocumented) +@end + +@interface __NSCFString +@end + +@interface CKConversationList ++ (id)sharedConversationList; +- (id)conversationForExistingChatWithGroupID:(id)arg1; +- (id)conversationForExistingChatWithPinningIdentifier:(id)arg1; +@end + +@interface CKComposition : NSObject ++ (CKComposition *)composition; +- (id)initWithText:(id)arg1 subject:(id)arg2; +- (id)compositionByAppendingMediaObject:(id)arg1; +- (id)compositionByAppendingText:(id)arg1; +- (void)setSubject:(id)arg1; +- (void)setText:(id)arg1; +@end + +@interface CKMediaObject : NSObject +@end + +@interface CKMediaObjectManager : NSObject ++ (id)sharedInstance; +- (id)mediaObjectWithFileURL:(id)arg1 filename:(id)arg2 transcoderUserInfo:(id)arg3 attributionInfo:(id)arg4 hideAttachment:(_Bool)arg5; +@end + +@interface IMDaemonController ++ (id)sharedController; +- (BOOL)connectToDaemon; +@end + +@interface IMPinnedConversationsController +- (NSOrderedSet *)pinnedConversationIdentifierSet; +@end + +@interface NSConcreteNotification +- (id)object; +- (id)userInfo; +@end + +@interface IMItemsController +@end + +@interface IMChat : IMItemsController +- (void)sendMessage:(id)arg1; +- (void)markAllMessagesAsRead; +- (void)sendMessageAcknowledgment:(long long)arg1 forChatItem:(id)arg2 withMessageSummaryInfo:(id)arg3; +- (void)sendMessageAcknowledgment:(long long)arg1 forChatItem:(id)arg2 withAssociatedMessageInfo:(id)arg3; +- (void)remove; +- (NSArray *)chatItems; +- (id)messageItemForGUID:(id)arg1; +- (id)messageForGUID:(id)arg1; +- (void)loadMessagesUpToGUID:(id)arg1 date:(id)arg2 limit:(unsigned long long)arg3 loadImmediately:(BOOL)arg4; +- (void)deleteChatItems:(id)arg1; +- (id)chatIdentifier; +- (id)lastSentMessage; +@end + +@interface CKConversation : NSObject +@property (nonatomic, retain) IMChat *chat; +- (id)messageWithComposition:(id)arg1; +- (void)sendMessage:(id)arg1 newComposition:(bool)arg2; +@end + +@interface IMChatItem : NSObject +- (id)_item; +@end + +@interface IMTranscriptChatItem : IMChatItem +- (NSString *)guid; +@end + +@interface IMTextMessagePartChatItem : IMTranscriptChatItem +@end + +@interface IMFileTransferCenter +@end + +@interface IMFileTransfer : NSObject +- (NSString *)guid; +@end + +@interface IMChatRegistry ++ (id)sharedInstance; +- (id)chatForIMHandle:(id)arg1; +- (id)existingChatWithChatIdentifier:(id)arg1; +@end + +@interface IMHandle : NSObject { + NSString *_id; +} +- (id)initWithAccount:(id)arg1 ID:(id)arg2 alreadyCanonical:(_Bool)arg3; +@end + +@interface IMItem +@property (nonatomic,retain) NSString * handle; +@end + +@interface IMMessageItem : IMItem +- (id)_initWithItem:(id)arg1 text:(id)arg2 index:(long long)arg3 messagePartRange:(NSRange)arg4 subject:(id)arg5; +- (NSString *)subject; +- (NSAttributedString *)body; +- (id)sender; +-(id)message; +@end + +@interface IMMessage : NSObject { + IMHandle *_subject; +} ++ (id)instantMessageWithText:(id)arg1 flags:(unsigned long long)arg2; ++ (id)instantMessageWithText:(id)arg1 flags:(unsigned long long)arg2 threadIdentifier:(id)arg3; +- (NSString *)guid; +- (IMMessageItem *)_imMessageItem; +- (bool)hasInlineAttachments; +- (NSArray *)inlineAttachmentAttributesArray; +- (bool)isFromMe; +- (bool)isDelivered; +- (bool)isRead; +@end + +@interface IMAccount : NSObject { + NSString *_loginID; +} +@end + +@interface IMAccountController : NSObject ++ (id)sharedInstance; +- (id)activeIMessageAccount; +- (IMAccount *)activeSMSAccount; +@end + +@interface SBApplicationController ++ (id)sharedInstance; +- (id)applicationWithBundleIdentifier:(id)arg1; +@end + +@interface SBApplicationProcessState +@end + +@interface SBApplication +@property(readonly, nonatomic) SBApplicationProcessState *processState; +@end + +@interface NSBundle (Undocumented) ++ (id)mainBundle; +@property (readonly, copy) NSString *bundleIdentifier; +@end + +//[Black NewCodeStarts] NSTask remove \ No newline at end of file diff --git a/Nova/Tweak/SMSScheuler.xm b/Nova/Tweak/SMSScheuler.xm new file mode 100644 index 0000000..2b493d7 --- /dev/null +++ b/Nova/Tweak/SMSScheuler.xm @@ -0,0 +1,130 @@ +#import +#import +#import "SMSScheuler.h" +#import "ScheduleManager.h" + + +@interface SMSScheuler : NSObject{ + CPDistributedMessagingCenter * _messagingCenter; +} +@end + +@implementation SMSScheuler + ++ (void)load { + [self sharedInstance]; +} + ++ (instancetype)sharedInstance { + static dispatch_once_t once = 0; + __strong static id sharedInstance = nil; + dispatch_once(&once, ^{ + sharedInstance = [self new]; + }); + return sharedInstance; +} + +- (instancetype)init { + if ((self = [super init])) { + _messagingCenter = [CPDistributedMessagingCenter centerNamed:@"com.TitanD3v.SMSScheuler"]; + rocketbootstrap_distributedmessagingcenter_apply(_messagingCenter); + + [_messagingCenter runServerOnCurrentThread]; + [_messagingCenter registerForMessageName:@"SMSScheuler" target:self selector:@selector(sendText:withUserInfo:)]; + } + + return self; +} + +- (NSNumber *)sendText:(NSString*)name withUserInfo:(NSDictionary *)vals{ + __block NSNumber* ret_bool = 0; + + IMDaemonController* controller = [%c(IMDaemonController) sharedController]; + + void (^processBlock)() = ^{ + + if ([controller connectToDaemon]){ + NSString* Message = vals[@"Message"]; + NSString* Phone = vals[@"Phone"]; + NSArray* attachments = vals[@"Attachment"]; + + if([Message isEqualToString:@"Write a message..."] && [attachments count] !=0) + Message = @"Attachment(s)"; + + NSAttributedString* text = [[NSAttributedString alloc] initWithString:Message]; + + CKConversationList* list = [%c(CKConversationList) sharedConversationList]; + CKConversation* conversation = [list conversationForExistingChatWithGroupID:Phone]; + if (conversation != nil) { + CKComposition* composition = [%c(CKComposition) composition]; + + CKMediaObjectManager* si = [%c(CKMediaObjectManager) sharedInstance]; + for (NSString* obj in attachments) { + + NSURL* file_url = [NSURL fileURLWithPath:obj]; + CKMediaObject* object = [si mediaObjectWithFileURL:file_url filename:nil transcoderUserInfo:@{} attributionInfo:@{} hideAttachment:NO]; + + composition = [composition compositionByAppendingMediaObject:object]; + } + + if ([text length] > 0) + composition = [composition compositionByAppendingText:text]; + IMMessage* message = [conversation messageWithComposition:composition]; + [conversation sendMessage:message newComposition:YES]; + + } else { + IMAccountController *sharedAccountController = [%c(IMAccountController) sharedInstance]; + IMAccount *myAccount = [sharedAccountController activeIMessageAccount]; + + if (myAccount == nil) + myAccount = [sharedAccountController activeSMSAccount]; + + __NSCFString *handleId = (__NSCFString *)Phone; + IMHandle *handle = [[%c(IMHandle) alloc] initWithAccount:myAccount ID:handleId alreadyCanonical:YES]; + + IMChatRegistry *registry = [%c(IMChatRegistry) sharedInstance]; + IMChat *chat = [registry chatForIMHandle:handle]; + + IMMessage* message; + if ([[[%c(UIDevice) currentDevice] systemVersion] floatValue] >= 14.0) + message = [%c(IMMessage) instantMessageWithText:text flags:1048581 threadIdentifier:nil]; + else + message = [%c(IMMessage) instantMessageWithText:text flags:1048581]; + + [chat sendMessage:message]; + } + + ret_bool = @1; + } + }; + + //[Black NewCodeEnds] + + if ([NSThread isMainThread]) + processBlock(); + else + dispatch_sync(dispatch_get_main_queue(), ^{ + processBlock(); + }); + + return ret_bool; +} +@end + +%hook IMDaemonController +- (unsigned)_capabilities { + NSString *process = [[NSProcessInfo processInfo] processName]; + if ([process isEqualToString:@"SpringBoard"] || [process isEqualToString:@"MobileSMS"] || [process isEqualToString:@"Nova"]) + return 17159; + else + return %orig; +} + +%end + + +%ctor { + NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; + if ([bundleID isEqualToString:@"com.apple.springboard"]) + [SMSScheuler sharedInstance]; +} \ No newline at end of file diff --git a/Nova/Tweak/ScheduleManager.h b/Nova/Tweak/ScheduleManager.h new file mode 100644 index 0000000..204980a --- /dev/null +++ b/Nova/Tweak/ScheduleManager.h @@ -0,0 +1,79 @@ +#import +//[Black NewCodeStarts] replace your file with this file's code +#import + +@interface ScheduleManager : NSObject +@property (nonatomic, retain) NSMutableDictionary *scheduleMsgs; ++(instancetype)sharedInstance; +-(id)init; + +-(NSDate*)getTodaysDate; +-(NSString*)dateToStr:(NSDate*)date; + + +-(NSString*)getUDID; + +-(void)saveAvatarWithId:(NSString*)withID; + +-(NSMutableDictionary*)getAllSchedules; +-(NSMutableArray*)getSentSchedules; +-(NSMutableArray*)getTodaysSchedules; +-(NSMutableArray*)getFutureSchedules; + +-(void)deleteScheduleWithId:(NSString*)withID; +-(void)addScheduleWithId:(NSString*)withID data:(NSDictionary*)data; + +-(NSString*)getTimeLeft:(NSDate*)date1; +-(NSDate*)strToDate:(NSString*)dateStr; +-(NSMutableArray*)sortedSchedules:(NSMutableArray*)arrayToSort; + +-(void)markMsgAsSentWithId:(NSString*)withID data:(NSDictionary*)data; + +-(void)saveAttachtedImagesWithId:(NSString*)withID attachedImages:(NSArray*)images; +-(NSMutableArray*)arrangeAttachedWithId:(NSString*)withID attachedImages:(NSArray*)images; +@end + + + + + + + + + + + + + + + + + + +@interface BBAction : NSObject ++ (id)actionWithLaunchBundleID:(id)arg1 callblock:(id)arg2; +@end + +@interface BBBulletin : NSObject +@property(nonatomic, copy)NSString* sectionID; +@property(nonatomic, copy)NSString* recordID; +@property(nonatomic, copy)NSString* publisherBulletinID; +@property(nonatomic, copy)NSString* title; +@property(nonatomic, copy)NSString* message; +@property(nonatomic, retain)NSDate* date; +@property(assign, nonatomic)BOOL clearable; +@property(nonatomic)BOOL showsMessagePreview; +@property(nonatomic, copy)BBAction* defaultAction; +@property(nonatomic, copy)NSString* bulletinID; +@property(nonatomic, retain)NSDate* lastInterruptDate; +@property(nonatomic, retain)NSDate* publicationDate; +@end + +@interface BBServer : NSObject +- (void)publishBulletin:(BBBulletin *)arg1 destinations:(NSUInteger)arg2 alwaysToLockScreen:(BOOL)arg3; +- (void)publishBulletin:(id)arg1 destinations:(unsigned long long)arg2; +-(void)_removeBulletins:(id)arg1 forSectionID:(id)arg2 shouldSync:(BOOL)arg3 ; +-(id)_bulletinsForIDs:(id)arg1 ; +-(id)allBulletinIDsForSectionID:(id)arg1 ; +-(void)_removeActiveSectionID:(id)arg1 ; +@end \ No newline at end of file diff --git a/Nova/Tweak/ScheduleManager.m b/Nova/Tweak/ScheduleManager.m new file mode 100644 index 0000000..b78dc9d --- /dev/null +++ b/Nova/Tweak/ScheduleManager.m @@ -0,0 +1,246 @@ +#import "ScheduleManager.h" + + +//[Black NewCodeStarts] replace your file with this file's code + +static NSString *savedSchedulesPlist = @"/Library/Application Support/Nova.bundle/savedSchedulesPlist.plist"; +NSDateFormatter *dateFormatter; + +@interface CNPhoneNumber (private) +-(NSString *)countryCode; +-(id)initWithStringValue:(id)arg1 ; +-(NSString *)digits; +-(id)formattedStringValueRemovingDialingCode; +@end + +static NSString* filterPhoneNumber(NSString *phone){ + CNPhoneNumber *phonee = [[NSClassFromString(@"CNPhoneNumber") alloc] initWithStringValue:phone]; + phone = [phonee formattedStringValueRemovingDialingCode]; + phone = [phone stringByReplacingOccurrencesOfString:@" " withString:@""]; + phone = [phone stringByReplacingOccurrencesOfString:@"(" withString:@""]; + phone = [phone stringByReplacingOccurrencesOfString:@")" withString:@""]; + phone = [phone stringByReplacingOccurrencesOfString:@"+" withString:@""]; + phone = [phone stringByReplacingOccurrencesOfString:@"-" withString:@""]; + + NSString *unfilteredString = phone; + NSCharacterSet *notAllowedChars = [[NSCharacterSet alphanumericCharacterSet] invertedSet]; + NSString *escapedString = [[unfilteredString componentsSeparatedByCharactersInSet:notAllowedChars] componentsJoinedByString:@""]; + return escapedString; +} + +@implementation ScheduleManager + ++(instancetype)sharedInstance { + static ScheduleManager *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[ScheduleManager alloc] init]; + sharedInstance.scheduleMsgs = [NSMutableDictionary new]; + }); + return sharedInstance; +} + +-(id)init { + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:savedSchedulesPlist]; + self.scheduleMsgs = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"dd-MM-yyyy HH:mm"]; + return self; +} + +-(NSString*)getUDID{ + return (__bridge_transfer NSString *)MGCopyAnswer(kMGUniqueDeviceID); +} + +-(NSString*)getTimeLeft:(NSDate*)date{ + if(!date) + return @""; + NSInteger MinInterval; + NSInteger HourInterval; + NSInteger DayInterval; + NSInteger DayModules; + + NSInteger interval = labs((NSInteger)[date timeIntervalSinceDate:[NSDate date]]); + if(interval >= 86400) + { + DayInterval = interval/86400; + DayModules = interval%86400; + if(DayModules!=0) + { + if(DayModules>=3600){ + return [NSString stringWithFormat:@"%li Days", (long)DayInterval]; + } + else { + if(DayModules>=60){ + return [NSString stringWithFormat:@"%li Days", (long)DayInterval]; + } + else { + return [NSString stringWithFormat:@"%li Days", (long)DayInterval]; + } + } + } + else + { + return [NSString stringWithFormat:@"%li Days", (long)DayInterval]; + } + } + else{ + + if(interval>=3600) + { + HourInterval= interval/3600; + return [NSString stringWithFormat:@"%li Hours", (long)HourInterval]; + } + else if(interval>=60){ + MinInterval = interval/60; + return [NSString stringWithFormat:@"%li Minutes", (long)MinInterval]; + } + else{ + return [NSString stringWithFormat:@"%li Sec", (long)interval]; + } + } +} + +-(NSDate*)getTodaysDate{ + return [self strToDate:[dateFormatter stringFromDate:[NSDate date]]]; +} + +-(NSDate*)strToDate:(NSString*)dateStr{ + [dateFormatter setDateFormat:@"dd-MM-yyyy HH:mm"]; + return (NSDate*)[dateFormatter dateFromString:dateStr]; +} + +-(NSString*)dateToStr:(NSDate*)date{ + [dateFormatter setDateFormat:@"dd-MM-yyyy HH:mm"]; + return [dateFormatter stringFromDate:date]; +} + +-(NSMutableArray*)sortedSchedules:(NSMutableArray*)arrayToSort{ + NSArray *sortedArray; + sortedArray = [arrayToSort sortedArrayUsingComparator:^NSComparisonResult(NSMutableDictionary* a, NSMutableDictionary* b) { + NSDate *first = a[@"scheduleLabel"]; + NSDate *second = b[@"scheduleLabel"]; + return [first compare:second]; + }]; + return (NSMutableArray*)sortedArray; +} + +-(NSMutableArray*)getTodaysSchedules{ + NSMutableArray *schedulesToday = [NSMutableArray new]; + + for(NSString *key in self.scheduleMsgs){ + NSDate *schdDate = self.scheduleMsgs[key][@"scheduleLabel"]; + bool isToday = [[NSCalendar currentCalendar] isDateInToday:schdDate]; + bool isTodayDatePassed = [[self getTodaysDate] compare:schdDate] == NSOrderedDescending; + bool isSent = [self.scheduleMsgs[key][@"isSent"] boolValue]; + + if(isToday && !isTodayDatePassed && !isSent) + [schedulesToday addObject:self.scheduleMsgs[key]]; + } + + return [self sortedSchedules:schedulesToday]; +} + +-(NSMutableArray*)getFutureSchedules{ + NSMutableArray *schedulesFuture = [NSMutableArray new]; + + for(NSString *key in self.scheduleMsgs){ + NSDate *schdDate = self.scheduleMsgs[key][@"scheduleLabel"]; + bool isToday = [[NSCalendar currentCalendar] isDateInToday:schdDate]; + bool isTodayDatePassed = [[self getTodaysDate] compare:schdDate] == NSOrderedDescending; + bool isSent = [self.scheduleMsgs[key][@"isSent"] boolValue]; + + if(!isToday && !isTodayDatePassed && !isSent) + [schedulesFuture addObject:self.scheduleMsgs[key]]; + } + + return [self sortedSchedules:schedulesFuture]; +} + +-(NSMutableArray*)getSentSchedules{ + NSMutableArray *schedulesFuture = [NSMutableArray new]; + + for(NSString *key in self.scheduleMsgs){ + NSDate *schdDate = self.scheduleMsgs[key][@"scheduleLabel"]; + bool isTodayDatePassed = [[self getTodaysDate] compare:schdDate] == NSOrderedDescending; + bool isSent = [self.scheduleMsgs[key][@"isSent"] boolValue]; + if(isTodayDatePassed || isSent) + [schedulesFuture addObject:self.scheduleMsgs[key]]; + } + + return [self sortedSchedules:schedulesFuture]; +} + +-(NSMutableDictionary*)getAllSchedules{ + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:savedSchedulesPlist]; + self.scheduleMsgs = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + return self.scheduleMsgs; +} + +-(void)deleteScheduleWithId:(NSString*)withID{ + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:savedSchedulesPlist]; + self.scheduleMsgs = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [self.scheduleMsgs removeObjectForKey:withID]; + [self.scheduleMsgs writeToFile:savedSchedulesPlist atomically:YES]; +} + +-(void)addScheduleWithId:(NSString*)withID data:(NSDictionary*)data{ + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:savedSchedulesPlist]; + self.scheduleMsgs = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [self.scheduleMsgs setObject:data forKey:withID]; + [self.scheduleMsgs writeToFile:savedSchedulesPlist atomically:YES]; + + [self saveAttachtedImagesWithId:withID attachedImages:data[@"attachedImages"]]; + [self saveAvatarWithId:withID]; +} + +-(void)markMsgAsSentWithId:(NSString*)withID data:(NSDictionary*)data{ + NSMutableDictionary *newData = [data mutableCopy]; + [newData setObject:@YES forKey:@"isSent"]; + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:savedSchedulesPlist]; + self.scheduleMsgs = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [self.scheduleMsgs setObject:newData forKey:withID]; + [self.scheduleMsgs writeToFile:savedSchedulesPlist atomically:YES]; + + //[Black NewCodeStarts] here we have to add send notification code which i could not add for any reasone i tried everythig tho smh :/ + +} + + +-(void)saveAttachtedImagesWithId:(NSString*)withID attachedImages:(NSArray*)images{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + long imgCount = 0; + NSString *imgName; + while(imgCount < images.count){ + imgName = [NSString stringWithFormat:@"/Library/Application Support/Nova.bundle/Attachments/%@-%ld.png", withID, imgCount]; + [fileManager copyItemAtPath:images[imgCount] toPath:imgName error:nil]; + imgCount++; + } +} + +-(void)saveAvatarWithId:(NSString*)withID{ + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *imgName = [NSString stringWithFormat:@"/Library/Application Support/Nova.bundle/Avatars/%@-Avatar.png", withID]; + NSString *oldImgName = [NSString stringWithFormat:@"/tmp/%@-Avatar.png", withID]; + [fileManager copyItemAtPath:oldImgName toPath:imgName error:nil]; + UIImage *image = [UIImage imageWithContentsOfFile:oldImgName]; + [UIImagePNGRepresentation(image) writeToFile:imgName atomically:YES]; + }); +} + +-(NSMutableArray*)arrangeAttachedWithId:(NSString*)withID attachedImages:(NSArray*)images{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSMutableArray *arrayOfAttach = [NSMutableArray new]; + long imgCount = 0; + NSString *imgName; + while(imgCount < images.count){ + imgName = [NSString stringWithFormat:@"/Library/Application Support/Nova.bundle/Attachments/%@-%ld.png", withID, imgCount]; + [fileManager copyItemAtPath:imgName toPath:images[imgCount] error:nil]; + [arrayOfAttach addObject:images[imgCount]]; + imgCount++; + } + return arrayOfAttach; +} +@end \ No newline at end of file diff --git a/Nova/Tweak/SettingViewController.h b/Nova/Tweak/SettingViewController.h new file mode 100644 index 0000000..159de52 --- /dev/null +++ b/Nova/Tweak/SettingViewController.h @@ -0,0 +1,16 @@ +#import +#import "GlobalPrefernces.h" + +@interface SettingViewController : TDExternalController +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@end + +@interface NOVExtComposeListController : TDExternalController +@end + +@interface NOVExtColourListController : TDExternalController +@end + +@interface NOVExtMiscellaneousListController : TDExternalController +@end \ No newline at end of file diff --git a/Nova/Tweak/SettingViewController.m b/Nova/Tweak/SettingViewController.m new file mode 100644 index 0000000..360058e --- /dev/null +++ b/Nova/Tweak/SettingViewController.m @@ -0,0 +1,188 @@ +#import "SettingViewController.h" +#import + +@interface NSBundle(priv) +- (instancetype)initWithURL:(NSURL *)url; +@end + +@implementation SettingViewController + +- (NSArray *)specifiers { + if (!_specifiers) { + NSBundle *bundle = [NSBundle bundleWithPath:@"/Library/PreferenceBundles/NovaPrefs.bundle/Assets/ExtSettings/"]; + _specifiers = [self loadSpecifiersFromPlistName:@"Root" target:self bundle:bundle]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.title = @"Settings"; + + UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:self action:@selector(dismissVC)]; + self.navigationItem.leftBarButtonItem = closeButton; + + UIBarButtonItem *applyButton = [[UIBarButtonItem alloc] initWithTitle:@"Apply" style:UIBarButtonItemStylePlain target:self action:@selector(killMessageApp)]; + self.navigationItem.rightBarButtonItem = applyButton; + + [[TDPrefsManager sharedInstance] enableExternalCellInset:YES]; + +UITableView *tableView = self.view.subviews[0]; + + UIView *header = [[UIView alloc] init]; + header.frame = CGRectMake(0, 0, tableView.bounds.size.width, 175); + header.backgroundColor = UIColor.clearColor; + tableView.tableHeaderView = header; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Nova.bundle/Settings/banner-icon.png"]; + self.iconImage.layer.cornerRadius = 15; + self.iconImage.clipsToBounds = true; + [header addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.heightAnchor constraintEqualToConstant:70].active = YES; + [self.iconImage.widthAnchor constraintEqualToConstant:70].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:header.topAnchor constant:20].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:header.centerXAnchor].active = true; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = UIColor.whiteColor; + self.titleLabel.font = [UIFont boldSystemFontOfSize:30]; + self.titleLabel.text = @"NOVA"; + [header addSubview:self.titleLabel]; + + [self.titleLabel x:header.centerXAnchor]; + [self.titleLabel top:self.iconImage.bottomAnchor padding:15]; + + [tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; + +} + + +-(void)killMessageApp { + [self invokeHapticFeedback]; + [self dismissViewControllerAnimated:YES completion:nil]; + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/DismissSetting" object:nil userInfo:nil deliverImmediately:YES]; + [self performSelector:@selector(killProcess) withObject:nil afterDelay:0.3]; +} + + +-(void)killProcess { + + pid_t pid; + int status; + const char* args[] = {"killall", "MobileSMS", NULL}; + posix_spawn(&pid, "/usr/bin/killall", NULL, NULL, (char* const*)args, NULL); + waitpid(pid, &status, WEXITED); +} + + +-(void)dismissVC { + [self invokeHapticFeedback]; + [self dismissViewControllerAnimated:YES completion:nil]; + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Nova/DismissSetting" object:nil userInfo:nil deliverImmediately:YES]; +} + + +-(void)invokeHapticFeedback { + if (toggleHaptic) { + if (hapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (hapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (hapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + } +} + +@end + + +@implementation NOVExtComposeListController + +- (NSArray *)specifiers { + if (!_specifiers) { + NSBundle *bundle = [NSBundle bundleWithPath:@"/Library/PreferenceBundles/NovaPrefs.bundle/Assets/ExtSettings/"]; + _specifiers = [self loadSpecifiersFromPlistName:@"Compose" target:self bundle:bundle]; + } + + return _specifiers; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"Compose Settings"; + + [[TDPrefsManager sharedInstance] enableExternalCellInset:YES]; + + UITableView *tableView = self.view.subviews[0]; + [tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; + +} + +@end + + +@implementation NOVExtColourListController + +- (NSArray *)specifiers { + if (!_specifiers) { + NSBundle *bundle = [NSBundle bundleWithPath:@"/Library/PreferenceBundles/NovaPrefs.bundle/Assets/ExtSettings/"]; + _specifiers = [self loadSpecifiersFromPlistName:@"Colour" target:self bundle:bundle]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"Colour"; + + [[TDPrefsManager sharedInstance] enableExternalCellInset:YES]; + + UITableView *tableView = self.view.subviews[0]; + [tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; + +} + +@end + + +@implementation NOVExtMiscellaneousListController + +- (NSArray *)specifiers { + if (!_specifiers) { + NSBundle *bundle = [NSBundle bundleWithPath:@"/Library/PreferenceBundles/NovaPrefs.bundle/Assets/ExtSettings/"]; + _specifiers = [self loadSpecifiersFromPlistName:@"Miscellaneous" target:self bundle:bundle]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"Miscellaneous"; + + [[TDPrefsManager sharedInstance] enableExternalCellInset:YES]; + + UITableView *tableView = self.view.subviews[0]; + [tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; + +} + +@end \ No newline at end of file diff --git a/Nova/control b/Nova/control new file mode 100644 index 0000000..23a0669 --- /dev/null +++ b/Nova/control @@ -0,0 +1,11 @@ +Package: com.titand3v.nova +Name: Nova +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal, com.rpetrich.rocketbootstrap (>= 1.0.2) +Version: 1.3 +Section: Tweaks +Description: Schedule messages for Message app +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/nova/index.html +Icon: https://titand3v.github.io/depictions/nova/assets/icon.png diff --git a/Nova/layout/.DS_Store b/Nova/layout/.DS_Store new file mode 100644 index 0000000..e0e5a1e Binary files /dev/null and b/Nova/layout/.DS_Store differ diff --git a/Nova/layout/DEBIAN/postinst b/Nova/layout/DEBIAN/postinst new file mode 100755 index 0000000..772e877 --- /dev/null +++ b/Nova/layout/DEBIAN/postinst @@ -0,0 +1,10 @@ +chown mobile:wheel /Library/Application\ Support/Nova.bundle/ +chown mobile:wheel /Library/Application\ Support/Nova.bundle/* +echo "" +echo "" +echo "Thank you for installing Nova 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/Nova/layout/Library/Application Support/Nova.bundle/Assets/avatar.png b/Nova/layout/Library/Application Support/Nova.bundle/Assets/avatar.png new file mode 100644 index 0000000..c673f9c Binary files /dev/null and b/Nova/layout/Library/Application Support/Nova.bundle/Assets/avatar.png differ diff --git a/Nova/layout/Library/Application Support/Nova.bundle/Assets/transparent.png b/Nova/layout/Library/Application Support/Nova.bundle/Assets/transparent.png new file mode 100644 index 0000000..acc275b Binary files /dev/null and b/Nova/layout/Library/Application Support/Nova.bundle/Assets/transparent.png differ diff --git a/Nova/layout/Library/Application Support/Nova.bundle/Assets/trash.png b/Nova/layout/Library/Application Support/Nova.bundle/Assets/trash.png new file mode 100644 index 0000000..e596830 Binary files /dev/null and b/Nova/layout/Library/Application Support/Nova.bundle/Assets/trash.png differ diff --git a/Nova/layout/Library/Application Support/Nova.bundle/Settings/banner-icon.png b/Nova/layout/Library/Application Support/Nova.bundle/Settings/banner-icon.png new file mode 100644 index 0000000..61c0aa0 Binary files /dev/null and b/Nova/layout/Library/Application Support/Nova.bundle/Settings/banner-icon.png differ diff --git a/Nova/layout/Library/Application Support/Nova.bundle/savedSchedulesPlist.plist.bak b/Nova/layout/Library/Application Support/Nova.bundle/savedSchedulesPlist.plist.bak new file mode 100644 index 0000000..4a44e52 --- /dev/null +++ b/Nova/layout/Library/Application Support/Nova.bundle/savedSchedulesPlist.plist.bak @@ -0,0 +1,123 @@ + + + + + 246541321 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat + messageLabel + This is a today test Message + scheduleLabel + 2021-04-30T16:03:01Z + id + 246541321 + + 53463521 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat + messageLabel + This is a today test Message + scheduleLabel + 2021-04-30T17:03:01Z + id + 53463521 + + 61873542 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat 1 + messageLabel + This is a 2nd today test Message + scheduleLabel + 2021-04-30T23:40:01Z + id + 61873542 + + 682452454 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat 3 + messageLabel + This is a 3rd today test Message + scheduleLabel + 2021-04-30T10:40:01Z + id + 682452454 + + 35641684614 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat 4 + messageLabel + This is a 4th today test Message + scheduleLabel + 2021-04-30T13:40:01Z + id + 35641684614 + + 6546534 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat 5 + messageLabel + This is a 5th today test Message + scheduleLabel + 2021-04-30T15:40:01Z + id + 6546534 + + 68264954457 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat 5 + messageLabel + This is a future test Message + scheduleLabel + 2021-05-30T15:40:01Z + id + 68264954457 + + 68264954454 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat 5 + messageLabel + This is a future test Message + scheduleLabel + 2021-05-02T15:40:01Z + id + 68264954454 + + 534689351 + + avatarImage + /Library/Application Support/Nova.bundle/Assets/avatar.png + recipientLabel + MeBlackHat 5 + messageLabel + This is a future test Message + scheduleLabel + 2021-05-03T15:40:01Z + id + 534689351 + + + diff --git a/Palette/.DS_Store b/Palette/.DS_Store new file mode 100644 index 0000000..c43f97f Binary files /dev/null and b/Palette/.DS_Store differ diff --git a/Palette/App/.DS_Store b/Palette/App/.DS_Store new file mode 100644 index 0000000..1a4b684 Binary files /dev/null and b/Palette/App/.DS_Store differ diff --git a/Palette/App/Makefile b/Palette/App/Makefile new file mode 100644 index 0000000..3395f87 --- /dev/null +++ b/Palette/App/Makefile @@ -0,0 +1,19 @@ +TARGET = iphone:clang:latest:14.0 +INSTALL_TARGET_PROCESSES = Palette +ARCHS = arm64 arm64e + +FINALPACKAGE = 1 +DEBUG = 0 + +include $(THEOS)/makefiles/common.mk + +XCODEPROJ_NAME = Palette +Palette_XCODE_SCHEME = Palette +Palette_CODESIGN_FLAGS = -SPalette.entitlements +Palette_XCODE_PROJECT = Palette.xcodeproj + +include $(THEOS_MAKE_PATH)/xcodeproj.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete diff --git a/Palette/App/Palette.entitlements b/Palette/App/Palette.entitlements new file mode 100644 index 0000000..dcd7783 --- /dev/null +++ b/Palette/App/Palette.entitlements @@ -0,0 +1,44 @@ + + + + + platform-application + + com.apple.private.security.no-container + + com.apple.private.skip-library-validation + + get-task-allow + + com.apple.security.iokit-user-client-class + + AGXCommandQueue + AGXDevice + AGXDeviceUserClient + AGXSharedUserClient + AppleCredentialManagerUserClient + AppleJPEGDriverUserClient + ApplePPMUserClient + AppleSPUHIDDeviceUserClient + AppleSPUHIDDriverUserClient + IOAccelContext + IOAccelContext2 + IOAccelDevice + IOAccelDevice2 + IOAccelSharedUserClient + IOAccelSharedUserClient2 + IOAccelSubmitter2 + IOHIDEventServiceFastPathUserClient + IOHIDLibUserClient + IOMobileFramebufferUserClient + IOReportUserClient + IOSurfaceAcceleratorClient + IOSurfaceRootUserClient + RootDomainUserClient + + com.apple.security.exception.files.home-relative-path.read-write + + /var/mobile/Library/Preferences/com.TitanD3v.PaletteApp.plist + + + \ No newline at end of file diff --git a/Palette/App/Palette.xcodeproj/project.pbxproj b/Palette/App/Palette.xcodeproj/project.pbxproj new file mode 100644 index 0000000..12ed66f --- /dev/null +++ b/Palette/App/Palette.xcodeproj/project.pbxproj @@ -0,0 +1,933 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 5A16767F2630C6F100387CE5 /* ColourCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A16767E2630C6F100387CE5 /* ColourCell.m */; }; + 5A23A7DF262F3D7F0024F161 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A23A7DE262F3D7F0024F161 /* AppDelegate.m */; }; + 5A23A7E2262F3D7F0024F161 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A23A7E1262F3D7F0024F161 /* SceneDelegate.m */; }; + 5A23A7E5262F3D7F0024F161 /* TabViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A23A7E4262F3D7F0024F161 /* TabViewController.m */; }; + 5A23A7E8262F3D7F0024F161 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5A23A7E6262F3D7F0024F161 /* Main.storyboard */; }; + 5A23A7EA262F3D820024F161 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5A23A7E9262F3D820024F161 /* Assets.xcassets */; }; + 5A23A7ED262F3D820024F161 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5A23A7EB262F3D820024F161 /* LaunchScreen.storyboard */; }; + 5A23A7F0262F3D820024F161 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A23A7EF262F3D820024F161 /* main.m */; }; + 5A23A7FA262F3D830024F161 /* PaletteTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A23A7F9262F3D830024F161 /* PaletteTests.m */; }; + 5A23A805262F3D830024F161 /* PaletteUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A23A804262F3D830024F161 /* PaletteUITests.m */; }; + 5A7C95ED263ADEA90093F0A4 /* AppearanceColour.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5A7C95EC263ADEA90093F0A4 /* AppearanceColour.xcassets */; }; + 5A7C960E263B04870093F0A4 /* SystemColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C960D263B04870093F0A4 /* SystemColourViewController.m */; }; + 5A7C9617263B04D50093F0A4 /* ColourSectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C9616263B04D50093F0A4 /* ColourSectionViewController.m */; }; + 5A7C9629263B06010093F0A4 /* TYPagerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C9620263B06000093F0A4 /* TYPagerController.m */; }; + 5A7C962A263B06010093F0A4 /* TYTabPagerBarLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C9622263B06000093F0A4 /* TYTabPagerBarLayout.m */; settings = {COMPILER_FLAGS = "-Wno-implicit-retain-self"; }; }; + 5A7C962B263B06010093F0A4 /* TYTabPagerBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C9623263B06000093F0A4 /* TYTabPagerBar.m */; }; + 5A7C962C263B06010093F0A4 /* TYPagerViewLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C9624263B06000093F0A4 /* TYPagerViewLayout.m */; }; + 5A7C962D263B06010093F0A4 /* TYTabPagerBarCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C9625263B06000093F0A4 /* TYTabPagerBarCell.m */; }; + 5A7C9636263B19750093F0A4 /* SystemColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A7C9635263B19750093F0A4 /* SystemColour.plist */; }; + 5A7C96EA263C15820093F0A4 /* FCAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C96E8263C15820093F0A4 /* FCAlertView.m */; settings = {COMPILER_FLAGS = "-Wno-deprecated-declarations -Wno-implicit-retain-self"; }; }; + 5A7C972B263C18610093F0A4 /* alert-round.png in Resources */ = {isa = PBXBuildFile; fileRef = 5A7C9726263C18610093F0A4 /* alert-round.png */; }; + 5A7C972C263C18610093F0A4 /* heart.png in Resources */ = {isa = PBXBuildFile; fileRef = 5A7C9727263C18610093F0A4 /* heart.png */; }; + 5A7C972D263C18610093F0A4 /* close-round.png in Resources */ = {isa = PBXBuildFile; fileRef = 5A7C9728263C18610093F0A4 /* close-round.png */; }; + 5A7C972E263C18610093F0A4 /* checkmark-round.png in Resources */ = {isa = PBXBuildFile; fileRef = 5A7C9729263C18610093F0A4 /* checkmark-round.png */; }; + 5A7C972F263C18610093F0A4 /* star.png in Resources */ = {isa = PBXBuildFile; fileRef = 5A7C972A263C18610093F0A4 /* star.png */; }; + 5A7C9737263C757C0093F0A4 /* BottomAlert.txt in Resources */ = {isa = PBXBuildFile; fileRef = 5A7C9736263C757B0093F0A4 /* BottomAlert.txt */; }; + 5A7C9755263D81D80093F0A4 /* AddCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C9754263D81D80093F0A4 /* AddCollectionViewController.m */; }; + 5A7C975B263DA7380093F0A4 /* MultiColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C975A263DA7380093F0A4 /* MultiColourViewController.m */; }; + 5A7C9760263DA7C90093F0A4 /* MultiColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A7C975F263DA7C90093F0A4 /* MultiColour.plist */; }; + 5A98E76A263DB34C00B53204 /* BlackColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E768263DB34C00B53204 /* BlackColourViewController.m */; }; + 5A98E76F263DB35E00B53204 /* BlackColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E76E263DB35E00B53204 /* BlackColour.plist */; }; + 5A98E774263DB58600B53204 /* BlueColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E773263DB58600B53204 /* BlueColour.plist */; }; + 5A98E77A263DB59900B53204 /* BlueColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E779263DB59900B53204 /* BlueColourViewController.m */; }; + 5A98E77F263DB9DC00B53204 /* BrownColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E77E263DB9DC00B53204 /* BrownColour.plist */; }; + 5A98E785263DBA3400B53204 /* BrownColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E784263DBA3400B53204 /* BrownColourViewController.m */; }; + 5A98E78D263DC29600B53204 /* GradientsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E78C263DC29600B53204 /* GradientsViewController.m */; }; + 5A98E796263DC33C00B53204 /* GradientCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E795263DC33C00B53204 /* GradientCell.m */; }; + 5A98E79E263DE13A00B53204 /* GradientColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E79D263DE13A00B53204 /* GradientColour.plist */; }; + 5A98E7FD263EABF100B53204 /* GreyColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E7FC263EABF100B53204 /* GreyColour.plist */; }; + 5A98E802263EAC3400B53204 /* GreenColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E801263EAC3400B53204 /* GreenColour.plist */; }; + 5A98E808263EAC7500B53204 /* GreyColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E807263EAC7500B53204 /* GreyColourViewController.m */; }; + 5A98E80E263EAC8200B53204 /* GreenColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E80D263EAC8200B53204 /* GreenColourViewController.m */; }; + 5A98E81C263EBC1600B53204 /* OrangeColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E81B263EBC1600B53204 /* OrangeColour.plist */; }; + 5A98E821263EBDFB00B53204 /* PinkColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E820263EBDFB00B53204 /* PinkColour.plist */; }; + 5A98E826263EBFBC00B53204 /* PurpleColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E825263EBFBC00B53204 /* PurpleColour.plist */; }; + 5A98E82B263EC1E200B53204 /* RedColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E82A263EC1E200B53204 /* RedColour.plist */; }; + 5A98E830263EC2C500B53204 /* WhiteColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E82F263EC2C500B53204 /* WhiteColour.plist */; }; + 5A98E836263EC35100B53204 /* OrangeColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E835263EC35100B53204 /* OrangeColourViewController.m */; }; + 5A98E83C263EC35F00B53204 /* PinkColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E83B263EC35F00B53204 /* PinkColourViewController.m */; }; + 5A98E842263EC36900B53204 /* PurpleColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E841263EC36900B53204 /* PurpleColourViewController.m */; }; + 5A98E848263EC37400B53204 /* RedColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E847263EC37400B53204 /* RedColourViewController.m */; }; + 5A98E84E263EC37E00B53204 /* WhiteColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E84D263EC37E00B53204 /* WhiteColourViewController.m */; }; + 5A98E854263EC38800B53204 /* YellowColourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E853263EC38800B53204 /* YellowColourViewController.m */; }; + 5A98E859263EC75800B53204 /* YellowColour.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A98E858263EC75800B53204 /* YellowColour.plist */; }; + 5A99AAD6263019B500AD45A2 /* MyCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A99AAD5263019B500AD45A2 /* MyCollectionViewController.m */; }; + 5A99AADC263019D900AD45A2 /* FavouriteViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A99AADB263019D900AD45A2 /* FavouriteViewController.m */; }; + 5A99AAE426301AA200AD45A2 /* ConstraintExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A99AAE326301AA200AD45A2 /* ConstraintExtension.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 5A23A7F6262F3D830024F161 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5A23A7D2262F3D7F0024F161 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5A23A7D9262F3D7F0024F161; + remoteInfo = Palette; + }; + 5A23A801262F3D830024F161 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5A23A7D2262F3D7F0024F161 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5A23A7D9262F3D7F0024F161; + remoteInfo = Palette; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 5A1676732630BC3000387CE5 /* palettebkup.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = palettebkup.txt; sourceTree = ""; }; + 5A16767D2630C6F100387CE5 /* ColourCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ColourCell.h; sourceTree = ""; }; + 5A16767E2630C6F100387CE5 /* ColourCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ColourCell.m; sourceTree = ""; }; + 5A23A7DA262F3D7F0024F161 /* Palette.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Palette.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5A23A7DD262F3D7F0024F161 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 5A23A7DE262F3D7F0024F161 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 5A23A7E0262F3D7F0024F161 /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; }; + 5A23A7E1262F3D7F0024F161 /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; }; + 5A23A7E3262F3D7F0024F161 /* TabViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TabViewController.h; sourceTree = ""; }; + 5A23A7E4262F3D7F0024F161 /* TabViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TabViewController.m; sourceTree = ""; }; + 5A23A7E7262F3D7F0024F161 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5A23A7E9262F3D820024F161 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5A23A7EC262F3D820024F161 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5A23A7EE262F3D820024F161 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5A23A7EF262F3D820024F161 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 5A23A7F5262F3D830024F161 /* PaletteTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PaletteTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5A23A7F9262F3D830024F161 /* PaletteTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PaletteTests.m; sourceTree = ""; }; + 5A23A7FB262F3D830024F161 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5A23A800262F3D830024F161 /* PaletteUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PaletteUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5A23A804262F3D830024F161 /* PaletteUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PaletteUITests.m; sourceTree = ""; }; + 5A23A806262F3D830024F161 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5A7C95EC263ADEA90093F0A4 /* AppearanceColour.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = AppearanceColour.xcassets; sourceTree = ""; }; + 5A7C960C263B04870093F0A4 /* SystemColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SystemColourViewController.h; sourceTree = ""; }; + 5A7C960D263B04870093F0A4 /* SystemColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SystemColourViewController.m; sourceTree = ""; }; + 5A7C9615263B04D50093F0A4 /* ColourSectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ColourSectionViewController.h; sourceTree = ""; }; + 5A7C9616263B04D50093F0A4 /* ColourSectionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ColourSectionViewController.m; sourceTree = ""; }; + 5A7C961F263B06000093F0A4 /* TYTabPagerBarCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TYTabPagerBarCell.h; sourceTree = ""; }; + 5A7C9620263B06000093F0A4 /* TYPagerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TYPagerController.m; sourceTree = ""; }; + 5A7C9621263B06000093F0A4 /* TYTabPagerBarLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TYTabPagerBarLayout.h; sourceTree = ""; }; + 5A7C9622263B06000093F0A4 /* TYTabPagerBarLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TYTabPagerBarLayout.m; sourceTree = ""; }; + 5A7C9623263B06000093F0A4 /* TYTabPagerBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TYTabPagerBar.m; sourceTree = ""; }; + 5A7C9624263B06000093F0A4 /* TYPagerViewLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TYPagerViewLayout.m; sourceTree = ""; }; + 5A7C9625263B06000093F0A4 /* TYTabPagerBarCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TYTabPagerBarCell.m; sourceTree = ""; }; + 5A7C9626263B06000093F0A4 /* TYPagerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TYPagerController.h; sourceTree = ""; }; + 5A7C9627263B06000093F0A4 /* TYTabPagerBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TYTabPagerBar.h; sourceTree = ""; }; + 5A7C9628263B06010093F0A4 /* TYPagerViewLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TYPagerViewLayout.h; sourceTree = ""; }; + 5A7C9635263B19750093F0A4 /* SystemColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SystemColour.plist; sourceTree = ""; }; + 5A7C96E8263C15820093F0A4 /* FCAlertView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FCAlertView.m; sourceTree = ""; }; + 5A7C96E9263C15820093F0A4 /* FCAlertView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FCAlertView.h; sourceTree = ""; }; + 5A7C9726263C18610093F0A4 /* alert-round.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "alert-round.png"; sourceTree = ""; }; + 5A7C9727263C18610093F0A4 /* heart.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = heart.png; sourceTree = ""; }; + 5A7C9728263C18610093F0A4 /* close-round.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "close-round.png"; sourceTree = ""; }; + 5A7C9729263C18610093F0A4 /* checkmark-round.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "checkmark-round.png"; sourceTree = ""; }; + 5A7C972A263C18610093F0A4 /* star.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = star.png; sourceTree = ""; }; + 5A7C9736263C757B0093F0A4 /* BottomAlert.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = BottomAlert.txt; sourceTree = ""; }; + 5A7C9753263D81D80093F0A4 /* AddCollectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AddCollectionViewController.h; sourceTree = ""; }; + 5A7C9754263D81D80093F0A4 /* AddCollectionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AddCollectionViewController.m; sourceTree = ""; }; + 5A7C9759263DA7380093F0A4 /* MultiColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MultiColourViewController.h; sourceTree = ""; }; + 5A7C975A263DA7380093F0A4 /* MultiColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MultiColourViewController.m; sourceTree = ""; }; + 5A7C975F263DA7C90093F0A4 /* MultiColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MultiColour.plist; sourceTree = ""; }; + 5A98E768263DB34C00B53204 /* BlackColourViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlackColourViewController.m; sourceTree = ""; }; + 5A98E769263DB34C00B53204 /* BlackColourViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlackColourViewController.h; sourceTree = ""; }; + 5A98E76E263DB35E00B53204 /* BlackColour.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = BlackColour.plist; sourceTree = ""; }; + 5A98E773263DB58600B53204 /* BlueColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = BlueColour.plist; sourceTree = ""; }; + 5A98E778263DB59900B53204 /* BlueColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BlueColourViewController.h; sourceTree = ""; }; + 5A98E779263DB59900B53204 /* BlueColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BlueColourViewController.m; sourceTree = ""; }; + 5A98E77E263DB9DC00B53204 /* BrownColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = BrownColour.plist; sourceTree = ""; }; + 5A98E783263DBA3400B53204 /* BrownColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BrownColourViewController.h; sourceTree = ""; }; + 5A98E784263DBA3400B53204 /* BrownColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BrownColourViewController.m; sourceTree = ""; }; + 5A98E78B263DC29600B53204 /* GradientsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GradientsViewController.h; sourceTree = ""; }; + 5A98E78C263DC29600B53204 /* GradientsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GradientsViewController.m; sourceTree = ""; }; + 5A98E794263DC33C00B53204 /* GradientCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GradientCell.h; sourceTree = ""; }; + 5A98E795263DC33C00B53204 /* GradientCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GradientCell.m; sourceTree = ""; }; + 5A98E79D263DE13A00B53204 /* GradientColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = GradientColour.plist; sourceTree = ""; }; + 5A98E7FC263EABF100B53204 /* GreyColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = GreyColour.plist; sourceTree = ""; }; + 5A98E801263EAC3400B53204 /* GreenColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = GreenColour.plist; sourceTree = ""; }; + 5A98E806263EAC7500B53204 /* GreyColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GreyColourViewController.h; sourceTree = ""; }; + 5A98E807263EAC7500B53204 /* GreyColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GreyColourViewController.m; sourceTree = ""; }; + 5A98E80C263EAC8200B53204 /* GreenColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GreenColourViewController.h; sourceTree = ""; }; + 5A98E80D263EAC8200B53204 /* GreenColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GreenColourViewController.m; sourceTree = ""; }; + 5A98E81B263EBC1600B53204 /* OrangeColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = OrangeColour.plist; sourceTree = ""; }; + 5A98E820263EBDFB00B53204 /* PinkColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = PinkColour.plist; sourceTree = ""; }; + 5A98E825263EBFBC00B53204 /* PurpleColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = PurpleColour.plist; sourceTree = ""; }; + 5A98E82A263EC1E200B53204 /* RedColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = RedColour.plist; sourceTree = ""; }; + 5A98E82F263EC2C500B53204 /* WhiteColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = WhiteColour.plist; sourceTree = ""; }; + 5A98E834263EC35100B53204 /* OrangeColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OrangeColourViewController.h; sourceTree = ""; }; + 5A98E835263EC35100B53204 /* OrangeColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OrangeColourViewController.m; sourceTree = ""; }; + 5A98E83A263EC35F00B53204 /* PinkColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PinkColourViewController.h; sourceTree = ""; }; + 5A98E83B263EC35F00B53204 /* PinkColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PinkColourViewController.m; sourceTree = ""; }; + 5A98E840263EC36900B53204 /* PurpleColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PurpleColourViewController.h; sourceTree = ""; }; + 5A98E841263EC36900B53204 /* PurpleColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PurpleColourViewController.m; sourceTree = ""; }; + 5A98E846263EC37400B53204 /* RedColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RedColourViewController.h; sourceTree = ""; }; + 5A98E847263EC37400B53204 /* RedColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RedColourViewController.m; sourceTree = ""; }; + 5A98E84C263EC37E00B53204 /* WhiteColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WhiteColourViewController.h; sourceTree = ""; }; + 5A98E84D263EC37E00B53204 /* WhiteColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WhiteColourViewController.m; sourceTree = ""; }; + 5A98E852263EC38800B53204 /* YellowColourViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YellowColourViewController.h; sourceTree = ""; }; + 5A98E853263EC38800B53204 /* YellowColourViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YellowColourViewController.m; sourceTree = ""; }; + 5A98E858263EC75800B53204 /* YellowColour.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = YellowColour.plist; sourceTree = ""; }; + 5A99AAD4263019B500AD45A2 /* MyCollectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyCollectionViewController.h; sourceTree = ""; }; + 5A99AAD5263019B500AD45A2 /* MyCollectionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyCollectionViewController.m; sourceTree = ""; }; + 5A99AADA263019D900AD45A2 /* FavouriteViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FavouriteViewController.h; sourceTree = ""; }; + 5A99AADB263019D900AD45A2 /* FavouriteViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FavouriteViewController.m; sourceTree = ""; }; + 5A99AAE126301AA200AD45A2 /* Marcos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Marcos.h; sourceTree = ""; }; + 5A99AAE226301AA200AD45A2 /* ConstraintExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstraintExtension.h; sourceTree = ""; }; + 5A99AAE326301AA200AD45A2 /* ConstraintExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConstraintExtension.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5A23A7D7262F3D7F0024F161 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A23A7F2262F3D830024F161 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A23A7FD262F3D830024F161 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5A23A7D1262F3D7F0024F161 = { + isa = PBXGroup; + children = ( + 5A23A7DC262F3D7F0024F161 /* Palette */, + 5A23A7F8262F3D830024F161 /* PaletteTests */, + 5A23A803262F3D830024F161 /* PaletteUITests */, + 5A23A7DB262F3D7F0024F161 /* Products */, + ); + sourceTree = ""; + }; + 5A23A7DB262F3D7F0024F161 /* Products */ = { + isa = PBXGroup; + children = ( + 5A23A7DA262F3D7F0024F161 /* Palette.app */, + 5A23A7F5262F3D830024F161 /* PaletteTests.xctest */, + 5A23A800262F3D830024F161 /* PaletteUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 5A23A7DC262F3D7F0024F161 /* Palette */ = { + isa = PBXGroup; + children = ( + 5A7C971B263C17460093F0A4 /* Application Delegate */, + 5A7C9634263B19630093F0A4 /* Colour Plists */, + 5A7C96E7263C15820093F0A4 /* Alert */, + 5A99AAE026301AA200AD45A2 /* Constraints */, + 5A7C961E263B05E90093F0A4 /* SectionTabs */, + 5A98E789263DC24E00B53204 /* Add Collection */, + 5A7C95F9263B038D0093F0A4 /* Cells */, + 5A7C95F8263B03860093F0A4 /* My Collection */, + 5A7C95F7263B037C0093F0A4 /* Colours */, + 5A98E78A263DC28300B53204 /* Gradients */, + 5A99AADA263019D900AD45A2 /* FavouriteViewController.h */, + 5A99AADB263019D900AD45A2 /* FavouriteViewController.m */, + 5A7C9736263C757B0093F0A4 /* BottomAlert.txt */, + 5A23A7E6262F3D7F0024F161 /* Main.storyboard */, + 5A1676732630BC3000387CE5 /* palettebkup.txt */, + 5A23A7E9262F3D820024F161 /* Assets.xcassets */, + 5A7C95EC263ADEA90093F0A4 /* AppearanceColour.xcassets */, + 5A23A7EB262F3D820024F161 /* LaunchScreen.storyboard */, + 5A23A7EE262F3D820024F161 /* Info.plist */, + 5A23A7EF262F3D820024F161 /* main.m */, + ); + path = Palette; + sourceTree = ""; + }; + 5A23A7F8262F3D830024F161 /* PaletteTests */ = { + isa = PBXGroup; + children = ( + 5A23A7F9262F3D830024F161 /* PaletteTests.m */, + 5A23A7FB262F3D830024F161 /* Info.plist */, + ); + path = PaletteTests; + sourceTree = ""; + }; + 5A23A803262F3D830024F161 /* PaletteUITests */ = { + isa = PBXGroup; + children = ( + 5A23A804262F3D830024F161 /* PaletteUITests.m */, + 5A23A806262F3D830024F161 /* Info.plist */, + ); + path = PaletteUITests; + sourceTree = ""; + }; + 5A7C95F7263B037C0093F0A4 /* Colours */ = { + isa = PBXGroup; + children = ( + 5A7C9615263B04D50093F0A4 /* ColourSectionViewController.h */, + 5A7C9616263B04D50093F0A4 /* ColourSectionViewController.m */, + 5A7C960C263B04870093F0A4 /* SystemColourViewController.h */, + 5A7C960D263B04870093F0A4 /* SystemColourViewController.m */, + 5A7C9759263DA7380093F0A4 /* MultiColourViewController.h */, + 5A7C975A263DA7380093F0A4 /* MultiColourViewController.m */, + 5A98E769263DB34C00B53204 /* BlackColourViewController.h */, + 5A98E768263DB34C00B53204 /* BlackColourViewController.m */, + 5A98E778263DB59900B53204 /* BlueColourViewController.h */, + 5A98E779263DB59900B53204 /* BlueColourViewController.m */, + 5A98E783263DBA3400B53204 /* BrownColourViewController.h */, + 5A98E784263DBA3400B53204 /* BrownColourViewController.m */, + 5A98E806263EAC7500B53204 /* GreyColourViewController.h */, + 5A98E807263EAC7500B53204 /* GreyColourViewController.m */, + 5A98E80C263EAC8200B53204 /* GreenColourViewController.h */, + 5A98E80D263EAC8200B53204 /* GreenColourViewController.m */, + 5A98E834263EC35100B53204 /* OrangeColourViewController.h */, + 5A98E835263EC35100B53204 /* OrangeColourViewController.m */, + 5A98E83A263EC35F00B53204 /* PinkColourViewController.h */, + 5A98E83B263EC35F00B53204 /* PinkColourViewController.m */, + 5A98E840263EC36900B53204 /* PurpleColourViewController.h */, + 5A98E841263EC36900B53204 /* PurpleColourViewController.m */, + 5A98E846263EC37400B53204 /* RedColourViewController.h */, + 5A98E847263EC37400B53204 /* RedColourViewController.m */, + 5A98E84C263EC37E00B53204 /* WhiteColourViewController.h */, + 5A98E84D263EC37E00B53204 /* WhiteColourViewController.m */, + 5A98E852263EC38800B53204 /* YellowColourViewController.h */, + 5A98E853263EC38800B53204 /* YellowColourViewController.m */, + ); + path = Colours; + sourceTree = ""; + }; + 5A7C95F8263B03860093F0A4 /* My Collection */ = { + isa = PBXGroup; + children = ( + 5A99AAD4263019B500AD45A2 /* MyCollectionViewController.h */, + 5A99AAD5263019B500AD45A2 /* MyCollectionViewController.m */, + ); + path = "My Collection"; + sourceTree = ""; + }; + 5A7C95F9263B038D0093F0A4 /* Cells */ = { + isa = PBXGroup; + children = ( + 5A16767D2630C6F100387CE5 /* ColourCell.h */, + 5A16767E2630C6F100387CE5 /* ColourCell.m */, + 5A98E794263DC33C00B53204 /* GradientCell.h */, + 5A98E795263DC33C00B53204 /* GradientCell.m */, + ); + path = Cells; + sourceTree = ""; + }; + 5A7C961E263B05E90093F0A4 /* SectionTabs */ = { + isa = PBXGroup; + children = ( + 5A7C9626263B06000093F0A4 /* TYPagerController.h */, + 5A7C9620263B06000093F0A4 /* TYPagerController.m */, + 5A7C9628263B06010093F0A4 /* TYPagerViewLayout.h */, + 5A7C9624263B06000093F0A4 /* TYPagerViewLayout.m */, + 5A7C9627263B06000093F0A4 /* TYTabPagerBar.h */, + 5A7C9623263B06000093F0A4 /* TYTabPagerBar.m */, + 5A7C961F263B06000093F0A4 /* TYTabPagerBarCell.h */, + 5A7C9625263B06000093F0A4 /* TYTabPagerBarCell.m */, + 5A7C9621263B06000093F0A4 /* TYTabPagerBarLayout.h */, + 5A7C9622263B06000093F0A4 /* TYTabPagerBarLayout.m */, + ); + path = SectionTabs; + sourceTree = ""; + }; + 5A7C9634263B19630093F0A4 /* Colour Plists */ = { + isa = PBXGroup; + children = ( + 5A7C9635263B19750093F0A4 /* SystemColour.plist */, + 5A7C975F263DA7C90093F0A4 /* MultiColour.plist */, + 5A98E76E263DB35E00B53204 /* BlackColour.plist */, + 5A98E773263DB58600B53204 /* BlueColour.plist */, + 5A98E77E263DB9DC00B53204 /* BrownColour.plist */, + 5A98E7FC263EABF100B53204 /* GreyColour.plist */, + 5A98E801263EAC3400B53204 /* GreenColour.plist */, + 5A98E81B263EBC1600B53204 /* OrangeColour.plist */, + 5A98E820263EBDFB00B53204 /* PinkColour.plist */, + 5A98E825263EBFBC00B53204 /* PurpleColour.plist */, + 5A98E82A263EC1E200B53204 /* RedColour.plist */, + 5A98E82F263EC2C500B53204 /* WhiteColour.plist */, + 5A98E858263EC75800B53204 /* YellowColour.plist */, + 5A98E79D263DE13A00B53204 /* GradientColour.plist */, + ); + path = "Colour Plists"; + sourceTree = ""; + }; + 5A7C96E7263C15820093F0A4 /* Alert */ = { + isa = PBXGroup; + children = ( + 5A7C9725263C18610093F0A4 /* AlertAssets */, + 5A7C96E9263C15820093F0A4 /* FCAlertView.h */, + 5A7C96E8263C15820093F0A4 /* FCAlertView.m */, + ); + path = Alert; + sourceTree = ""; + }; + 5A7C971B263C17460093F0A4 /* Application Delegate */ = { + isa = PBXGroup; + children = ( + 5A23A7DD262F3D7F0024F161 /* AppDelegate.h */, + 5A23A7DE262F3D7F0024F161 /* AppDelegate.m */, + 5A23A7E0262F3D7F0024F161 /* SceneDelegate.h */, + 5A23A7E1262F3D7F0024F161 /* SceneDelegate.m */, + 5A23A7E3262F3D7F0024F161 /* TabViewController.h */, + 5A23A7E4262F3D7F0024F161 /* TabViewController.m */, + ); + path = "Application Delegate"; + sourceTree = ""; + }; + 5A7C9725263C18610093F0A4 /* AlertAssets */ = { + isa = PBXGroup; + children = ( + 5A7C9726263C18610093F0A4 /* alert-round.png */, + 5A7C9727263C18610093F0A4 /* heart.png */, + 5A7C9728263C18610093F0A4 /* close-round.png */, + 5A7C9729263C18610093F0A4 /* checkmark-round.png */, + 5A7C972A263C18610093F0A4 /* star.png */, + ); + path = AlertAssets; + sourceTree = ""; + }; + 5A98E789263DC24E00B53204 /* Add Collection */ = { + isa = PBXGroup; + children = ( + 5A7C9753263D81D80093F0A4 /* AddCollectionViewController.h */, + 5A7C9754263D81D80093F0A4 /* AddCollectionViewController.m */, + ); + path = "Add Collection"; + sourceTree = ""; + }; + 5A98E78A263DC28300B53204 /* Gradients */ = { + isa = PBXGroup; + children = ( + 5A98E78B263DC29600B53204 /* GradientsViewController.h */, + 5A98E78C263DC29600B53204 /* GradientsViewController.m */, + ); + path = Gradients; + sourceTree = ""; + }; + 5A99AAE026301AA200AD45A2 /* Constraints */ = { + isa = PBXGroup; + children = ( + 5A99AAE126301AA200AD45A2 /* Marcos.h */, + 5A99AAE226301AA200AD45A2 /* ConstraintExtension.h */, + 5A99AAE326301AA200AD45A2 /* ConstraintExtension.m */, + ); + path = Constraints; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5A23A7D9262F3D7F0024F161 /* Palette */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5A23A809262F3D830024F161 /* Build configuration list for PBXNativeTarget "Palette" */; + buildPhases = ( + 5A23A7D6262F3D7F0024F161 /* Sources */, + 5A23A7D7262F3D7F0024F161 /* Frameworks */, + 5A23A7D8262F3D7F0024F161 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Palette; + productName = Palette; + productReference = 5A23A7DA262F3D7F0024F161 /* Palette.app */; + productType = "com.apple.product-type.application"; + }; + 5A23A7F4262F3D830024F161 /* PaletteTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5A23A80C262F3D830024F161 /* Build configuration list for PBXNativeTarget "PaletteTests" */; + buildPhases = ( + 5A23A7F1262F3D830024F161 /* Sources */, + 5A23A7F2262F3D830024F161 /* Frameworks */, + 5A23A7F3262F3D830024F161 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5A23A7F7262F3D830024F161 /* PBXTargetDependency */, + ); + name = PaletteTests; + productName = PaletteTests; + productReference = 5A23A7F5262F3D830024F161 /* PaletteTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 5A23A7FF262F3D830024F161 /* PaletteUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5A23A80F262F3D830024F161 /* Build configuration list for PBXNativeTarget "PaletteUITests" */; + buildPhases = ( + 5A23A7FC262F3D830024F161 /* Sources */, + 5A23A7FD262F3D830024F161 /* Frameworks */, + 5A23A7FE262F3D830024F161 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5A23A802262F3D830024F161 /* PBXTargetDependency */, + ); + name = PaletteUITests; + productName = PaletteUITests; + productReference = 5A23A800262F3D830024F161 /* PaletteUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5A23A7D2262F3D7F0024F161 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1230; + TargetAttributes = { + 5A23A7D9262F3D7F0024F161 = { + CreatedOnToolsVersion = 12.3; + }; + 5A23A7F4262F3D830024F161 = { + CreatedOnToolsVersion = 12.3; + TestTargetID = 5A23A7D9262F3D7F0024F161; + }; + 5A23A7FF262F3D830024F161 = { + CreatedOnToolsVersion = 12.3; + TestTargetID = 5A23A7D9262F3D7F0024F161; + }; + }; + }; + buildConfigurationList = 5A23A7D5262F3D7F0024F161 /* Build configuration list for PBXProject "Palette" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5A23A7D1262F3D7F0024F161; + productRefGroup = 5A23A7DB262F3D7F0024F161 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5A23A7D9262F3D7F0024F161 /* Palette */, + 5A23A7F4262F3D830024F161 /* PaletteTests */, + 5A23A7FF262F3D830024F161 /* PaletteUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5A23A7D8262F3D7F0024F161 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5A98E82B263EC1E200B53204 /* RedColour.plist in Resources */, + 5A7C9737263C757C0093F0A4 /* BottomAlert.txt in Resources */, + 5A23A7ED262F3D820024F161 /* LaunchScreen.storyboard in Resources */, + 5A98E76F263DB35E00B53204 /* BlackColour.plist in Resources */, + 5A7C972C263C18610093F0A4 /* heart.png in Resources */, + 5A98E802263EAC3400B53204 /* GreenColour.plist in Resources */, + 5A98E830263EC2C500B53204 /* WhiteColour.plist in Resources */, + 5A23A7EA262F3D820024F161 /* Assets.xcassets in Resources */, + 5A7C972D263C18610093F0A4 /* close-round.png in Resources */, + 5A98E7FD263EABF100B53204 /* GreyColour.plist in Resources */, + 5A98E774263DB58600B53204 /* BlueColour.plist in Resources */, + 5A7C95ED263ADEA90093F0A4 /* AppearanceColour.xcassets in Resources */, + 5A7C972F263C18610093F0A4 /* star.png in Resources */, + 5A23A7E8262F3D7F0024F161 /* Main.storyboard in Resources */, + 5A98E821263EBDFB00B53204 /* PinkColour.plist in Resources */, + 5A98E77F263DB9DC00B53204 /* BrownColour.plist in Resources */, + 5A98E859263EC75800B53204 /* YellowColour.plist in Resources */, + 5A7C9760263DA7C90093F0A4 /* MultiColour.plist in Resources */, + 5A98E81C263EBC1600B53204 /* OrangeColour.plist in Resources */, + 5A7C972E263C18610093F0A4 /* checkmark-round.png in Resources */, + 5A98E79E263DE13A00B53204 /* GradientColour.plist in Resources */, + 5A7C9636263B19750093F0A4 /* SystemColour.plist in Resources */, + 5A7C972B263C18610093F0A4 /* alert-round.png in Resources */, + 5A98E826263EBFBC00B53204 /* PurpleColour.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A23A7F3262F3D830024F161 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A23A7FE262F3D830024F161 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5A23A7D6262F3D7F0024F161 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5A99AADC263019D900AD45A2 /* FavouriteViewController.m in Sources */, + 5A23A7E5262F3D7F0024F161 /* TabViewController.m in Sources */, + 5A98E78D263DC29600B53204 /* GradientsViewController.m in Sources */, + 5A98E83C263EC35F00B53204 /* PinkColourViewController.m in Sources */, + 5A98E84E263EC37E00B53204 /* WhiteColourViewController.m in Sources */, + 5A98E76A263DB34C00B53204 /* BlackColourViewController.m in Sources */, + 5A98E80E263EAC8200B53204 /* GreenColourViewController.m in Sources */, + 5A98E848263EC37400B53204 /* RedColourViewController.m in Sources */, + 5A7C9629263B06010093F0A4 /* TYPagerController.m in Sources */, + 5A7C962C263B06010093F0A4 /* TYPagerViewLayout.m in Sources */, + 5A7C96EA263C15820093F0A4 /* FCAlertView.m in Sources */, + 5A98E808263EAC7500B53204 /* GreyColourViewController.m in Sources */, + 5A23A7DF262F3D7F0024F161 /* AppDelegate.m in Sources */, + 5A99AAE426301AA200AD45A2 /* ConstraintExtension.m in Sources */, + 5A98E77A263DB59900B53204 /* BlueColourViewController.m in Sources */, + 5A98E854263EC38800B53204 /* YellowColourViewController.m in Sources */, + 5A23A7F0262F3D820024F161 /* main.m in Sources */, + 5A7C960E263B04870093F0A4 /* SystemColourViewController.m in Sources */, + 5A7C9617263B04D50093F0A4 /* ColourSectionViewController.m in Sources */, + 5A7C975B263DA7380093F0A4 /* MultiColourViewController.m in Sources */, + 5A98E836263EC35100B53204 /* OrangeColourViewController.m in Sources */, + 5A98E842263EC36900B53204 /* PurpleColourViewController.m in Sources */, + 5A7C962D263B06010093F0A4 /* TYTabPagerBarCell.m in Sources */, + 5A98E796263DC33C00B53204 /* GradientCell.m in Sources */, + 5A23A7E2262F3D7F0024F161 /* SceneDelegate.m in Sources */, + 5A99AAD6263019B500AD45A2 /* MyCollectionViewController.m in Sources */, + 5A98E785263DBA3400B53204 /* BrownColourViewController.m in Sources */, + 5A7C962B263B06010093F0A4 /* TYTabPagerBar.m in Sources */, + 5A7C9755263D81D80093F0A4 /* AddCollectionViewController.m in Sources */, + 5A7C962A263B06010093F0A4 /* TYTabPagerBarLayout.m in Sources */, + 5A16767F2630C6F100387CE5 /* ColourCell.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A23A7F1262F3D830024F161 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5A23A7FA262F3D830024F161 /* PaletteTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A23A7FC262F3D830024F161 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5A23A805262F3D830024F161 /* PaletteUITests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 5A23A7F7262F3D830024F161 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5A23A7D9262F3D7F0024F161 /* Palette */; + targetProxy = 5A23A7F6262F3D830024F161 /* PBXContainerItemProxy */; + }; + 5A23A802262F3D830024F161 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5A23A7D9262F3D7F0024F161 /* Palette */; + targetProxy = 5A23A801262F3D830024F161 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 5A23A7E6262F3D7F0024F161 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5A23A7E7262F3D7F0024F161 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5A23A7EB262F3D820024F161 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5A23A7EC262F3D820024F161 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5A23A807262F3D830024F161 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 5A23A808262F3D830024F161 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5A23A80A262F3D830024F161 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = Palette/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.SouthernGirlWhoCode.Palette; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Debug; + }; + 5A23A80B262F3D830024F161 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = Palette/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.SouthernGirlWhoCode.Palette; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Release; + }; + 5A23A80D262F3D830024F161 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = PaletteTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.SouthernGirlWhoCode.PaletteTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Palette.app/Palette"; + }; + name = Debug; + }; + 5A23A80E262F3D830024F161 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = PaletteTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.SouthernGirlWhoCode.PaletteTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Palette.app/Palette"; + }; + name = Release; + }; + 5A23A810262F3D830024F161 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = PaletteUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.SouthernGirlWhoCode.PaletteUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Palette; + }; + name = Debug; + }; + 5A23A811262F3D830024F161 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = PaletteUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.SouthernGirlWhoCode.PaletteUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Palette; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5A23A7D5262F3D7F0024F161 /* Build configuration list for PBXProject "Palette" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5A23A807262F3D830024F161 /* Debug */, + 5A23A808262F3D830024F161 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5A23A809262F3D830024F161 /* Build configuration list for PBXNativeTarget "Palette" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5A23A80A262F3D830024F161 /* Debug */, + 5A23A80B262F3D830024F161 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5A23A80C262F3D830024F161 /* Build configuration list for PBXNativeTarget "PaletteTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5A23A80D262F3D830024F161 /* Debug */, + 5A23A80E262F3D830024F161 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5A23A80F262F3D830024F161 /* Build configuration list for PBXNativeTarget "PaletteUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5A23A810262F3D830024F161 /* Debug */, + 5A23A811262F3D830024F161 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5A23A7D2262F3D7F0024F161 /* Project object */; +} diff --git a/Palette/App/Palette.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Palette/App/Palette.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Palette/App/Palette.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Palette/App/Palette.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Palette/App/Palette.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Palette/App/Palette.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Palette/App/Palette.xcodeproj/project.xcworkspace/xcuserdata/Prysm.xcuserdatad/UserInterfaceState.xcuserstate b/Palette/App/Palette.xcodeproj/project.xcworkspace/xcuserdata/Prysm.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..a9403ad Binary files /dev/null and b/Palette/App/Palette.xcodeproj/project.xcworkspace/xcuserdata/Prysm.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Palette/App/Palette.xcodeproj/project.xcworkspace/xcuserdata/dylan4char.xcuserdatad/UserInterfaceState.xcuserstate b/Palette/App/Palette.xcodeproj/project.xcworkspace/xcuserdata/dylan4char.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..ebfdbab Binary files /dev/null and b/Palette/App/Palette.xcodeproj/project.xcworkspace/xcuserdata/dylan4char.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Palette/App/Palette.xcodeproj/xcuserdata/Prysm.xcuserdatad/xcschemes/xcschememanagement.plist b/Palette/App/Palette.xcodeproj/xcuserdata/Prysm.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..5466902 --- /dev/null +++ b/Palette/App/Palette.xcodeproj/xcuserdata/Prysm.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + Palette.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/Palette/App/Palette.xcodeproj/xcuserdata/dylan4char.xcuserdatad/xcschemes/xcschememanagement.plist b/Palette/App/Palette.xcodeproj/xcuserdata/dylan4char.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..5466902 --- /dev/null +++ b/Palette/App/Palette.xcodeproj/xcuserdata/dylan4char.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + Palette.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/Palette/App/Palette/Add Collection/AddCollectionViewController.h b/Palette/App/Palette/Add Collection/AddCollectionViewController.h new file mode 100644 index 0000000..33fa97d --- /dev/null +++ b/Palette/App/Palette/Add Collection/AddCollectionViewController.h @@ -0,0 +1,14 @@ +#import +#import "ConstraintExtension.h" +#import "FCAlertView.h" + +@interface AddCollectionViewController : UIViewController +@property (nonatomic, retain) UIButton *cancelButton; +@property (nonatomic, retain) UIButton *addButton; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UITextField *textField; +@property (nonatomic, retain) NSMutableDictionary *mutableDict; +@property (nonatomic, retain) NSString *hexCode; +@end + diff --git a/Palette/App/Palette/Add Collection/AddCollectionViewController.m b/Palette/App/Palette/Add Collection/AddCollectionViewController.m new file mode 100644 index 0000000..6a3e160 --- /dev/null +++ b/Palette/App/Palette/Add Collection/AddCollectionViewController.m @@ -0,0 +1,161 @@ +#import "AddCollectionViewController.h" + +@implementation AddCollectionViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + + self.cancelButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [self.cancelButton addTarget:self action:@selector(dismissVC) forControlEvents:UIControlEventTouchUpInside]; + [self.cancelButton setTitle:@"Cancel" forState:UIControlStateNormal]; + [self.cancelButton setTitleColor:[UIColor colorNamed:@"Accent"] forState:UIControlStateNormal]; + [self.view addSubview:self.cancelButton]; + + [self.cancelButton top:self.view.topAnchor padding:16]; + [self.cancelButton leading:self.view.leadingAnchor padding:20]; + + + self.addButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [self.addButton addTarget:self action:@selector(addCollection) forControlEvents:UIControlEventTouchUpInside]; + [self.addButton setTitle:@"Add" forState:UIControlStateNormal]; + [self.addButton setTitleColor:[UIColor colorNamed:@"Accent"] forState:UIControlStateNormal]; + self.addButton.hidden = YES; + [self.view addSubview:self.addButton]; + + [self.addButton top:self.view.topAnchor padding:16]; + [self.addButton trailing:self.view.trailingAnchor padding:-20]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + self.iconImage.image = [UIImage systemImageNamed:@"heart.fill"]; + [self.view addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(80, 80)]; + [self.iconImage top:self.addButton.bottomAnchor padding:25]; + [self.iconImage x:self.view.centerXAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.font = [UIFont systemFontOfSize:25 weight:UIFontWeightSemibold]; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.text = @"Collection Name"; + self.titleLabel.numberOfLines = 2; + [self.view addSubview:self.titleLabel]; + + [self.titleLabel top:self.iconImage.bottomAnchor padding:30]; + [self.titleLabel leading:self.view.leadingAnchor padding:20]; + [self.titleLabel trailing:self.view.trailingAnchor padding:-20]; + [self.titleLabel x:self.view.centerXAnchor]; + + + self.textField = [[UITextField alloc] init]; + self.textField.borderStyle = UITextBorderStyleRoundedRect; + self.textField.font = [UIFont systemFontOfSize:15]; + self.textField.placeholder = @"Enter collection name..."; + self.textField.autocorrectionType = UITextAutocorrectionTypeNo; + self.textField.keyboardType = UIKeyboardTypeDefault; + self.textField.backgroundColor = [UIColor colorNamed:@"Containers"]; + self.textField.textColor = UIColor.labelColor; + self.textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; + self.textField.delegate = self; + [self.textField addTarget:self action:@selector(textFieldDidChange:)forControlEvents:UIControlEventEditingChanged]; + [self.view addSubview:self.textField]; + + [self.textField height:40]; + [self.textField top:self.titleLabel.bottomAnchor padding:30]; + [self.textField leading:self.view.leadingAnchor padding:20]; + [self.textField trailing:self.view.trailingAnchor padding:-20]; + [self.textField x:self.view.centerXAnchor]; + + [self.textField becomeFirstResponder]; +} + + +- (void)textFieldDidChange:(id)sender { + + if (self.textField.text && self.textField.text.length > 0) { + self.addButton.hidden = NO; + } else { + self.addButton.hidden = YES; + } + +} + + +- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + + if (self.textField.text && self.textField.text.length > 0) { + self.addButton.hidden = NO; + } else { + self.addButton.hidden = YES; + } + + return YES; +} + + +- (BOOL)textFieldShouldEndEditing:(UITextField *)textField { + + if (self.textField.text && self.textField.text.length > 0) { + self.addButton.hidden = NO; + } else { + self.addButton.hidden = YES; + } + + return YES; +} + + +-(void)addCollection { + + [self.textField resignFirstResponder]; + + //NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + //NSString *prefPath = [NSString stringWithFormat:@"%@/MyCollection.plist", aDocumentsDirectory]; + NSString *prefPath = @"/var/mobile/Library/Preferences/PaletteCollections.plist"; + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:prefPath]; + self.mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + NSString *withID = [NSString stringWithFormat:@"%lld", (long long)([[NSDate date] timeIntervalSince1970] * 1000.0)]; + NSDictionary *data = @{@"id" : withID, @"colourName" : self.textField.text, @"hexCode" : self.hexCode}; + [self.mutableDict setValue:data forKey:withID]; + [self.mutableDict writeToFile:prefPath atomically:YES]; + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:@"" withSubtitle:[NSString stringWithFormat:@"%@ have been added to your collection", self.textField.text] withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; + + [self performSelector:@selector(dismissVC2) withObject:nil afterDelay:2.5]; + +} + + +- (void)dismissVC { + + [self.textField resignFirstResponder]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +- (void)dismissVC2 { + [[NSNotificationCenter defaultCenter] postNotificationName:@"NewCollectionNotification" object:self]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +@end diff --git a/Palette/App/Palette/Alert/AlertAssets/alert-round.png b/Palette/App/Palette/Alert/AlertAssets/alert-round.png new file mode 100644 index 0000000..704db46 Binary files /dev/null and b/Palette/App/Palette/Alert/AlertAssets/alert-round.png differ diff --git a/Palette/App/Palette/Alert/AlertAssets/checkmark-round.png b/Palette/App/Palette/Alert/AlertAssets/checkmark-round.png new file mode 100755 index 0000000..bf6361e Binary files /dev/null and b/Palette/App/Palette/Alert/AlertAssets/checkmark-round.png differ diff --git a/Palette/App/Palette/Alert/AlertAssets/close-round.png b/Palette/App/Palette/Alert/AlertAssets/close-round.png new file mode 100755 index 0000000..81aa367 Binary files /dev/null and b/Palette/App/Palette/Alert/AlertAssets/close-round.png differ diff --git a/Palette/App/Palette/Alert/AlertAssets/heart.png b/Palette/App/Palette/Alert/AlertAssets/heart.png new file mode 100755 index 0000000..8a444fb Binary files /dev/null and b/Palette/App/Palette/Alert/AlertAssets/heart.png differ diff --git a/Palette/App/Palette/Alert/AlertAssets/star.png b/Palette/App/Palette/Alert/AlertAssets/star.png new file mode 100755 index 0000000..7d87719 Binary files /dev/null and b/Palette/App/Palette/Alert/AlertAssets/star.png differ diff --git a/Palette/App/Palette/Alert/FCAlertView.h b/Palette/App/Palette/Alert/FCAlertView.h new file mode 100644 index 0000000..86648e9 --- /dev/null +++ b/Palette/App/Palette/Alert/FCAlertView.h @@ -0,0 +1,214 @@ +#import +#import + +#import +#import + +@protocol FCAlertViewDelegate; + +@interface FCAlertView : UIView { + + // Blur + + UIVisualEffectView *backgroundVisualEffectView; + + // Default UI adjustments + + CGFloat defaultHeight; + CGFloat defaultSpacing; + + // AlertView & Contents + + UIView *alertView; + UIView *alertViewContents; + CAShapeLayer *circleLayer; + + // Customizations made to UI + + NSMutableArray *alertButtons; + NSMutableArray *alertTextFields; + NSMutableArray *alertTextFieldHolder; + NSInteger alertViewWithVector; + NSString *doneTitle; + UIImage *vectorImage; + NSString *alertType; + + // Frames + + CGRect alertViewFrame; + CGRect currentAVCFrames; + CGRect descriptionLabelFrames; + + // Alert AudioPlayer + + AVAudioPlayer *player; + + // Alert Rating Types + + NSInteger alertTypeRatingHearts; + NSInteger alertTypeRatingStars; + + UIView *ratingController; + UIButton *item1; + UIButton *item2; + UIButton *item3; + UIButton *item4; + UIButton *item5; + + NSInteger currentRating; + +} + +// Delegate + +@property (nonatomic, weak) id delegate; + +// AlertView Title & Subtitle Text + +@property (nonatomic, retain) NSString *title; +@property (nonatomic, retain) NSString *subTitle; +@property (nonatomic, retain) NSAttributedString *attributedTitle; +@property (nonatomic, retain) NSAttributedString *attributedSubTitle; +@property (nonatomic, retain) UIFont *titleFont; +@property (nonatomic, retain) UIFont *subtitleFont; + +// AlertView Background + +@property (nonatomic, retain) UIView *alertBackground; + +// AlertView TextView + +@property (nonatomic, retain) UITextField *textField; + +// AlertView Customizations + +@property CGFloat customHeight; +@property CGFloat customSpacing; + +@property NSInteger numberOfButtons; +@property NSInteger autoHideSeconds; +@property CGFloat cornerRadius; + +@property BOOL dismissOnOutsideTouch; +@property BOOL overrideForcedDismiss; +@property BOOL hideAllButtons; +@property BOOL hideDoneButton; +@property BOOL avoidCustomImageTint; +@property BOOL blurBackground; +@property BOOL bounceAnimations; +@property BOOL darkTheme; +@property BOOL detachButtons; +@property BOOL fullCircleCustomImage; +@property BOOL hideSeparatorLineView; +@property CGFloat customImageScale; + +// Default Types of Alerts + +- (void) makeAlertTypeWarning; +- (void) makeAlertTypeCaution; +- (void) makeAlertTypeSuccess; +- (void) makeAlertTypeProgress; + +typedef void (^FCRatingBlock)(NSInteger rating); +@property (nonatomic, copy) FCRatingBlock ratingBlock; + +- (void) makeAlertTypeRateHearts:(FCRatingBlock)ratingBlock; +- (void) makeAlertTypeRateStars:(FCRatingBlock)ratingBlock; + +// Alert Animation Types + +@property BOOL animateAlertInFromTop; +@property BOOL animateAlertOutToTop; + +@property BOOL animateAlertInFromRight; +@property BOOL animateAlertOutToRight; + +@property BOOL animateAlertInFromBottom; +@property BOOL animateAlertOutToBottom; + +@property BOOL animateAlertInFromLeft; +@property BOOL animateAlertOutToLeft; + +// Play Sound with Alert + +- (void) setAlertSoundWithFileName:(NSString *)filename; + +// Presenting AlertView + +- (void) showAlertInView:(UIViewController *)view withTitle:(NSString *)title withSubtitle:(NSString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons; + +- (void) showAlertInWindow:(UIWindow *)window withTitle:(NSString *)title withSubtitle:(NSString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons; + +- (void) showAlertWithTitle:(NSString *)title withSubtitle:(NSString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons; + +- (void) showAlertWithAttributedTitle:(NSAttributedString *)title withSubtitle:(NSString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons; + +- (void) showAlertWithTitle:(NSString *)title withAttributedSubtitle:(NSAttributedString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons; + +- (void) showAlertWithAttributedTitle:(NSAttributedString *)title withAttributedSubtitle:(NSAttributedString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons; + + +- (void)setAlertViewAttributes:(NSString *)title withSubtitle:(NSString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons; + +// Dismissing AlertView + +- (void) dismissAlertView; + +// Alert Action Block Method + +typedef void (^FCActionBlock)(void); +@property (nonatomic, copy) FCActionBlock actionBlock; +@property (nonatomic, copy) FCActionBlock doneBlock; +- (void)addButton:(NSString *)title withActionBlock:(FCActionBlock)action; +- (void)doneActionBlock:(FCActionBlock)action; + +// Alert TextField Block Method + +typedef void (^FCTextReturnBlock)(NSString *text); +@property (nonatomic, copy) FCTextReturnBlock textReturnBlock; +- (void)addTextFieldWithPlaceholder:(NSString *)placeholder andTextReturnBlock:(FCTextReturnBlock)textReturn; +- (void)addTextFieldWithCustomTextField:(UITextField *)field andPlaceholder:(NSString *)placeholder andTextReturnBlock:(FCTextReturnBlock)textReturn; + +// Color Schemes + +@property (nonatomic, retain) UIColor * colorScheme; +@property (nonatomic, retain) UIColor * titleColor; +@property (nonatomic, retain) UIColor * subTitleColor; +@property (nonatomic, retain) UIColor *alertBackgroundColor; + +@property (nonatomic, retain) UIColor * doneButtonTitleColor; +@property (nonatomic, retain) UIFont * doneButtonCustomFont; +@property (nonatomic, retain) UIColor * doneButtonHighlightedBackgroundColor; + +@property (nonatomic, retain) UIColor * firstButtonTitleColor; +@property (nonatomic, retain) UIFont * firstButtonCustomFont; +@property (nonatomic, retain) UIColor * firstButtonBackgroundColor; +@property (nonatomic, retain) UIColor * firstButtonHighlightedBackgroundColor; + +@property (nonatomic, retain) UIColor * secondButtonTitleColor; +@property (nonatomic, retain) UIFont * secondButtonCustomFont; +@property (nonatomic, retain) UIColor * secondButtonBackgroundColor; +@property (nonatomic, retain) UIColor * secondButtonHighlightedBackgroundColor; + +// Preset Flat Colors + +@property (nonatomic, retain) UIColor * flatTurquoise; +@property (nonatomic, retain) UIColor * flatGreen; +@property (nonatomic, retain) UIColor * flatBlue; +@property (nonatomic, retain) UIColor * flatMidnight; +@property (nonatomic, retain) UIColor * flatPurple; +@property (nonatomic, retain) UIColor * flatOrange; +@property (nonatomic, retain) UIColor * flatRed; +@property (nonatomic, retain) UIColor * flatSilver; +@property (nonatomic, retain) UIColor * flatGray; + +@end + +@protocol FCAlertViewDelegate +@optional +- (void)FCAlertView:( FCAlertView *)alertView clickedButtonIndex:(NSInteger)index buttonTitle:(NSString *)title; +- (void)FCAlertViewDismissed:(FCAlertView *)alertView; +- (void)FCAlertViewWillAppear:(FCAlertView *)alertView; +- (void)FCAlertDoneButtonClicked:(FCAlertView *)alertView; + +@end diff --git a/Palette/App/Palette/Alert/FCAlertView.m b/Palette/App/Palette/Alert/FCAlertView.m new file mode 100644 index 0000000..590a5c2 --- /dev/null +++ b/Palette/App/Palette/Alert/FCAlertView.m @@ -0,0 +1,1879 @@ +#import "FCAlertView.h" + +@implementation FCAlertView + +- (id)init +{ + self = [super init]; + if (self) { + + // INITIALIZATIONS - Setting Up Basic UI Adjustments + + CGSize result = [[UIScreen mainScreen] bounds].size; + + self.frame = CGRectMake(0, + 0, + result.width, + result.height); + + self.backgroundColor = [UIColor clearColor]; + + // ALERTVIEW BACKGROUND - Setting up Background View + + _alertBackground = [[UIView alloc] init]; + _alertBackground.frame = CGRectMake(0, + 0, + result.width, + result.height); + _alertBackground.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.35]; + + [self addSubview:_alertBackground]; + + // PRESET FLAT COLORS - Setting up RGB of Flat Colors - Put in another file? REMOVE + + _flatTurquoise = [UIColor colorWithRed:26.0/255.0f green:188.0/255.0f blue:156.0/255.0f alpha:1.0]; + _flatGreen = [UIColor colorWithRed:39.0/255.0f green:174.0/255.0f blue:96.0/255.0f alpha:1.0]; + _flatBlue = [UIColor colorWithRed:41.0/255.0f green:128.0/255.0f blue:185.0/255.0f alpha:1.0]; + _flatMidnight = [UIColor colorWithRed:44.0/255.0f green:62.0/255.0f blue:80.0/255.0f alpha:1.0]; + _flatPurple = [UIColor colorWithRed:142.0/255.0f green:68.0/255.0f blue:173.0/255.0f alpha:1.0]; + _flatOrange = [UIColor colorWithRed:243.0/255.0f green:156.0/255.0f blue:18.0/255.0f alpha:1.0]; + _flatRed = [UIColor colorWithRed:192.0/255.0f green:57.0/255.0f blue:43.0/255.0f alpha:1.0]; + _flatSilver = [UIColor colorWithRed:189.0/255.0f green:195.0/255.0f blue:199.0/255.0f alpha:1.0]; + _flatGray = [UIColor colorWithRed:127.0/255.0f green:140.0/255.0f blue:141.0/255.0f alpha:1.0]; + + // CUSTOMIZATIONS - Setting Default Customization Settings & Checks + + alertButtons = [[NSMutableArray alloc] init]; + alertTextFields = [[NSMutableArray alloc] init]; + alertTextFieldHolder = [[NSMutableArray alloc] init]; + + _numberOfButtons = 0; + _autoHideSeconds = 0; + _cornerRadius = 18.0f; + + _dismissOnOutsideTouch = NO; + _hideAllButtons = NO; + _hideDoneButton = NO; + _avoidCustomImageTint = NO; + _blurBackground = NO; + _bounceAnimations = NO; + _darkTheme = NO; + _detachButtons = NO; + _fullCircleCustomImage = NO; + _hideSeparatorLineView = NO; + _customImageScale = 1; + _titleFont = [UIFont systemFontOfSize:18.0f weight:UIFontWeightMedium]; + _subtitleFont = nil; + defaultSpacing = [self configureAVWidth]; + defaultHeight = [self configureAVHeight]; + + } + + return self; + +} + +#pragma mark - Frame Configuration + +- (CGFloat) configureAVWidth { + + if (_customSpacing == 0) { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) + { + CGSize result = [[UIScreen mainScreen] bounds].size; + + if(result.height == 1366) + return 105.0f + 600.0f; + else + return 105.0f + 350.0f; + } + if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) + { + CGSize result = [[UIScreen mainScreen] bounds].size; + if(result.height == 480) + { + // iPhone Classic + return 55.0f; + + } + if(result.height == 568) + { + // iPhone 5 + return 65.0f; + + } + if (result.height == 736) + { + // iPhone 6/7 Plus + return 130.0f; + } + else + { + return 105.0f; + } + + } + } + + return _customSpacing; + +} + +- (CGFloat) configureAVHeight { + + if (_customHeight == 0) { + return 200.0f; + } else { + return _customHeight; + } +} + +#pragma mark - FCAlertView Checks +#pragma mark - Customization Data Checkpoint + +- (void) checkCustomizationValid { + + if (_darkTheme) { + if (self.titleColor == nil) { + self.titleColor = [UIColor whiteColor]; + } + if (self.subTitleColor == nil) { + self.subTitleColor = [UIColor whiteColor]; + } + } + + if (![self hasSubTitle]) + if (![self hasTitle]) + NSLog(@"FCAlertView Warning: Your Alert should have a title and/or subtitle."); + + if (doneTitle == nil || [doneTitle isEqualToString:@""]) { + doneTitle = @"OK"; + } + + if (_cornerRadius == 0.0f) + _cornerRadius = 18.0f; + + if (vectorImage != nil) + alertViewWithVector = 1; + +} + +#pragma mark - Safety Close Check + +- (void) safetyCloseCheck { + + if (_hideDoneButton || _hideAllButtons) { + + if (_autoHideSeconds == 0 && !_overrideForcedDismiss) { + + _dismissOnOutsideTouch = YES; + + NSLog(@"Forced Dismiss on Outside Touch"); + + } + + } + +} + +#pragma mark - Title Validation +-(BOOL)hasTitle { + return (_title != nil && _title.length > 0) || + (_attributedTitle != nil && _attributedTitle.length > 0); +} + +-(BOOL)hasSubTitle { + return (_subTitle != nil && _subTitle.length > 0) || + (_attributedSubTitle != nil && _attributedSubTitle.length > 0); +} + +#pragma mark - Touch Events + +-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + + if (alertTypeRatingStars || alertTypeRatingHearts) { + UITouch *touch = [touches anyObject]; + + if([item1 pointInside:[touch locationInView:item1] withEvent:nil]) + [self rate1Triggered]; + + + if([item2 pointInside:[touch locationInView:item2] withEvent:nil]) + [self rate2Triggered]; + + + if([item3 pointInside:[touch locationInView:item3] withEvent:nil]) + [self rate3Triggered]; + + + if([item4 pointInside:[touch locationInView:item4] withEvent:nil]) + [self rate4Triggered]; + + if([item5 pointInside:[touch locationInView:item5] withEvent:nil]) + [self rate5Triggered]; + + } +} + +-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + + if (alertTypeRatingStars || alertTypeRatingHearts) { + UITouch *touch = [touches anyObject]; + + if([item1 pointInside:[touch locationInView:item1] withEvent:nil]){ + [self rate1Triggered]; + } + if([item2 pointInside:[touch locationInView:item2] withEvent:nil]){ + [self rate2Triggered]; + } + if([item3 pointInside:[touch locationInView:item3] withEvent:nil]){ + [self rate3Triggered]; + } + if([item4 pointInside:[touch locationInView:item4] withEvent:nil]){ + [self rate4Triggered]; + } + if([item5 pointInside:[touch locationInView:item5] withEvent:nil]){ + [self rate5Triggered]; + } + } + +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + + UITouch *touch = [touches anyObject]; + + CGPoint touchPoint = [touch locationInView:_alertBackground]; + CGPoint touchPoint2 = [touch locationInView:alertViewContents]; + + BOOL isPointInsideBackview = [_alertBackground pointInside:touchPoint withEvent:nil]; + BOOL isPointInsideAlertView = [alertViewContents pointInside:touchPoint2 withEvent:nil]; + + if (_dismissOnOutsideTouch && isPointInsideBackview && !isPointInsideAlertView) + [self dismissAlertView]; + + if (alertTextFields.count > 0 && isPointInsideBackview && !isPointInsideAlertView) + [self endEditing:YES]; + +} + +#pragma mark - Drawing AlertView + +- (void)drawRect:(CGRect)rect { + + defaultSpacing = [self configureAVWidth]; + defaultHeight = [self configureAVHeight]; + + CGSize result = [[UIScreen mainScreen] bounds].size; + + self.alpha = 0; + + // Adjusting AlertView Frames + + if (alertViewWithVector) // Frames for when AlertView contains an image + alertViewFrame = CGRectMake(self.frame.size.width/2 - ((result.width - defaultSpacing)/2), + self.frame.size.height/2 - (200.0f/2), + result.width - defaultSpacing, + defaultHeight); + else + alertViewFrame = CGRectMake(self.frame.size.width/2 - ((result.width - defaultSpacing)/2), + self.frame.size.height/2 - (170.0f/2), + result.width - defaultSpacing, + defaultHeight - 30); + + if (![self hasTitle]) // Frames for when AlertView doesn't contain a title + alertViewFrame = CGRectMake(self.frame.size.width/2 - ((result.width - defaultSpacing)/2), + self.frame.size.height/2 - ((alertViewFrame.size.height - 50)/2), + result.width - defaultSpacing, + alertViewFrame.size.height - 10); + + if (_hideAllButtons) { // Frames for when AlertView has hidden all buttons + alertViewFrame = CGRectMake(self.frame.size.width/2 - ((result.width - defaultSpacing)/2), + self.frame.size.height/2 - ((alertViewFrame.size.height - 50)/2), + result.width - defaultSpacing, + alertViewFrame.size.height - 45); + + } else { + if (_hideDoneButton && _numberOfButtons == 0) { // Frames for when AlertView has hidden the DONE/DISMISS button + alertViewFrame = CGRectMake(self.frame.size.width/2 - ((result.width - defaultSpacing)/2), + self.frame.size.height/2 - ((alertViewFrame.size.height - 50)/2), + result.width - defaultSpacing, + alertViewFrame.size.height - 45); + } + if (!_hideDoneButton && _numberOfButtons >= 2) // Frames for AlertView with 2 added buttons (vertical buttons) + alertViewFrame = CGRectMake(self.frame.size.width/2 - ((result.width - defaultSpacing)/2), + self.frame.size.height/2 - ((alertViewFrame.size.height - 50 + 140)/2), + result.width - defaultSpacing, + alertViewFrame.size.height - 50 + 140); + } + + if (alertTextFields.count > 0) + alertViewFrame = CGRectMake(self.frame.size.width/2 - ((result.width - defaultSpacing)/2), + self.frame.size.height/2 - ((alertViewFrame.size.height + 45*(MIN(alertTextFields.count,4)))/2), + result.width - defaultSpacing, + alertViewFrame.size.height + 45*(MIN(alertTextFields.count,4))); + else + alertViewFrame = CGRectMake(self.frame.size.width/2 - ((result.width - defaultSpacing)/2), + self.frame.size.height/2 - ((alertViewFrame.size.height - 50 + 140)/2), + result.width - defaultSpacing, + alertViewFrame.size.height); + + if (alertTypeRatingStars || alertTypeRatingHearts) + alertViewFrame = CGRectMake(self.frame.size.width/2 - ((result.width - defaultSpacing)/2), + self.frame.size.height/2 - ((alertViewFrame.size.height - 50 + 140)/2), + result.width - defaultSpacing, + alertViewFrame.size.height + 50); + + // Landscape Orientation Width Fix + + if(UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) + { + alertViewFrame = CGRectMake(self.frame.size.width/2 - (300/2), + self.frame.size.height/2 - (alertViewFrame.size.height/2), + 300, + alertViewFrame.size.height); + } + + // Description Label + + NSInteger descriptionLevel = 45.0f; + + if (![self hasTitle]) { + + descriptionLevel = 15.0f; + alertViewFrame = CGRectMake(alertViewFrame.origin.x, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height - 20); + } + + UILabel *descriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(25.0f, + descriptionLevel + (alertViewWithVector * 30), + alertViewFrame.size.width - 50.0f, + 60.0f)]; + if (_subtitleFont != nil) + descriptionLabel.font = self.subtitleFont; + else if (_title != nil) + descriptionLabel.font = [UIFont systemFontOfSize:15.0f weight:UIFontWeightLight]; + else + descriptionLabel.font = [UIFont systemFontOfSize:16.0f weight:UIFontWeightRegular]; + + descriptionLabel.textColor = self.subTitleColor; + if (_subTitle == nil) + descriptionLabel.attributedText = self.attributedSubTitle; + else + descriptionLabel.text = self.subTitle; + descriptionLabel.textAlignment = NSTextAlignmentCenter; + descriptionLabel.adjustsFontSizeToFitWidth = NO; + + descriptionLabel.numberOfLines = 0; + descriptionLabel.lineBreakMode = NSLineBreakByTruncatingTail; + + // HEADER VIEW - With Title & Subtitle + + UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(15.0f, + 20.0f + (alertViewWithVector * 30), + alertViewFrame.size.width - 30.0f, + 30.0f)]; + + titleLabel.font = self.titleFont; + titleLabel.numberOfLines = 1; + titleLabel.textColor = self.titleColor; + if (_title == nil) + titleLabel.attributedText = self.attributedTitle; + else + titleLabel.text = self.title; + titleLabel.textAlignment = NSTextAlignmentCenter; + + // Re-adjusting Frames based on height of title - Requirement is to not have over 2 lines of title + + CGSize size = [titleLabel.text sizeWithAttributes:@{NSFontAttributeName : titleLabel.font}]; + if (size.width > titleLabel.bounds.size.width) { + titleLabel.numberOfLines = 2; + titleLabel.frame = CGRectMake(titleLabel.frame.origin.x, titleLabel.frame.origin.y, titleLabel.frame.size.width, 60.0f); + descriptionLabel.frame = CGRectMake(descriptionLabel.frame.origin.x, + descriptionLabel.frame.origin.y + 30.0f, + descriptionLabel.frame.size.width, + descriptionLabel.frame.size.height); + + alertViewFrame = CGRectMake(alertViewFrame.origin.x, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height + 30.0f); + } + + // Re-adjusting Frames based on height of subTitle - Requirement is to not have over 6 lines of subTitle + + CGSize constraint = CGSizeMake(descriptionLabel.frame.size.width, CGFLOAT_MAX); + + NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init]; + CGSize boundingBox = [descriptionLabel.text boundingRectWithSize:constraint + options:NSStringDrawingUsesLineFragmentOrigin + attributes:@{NSFontAttributeName:descriptionLabel.font} + context:context].size; + + CGFloat heightDiff = descriptionLabel.frame.size.height - boundingBox.height; + + descriptionLabel.frame = CGRectMake(descriptionLabel.frame.origin.x, + descriptionLabel.frame.origin.y + 7.5, + descriptionLabel.frame.size.width, + boundingBox.height); + + alertViewFrame = CGRectMake(alertViewFrame.origin.x, + alertViewFrame.origin.y + ((heightDiff + 15)/2), + alertViewFrame.size.width, + alertViewFrame.size.height - heightDiff + 15); + + descriptionLabelFrames = descriptionLabel.frame; + + // Setting Up Contents of AlertView + + alertViewContents = [[UIView alloc] initWithFrame:alertViewFrame]; + [self addSubview:alertViewContents]; + + alertView = [[UIView alloc] initWithFrame:CGRectMake(0, + 0, + alertViewFrame.size.width, + alertViewFrame.size.height)]; + + // Setting Background Color of AlertView + + if (alertViewWithVector) { + alertView.backgroundColor = [UIColor clearColor]; + } else { + if (!self.alertBackgroundColor) + alertView.backgroundColor = [UIColor whiteColor]; + else + alertView.backgroundColor = _alertBackgroundColor; + if (_darkTheme) + alertView.backgroundColor = [UIColor colorWithWhite:48.0f/255.0f alpha:1.0]; + } + + [alertViewContents addSubview:alertView]; + + // CREATING ALERTVIEW + // CUSTOM SHAPING - Displaying Cut out circle for Vector Type Alerts + + int radius = alertView.frame.size.width; + UIBezierPath *rectPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, + 0, + self.frame.size.width, + alertView.bounds.size.height) + cornerRadius:0]; + UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(alertViewFrame.size.width/2 - 33.75f, + -33.75f, + 67.5f, + 67.5f) + cornerRadius:radius]; + [rectPath appendPath:circlePath]; + [rectPath setUsesEvenOddFillRule:YES]; + + CAShapeLayer *fillLayer = [CAShapeLayer layer]; + fillLayer.path = rectPath.CGPath; + fillLayer.fillRule = kCAFillRuleEvenOdd; + if (!self.alertBackgroundColor) + fillLayer.fillColor = [UIColor whiteColor].CGColor; + else + fillLayer.fillColor = _alertBackgroundColor.CGColor; + if (_darkTheme) + fillLayer.fillColor = [UIColor colorWithWhite:48.0f/255.0f alpha:1.0].CGColor; + fillLayer.opacity = 1.0; + + if (alertViewWithVector) + [alertView.layer addSublayer:fillLayer]; + + // SEPARATOR LINE - Seperating Header View with Button View + + UIView* separatorLineView = [[UIView alloc] initWithFrame:CGRectMake(0, + alertViewFrame.size.height - 47, + alertViewFrame.size.width, + 2)]; + + separatorLineView.backgroundColor = [UIColor colorWithWhite:100.0f/255.0f alpha:1.0]; // set color as you want. + if (_darkTheme) + separatorLineView.backgroundColor = [UIColor colorWithWhite:58.0f/255.0f alpha:1.0]; + + // TEXTFIELD VIEW - Section with TextField + + if (alertTextFields.count > 0) { + + for (int i = 0; i < MIN(alertTextFields.count,4); i++) { + + UITextField *tf = [[UITextField alloc] initWithFrame:CGRectMake(12.5, descriptionLabel.frame.size.height + descriptionLabel.frame.origin.y + 10.5 + 45*i, alertViewFrame.size.width - 25, 40)]; + + if ([[alertTextFields objectAtIndex:i] objectForKey:@"field"] != nil && + [[[alertTextFields objectAtIndex:i] objectForKey:@"field"] isKindOfClass:[UITextField class]]) { + + tf = [[alertTextFields objectAtIndex:i] objectForKey:@"field"]; + tf.frame = CGRectMake(12.5, descriptionLabel.frame.size.height + descriptionLabel.frame.origin.y + 10.5 + 45*i, alertViewFrame.size.width - 25, 40); + + } + + if (tf.layer.cornerRadius == 0) + tf.layer.cornerRadius = 3.0f; + tf.layer.masksToBounds = YES; + tf.layer.borderColor = [[UIColor colorWithWhite:217.0f/255.0f alpha:0.3] CGColor]; + + if (tf.layer.borderWidth == 0) + tf.layer.borderWidth = 1.0f; + + tf.delegate = self; + tf.tag = i; + if (tf.placeholder.length == 0 && + [[alertTextFields objectAtIndex:i] objectForKey:@"placeholder"] != nil && + [[[alertTextFields objectAtIndex:i] objectForKey:@"placeholder"] length] > 0) + tf.placeholder = [[alertTextFields objectAtIndex:i] objectForKey:@"placeholder"]; + + if (self.darkTheme) + tf.backgroundColor = [UIColor colorWithWhite:227.0f/255.0f alpha:1.0]; + else + tf.backgroundColor = [UIColor colorNamed:@"Alert"]; + + if (i+1 == MIN(alertTextFields.count,4)) + [tf setReturnKeyType:UIReturnKeyDone]; + else + [tf setReturnKeyType:UIReturnKeyNext]; + + UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)]; + tf.leftView = paddingView; + tf.leftViewMode = UITextFieldViewModeAlways; + + [alertTextFieldHolder addObject:tf]; + + [alertView addSubview:tf]; + + } + + } + + // BUTTON(S) VIEW - Section containing all Buttons + + if (_numberOfButtons == 0) { // View only contains DONE/DISMISS Button + + UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeSystem]; + if (_colorScheme == nil) { + doneButton.backgroundColor = [UIColor whiteColor]; + if (_detachButtons) + doneButton.backgroundColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + if (_darkTheme) + doneButton.backgroundColor = [UIColor colorWithWhite:78.0f/255.0f alpha:1.0]; + } else { + doneButton.backgroundColor = _colorScheme; + } + + if (_doneButtonHighlightedBackgroundColor) + [doneButton setBackgroundImage:[self imageWithColor:_doneButtonHighlightedBackgroundColor] forState:UIControlStateHighlighted]; + + doneButton.frame = CGRectMake(0, + alertViewFrame.size.height - 45, + alertViewFrame.size.width, + 45); + if (_detachButtons) { + doneButton.frame = CGRectMake(8, + alertViewFrame.size.height - 50, + alertViewFrame.size.width - 16, + 40); + doneButton.layer.cornerRadius = MIN(self.cornerRadius, doneButton.frame.size.height/2); + doneButton.layer.masksToBounds = YES; + } + + [doneButton setTitle:doneTitle forState:UIControlStateNormal]; + [doneButton addTarget:self action:@selector(donePressed) forControlEvents:UIControlEventTouchUpInside]; + [doneButton addTarget:self action:@selector(btnTouched) forControlEvents:UIControlEventTouchDown]; + [doneButton addTarget:self action:@selector(btnReleased) forControlEvents:UIControlEventTouchDragExit]; + doneButton.titleLabel.font = [UIFont systemFontOfSize:18.0f weight:UIFontWeightMedium]; + if (self.doneButtonCustomFont) + doneButton.titleLabel.font = self.doneButtonCustomFont; + if (_colorScheme != nil || _darkTheme) + doneButton.tintColor = [UIColor whiteColor]; + if (self.doneButtonTitleColor != nil) + doneButton.tintColor = self.doneButtonTitleColor; + + if (!_hideAllButtons && !_hideDoneButton) + [alertView addSubview:doneButton]; + + } else if (_numberOfButtons == 1) { // View also contains OTHER (One) Button + + UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeSystem]; + if (_colorScheme == nil) { + doneButton.backgroundColor = [UIColor whiteColor]; + if (_detachButtons) + doneButton.backgroundColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + if (_darkTheme) + doneButton.backgroundColor = [UIColor colorWithWhite:78.0f/255.0f alpha:1.0]; + } else { + doneButton.backgroundColor = _colorScheme; + } + + if (_doneButtonHighlightedBackgroundColor) + [doneButton setBackgroundImage:[self imageWithColor:_doneButtonHighlightedBackgroundColor] forState:UIControlStateHighlighted]; + + doneButton.frame = CGRectMake(alertViewFrame.size.width/2, + alertViewFrame.size.height - 45, + alertViewFrame.size.width/2, + 45); + if (_detachButtons) { + doneButton.frame = CGRectMake(alertViewFrame.size.width/2 + 6, + doneButton.frame.origin.y - 5, + doneButton.frame.size.width - 16, + 40); + doneButton.layer.cornerRadius = MIN(self.cornerRadius, doneButton.frame.size.height/2); + doneButton.layer.masksToBounds = YES; + } + + [doneButton setTitle:doneTitle forState:UIControlStateNormal]; + [doneButton addTarget:self action:@selector(donePressed) forControlEvents:UIControlEventTouchUpInside]; + [doneButton addTarget:self action:@selector(btnTouched) forControlEvents:UIControlEventTouchDown]; + [doneButton addTarget:self action:@selector(btnReleased) forControlEvents:UIControlEventTouchDragExit]; + doneButton.titleLabel.font = [UIFont systemFontOfSize:16.0f weight:UIFontWeightMedium]; + if (self.doneButtonCustomFont) + doneButton.titleLabel.font = self.doneButtonCustomFont; + if (_colorScheme != nil || _darkTheme) + doneButton.tintColor = [UIColor whiteColor]; + if (self.doneButtonTitleColor != nil) + doneButton.tintColor = self.doneButtonTitleColor; + + UIButton *otherButton = [UIButton buttonWithType:UIButtonTypeSystem]; + otherButton.backgroundColor = [UIColor whiteColor]; + if (_detachButtons) + otherButton.backgroundColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + if (_darkTheme) + otherButton.backgroundColor = [UIColor colorWithWhite:78.0f/255.0f alpha:1.0]; + if (self.firstButtonBackgroundColor != nil) + otherButton.backgroundColor = self.firstButtonBackgroundColor; + + if (_firstButtonHighlightedBackgroundColor) + [otherButton setBackgroundImage:[self imageWithColor:_firstButtonHighlightedBackgroundColor] forState:UIControlStateHighlighted]; + + otherButton.frame = CGRectMake(0, + alertViewFrame.size.height - 45, + alertViewFrame.size.width/2, + 45); + if (_hideDoneButton) + otherButton.frame = CGRectMake(0, + alertViewFrame.size.height - 45, + alertViewFrame.size.width, + 45); + + if (_detachButtons) { + otherButton.frame = CGRectMake(alertViewFrame.size.width/2 - otherButton.frame.size.width + 16 - 6, + otherButton.frame.origin.y - 5, + otherButton.frame.size.width - 16, + 40); + otherButton.layer.cornerRadius = MIN(self.cornerRadius, otherButton.frame.size.height/2); + otherButton.layer.masksToBounds = YES; + } + + [otherButton setTitle:[[alertButtons objectAtIndex:0] objectForKey:@"title"] forState:UIControlStateNormal]; + [otherButton addTarget:self action:@selector(handleButton:) forControlEvents:UIControlEventTouchUpInside]; + [otherButton addTarget:self action:@selector(btnTouched) forControlEvents:UIControlEventTouchDown]; + [otherButton addTarget:self action:@selector(btnReleased) forControlEvents:UIControlEventTouchDragExit]; + otherButton.titleLabel.font = [UIFont systemFontOfSize:16.0f weight:UIFontWeightRegular]; + if (self.firstButtonCustomFont) + otherButton.titleLabel.font = self.firstButtonCustomFont; + otherButton.tintColor = self.colorScheme; + if (self.colorScheme == nil && _darkTheme) + otherButton.tintColor = [UIColor whiteColor]; + if (self.firstButtonTitleColor != nil) + otherButton.tintColor = self.firstButtonTitleColor; + + otherButton.titleLabel.adjustsFontSizeToFitWidth = YES; + otherButton.titleLabel.minimumScaleFactor = 0.8; + + if (!_hideAllButtons) { + [alertView addSubview:otherButton]; + } + + if (!_hideAllButtons && !_hideDoneButton) + [alertView addSubview:doneButton]; + + UIView *horizontalSeparator = [[UIView alloc] initWithFrame:CGRectMake(alertViewFrame.size.width/2 - 1, + otherButton.frame.origin.y - 2, + 2, + 47)]; + + horizontalSeparator.backgroundColor = [UIColor colorWithWhite:100.0f/255.0f alpha:1.0]; // set color as you want. + if (_darkTheme) + horizontalSeparator.backgroundColor = [UIColor colorWithWhite:58.0f/255.0f alpha:1.0]; + + UIVisualEffect *blurEffect; + blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]; + if (_darkTheme) + blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *visualEffectView3; + visualEffectView3 = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + visualEffectView3.frame = horizontalSeparator.bounds; + visualEffectView3.userInteractionEnabled = NO; + [horizontalSeparator addSubview:visualEffectView3]; + + if (!_hideAllButtons && !_hideDoneButton && !_detachButtons && !_hideSeparatorLineView) { + [alertView addSubview:horizontalSeparator]; + } + + } else if (_numberOfButtons >= 2) { // View contains TWO OTHER Buttons - First & Second Button + + UIButton *firstButton = [UIButton buttonWithType:UIButtonTypeSystem]; + firstButton.backgroundColor = [UIColor whiteColor]; + if (_detachButtons) + firstButton.backgroundColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + if (_darkTheme) + firstButton.backgroundColor = [UIColor colorWithWhite:78.0f/255.0f alpha:1.0]; + if (self.firstButtonBackgroundColor != nil) + firstButton.backgroundColor = self.firstButtonBackgroundColor; + + if (_firstButtonHighlightedBackgroundColor) + [firstButton setBackgroundImage:[self imageWithColor:_firstButtonHighlightedBackgroundColor] forState:UIControlStateHighlighted]; + + firstButton.frame = CGRectMake(0, + alertViewFrame.size.height - 135, + alertViewFrame.size.width, + 45); + + if (_hideDoneButton) + firstButton.frame = CGRectMake(0, + alertViewFrame.size.height - 45, + alertViewFrame.size.width/2, + 45); + + if (_detachButtons) { + firstButton.frame = CGRectMake(firstButton.frame.origin.x + 8, + firstButton.frame.origin.y - 5, + firstButton.frame.size.width - 16, + 40); + firstButton.layer.cornerRadius = MIN(self.cornerRadius, firstButton.frame.size.height/2); + firstButton.layer.masksToBounds = YES; + } + + [firstButton setTitle:[[alertButtons objectAtIndex:0] objectForKey:@"title"] forState:UIControlStateNormal]; + [firstButton addTarget:self action:@selector(handleButton:) forControlEvents:UIControlEventTouchUpInside]; + [firstButton addTarget:self action:@selector(btnTouched) forControlEvents:UIControlEventTouchDown]; + [firstButton addTarget:self action:@selector(btnReleased) forControlEvents:UIControlEventTouchDragExit]; + firstButton.titleLabel.font = [UIFont systemFontOfSize:16.0f weight:UIFontWeightRegular]; + if (self.firstButtonCustomFont) + firstButton.titleLabel.font = self.firstButtonCustomFont; + firstButton.tintColor = self.colorScheme; + if (self.colorScheme == nil && _darkTheme) + firstButton.tintColor = [UIColor whiteColor]; + if (self.firstButtonTitleColor != nil) + firstButton.tintColor = self.firstButtonTitleColor; + + firstButton.titleLabel.adjustsFontSizeToFitWidth = YES; + firstButton.titleLabel.minimumScaleFactor = 0.8; + firstButton.tag = 0; + + UIButton *secondButton = [UIButton buttonWithType:UIButtonTypeSystem]; + secondButton.backgroundColor = [UIColor whiteColor]; + if (_detachButtons) + secondButton.backgroundColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + if (_darkTheme) + secondButton.backgroundColor = [UIColor colorWithWhite:78.0f/255.0f alpha:1.0]; + if (self.secondButtonBackgroundColor != nil) + secondButton.backgroundColor = self.secondButtonBackgroundColor; + + if (_secondButtonHighlightedBackgroundColor) + [secondButton setBackgroundImage:[self imageWithColor:_secondButtonHighlightedBackgroundColor] forState:UIControlStateHighlighted]; + + secondButton.frame = CGRectMake(0, + alertViewFrame.size.height - 90, + alertViewFrame.size.width, + 45); + if (_hideDoneButton) + secondButton.frame = CGRectMake(alertViewFrame.size.width/2, + alertViewFrame.size.height - 45, + alertViewFrame.size.width/2, + 45); + + if (_detachButtons) { + secondButton.frame = CGRectMake(secondButton.frame.origin.x + 8, + secondButton.frame.origin.y - 5, + secondButton.frame.size.width - 16, + 40); + secondButton.layer.cornerRadius = MIN(self.cornerRadius, secondButton.frame.size.height/2); + secondButton.layer.masksToBounds = YES; + } + + [secondButton setTitle:[[alertButtons objectAtIndex:1] objectForKey:@"title"] forState:UIControlStateNormal]; + [secondButton addTarget:self action:@selector(handleButton:) forControlEvents:UIControlEventTouchUpInside]; + [secondButton addTarget:self action:@selector(btnTouched) forControlEvents:UIControlEventTouchDown]; + [secondButton addTarget:self action:@selector(btnReleased) forControlEvents:UIControlEventTouchDragExit]; + secondButton.titleLabel.font = [UIFont systemFontOfSize:16.0f weight:UIFontWeightRegular]; + if (self.secondButtonCustomFont) + secondButton.titleLabel.font = self.secondButtonCustomFont; + secondButton.tintColor = self.colorScheme; + if (self.colorScheme == nil && _darkTheme) + secondButton.tintColor = [UIColor whiteColor]; + if (self.secondButtonTitleColor != nil) + secondButton.tintColor = self.secondButtonTitleColor; + + secondButton.titleLabel.adjustsFontSizeToFitWidth = YES; + secondButton.titleLabel.minimumScaleFactor = 0.8; + secondButton.tag = 1; + + UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeSystem]; + if (_colorScheme == nil) { + doneButton.backgroundColor = [UIColor whiteColor]; + if (_detachButtons) + doneButton.backgroundColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + if (_darkTheme) + doneButton.backgroundColor = [UIColor colorWithWhite:78.0f/255.0f alpha:1.0]; + } else { + doneButton.backgroundColor = _colorScheme; + } + + if (_doneButtonHighlightedBackgroundColor) + [doneButton setBackgroundImage:[self imageWithColor:_doneButtonHighlightedBackgroundColor] forState:UIControlStateHighlighted]; + + doneButton.frame = CGRectMake(0, + alertViewFrame.size.height - 45, + alertViewFrame.size.width, + 45); + if (_detachButtons) { + doneButton.frame = CGRectMake(8, + alertViewFrame.size.height - 50, + alertViewFrame.size.width - 16, + 40); + doneButton.layer.cornerRadius = MIN(self.cornerRadius, doneButton.frame.size.height/2); + doneButton.layer.masksToBounds = YES; + } + + [doneButton setTitle:doneTitle forState:UIControlStateNormal]; + [doneButton addTarget:self action:@selector(donePressed) forControlEvents:UIControlEventTouchUpInside]; + [doneButton addTarget:self action:@selector(btnTouched) forControlEvents:UIControlEventTouchDown]; + [doneButton addTarget:self action:@selector(btnReleased) forControlEvents:UIControlEventTouchDragExit]; + doneButton.titleLabel.font = [UIFont systemFontOfSize:18.0f weight:UIFontWeightMedium]; + if (self.doneButtonCustomFont) + doneButton.titleLabel.font = self.doneButtonCustomFont; + if (_colorScheme != nil || _darkTheme) + doneButton.tintColor = [UIColor whiteColor]; + if (self.doneButtonTitleColor != nil) + doneButton.tintColor = self.doneButtonTitleColor; + + if (!_hideAllButtons) { + [alertView addSubview:firstButton]; + [alertView addSubview:secondButton]; + } + + if (!_hideAllButtons && !_hideDoneButton) + [alertView addSubview:doneButton]; + + UIView *firstSeparator = [[UIView alloc] initWithFrame:CGRectMake(0, + firstButton.frame.origin.y - 2, + alertViewFrame.size.width, + 2)]; + firstSeparator.backgroundColor = [UIColor colorWithWhite:100.0f/255.0f alpha:1.0]; // set color as you want. + if (_darkTheme) + firstSeparator.backgroundColor = [UIColor colorWithWhite:58.0f/255.0f alpha:1.0]; + + UIView *secondSeparator = [[UIView alloc] initWithFrame:CGRectMake(0, + secondButton.frame.origin.y - 2, + alertViewFrame.size.width, + 2)]; + if (_hideDoneButton) + secondSeparator.frame = CGRectMake(alertViewFrame.size.width/2 - 1, + secondButton.frame.origin.y, + 2, + 45); + secondSeparator.backgroundColor = [UIColor colorWithWhite:100.0f/255.0f alpha:1.0]; // set color as you want. + if (_darkTheme) + secondSeparator.backgroundColor = [UIColor colorWithWhite:58.0f/255.0f alpha:1.0]; + + UIVisualEffect *blurEffect; + blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]; + if (_darkTheme) + blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *visualEffectView; + visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + visualEffectView.frame = firstSeparator.bounds; + visualEffectView.userInteractionEnabled = NO; + [firstSeparator addSubview:visualEffectView]; + + UIVisualEffectView *visualEffectView2; + visualEffectView2 = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + visualEffectView2.frame = secondSeparator.bounds; + visualEffectView2.userInteractionEnabled = NO; + [secondSeparator addSubview:visualEffectView2]; + + if (!_hideAllButtons && !_detachButtons && !_hideSeparatorLineView) { + [alertView addSubview:firstSeparator]; + [alertView addSubview:secondSeparator]; + } + + } + + UIVisualEffect *blurEffect; + blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]; + if (_darkTheme) + blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + UIVisualEffectView *visualEffectView; + visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + visualEffectView.frame = separatorLineView.bounds; + visualEffectView.userInteractionEnabled = NO; + [separatorLineView addSubview:visualEffectView]; + + if (!_fullCircleCustomImage) { + circleLayer = [CAShapeLayer layer]; + [circleLayer setPath:[[UIBezierPath bezierPathWithOvalInRect:CGRectMake(alertViewContents.frame.size.width/2 - 30.0f, -30.0f, 60.0f, 60.0f)] CGPath]]; + if (!self.alertBackgroundColor) + [circleLayer setFillColor:[UIColor whiteColor].CGColor]; + else + [circleLayer setFillColor:_alertBackgroundColor.CGColor]; + } + + if (_darkTheme) + circleLayer.fillColor = [UIColor colorWithWhite:48.0f/255.0f alpha:1.0].CGColor; + if ([alertType isEqualToString:@"Progress"] && _colorScheme != nil) + [circleLayer setFillColor:[self.colorScheme CGColor]]; + + UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(alertViewContents.frame.size.width/2 - 30.0f, -30.0f, 60.0f, 60.0f)]; + if (circleLayer.fillColor == [UIColor whiteColor].CGColor) + [spinner setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray]; + else + [spinner setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhite]; + [spinner startAnimating]; + + UIImageView *alertViewVector; + + if (_avoidCustomImageTint && alertType.length == 0) { + alertViewVector = [[UIImageView alloc] init]; + alertViewVector.image = vectorImage; + } else { + alertViewVector = [[UIImageView alloc] init]; + alertViewVector.image = [vectorImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } + + if (_fullCircleCustomImage) + _customImageScale = 2; + + if (_customImageScale <= 0) { + _customImageScale = 1; + } + + CGFloat vectorSize = 30.0f * MIN(2, _customImageScale); + + alertViewVector.frame = CGRectMake(alertViewContents.frame.size.width/2 - (vectorSize/2), + -(vectorSize/2) - 0.5, + vectorSize, + vectorSize); + + alertViewVector.contentMode = UIViewContentModeScaleAspectFit; + alertViewVector.userInteractionEnabled = 0; + alertViewVector.tintColor = _colorScheme; + + // VIEW BORDER - Rounding Corners of AlertView + + alertView.layer.cornerRadius = self.cornerRadius; + alertView.layer.masksToBounds = YES; + + // ADDING CONTENTS - Contained in Header and Separator Views + + [alertViewContents addSubview:titleLabel]; + [alertViewContents addSubview:descriptionLabel]; + + if (!_hideAllButtons && !_hideSeparatorLineView) { + if (_numberOfButtons == 1 && !_detachButtons) + [alertViewContents addSubview:separatorLineView]; + else if (!_hideDoneButton && !_detachButtons) + [alertViewContents addSubview:separatorLineView]; + } + + if (alertViewWithVector) { + [alertViewContents.layer addSublayer:circleLayer]; + [alertViewContents addSubview:alertViewVector]; + if ([alertType isEqualToString:@"Progress"]) + [alertViewContents addSubview:spinner]; + + } + + // SCALING ALERTVIEW - Before Animation + + if (!_animateAlertInFromTop && !_animateAlertInFromLeft && !_animateAlertInFromRight && !_animateAlertInFromBottom) { + alertViewContents.transform = CGAffineTransformMakeScale(1.15, 1.15); + } else { + if (_animateAlertInFromTop) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + 0 - alertViewFrame.size.height - 15, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertInFromRight) + alertViewContents.frame = CGRectMake(self.frame.size.width + alertViewFrame.size.width + 15, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertInFromBottom) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + self.frame.size.height + alertViewFrame.size.height + 15, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertInFromLeft) + alertViewContents.frame = CGRectMake(0 - alertViewFrame.size.width - 15, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + } + + // ADDING RATING SYSTEM + + UITextField *tf = [alertTextFieldHolder firstObject]; + + ratingController = [[UIView alloc] initWithFrame:CGRectMake(20, + descriptionLevel + descriptionLabelFrames.size.height + 32.5 + 15+ (MAX(1, MIN(alertTextFields.count,4))*(tf.frame.size.height + 7.5)), + alertViewFrame.size.width - 40, + 40)]; + + CGFloat spacingBetween = (ratingController.frame.size.width - (40*4))/5; + + UIImage *starImage = [[self loadImageFromResourceBundle:@"star.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + UIImage *heartImage = [[self loadImageFromResourceBundle:@"heart.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + + item1 = [UIButton buttonWithType:UIButtonTypeCustom]; + item1.tintColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + item1.frame = CGRectMake(40*0 + spacingBetween, 0, 40.0f, 40.0f); + item1.userInteractionEnabled = 0; + + item2 = [UIButton buttonWithType:UIButtonTypeCustom]; + item2.tintColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + item2.frame = CGRectMake(40*1 + spacingBetween, 0, 40.0f, 40.0f); + item2.userInteractionEnabled = 0; + + item3 = [UIButton buttonWithType:UIButtonTypeCustom]; + item3.tintColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + item3.frame = CGRectMake(40*2 + spacingBetween, 0, 40.0f, 40.0f); + item3.userInteractionEnabled = 0; + + item4 = [UIButton buttonWithType:UIButtonTypeCustom]; + item4.tintColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + item4.frame = CGRectMake(40*3 + spacingBetween, 0, 40.0f, 40.0f); + item4.userInteractionEnabled = 0; + + item5 = [UIButton buttonWithType:UIButtonTypeCustom]; + item5.tintColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + item5.frame = CGRectMake(40*4 + spacingBetween, 0, 40.0f, 40.0f); + item5.userInteractionEnabled = 0; + + if (alertTypeRatingHearts) { + [item1 setImage:heartImage forState:UIControlStateNormal]; + [item2 setImage:heartImage forState:UIControlStateNormal]; + [item3 setImage:heartImage forState:UIControlStateNormal]; + [item4 setImage:heartImage forState:UIControlStateNormal]; + [item5 setImage:heartImage forState:UIControlStateNormal]; + } + + if (alertTypeRatingStars) { + [item1 setImage:starImage forState:UIControlStateNormal]; + [item2 setImage:starImage forState:UIControlStateNormal]; + [item3 setImage:starImage forState:UIControlStateNormal]; + [item4 setImage:starImage forState:UIControlStateNormal]; + [item5 setImage:starImage forState:UIControlStateNormal]; + } + + item1.adjustsImageWhenHighlighted = NO; + item2.adjustsImageWhenHighlighted = NO; + item3.adjustsImageWhenHighlighted = NO; + item4.adjustsImageWhenHighlighted = NO; + item5.adjustsImageWhenHighlighted = NO; + + [ratingController addSubview:item1]; + [ratingController addSubview:item2]; + [ratingController addSubview:item3]; + [ratingController addSubview:item4]; + [ratingController addSubview:item5]; + + if (alertTypeRatingHearts || alertTypeRatingStars) + [alertViewContents addSubview:ratingController]; + + // APPLYING SHADOW + + [self.layer setShadowColor:[UIColor blackColor].CGColor]; + [self.layer setShadowOpacity:0.10f]; + [self.layer setShadowRadius:10.0f]; + [self.layer setShadowOffset:CGSizeMake(0.0f, 0.0f)]; + + if (_bounceAnimations) { + + UIInterpolatingMotionEffect *horizontalMotionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis]; + horizontalMotionEffect.minimumRelativeValue = @(-22.5); + horizontalMotionEffect.maximumRelativeValue = @(22.5); + + UIInterpolatingMotionEffect *verticalMotionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis]; + verticalMotionEffect.minimumRelativeValue = @(-22.5); + verticalMotionEffect.maximumRelativeValue = @(22.5); + + [alertViewContents addMotionEffect:horizontalMotionEffect]; + [alertViewContents addMotionEffect:verticalMotionEffect]; + + } + + [self showAlertView]; + +} + +#pragma mark - Create Image with Color + +- (UIImage *)imageWithColor:(UIColor *)color { + CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); + UIGraphicsBeginImageContext(rect.size); + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGContextSetFillColorWithColor(context, [color CGColor]); + CGContextFillRect(context, rect); + + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return image; +} + +#pragma mark - Getting Resources from Bundle + ++(NSBundle *)getResourcesBundle +{ + NSBundle *bundle = [NSBundle bundleWithURL:[[NSBundle bundleForClass:[self class]] URLForResource:@"AlertAssets" withExtension:@"bundle"]]; + return bundle; +} + +-(UIImage *)loadImageFromResourceBundle:(NSString *)imageName +{ + UIImage *icon = [UIImage imageNamed:imageName]; + + CGImageRef cgref = [icon CGImage]; + CIImage *cim = [icon CIImage]; + + if (cim == nil && cgref == NULL) + { + NSBundle *bundle = [FCAlertView getResourcesBundle]; + NSString *imageFileName = [NSString stringWithFormat:@"%@.png",imageName]; + UIImage *image = [UIImage imageNamed:imageFileName inBundle:bundle compatibleWithTraitCollection:nil]; + return image; + } + + return icon; +} + +#pragma mark - Default Types of Alerts + +- (void) makeAlertTypeWarning { + vectorImage = [self loadImageFromResourceBundle:@"close-round.png"]; + alertViewWithVector = 1; + self.colorScheme = self.flatRed; + alertType = @"Warning"; +} + +- (void) makeAlertTypeCaution { + vectorImage = [self loadImageFromResourceBundle:@"alert-round.png"]; + alertViewWithVector = 1; + self.colorScheme = self.flatOrange; + alertType = @"Caution"; +} + +- (void) makeAlertTypeSuccess { + vectorImage = [self loadImageFromResourceBundle:@"checkmark-round.png"]; + alertViewWithVector = 1; + self.colorScheme = self.flatGreen; + alertType = @"Success"; +} + +- (void) makeAlertTypeProgress { + [circleLayer setFillColor:[self.colorScheme CGColor]]; + alertViewWithVector = 1; + alertType = @"Progress"; +} + +- (void) makeAlertTypeRateHearts:(FCRatingBlock)ratingBlock { + _ratingBlock = ratingBlock; + vectorImage = [self loadImageFromResourceBundle:@"heart.png"]; + alertViewWithVector = 1; + alertTypeRatingHearts = 1; + alertTypeRatingStars = 0; + self.colorScheme = [UIColor colorWithRed:228.0f/255.0f green:77.0f/255.0f blue:65.0f/255.0f alpha:1.0]; +} + +- (void) makeAlertTypeRateStars:(FCRatingBlock)ratingBlock { + _ratingBlock = ratingBlock; + vectorImage = [self loadImageFromResourceBundle:@"star.png"]; + alertViewWithVector = 1; + alertTypeRatingStars = 1; + alertTypeRatingHearts = 0; + self.colorScheme = [UIColor colorWithRed:234.0f/255.0f green:201.0f/255.0f blue:77.0f/255.0f alpha:1.0]; +} + +#pragma mark - Play Sound with Alert + +- (void) setAlertSoundWithFileName:(NSString *)filename { + + NSString *soundFilePath = [NSString stringWithFormat:@"%@/%@", + [[NSBundle mainBundle] resourcePath], filename]; + NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath]; + player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL + error:nil]; + player.numberOfLoops = 0; + +} + +#pragma mark - Presenting AlertView + +- (void) showAlertInView:(UIViewController *)view withTitle:(NSString *)title withSubtitle:(NSString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons { + + // Blur Effect + + if (_blurBackground && NSClassFromString(@"UIVisualEffectView") != nil) { + UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; + backgroundVisualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + backgroundVisualEffectView.frame = view.view.bounds; + _alertBackground.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5]; + [view.view addSubview:backgroundVisualEffectView]; + } + + // Adding Alert + + [self setAlertViewAttributes:title withSubtitle:subTitle withCustomImage:image withDoneButtonTitle:done andButtons:buttons]; + [view.view.window addSubview:self]; + +} + +- (void) showAlertInWindow:(UIWindow *)window withTitle:(NSString *)title withSubtitle:(NSString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons { + + // Blur Effect + + if (_blurBackground && NSClassFromString(@"UIVisualEffectView") != nil) { + UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; + backgroundVisualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + backgroundVisualEffectView.frame = window.bounds; + _alertBackground.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5]; + [window addSubview:backgroundVisualEffectView]; + } + + // Adding Alert + + [self setAlertViewAttributes:title withSubtitle:subTitle withCustomImage:image withDoneButtonTitle:done andButtons:buttons]; + [window addSubview:self]; + +} + +- (void) showAlertWithTitle:(NSString *)title withSubtitle:(NSString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons{ + + [self setAlertViewAttributes:title withSubtitle:subTitle withCustomImage:image withDoneButtonTitle:done andButtons:buttons]; + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + + // Blur Effect + if (_blurBackground && NSClassFromString(@"UIVisualEffectView") != nil) { + UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; + backgroundVisualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + backgroundVisualEffectView.frame = window.bounds; + _alertBackground.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5]; + [window addSubview:backgroundVisualEffectView]; + } + + // Adding Alert + + [window addSubview:self]; + [window bringSubviewToFront:self]; + +} + +- (void) showAlertWithAttributedTitle:(NSAttributedString *)title withSubtitle:(NSString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons { + + self.attributedTitle = title; + [self setAlertViewAttributes:nil withSubtitle:subTitle withCustomImage:image withDoneButtonTitle:done andButtons:buttons]; + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + + // Blur Effect + if (_blurBackground && NSClassFromString(@"UIVisualEffectView") != nil) { + UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; + backgroundVisualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + backgroundVisualEffectView.frame = window.bounds; + _alertBackground.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5]; + [window addSubview:backgroundVisualEffectView]; + } + + // Adding Alert + + [window addSubview:self]; + [window bringSubviewToFront:self]; +} + +- (void) showAlertWithTitle:(NSString *)title withAttributedSubtitle:(NSAttributedString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons { + + self.attributedSubTitle = subTitle; + [self setAlertViewAttributes:title withSubtitle:nil withCustomImage:image withDoneButtonTitle:done andButtons:buttons]; + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + + // Blur Effect + if (_blurBackground && NSClassFromString(@"UIVisualEffectView") != nil) { + UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; + backgroundVisualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + backgroundVisualEffectView.frame = window.bounds; + _alertBackground.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5]; + [window addSubview:backgroundVisualEffectView]; + } + + // Adding Alert + + [window addSubview:self]; + [window bringSubviewToFront:self]; +} + +- (void) showAlertWithAttributedTitle:(NSAttributedString *)title withAttributedSubtitle:(NSAttributedString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons { + + self.attributedTitle = title; + self.attributedSubTitle = subTitle; + [self setAlertViewAttributes:nil withSubtitle:nil withCustomImage:image withDoneButtonTitle:done andButtons:buttons]; + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + + // Blur Effect + if (_blurBackground && NSClassFromString(@"UIVisualEffectView") != nil) { + UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; + backgroundVisualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; + backgroundVisualEffectView.frame = window.bounds; + _alertBackground.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5]; + [window addSubview:backgroundVisualEffectView]; + } + + // Adding Alert + + [window addSubview:self]; + [window bringSubviewToFront:self]; +} + + +- (void)setAlertViewAttributes:(NSString *)title withSubtitle:(NSString *)subTitle withCustomImage:(UIImage *)image withDoneButtonTitle:(NSString *)done andButtons:(NSArray *)buttons{ + + self.title = title; + self.subTitle = subTitle; + + for (int i = 0; i < buttons.count; i++) { + NSDictionary *btnDict = @{@"title" : [buttons objectAtIndex:i], + @"action" : @0}; + [alertButtons addObject:btnDict]; + } + + _numberOfButtons = alertButtons.count; + doneTitle = done; + + if (!alertViewWithVector) + vectorImage = image; + + // Checks prior to presenting View + + [self checkCustomizationValid]; + [self safetyCloseCheck]; + +} + +#pragma mark - Showing and Hiding AlertView Animations + +- (void) showAlertView { + + id strongDelegate = self.delegate; + + if ([strongDelegate respondsToSelector:@selector(FCAlertViewWillAppear:)]) { + [strongDelegate FCAlertViewWillAppear:self]; + } + + [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + self.alpha = 1; + if (_bounceAnimations) { + if (!_animateAlertInFromTop && !_animateAlertInFromLeft && !_animateAlertInFromRight && !_animateAlertInFromBottom) + alertViewContents.transform = CGAffineTransformMakeScale(0.95, 0.95); + if (_animateAlertInFromTop) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + alertViewFrame.origin.y + 7.5, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertInFromRight) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x - 7.5, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertInFromBottom) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + alertViewFrame.origin.y - 7.5, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertInFromLeft) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x + 7.5, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + } else { + alertViewContents.transform = CGAffineTransformMakeScale(1.0, 1.0); + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + } + + } completion:^(BOOL finished) { + if (_bounceAnimations) + [UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + if (!_animateAlertInFromTop && !_animateAlertInFromLeft && !_animateAlertInFromRight && !_animateAlertInFromBottom) + alertViewContents.transform = CGAffineTransformMakeScale(1.00, 1.00); + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + } completion:nil]; + if (self.autoHideSeconds != 0) { + [self performSelector:@selector(dismissAlertView) withObject:nil afterDelay:self.autoHideSeconds]; + } + }]; + + // Playing Sound for Alert (when there is one) + + [player play]; + +} + +- (void) dismissAlertView { + + [UIView animateWithDuration:0.175 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + + if (!_animateAlertOutToTop && !_animateAlertOutToLeft && !_animateAlertOutToRight && !_animateAlertOutToBottom) { + self.alpha = 0; + backgroundVisualEffectView.alpha = 0; + alertViewContents.transform = CGAffineTransformMakeScale(0.9, 0.9); + } else { + + if (_bounceAnimations) { + if (_animateAlertOutToTop) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + alertViewFrame.origin.y + 7.5, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertOutToRight) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x - 7.5, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertOutToBottom) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + alertViewFrame.origin.y - 7.5, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertOutToLeft) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x + 7.5, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + } else { + self.alpha = 0; + backgroundVisualEffectView.alpha = 0; + + if (_animateAlertOutToTop) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + 0 - alertViewFrame.size.height - 15, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertOutToRight) + alertViewContents.frame = CGRectMake(self.frame.size.width + alertViewFrame.size.width + 15, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertOutToBottom) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + self.frame.size.height + alertViewFrame.size.height + 15, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertOutToLeft) + alertViewContents.frame = CGRectMake(0 - alertViewFrame.size.width - 15, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + } + } + + } completion:^(BOOL finished) { + + if (!_animateAlertOutToTop && !_animateAlertOutToLeft && !_animateAlertOutToRight && !_animateAlertOutToBottom) { + id strongDelegate = self.delegate; + + if ([strongDelegate respondsToSelector:@selector(FCAlertViewDismissed:)]) { + [strongDelegate FCAlertViewDismissed:self]; + } + + [backgroundVisualEffectView removeFromSuperview]; + [self removeFromSuperview]; + } else { + if (_bounceAnimations) { + [UIView animateWithDuration:0.175 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + + self.alpha = 0; + backgroundVisualEffectView.alpha = 0; + + if (_animateAlertOutToTop) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + 0 - alertViewFrame.size.height - 15, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertOutToRight) + alertViewContents.frame = CGRectMake(self.frame.size.width + alertViewFrame.size.width + 15, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertOutToBottom) + alertViewContents.frame = CGRectMake(alertViewFrame.origin.x, + self.frame.size.height + alertViewFrame.size.height + 15, + alertViewFrame.size.width, + alertViewFrame.size.height); + if (_animateAlertOutToLeft) + alertViewContents.frame = CGRectMake(0 - alertViewFrame.size.width - 15, + alertViewFrame.origin.y, + alertViewFrame.size.width, + alertViewFrame.size.height); + }completion:^(BOOL finished) { + id strongDelegate = self.delegate; + + if ([strongDelegate respondsToSelector:@selector(FCAlertViewDismissed:)]) { + [strongDelegate FCAlertViewDismissed:self]; + } + + [backgroundVisualEffectView removeFromSuperview]; + [self removeFromSuperview]; + }]; + } else { + id strongDelegate = self.delegate; + + if ([strongDelegate respondsToSelector:@selector(FCAlertViewDismissed:)]) { + [strongDelegate FCAlertViewDismissed:self]; + } + + [backgroundVisualEffectView removeFromSuperview]; + [self removeFromSuperview]; + } + } + + }]; + +} + +#pragma mark - Action Block Methods + +- (void)addButton:(NSString *)title withActionBlock:(FCActionBlock)action { + + if (alertButtons.count < 2) { + if (action != nil) + [alertButtons addObject:@{@"title" : title, + @"action" : action}]; + else + [alertButtons addObject:@{@"title" : title, + @"action" : @0}]; + } + + _numberOfButtons = alertButtons.count; + +} + +- (void)doneActionBlock:(FCActionBlock)action { + + if (action != nil) + self.doneBlock = action; + +} + +#pragma mark - ACTIONS +#pragma mark Button Selection + +- (void)handleButton:(id)sender { + + id strongDelegate = self.delegate; + + // Return Text from TextField to Block + + for (int i = 0; i < alertTextFields.count; i ++) { + + FCTextReturnBlock textReturnBlock = [[alertTextFields objectAtIndex:i] objectForKey:@"action"]; + UITextField *tf = [alertTextFieldHolder objectAtIndex:i]; + if (textReturnBlock) + textReturnBlock(tf.text); + + } + + // Handling Button Block + + UIButton *clickedButton = (UIButton*)sender; + + NSDictionary *btnDict = [alertButtons objectAtIndex:[sender tag]]; + + if (btnDict != nil) { + if ([btnDict objectForKey:@"action"] != nil && ![[btnDict objectForKey:@"action"] isEqual:@0]) { + FCActionBlock block = [btnDict objectForKey:@"action"]; + if (block) + block(); + } + } + + if ([strongDelegate respondsToSelector:@selector(FCAlertView:clickedButtonIndex:buttonTitle:)]) { + [strongDelegate FCAlertView:self clickedButtonIndex:[sender tag] buttonTitle:clickedButton.titleLabel.text]; + } + + // Return Rating from Rating Controller + + if (_ratingBlock) + _ratingBlock(currentRating); + + [self dismissAlertView]; + +} + +#pragma mark - Button Actions + +- (void) btnTouched { + + if (_bounceAnimations) { + + [UIView animateWithDuration:0.15 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + self.alpha = 1; + if (_bounceAnimations) + alertViewContents.transform = CGAffineTransformMakeScale(0.95, 0.95); + }completion:nil]; + + } + +} + +- (void) donePressed { + + id strongDelegate = self.delegate; + + // Return Text from TextField to Block + + for (int i = 0; i < alertTextFields.count; i ++) { + + FCTextReturnBlock textReturnBlock = [[alertTextFields objectAtIndex:i] objectForKey:@"action"]; + UITextField *tf = [alertTextFieldHolder objectAtIndex:i]; + if (textReturnBlock) + textReturnBlock(tf.text); + + } + + // Handling Done Button Block + + if (self.doneBlock) + self.doneBlock(); + + if ([strongDelegate respondsToSelector:@selector(FCAlertDoneButtonClicked:)]) { + [strongDelegate FCAlertDoneButtonClicked:self]; + } + + // Return Rating from Rating Controller + + if (_ratingBlock) + _ratingBlock(currentRating); + + [self dismissAlertView]; + +} + +- (void) btnReleased { + + if (_bounceAnimations) { + + [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + alertViewContents.transform = CGAffineTransformMakeScale(1.05, 1.05); + }completion:^(BOOL finished) { + [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + alertViewContents.transform = CGAffineTransformMakeScale(1.00, 1.00); + }completion:nil]; + }]; + + } + +} + +#pragma mark - TEXT FIELD METHODS +#pragma mark - Text Field Begin Editing + +#pragma mark - Adding Alert TextField Block Method + +- (void)addTextFieldWithPlaceholder:(NSString *)placeholder andTextReturnBlock:(FCTextReturnBlock)textReturn { + + if (textReturn != nil) + [alertTextFields addObject:@{@"placeholder" : placeholder, + @"action" : textReturn}]; + else + [alertTextFields addObject:@{@"placeholder" : placeholder, + @"action" : @0}]; + +} + +- (void)addTextFieldWithCustomTextField:(UITextField *)field andPlaceholder:(NSString *)placeholder andTextReturnBlock:(FCTextReturnBlock)textReturn { + + if (placeholder == nil) + placeholder = @""; + + if (textReturn != nil) + [alertTextFields addObject:@{@"field" : field, + @"placeholder" : placeholder, + @"action" : textReturn}]; + else + [alertTextFields addObject:@{@"field" : field, + @"placeholder" : placeholder, + @"action" : @0}]; + +} + +- (void)textFieldDidBeginEditing:(UITextField *)textField { + + currentAVCFrames = alertViewContents.frame; + + [UIView animateWithDuration:0.30 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + alertViewContents.frame = CGRectMake(currentAVCFrames.origin.x, + currentAVCFrames.origin.y - 80, + currentAVCFrames.size.width, + currentAVCFrames.size.height); + } completion:nil]; + +} + +#pragma mark - Text Field End Editing + +- (void)textFieldDidEndEditing:(UITextField *)textField { + + [UIView animateWithDuration:0.30 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + alertViewContents.frame = CGRectMake(currentAVCFrames.origin.x, + currentAVCFrames.origin.y, + currentAVCFrames.size.width, + currentAVCFrames.size.height); + } completion:nil]; + +} + +#pragma mark - Text Field Returned + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + + if (textField.tag+1 == alertTextFieldHolder.count) { + [textField endEditing:YES]; + } else { + UITextField *tf = [alertTextFieldHolder objectAtIndex:(textField.tag+1)]; + [tf becomeFirstResponder]; + } + + return TRUE; +} + +#pragma mark - Rating System Trigger Methods + +- (void) rate1Triggered { + if (currentRating != 1) { + currentRating = 1; + [self setActiveRating:currentRating]; + } else { + currentRating = 0; + [self setActiveRating:currentRating]; + } + + if (_bounceAnimations) { + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + item1.transform = CGAffineTransformMakeScale(0.9, 0.9); + } completion:^(BOOL finished) { + [UIView animateWithDuration:0.35 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + item1.transform = CGAffineTransformMakeScale(1.0, 1.0); + } completion:nil]; + }]; + } + +} + +- (void) rate2Triggered { + currentRating = 2; + [self setActiveRating:currentRating]; + + if (_bounceAnimations) { + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + item2.transform = CGAffineTransformMakeScale(0.9, 0.9); + } completion:^(BOOL finished) { + [UIView animateWithDuration:0.35 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + item2.transform = CGAffineTransformMakeScale(1.0, 1.0); + } completion:nil]; + }]; + } +} + +- (void) rate3Triggered { + currentRating = 3; + [self setActiveRating:currentRating]; + + if (_bounceAnimations) { + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + item3.transform = CGAffineTransformMakeScale(0.9, 0.9); + } completion:^(BOOL finished) { + [UIView animateWithDuration:0.35 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + item3.transform = CGAffineTransformMakeScale(1.0, 1.0); + } completion:nil]; + }]; + } +} + +- (void) rate4Triggered { + currentRating = 4; + [self setActiveRating:currentRating]; + + if (_bounceAnimations) { + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + item4.transform = CGAffineTransformMakeScale(0.9, 0.9); + } completion:^(BOOL finished) { + [UIView animateWithDuration:0.35 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + item4.transform = CGAffineTransformMakeScale(1.0, 1.0); + } completion:nil]; + }]; + } +} + +- (void) rate5Triggered { + currentRating = 5; + [self setActiveRating:currentRating]; + + if (_bounceAnimations) { + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + item5.transform = CGAffineTransformMakeScale(0.9, 0.9); + } completion:^(BOOL finished) { + [UIView animateWithDuration:0.35 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + item5.transform = CGAffineTransformMakeScale(1.0, 1.0); + } completion:nil]; + }]; + } +} + +- (void) setActiveRating:(NSInteger)rating { + + item1.tintColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + item2.tintColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + item3.tintColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + item4.tintColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + item5.tintColor = [UIColor colorWithWhite:228.0f/255.0f alpha:1.0]; + + if (rating == 1) { + item1.tintColor = self.colorScheme; + } + + if (rating == 2) { + item1.tintColor = self.colorScheme; + item2.tintColor = self.colorScheme; + } + + if (rating == 3) { + item1.tintColor = self.colorScheme; + item2.tintColor = self.colorScheme; + item3.tintColor = self.colorScheme; + } + + if (rating == 4) { + item1.tintColor = self.colorScheme; + item2.tintColor = self.colorScheme; + item3.tintColor = self.colorScheme; + item4.tintColor = self.colorScheme; + } + + if (rating == 5) { + item1.tintColor = self.colorScheme; + item2.tintColor = self.colorScheme; + item3.tintColor = self.colorScheme; + item4.tintColor = self.colorScheme; + item5.tintColor = self.colorScheme; + } + +} + +@end diff --git a/Palette/App/Palette/AppearanceColour.xcassets/Accent.colorset/Contents.json b/Palette/App/Palette/AppearanceColour.xcassets/Accent.colorset/Contents.json new file mode 100644 index 0000000..cc34a04 --- /dev/null +++ b/Palette/App/Palette/AppearanceColour.xcassets/Accent.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.980", + "green" : "0.831", + "red" : "0.427" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.980", + "green" : "0.831", + "red" : "0.427" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/AppearanceColour.xcassets/Alert.colorset/Contents.json b/Palette/App/Palette/AppearanceColour.xcassets/Alert.colorset/Contents.json new file mode 100644 index 0000000..17ec699 --- /dev/null +++ b/Palette/App/Palette/AppearanceColour.xcassets/Alert.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.247", + "green" : "0.247", + "red" : "0.247" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/AppearanceColour.xcassets/Border.colorset/Contents.json b/Palette/App/Palette/AppearanceColour.xcassets/Border.colorset/Contents.json new file mode 100644 index 0000000..04050e9 --- /dev/null +++ b/Palette/App/Palette/AppearanceColour.xcassets/Border.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.500", + "blue" : "0.839", + "green" : "0.820", + "red" : "0.820" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.500", + "blue" : "0.290", + "green" : "0.282", + "red" : "0.282" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/AppearanceColour.xcassets/Cell Background.colorset/Contents.json b/Palette/App/Palette/AppearanceColour.xcassets/Cell Background.colorset/Contents.json new file mode 100644 index 0000000..22c4bb0 --- /dev/null +++ b/Palette/App/Palette/AppearanceColour.xcassets/Cell Background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/AppearanceColour.xcassets/Containers.colorset/Contents.json b/Palette/App/Palette/AppearanceColour.xcassets/Containers.colorset/Contents.json new file mode 100644 index 0000000..9a9aee9 --- /dev/null +++ b/Palette/App/Palette/AppearanceColour.xcassets/Containers.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.180", + "green" : "0.169", + "red" : "0.169" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/AppearanceColour.xcassets/Contents.json b/Palette/App/Palette/AppearanceColour.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Palette/App/Palette/AppearanceColour.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/AppearanceColour.xcassets/Main Background.colorset/Contents.json b/Palette/App/Palette/AppearanceColour.xcassets/Main Background.colorset/Contents.json new file mode 100644 index 0000000..b5471af --- /dev/null +++ b/Palette/App/Palette/AppearanceColour.xcassets/Main Background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.969", + "green" : "0.949", + "red" : "0.949" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.118", + "green" : "0.110", + "red" : "0.110" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/Application Delegate/AppDelegate.h b/Palette/App/Palette/Application Delegate/AppDelegate.h new file mode 100644 index 0000000..d79858b --- /dev/null +++ b/Palette/App/Palette/Application Delegate/AppDelegate.h @@ -0,0 +1,7 @@ +#import + +@interface AppDelegate : UIResponder + + +@end + diff --git a/Palette/App/Palette/Application Delegate/AppDelegate.m b/Palette/App/Palette/Application Delegate/AppDelegate.m new file mode 100644 index 0000000..8c7fce9 --- /dev/null +++ b/Palette/App/Palette/Application Delegate/AppDelegate.m @@ -0,0 +1,33 @@ +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + return YES; +} + + +#pragma mark - UISceneSession lifecycle + + +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; +} + + +- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. +} + + +@end diff --git a/Palette/App/Palette/Application Delegate/SceneDelegate.h b/Palette/App/Palette/Application Delegate/SceneDelegate.h new file mode 100644 index 0000000..a19a1ce --- /dev/null +++ b/Palette/App/Palette/Application Delegate/SceneDelegate.h @@ -0,0 +1,8 @@ +#import + +@interface SceneDelegate : UIResponder + +@property (strong, nonatomic) UIWindow * window; + +@end + diff --git a/Palette/App/Palette/Application Delegate/SceneDelegate.m b/Palette/App/Palette/Application Delegate/SceneDelegate.m new file mode 100644 index 0000000..484fe02 --- /dev/null +++ b/Palette/App/Palette/Application Delegate/SceneDelegate.m @@ -0,0 +1,41 @@ +#import "SceneDelegate.h" + +@interface SceneDelegate () + +@end + +@implementation SceneDelegate + + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { + [self.window setTintColor:[UIColor colorNamed:@"Accent"]]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"NewCollectionNotification" object:self]; +} + + +- (void)sceneDidDisconnect:(UIScene *)scene { + [[NSNotificationCenter defaultCenter] postNotificationName:@"NewCollectionNotification" object:self]; +} + + +- (void)sceneDidBecomeActive:(UIScene *)scene { + [[NSNotificationCenter defaultCenter] postNotificationName:@"NewCollectionNotification" object:self]; +} + + +- (void)sceneWillResignActive:(UIScene *)scene { + [[NSNotificationCenter defaultCenter] postNotificationName:@"NewCollectionNotification" object:self]; +} + + +- (void)sceneWillEnterForeground:(UIScene *)scene { + [[NSNotificationCenter defaultCenter] postNotificationName:@"NewCollectionNotification" object:self]; +} + + +- (void)sceneDidEnterBackground:(UIScene *)scene { + [[NSNotificationCenter defaultCenter] postNotificationName:@"NewCollectionNotification" object:self]; +} + + +@end diff --git a/Palette/App/Palette/Application Delegate/TabViewController.h b/Palette/App/Palette/Application Delegate/TabViewController.h new file mode 100644 index 0000000..ffcc7bb --- /dev/null +++ b/Palette/App/Palette/Application Delegate/TabViewController.h @@ -0,0 +1,9 @@ +#import +#import "MyCollectionViewController.h" +#import "ColourSectionViewController.h" +//#import "FavouriteViewController.h" +#import "GradientsViewController.h" + +@interface TabViewController : UITabBarController +@end + diff --git a/Palette/App/Palette/Application Delegate/TabViewController.m b/Palette/App/Palette/Application Delegate/TabViewController.m new file mode 100644 index 0000000..a6d04c3 --- /dev/null +++ b/Palette/App/Palette/Application Delegate/TabViewController.m @@ -0,0 +1,31 @@ +#import "TabViewController.h" + +@implementation TabViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + MyCollectionViewController *collectionVC = [[MyCollectionViewController alloc] init]; + UINavigationController *collectionNavigationController = [[UINavigationController alloc] initWithRootViewController:collectionVC]; + + ColourSectionViewController *colourSectionVC = [[ColourSectionViewController alloc] init]; + UINavigationController *colourSectionNavigationController = [[UINavigationController alloc] initWithRootViewController:colourSectionVC]; + + GradientsViewController *gradientVC = [[GradientsViewController alloc] init]; + UINavigationController *gradientNavigationController = [[UINavigationController alloc] initWithRootViewController:gradientVC]; + +// FavouriteViewController *fvc = [[FavouriteViewController alloc] init]; +// UINavigationController *favNavigationController = [[UINavigationController alloc] initWithRootViewController:fvc]; + + NSArray *tabbarArray = @[collectionNavigationController, colourSectionNavigationController, gradientNavigationController]; + [self setViewControllers:tabbarArray]; + + collectionVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"My Collection" image:[UIImage systemImageNamed:@"heart.fill"] tag:0]; + colourSectionVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Colours" image:[UIImage systemImageNamed:@"paintpalette.fill"] tag:1]; + gradientVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Gradients" image:[UIImage systemImageNamed:@"paintbrush.pointed.fill"] tag:2]; + //fvc.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Favourite" image:[UIImage systemImageNamed:@"heart.fill"] tag:3]; + +} + + +@end diff --git a/Palette/App/Palette/Assets.xcassets/AccentColor.colorset/Contents.json b/Palette/App/Palette/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/Palette/App/Palette/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/Assets.xcassets/AppIcon.appiconset/Contents.json b/Palette/App/Palette/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..4dc2778 --- /dev/null +++ b/Palette/App/Palette/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,100 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "xcode-120.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "xcode-180.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/Assets.xcassets/AppIcon.appiconset/xcode-120.png b/Palette/App/Palette/Assets.xcassets/AppIcon.appiconset/xcode-120.png new file mode 100644 index 0000000..ff29d09 Binary files /dev/null and b/Palette/App/Palette/Assets.xcassets/AppIcon.appiconset/xcode-120.png differ diff --git a/Palette/App/Palette/Assets.xcassets/AppIcon.appiconset/xcode-180.png b/Palette/App/Palette/Assets.xcassets/AppIcon.appiconset/xcode-180.png new file mode 100644 index 0000000..3c662d7 Binary files /dev/null and b/Palette/App/Palette/Assets.xcassets/AppIcon.appiconset/xcode-180.png differ diff --git a/Palette/App/Palette/Assets.xcassets/Contents.json b/Palette/App/Palette/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Palette/App/Palette/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/Assets.xcassets/transparent.imageset/Contents.json b/Palette/App/Palette/Assets.xcassets/transparent.imageset/Contents.json new file mode 100644 index 0000000..7eebd65 --- /dev/null +++ b/Palette/App/Palette/Assets.xcassets/transparent.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "transparent.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/Assets.xcassets/transparent.imageset/transparent.png b/Palette/App/Palette/Assets.xcassets/transparent.imageset/transparent.png new file mode 100644 index 0000000..acc275b Binary files /dev/null and b/Palette/App/Palette/Assets.xcassets/transparent.imageset/transparent.png differ diff --git a/Palette/App/Palette/Assets.xcassets/trash.imageset/Contents.json b/Palette/App/Palette/Assets.xcassets/trash.imageset/Contents.json new file mode 100644 index 0000000..4d12efa --- /dev/null +++ b/Palette/App/Palette/Assets.xcassets/trash.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "trash.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Palette/App/Palette/Assets.xcassets/trash.imageset/trash.png b/Palette/App/Palette/Assets.xcassets/trash.imageset/trash.png new file mode 100644 index 0000000..aa492c6 Binary files /dev/null and b/Palette/App/Palette/Assets.xcassets/trash.imageset/trash.png differ diff --git a/Palette/App/Palette/Base.lproj/LaunchScreen.storyboard b/Palette/App/Palette/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/Palette/App/Palette/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Palette/App/Palette/Base.lproj/Main.storyboard b/Palette/App/Palette/Base.lproj/Main.storyboard new file mode 100644 index 0000000..7aeaed8 --- /dev/null +++ b/Palette/App/Palette/Base.lproj/Main.storyboard @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Palette/App/Palette/BottomAlert.txt b/Palette/App/Palette/BottomAlert.txt new file mode 100644 index 0000000..5783d84 --- /dev/null +++ b/Palette/App/Palette/BottomAlert.txt @@ -0,0 +1,82 @@ + +#import "FavouriteViewController.h" + +@implementation FavouriteViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + + //self.view.backgroundColor = UIColor.yellowColor; + +// NSString *color = @"systemPinkColor"; +// self.view.backgroundColor = [UIColor performSelector:NSSelectorFromString(color)]; + + self.view.backgroundColor = [UIColor colorWithRed:233/255.0 green: 203/255.0 blue: 251/255.0 alpha: 1.00]; + + [self.view addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(testMethod)]]; +} + + +-(void)testMethod{ + + UIAlertController * view= [UIAlertController + alertControllerWithTitle:@"Staus ! " + message:@"Select your current status" + preferredStyle:UIAlertControllerStyleActionSheet]; + + + UIAlertAction* online = [UIAlertAction + actionWithTitle:@"Online" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) + { + //Do some thing here + [view dismissViewControllerAnimated:YES completion:nil]; + + }]; + UIAlertAction* offline = [UIAlertAction + actionWithTitle:@"Offline" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) + { + //[view dismissViewControllerAnimated:YES completion:nil]; + + }]; + UIAlertAction* doNotDistrbe = [UIAlertAction + actionWithTitle:@"Do not disturb" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) + { + [view dismissViewControllerAnimated:YES completion:nil]; + + }]; + UIAlertAction* away = [UIAlertAction + actionWithTitle:@"Do not disturb" + style:UIAlertActionStyleDestructive + handler:^(UIAlertAction * action) + { + [view dismissViewControllerAnimated:YES completion:nil]; + + }]; + + [online setValue:[[UIImage systemImageNamed:@"gear"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forKey:@"image"]; + [offline setValue:[[UIImage imageNamed:@"offline.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forKey:@"image"]; + [doNotDistrbe setValue:[[UIImage imageNamed:@"DND.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forKey:@"image"]; + [away setValue:[[UIImage imageNamed:@"away.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forKey:@"image"]; + + + //[online setValue:[NSNumber numberWithInt:NSTextAlignmentLeft] + //forKey:@"titleTextAlignment"]; + + + + [view addAction:online]; + [view addAction:away]; + [view addAction:offline]; + [view addAction:doNotDistrbe]; + [self presentViewController:view animated:YES completion:nil]; + +} + +@end diff --git a/Palette/App/Palette/Cells/ColourCell.h b/Palette/App/Palette/Cells/ColourCell.h new file mode 100644 index 0000000..d02d50c --- /dev/null +++ b/Palette/App/Palette/Cells/ColourCell.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" + +@interface ColourCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *colourView; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UILabel *hexLabel; +@property (nonatomic, retain) UILabel *rgbLabel; +@end + diff --git a/Palette/App/Palette/Cells/ColourCell.m b/Palette/App/Palette/Cells/ColourCell.m new file mode 100644 index 0000000..faf5f3b --- /dev/null +++ b/Palette/App/Palette/Cells/ColourCell.m @@ -0,0 +1,70 @@ +#import "ColourCell.h" + +@implementation ColourCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor colorNamed:@"Containers"]; + self.baseView.layer.cornerRadius = 25; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + self.baseView.layer.borderColor = [UIColor colorNamed:@"Border"].CGColor; + self.baseView.layer.borderWidth = 0.6; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:5]; + [self.baseView leading:self.leadingAnchor padding:10]; + [self.baseView trailing:self.trailingAnchor padding:-10]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + + self.colourView = [[UIView alloc] init]; + self.colourView.backgroundColor = UIColor.systemPinkColor; + [self.baseView addSubview:self.colourView]; + + [self.colourView top:self.baseView.topAnchor padding:0]; + [self.colourView leading:self.baseView.leadingAnchor padding:0]; + [self.colourView trailing:self.baseView.trailingAnchor padding:0]; + [self.colourView height:80]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.textColor = UIColor.whiteColor; + self.nameLabel.font = [UIFont boldSystemFontOfSize:15]; + self.nameLabel.textAlignment = NSTextAlignmentCenter; + [self.colourView addSubview:self.nameLabel]; + + [self.nameLabel top:self.colourView.topAnchor padding:10]; + [self.nameLabel x:self.colourView.centerXAnchor]; + + + self.hexLabel = [[UILabel alloc] init]; + self.hexLabel.font = [UIFont systemFontOfSize:15]; + self.hexLabel.textAlignment = NSTextAlignmentLeft; + self.hexLabel.numberOfLines = 1; + [self.baseView addSubview:self.hexLabel]; + + [self.hexLabel leading:self.baseView.leadingAnchor padding:15]; + [self.hexLabel top:self.colourView.bottomAnchor padding:10]; + + + self.rgbLabel = [[UILabel alloc] init]; + self.rgbLabel.font = [UIFont systemFontOfSize:15]; + self.rgbLabel.textAlignment = NSTextAlignmentLeft; + self.rgbLabel.numberOfLines = 1; + [self.baseView addSubview:self.rgbLabel]; + + [self.rgbLabel leading:self.baseView.leadingAnchor padding:15]; + [self.rgbLabel bottom:self.baseView.bottomAnchor padding:-10]; + + } + + return self; +} + +@end diff --git a/Palette/App/Palette/Cells/GradientCell.h b/Palette/App/Palette/Cells/GradientCell.h new file mode 100644 index 0000000..57be527 --- /dev/null +++ b/Palette/App/Palette/Cells/GradientCell.h @@ -0,0 +1,12 @@ +#import +#import "ConstraintExtension.h" + +@interface GradientCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *gradientView; +@property (nonatomic, retain) UIView *firstPreview; +@property (nonatomic, retain) UIView *secondPreview; +@property (nonatomic, retain) UILabel *firstLabel; +@property (nonatomic, retain) UILabel *secondLabel; +@property (nonatomic, retain) CAGradientLayer *gradient; +@end diff --git a/Palette/App/Palette/Cells/GradientCell.m b/Palette/App/Palette/Cells/GradientCell.m new file mode 100644 index 0000000..6c3b127 --- /dev/null +++ b/Palette/App/Palette/Cells/GradientCell.m @@ -0,0 +1,77 @@ +#import "GradientCell.h" + +@implementation GradientCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor colorNamed:@"Containers"]; + self.baseView.layer.cornerRadius = 25; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + self.baseView.layer.borderColor = [UIColor colorNamed:@"Border"].CGColor; + self.baseView.layer.borderWidth = 0.6; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.gradientView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height - 65)]; + self.gradientView.backgroundColor = UIColor.yellowColor; + [self.baseView addSubview:self.gradientView]; + + self.gradient = [CAGradientLayer layer]; + self.gradient.frame = self.gradientView.bounds; + self.gradient.startPoint = CGPointMake(1, 0); + self.gradient.endPoint = CGPointMake(0, 1); + [self.gradientView.layer insertSublayer:self.gradient atIndex:0]; + + + self.firstPreview = [[UIView alloc] init]; + self.firstPreview.layer.cornerRadius = 10; + self.firstPreview.clipsToBounds = true; + [self.baseView addSubview:self.firstPreview]; + + [self.firstPreview size:CGSizeMake(20, 20)]; + [self.firstPreview leading:self.baseView.leadingAnchor padding:15]; + [self.firstPreview top:self.gradientView.bottomAnchor padding:10]; + + + self.secondPreview = [[UIView alloc] init]; + self.secondPreview.layer.cornerRadius = 10; + self.secondPreview.clipsToBounds = true; + [self.baseView addSubview:self.secondPreview]; + + [self.secondPreview size:CGSizeMake(20, 20)]; + [self.secondPreview leading:self.baseView.leadingAnchor padding:15]; + [self.secondPreview bottom:self.baseView.bottomAnchor padding:-10]; + + + self.firstLabel = [[UILabel alloc] init]; + self.firstLabel.font = [UIFont systemFontOfSize:14]; + self.firstLabel.textAlignment = NSTextAlignmentLeft; + self.firstLabel.textColor = UIColor.labelColor; + [self.baseView addSubview:self.firstLabel]; + + [self.firstLabel y:self.firstPreview.centerYAnchor]; + [self.firstLabel leading:self.firstPreview.trailingAnchor padding:10]; + + + self.secondLabel = [[UILabel alloc] init]; + self.secondLabel.font = [UIFont systemFontOfSize:14]; + self.secondLabel.textAlignment = NSTextAlignmentLeft; + self.secondLabel.textColor = UIColor.labelColor; + [self.baseView addSubview:self.secondLabel]; + + [self.secondLabel y:self.secondPreview.centerYAnchor]; + [self.secondLabel leading:self.secondPreview.trailingAnchor padding:10]; + + } + return self; +} + +@end diff --git a/Palette/App/Palette/Colour Plists/BlackColour.plist b/Palette/App/Palette/Colour Plists/BlackColour.plist new file mode 100644 index 0000000..1f0dd06 --- /dev/null +++ b/Palette/App/Palette/Colour Plists/BlackColour.plist @@ -0,0 +1,49 @@ + + + + + + + colourName + Black + hexCode + 000000 + + + + colourName + Charcoal + hexCode + 36454F + + + + colourName + Jet Black + hexCode + 343434 + + + + colourName + Licorice + hexCode + 1B1212 + + + + colourName + Matte Black + hexCode + 28282B + + + + colourName + Onyx + hexCode + 353935 + + + + diff --git a/Palette/App/Palette/Colour Plists/BlueColour.plist b/Palette/App/Palette/Colour Plists/BlueColour.plist new file mode 100644 index 0000000..75c59b0 --- /dev/null +++ b/Palette/App/Palette/Colour Plists/BlueColour.plist @@ -0,0 +1,245 @@ + + + + + + + colourName + Aqua + hexCode + 00FFFF + + + + colourName + Azure + hexCode + F0FFFF + + + + colourName + Baby Blue + hexCode + 89CFF0 + + + + colourName + Blue + hexCode + 0000FF + + + + colourName + Blue Gray + hexCode + 7393B3 + + + + colourName + Blue Green + hexCode + 088F8F + + + + colourName + Bright Blue + hexCode + 0096FF + + + + colourName + Cadet Blue + hexCode + 5F9EA0 + + + + colourName + Cobalt Blue + hexCode + 0047AB + + + + colourName + Cornflower Blue + hexCode + 6495ED + + + + colourName + Cyan + hexCode + 00FFFF + + + + colourName + Dark Blue + hexCode + 00008B + + + + colourName + Denim + hexCode + 6F8FAF + + + + colourName + Egyptian Blue + hexCode + 1434A4 + + + + colourName + Electric Blue + hexCode + 7DF9FF + + + + colourName + Glaucous + hexCode + 6082B6 + + + + colourName + Indigo + hexCode + 3F00FF + + + + colourName + Light Blue + hexCode + ADD8E6 + + + + colourName + Midnight Blue + hexCode + 191970 + + + + colourName + Navy Blue + hexCode + 000080 + + + + colourName + Neon Blue + hexCode + 1F51FF + + + + colourName + Pastel Blue + hexCode + A7C7E7 + + + + colourName + Powder Blue + hexCode + B6D0E2 + + + + colourName + Robin Egg Blue + hexCode + 96DED1 + + + + colourName + Royal Blue + hexCode + 4169E1 + + + + colourName + Sapphire Blue + hexCode + 0F52BA + + + + colourName + Seafoam Green + hexCode + 9FE2BF + + + + colourName + Sky Blue + hexCode + 87CEEB + + + + colourName + Steel Blue + hexCode + 4682B4 + + + + colourName + Teal + hexCode + 008080 + + + + colourName + Turquoise + hexCode + 40E0D0 + + + + colourName + Ultramarine + hexCode + 0437F2 + + + + colourName + Verdigris + hexCode + 40B5AD + + + + colourName + Zaffre + hexCode + 0818A8 + + + + diff --git a/Palette/App/Palette/Colour Plists/BrownColour.plist b/Palette/App/Palette/Colour Plists/BrownColour.plist new file mode 100644 index 0000000..c8220df --- /dev/null +++ b/Palette/App/Palette/Colour Plists/BrownColour.plist @@ -0,0 +1,280 @@ + + + + + + + colourName + Almond + hexCode + EADDCA + + + + colourName + Brass + hexCode + E1C16E + + + + colourName + Bronze + hexCode + CD7F32 + + + + colourName + Brown + hexCode + A52A2A + + + + colourName + Buff + hexCode + DAA06D + + + + colourName + Burgundy + hexCode + 800020 + + + + colourName + Burnt Umber + hexCode + 6E260E + + + + colourName + Camel + hexCode + C19A6B + + + + colourName + Chestnut + hexCode + 954535 + + + + colourName + Chocolate + hexCode + 7B3F00 + + + + colourName + Cinnamon + hexCode + D27D2D + + + + colourName + Coffee + hexCode + 6F4E37 + + + + colourName + Cognac + hexCode + 834333 + + + + colourName + Copper + hexCode + B87333 + + + + colourName + Cordovan + hexCode + 814141 + + + + colourName + Dark Brown + hexCode + 5C4033 + + + + colourName + Dark Tan + hexCode + 988558 + + + + colourName + Ecru + hexCode + C2B280 + + + + colourName + Fallow + hexCode + C19A6B + + + + colourName + Fawn + hexCode + E5AA70 + + + + colourName + Garnet + hexCode + 9A2A2A + + + + colourName + Golden Brown + hexCode + 966919 + + + + colourName + Light Brown + hexCode + C4A484 + + + + colourName + Mahogany + hexCode + C04000 + + + + colourName + Maroon + hexCode + 800000 + + + + colourName + Mocha + hexCode + 967969 + + + + colourName + Nude + hexCode + F2D2BD + + + + colourName + Ochre + hexCode + CC7722 + + + + colourName + Puce + hexCode + A95C68 + + + + colourName + Red Brown + hexCode + A52A2A + + + + colourName + Russet + hexCode + 80461B + + + + colourName + Saddle Brown + hexCode + 8B4513 + + + + colourName + Sand + hexCode + C2B280 + + + + colourName + Sienna + hexCode + A0522D + + + + colourName + Tan + hexCode + D2B48C + + + + colourName + Taupe + hexCode + 483C32 + + + + colourName + Tuscan Red + hexCode + 7C3030 + + + + colourName + Wheat + hexCode + F5DEB3 + + + + colourName + Wine + hexCode + 722F37 + + + + diff --git a/Palette/App/Palette/Colour Plists/GradientColour.plist b/Palette/App/Palette/Colour Plists/GradientColour.plist new file mode 100644 index 0000000..7d9f3aa --- /dev/null +++ b/Palette/App/Palette/Colour Plists/GradientColour.plist @@ -0,0 +1,469 @@ + + + + + + + primraryHexCode + ff9a9e + secondaryHexCode + fad0c4 + + + + primraryHexCode + a18cd1 + secondaryHexCode + fbc2eb + + + + primraryHexCode + fad0c4 + secondaryHexCode + ffd1ff + + + + primraryHexCode + ffecd2 + secondaryHexCode + fcb69f + + + + primraryHexCode + FFFEFF + secondaryHexCode + D7FFFE + + + + primraryHexCode + d299c2 + secondaryHexCode + fef9d7 + + + + primraryHexCode + 74ebd5 + secondaryHexCode + 9face6 + + + + primraryHexCode + 6a85b6 + secondaryHexCode + bac8e0 + + + + primraryHexCode + fdcbf1 + secondaryHexCode + e6dee9 + + + + primraryHexCode + 84fab0 + secondaryHexCode + 8fd3f4 + + + + primraryHexCode + a1c4fd + secondaryHexCode + c2e9fb + + + + primraryHexCode + ff9a9e + secondaryHexCode + fecfef + + + + primraryHexCode + accbee + secondaryHexCode + e7f0fd + + + + primraryHexCode + 4facfe + secondaryHexCode + 00f2fe + + + + primraryHexCode + 667eea + secondaryHexCode + 764ba2 + + + + primraryHexCode + 2af598 + secondaryHexCode + 009efd + + + + primraryHexCode + 868f96 + secondaryHexCode + 596164 + + + + primraryHexCode + 6a11cb + secondaryHexCode + 2575fc + + + + primraryHexCode + c471f5 + secondaryHexCode + fa71cd + + + + primraryHexCode + c79081 + secondaryHexCode + dfa579 + + + + primraryHexCode + 48c6ef + secondaryHexCode + 6f86d6 + + + + primraryHexCode + ff758c + secondaryHexCode + ff7eb3 + + + + primraryHexCode + 243949 + secondaryHexCode + 517fa4 + + + + primraryHexCode + c1dfc4 + secondaryHexCode + deecdd + + + + primraryHexCode + c71d6f + secondaryHexCode + d09693 + + + + primraryHexCode + e6b980 + secondaryHexCode + eacda3 + + + + primraryHexCode + 1e3c72 + secondaryHexCode + 2a5298 + + + + primraryHexCode + bdc2e8 + secondaryHexCode + e6dee9 + + + + primraryHexCode + 434343 + secondaryHexCode + 000000 + + + + primraryHexCode + abecd6 + secondaryHexCode + fbed96 + + + + primraryHexCode + 96deda + secondaryHexCode + 50c9c3 + + + + primraryHexCode + a8caba + secondaryHexCode + 5d4157 + + + + primraryHexCode + f77062 + secondaryHexCode + fe5196 + + + + primraryHexCode + 29323c + secondaryHexCode + 485563 + + + + primraryHexCode + f794a4 + secondaryHexCode + fdd6bd + + + + primraryHexCode + dfe9f3 + secondaryHexCode + ffffff + + + + primraryHexCode + d7d2cc + secondaryHexCode + 304352 + + + + primraryHexCode + ffafbd + secondaryHexCode + ffc3a0 + + + + primraryHexCode + 2193b0 + secondaryHexCode + 6dd5ed + + + + primraryHexCode + cc2b5e + secondaryHexCode + 753a88 + + + + primraryHexCode + ee9ca7 + secondaryHexCode + ffdde1 + + + + primraryHexCode + 42275a + secondaryHexCode + 734b6d + + + + primraryHexCode + de6262 + secondaryHexCode + ffb88c + + + + primraryHexCode + a8ff78 + secondaryHexCode + 78ffd6 + + + + primraryHexCode + 00F260 + secondaryHexCode + 0575E6 + + + + primraryHexCode + 45a247 + secondaryHexCode + 283c86 + + + + primraryHexCode + 67B26F + secondaryHexCode + 4ca2cd + + + + primraryHexCode + 56ab2f + secondaryHexCode + a8e063 + + + + primraryHexCode + FDFC47 + secondaryHexCode + 24FE41 + + + + primraryHexCode + B3FFAB + secondaryHexCode + 12FFF7 + + + + primraryHexCode + 3CA55C + secondaryHexCode + B5AC49 + + + + primraryHexCode + f12711 + secondaryHexCode + f5af19 + + + + primraryHexCode + 544a7d + secondaryHexCode + ffd452 + + + + primraryHexCode + FDC830 + secondaryHexCode + F37335 + + + + primraryHexCode + fc4a1a + secondaryHexCode + f7b733 + + + + primraryHexCode + F2994A + secondaryHexCode + F2C94C + + + + primraryHexCode + f79d00 + secondaryHexCode + 64f38c + + + + primraryHexCode + FF5F6D + secondaryHexCode + FFC371 + + + + primraryHexCode + 4DA0B0 + secondaryHexCode + D39D38 + + + + primraryHexCode + FEAC5E + secondaryHexCode + C779D0 + + + + primraryHexCode + CC95C0 + secondaryHexCode + 7AA1D2 + + + + primraryHexCode + FF416C + secondaryHexCode + FF4B2B + + + + primraryHexCode + ff9966 + secondaryHexCode + ff5e62 + + + + primraryHexCode + ff4b1f + secondaryHexCode + ff9068 + + + + primraryHexCode + 34e89e + secondaryHexCode + 0f3443 + + + + primraryHexCode + 4facfe + secondaryHexCode + 78ffd6 + + + + diff --git a/Palette/App/Palette/Colour Plists/GreenColour.plist b/Palette/App/Palette/Colour Plists/GreenColour.plist new file mode 100644 index 0000000..deeb510 --- /dev/null +++ b/Palette/App/Palette/Colour Plists/GreenColour.plist @@ -0,0 +1,267 @@ + + + + + + + colourName + Aquamarine + hexCode + 7FFFD4 + + + + colourName + Army Green + hexCode + 454B1B + + + + colourName + Blue Green + hexCode + 088F8F + + + + colourName + Bright Green + hexCode + AAFF00 + + + + colourName + Cadet Blue + hexCode + 5F9EA0 + + + + colourName + Cadmium Green + hexCode + 097969 + + + + colourName + Celadon + hexCode + AFE1AF + + + + colourName + Chartreuse + hexCode + DFFF00 + + + + colourName + Citrine + hexCode + E4D00A + + + + colourName + Dark Green + hexCode + 023020 + + + + colourName + Emerald Green + hexCode + 50C878 + + + + colourName + Eucalyptus + hexCode + 5F8575 + + + + colourName + Fern Green + hexCode + 4F7942 + + + + colourName + Forest Green + hexCode + 228B22 + + + + colourName + Grass Green + hexCode + 7CFC00 + + + + colourName + Jung + hexCode + Green + + + + colourName + Kelly Green + hexCode + 4CBB17 + + + + colourName + Light Green + hexCode + 90EE90 + + + + colourName + Lime Green + hexCode + 32CD32 + + + + colourName + Lincoln Green + hexCode + 478778 + + + + colourName + Malachite + hexCode + 0BDA51 + + + + colourName + Mint Green + hexCode + 98FB98 + + + + colourName + Moss Green + hexCode + 8A9A5B + + + + colourName + Neon Green + hexCode + 0FFF50 + + + + colourName + Nyanza + hexCode + ECFFDC + + + + colourName + Olive Green + hexCode + 808000 + + + + colourName + Pastel Green + hexCode + C1E1C1 + + + + colourName + Pear + hexCode + C9CC3F + + + + colourName + Peridot + hexCode + B4C424 + + + + colourName + Pistachio + hexCode + 93C572 + + + + colourName + Robin Egg Blue + hexCode + 96DED1 + + + + colourName + Sage Green + hexCode + 8A9A5B + + + + colourName + Sea Green + hexCode + 2E8B57 + + + + colourName + Seafoam Green + hexCode + 9FE2BF + + + + colourName + Shamrock Green + hexCode + 009E60 + + + + colourName + Spring Green + hexCode + 00FF7F + + + + colourName + Teal + hexCode + 008080 + + + + + diff --git a/Palette/App/Palette/Colour Plists/GreyColour.plist b/Palette/App/Palette/Colour Plists/GreyColour.plist new file mode 100644 index 0000000..02cd99b --- /dev/null +++ b/Palette/App/Palette/Colour Plists/GreyColour.plist @@ -0,0 +1,112 @@ + + + + + + + colourName + Ash Gray + hexCode + B2BEB5 + + + + colourName + Blue Gray + hexCode + 7393B3 + + + + colourName + Charcoal + hexCode + 36454F + + + + colourName + Dark Gray + hexCode + A9A9A9 + + + + colourName + Glaucous + hexCode + 6082B6 + + + + colourName + Gray + hexCode + 808080 + + + + colourName + Gunmetal Gray + hexCode + 818589 + + + + colourName + Light Gray + hexCode + D3D3D3 + + + + colourName + Pewter + hexCode + 899499 + + + + colourName + Platinum + hexCode + E5E4E2 + + + + colourName + Sage Green + hexCode + 8A9A5B + + + + colourName + Silver + hexCode + C0C0C0 + + + + colourName + Slate Gray + hexCode + 708090 + + + + colourName + Smoke + hexCode + 848884 + + + + colourName + Steel Gray + hexCode + 71797E + + + + diff --git a/Palette/App/Palette/Colour Plists/MultiColour.plist b/Palette/App/Palette/Colour Plists/MultiColour.plist new file mode 100644 index 0000000..20ed18e --- /dev/null +++ b/Palette/App/Palette/Colour Plists/MultiColour.plist @@ -0,0 +1,1358 @@ + + + + + + + colourName + Air Force Blue + hexCode + 5D8AA8 + + + + colourName + Alice Blue + hexCode + F0F8FF + + + + colourName + Alizarin + hexCode + E32636 + + + + colourName + Amaranth + hexCode + FFBF00 + + + + colourName + Android Green + hexCode + A4C639 + + + + colourName + Apple Green + hexCode + 8DB600 + + + + colourName + Apricot + hexCode + FBCEB1 + + + + colourName + Aquamarine + hexCode + 7FFFD4 + + + + colourName + Army Green + hexCode + 4B5320 + + + + colourName + Arsenic + hexCode + 3B444B + + + + colourName + Arylide Yellow + hexCode + E9D66B + + + + colourName + Ash Grey + hexCode + B2BEB5 + + + + colourName + Asparagus + hexCode + 87A96B + + + + colourName + Atomic Tangerine + hexCode + FF9966 + + + + colourName + Auburn + hexCode + 6D351A + + + + colourName + Azure + hexCode + 007FFF + + + + colourName + Baby Blue + hexCode + 89CFF0 + + + + colourName + Baby Blue Eyes + hexCode + A1CAF1 + + + + colourName + Baby Pink + hexCode + F4C2C2 + + + + colourName + Banana Yellow + hexCode + FFD12A + + + + colourName + Battleship Grey + hexCode + 848482 + + + + colourName + Bazaar + hexCode + 98777B + + + + colourName + Beige + hexCode + F5F5DC + + + + colourName + Bistre + hexCode + 3D2B1F + + + + colourName + Black + hexCode + 000000 + + + + colourName + Bleu De France + hexCode + 318CE7 + + + + colourName + Blond + hexCode + FAF0BE + + + + colourName + Blue + hexCode + 0000FF + + + + colourName + Blush + hexCode + DE5D83 + + + + colourName + Bole + hexCode + 79443B + + + + colourName + Boston University Red + hexCode + CC0000 + + + + colourName + Brass + hexCode + B5A642 + + + + colourName + Bright Green + hexCode + 66FF00 + + + + colourName + Bright Lavender + hexCode + BF94E4 + + + + colourName + Bright Maroon + hexCode + C32148 + + + + colourName + Bright Pink + hexCode + FF007F + + + + colourName + Bright Turquoise + hexCode + 08E8DE + + + + colourName + Bright Ube + hexCode + D19FE8 + + + + colourName + British Racing Green + hexCode + 004225 + + + + colourName + Bronze + hexCode + CD7F32 + + + + colourName + Brown + hexCode + 964B00 + + + + colourName + Bubble Gum + hexCode + FFC1CC + + + + colourName + Bubbles + hexCode + E7FEFF + + + + colourName + Buff + hexCode + F0DC82 + + + + colourName + Burgundy + hexCode + 800020 + + + + colourName + Burlywood + hexCode + DEB887 + + + + colourName + Burnt Orange + hexCode + CC5500 + + + + colourName + Burnt Sienna + hexCode + E97451 + + + + colourName + Burnt Umber + hexCode + 8A3324 + + + + colourName + Byzantine + hexCode + BD33A4 + + + + colourName + Byzantium + hexCode + 702963 + + + + colourName + Cadet + hexCode + 536878 + + + + colourName + Cadmium Green + hexCode + 006B3C + + + + colourName + Cadmium Orange + hexCode + ED872D + + + + colourName + Cadmium Red + hexCode + E30022 + + + + colourName + Cambridge Blue + hexCode + A3C1AD + + + + colourName + Camouflage Green + hexCode + 78866B + + + + colourName + Canary Yellow + hexCode + FFEF00 + + + + colourName + Candy Apple Red + hexCode + FF0800 + + + + colourName + Cardinal + hexCode + C41E3A + + + + colourName + Caribbean Green + hexCode + 00CC99 + + + + colourName + Carmine + hexCode + 960018 + + + + colourName + Carolina Blue + hexCode + 99BADD + + + + colourName + Carrot Orange + hexCode + ED9121 + + + + colourName + Ceil + hexCode + 92A1CF + + + + colourName + Celadon + hexCode + ACE1AF + + + + colourName + Cerulean + hexCode + 007BA7 + + + + colourName + Cerulean Blue + hexCode + 2A52BE + + + + colourName + Chamoisee + hexCode + A0785A + + + + colourName + Champagne + hexCode + F7E7CE + + + + colourName + Charcoal + hexCode + 36454F + + + + colourName + Chartreuse + hexCode + DFFF00 + + + + colourName + Cherry + hexCode + DE3163 + + + + colourName + Cherry Blossom Pink + hexCode + FFB7C5 + + + + colourName + Chestnut + hexCode + CD5C5C + + + + colourName + Chocolate + hexCode + 7B3F00 + + + + colourName + Chrome Yellow + hexCode + FFA700 + + + + colourName + Cinereous + hexCode + 98817B + + + + colourName + Cinnabar + hexCode + E34234 + + + + colourName + Cinnamon + hexCode + D2691E + + + + colourName + Citrine + hexCode + E4D00A + + + + colourName + Classic Rose + hexCode + FBCCE7 + + + + colourName + Clover + hexCode + 00FF6F + + + + colourName + Cobalt + hexCode + 0047AB + + + + colourName + Columbia Blue + hexCode + 9BDDFF + + + + colourName + Cool Black + hexCode + 002E63 + + + + colourName + Cool Grey + hexCode + 8C92AC + + + + colourName + Copper + hexCode + B87333 + + + + colourName + Coquelicot + hexCode + FF3800 + + + + colourName + Coral + hexCode + FF7F50 + + + + colourName + Cordovan + hexCode + 893F45 + + + + colourName + Corn + hexCode + FBEC5D + + + + colourName + Cornell Red + hexCode + B31B1B + + + + colourName + Cornflower Blue + hexCode + 6495ED + + + + colourName + Cornsilk + hexCode + FFF8DC + + + + colourName + Cream + hexCode + FFFDD0 + + + + colourName + Crimson + hexCode + DC143C + + + + colourName + Cyan + hexCode + 00FFFF + + + + colourName + Daffodil + hexCode + FFFF31 + + + + colourName + Dandelion + hexCode + F0E130 + + + + colourName + Dark Blue + hexCode + 00008B + + + + colourName + Dark Brown + hexCode + 654321 + + + + colourName + Dark Byzantium + hexCode + 5D3954 + + + + colourName + Dark Candy Apple Red + hexCode + A40000 + + + + colourName + Dark Cerulean + hexCode + 08457E + + + + colourName + Dark Chestnut + hexCode + 986960 + + + + colourName + Dark Coral + hexCode + CD5B45 + + + + colourName + Dark Cyan + hexCode + 008B8B + + + + colourName + Dark Goldenrod + hexCode + B8860B + + + + colourName + Dark Green + hexCode + 013220 + + + + colourName + Dark Jungle Green + hexCode + 1A2421 + + + + colourName + Dark Khaki + hexCode + BDB76B + + + + colourName + Dark Lava + hexCode + 483C32 + + + + colourName + Dark Lavender + hexCode + 734F96 + + + + colourName + Dark Magenta + hexCode + 8B008B + + + + colourName + Dark Midnight Blue + hexCode + 003366 + + + + colourName + Dark Olive Green + hexCode + 556B2F + + + + colourName + Dark Orange + hexCode + FF8C00 + + + + colourName + Dark Pastel Blue + hexCode + 779ECB + + + + colourName + Dark Pastel Green + hexCode + 03C03C + + + + colourName + Dark Pastel Purple + hexCode + 966FD6 + + + + colourName + Dark Pastel Red + hexCode + C23B22 + + + + colourName + Dark Pink + hexCode + E75480 + + + + colourName + Dark Powder Blue + hexCode + 003399 + + + + colourName + Dark Raspberry + hexCode + 872657 + + + + colourName + Dark Salmon + hexCode + E9967A + + + + colourName + Dark Scarlet + hexCode + 560319 + + + + colourName + Dark Slate Gray + hexCode + 2F4F4F + + + + colourName + Dark Tan + hexCode + 918151 + + + + colourName + Dark Terra Cotta + hexCode + CC4E5C + + + + colourName + Davy'S Grey + hexCode + 555555 + + + + colourName + Desert + hexCode + C19A6B + + + + colourName + Dim Gray + hexCode + 696969 + + + + colourName + Duke Blue + hexCode + 00009C + + + + colourName + Eggplant + hexCode + 614051 + + + + colourName + Fawn + hexCode + E5AA70 + + + + colourName + Fire Engine Red + hexCode + CE1620 + + + + colourName + Flame + hexCode + E25822 + + + + colourName + Flavescent + hexCode + F7E98E + + + + colourName + Gamboge + hexCode + E49B0F + + + + colourName + Glaucous + hexCode + 6082B6 + + + + colourName + Golden Brown + hexCode + 996515 + + + + colourName + Goldenrod + hexCode + DAA520 + + + + colourName + Green + hexCode + 008000 + + + + colourName + Icterine + hexCode + FCF75E + + + + colourName + India Green + hexCode + 138808 + + + + colourName + Indian Yellow + hexCode + E3A857 + + + + colourName + Ivory + hexCode + FFFFF0 + + + + colourName + Jasper + hexCode + D73B3E + + + + colourName + Lavender + hexCode + B57EDC + + + + colourName + Lavender Blush + hexCode + FFF0F5 + + + + colourName + Lawn Green + hexCode + 7CFC00 + + + + colourName + Lime + hexCode + BFFF00 + + + + colourName + Mahogany + hexCode + C04000 + + + + colourName + Midnight Blue + hexCode + 191970 + + + + colourName + Mustard + hexCode + FFDB58 + + + + colourName + Ochre + hexCode + CC7722 + + + + colourName + Orange + hexCode + FF7F00 + + + + colourName + Pastel Blue + hexCode + AEC6CF + + + + colourName + Pastel Gray + hexCode + CFCFC4 + + + + colourName + Pastel Magenta + hexCode + F49AC2 + + + + colourName + Pastel Pink + hexCode + FFD1DC + + + + colourName + Pastel Red + hexCode + FF6961 + + + + colourName + Pastel Yellow + hexCode + FDFD96 + + + + colourName + Pear + hexCode + D1E231 + + + + colourName + Peridot + hexCode + E6E200 + + + + colourName + Pink + hexCode + FFC0CB + + + + colourName + Platinum + hexCode + E5E4E2 + + + + colourName + Portland Orange + hexCode + FF5A36 + + + + colourName + Pumpkin + hexCode + FF7518 + + + + colourName + Raspberry + hexCode + E30B5D + + + + colourName + Red + hexCode + FF0000 + + + + colourName + Rosewood + hexCode + 65000B + + + + colourName + Ruby + hexCode + E0115F + + + + colourName + Safety Orange + hexCode + FF6700 + + + + colourName + Salmon + hexCode + FF8C69 + + + + colourName + Sand Dune + hexCode + 967117 + + + + colourName + Sapphire + hexCode + 082567 + + + + colourName + Seashell + hexCode + FFF5EE + + + + colourName + Shadow + hexCode + 8A795D + + + + colourName + Sinopia + hexCode + CB410B + + + + colourName + Sky Magenta + hexCode + CF71AF + + + + colourName + Spring Bud + hexCode + A7FC00 + + + + colourName + Straw + hexCode + E4D96F + + + + colourName + Tangerine + hexCode + F28500 + + + + colourName + Terra Cotta + hexCode + E2725B + + + + colourName + Tropical Rain Forest + hexCode + 00755E + + + + colourName + Ultramarine + hexCode + 120A8F + + + + colourName + Vanilla + hexCode + F3E5AB + + + + colourName + Wheat + hexCode + F5DEB3 + + + + colourName + White Smoke + hexCode + F5F5F5 + + + + colourName + Yale Blue + hexCode + 0F4D92 + + + + colourName + Yellow + hexCode + FFFF00 + + + + diff --git a/Palette/App/Palette/Colour Plists/OrangeColour.plist b/Palette/App/Palette/Colour Plists/OrangeColour.plist new file mode 100644 index 0000000..45b470e --- /dev/null +++ b/Palette/App/Palette/Colour Plists/OrangeColour.plist @@ -0,0 +1,294 @@ + + + + + + + colourName + Amber + hexCode + FFBF00 + + + + colourName + Apricot + hexCode + FBCEB1 + + + + colourName + Bisque + hexCode + F2D2BD + + + + colourName + Bright Orange + hexCode + FFAC1C + + + + colourName + Bronze + hexCode + CD7F32 + + + + colourName + Buff + hexCode + DAA06D + + + + colourName + Burnt Orange + hexCode + CC5500 + + + + colourName + Burnt Sienna + hexCode + E97451 + + + + colourName + Butterscotch + hexCode + E3963E + + + + colourName + Cadmium Orange + hexCode + F28C28 + + + + colourName + Cinnamon + hexCode + D27D2D + + + + colourName + Copper + hexCode + B87333 + + + + colourName + Coral + hexCode + FF7F50 + + + + colourName + Dark Orange + hexCode + 8B4000 + + + + colourName + Desert + hexCode + FAD5A5 + + + + colourName + Gamboge + hexCode + E49B0F + + + + colourName + Golden Yellow + hexCode + FFC000 + + + + colourName + Goldenrod + hexCode + DAA520 + + + + colourName + Light Orange + hexCode + FFD580 + + + + colourName + Mahogany + hexCode + C04000 + + + + colourName + Mango + hexCode + F4BB44 + + + + colourName + Navajo White + hexCode + FFDEAD + + + + colourName + Neon Orange + hexCode + FF5F1F + + + + colourName + Ochre + hexCode + CC7722 + + + + colourName + Orange + hexCode + FFA500 + + + + colourName + Pastel Orange + hexCode + FAC898 + + + + colourName + Peach + hexCode + FFE5B4 + + + + colourName + Persimmon + hexCode + EC5800 + + + + colourName + Pink Orange + hexCode + F89880 + + + + colourName + Poppy + hexCode + E35335 + + + + colourName + Pumpkin Orange + hexCode + FF7518 + + + + colourName + Red Orange + hexCode + FF4433 + + + + colourName + + hexCode + + + + + colourName + Safety Orange + hexCode + FF5F15 + + + + colourName + Salmon + hexCode + FA8072 + + + + colourName + Seashell + hexCode + FFF5EE + + + + colourName + Sienna + hexCode + A0522D + + + + colourName + Sunset Orange + hexCode + FA5F55 + + + + colourName + Tangerine + hexCode + F08000 + + + + colourName + Terra Cotta + hexCode + E3735E + + + + colourName + Yellow Orange + hexCode + FFAA33 + + + + diff --git a/Palette/App/Palette/Colour Plists/PinkColour.plist b/Palette/App/Palette/Colour Plists/PinkColour.plist new file mode 100644 index 0000000..2dae29c --- /dev/null +++ b/Palette/App/Palette/Colour Plists/PinkColour.plist @@ -0,0 +1,231 @@ + + + + + + + colourName + Amaranth + hexCode + 9F2B68 + + + + colourName + Bisque + hexCode + F2D2BD + + + + colourName + Cerise + hexCode + DE3163 + + + + colourName + Claret + hexCode + 811331 + + + + colourName + Coral Pink + hexCode + F88379 + + + + colourName + Crimson + hexCode + DC143C + + + + colourName + Dark Pink + hexCode + AA336A + + + + colourName + Dusty Rose + hexCode + C9A9A6 + + + + colourName + Fuchsia + hexCode + FF00FF + + + + colourName + Hot Pink + hexCode + FF69B4 + + + + colourName + Light Pink + hexCode + FFB6C1 + + + + colourName + Magenta + hexCode + FF00FF + + + + colourName + Millennial Pink + hexCode + F3CFC6 + + + + colourName + Mulberry + hexCode + 770737 + + + + colourName + Neon Pink + hexCode + FF10F0 + + + + colourName + Orchid + hexCode + DA70D6 + + + + colourName + Pastel Pink + hexCode + F8C8DC + + + + colourName + Pastel Red + hexCode + FAA0A0 + + + + colourName + Pink + hexCode + FFC0CB + + + + colourName + Pink Orange + hexCode + F89880 + + + + colourName + Plum + hexCode + 673147 + + + + colourName + Puce + hexCode + A95C68 + + + + colourName + Raspberry + hexCode + E30B5C + + + + colourName + Red Purple + hexCode + 953553 + + + + colourName + Rose + hexCode + F33A6A + + + + colourName + Rose Gold + hexCode + E0BFB8 + + + + colourName + Rose Red + hexCode + C21E56 + + + + colourName + Ruby Red + hexCode + E0115F + + + + colourName + Salmon + hexCode + FA8072 + + + + colourName + Seashell + hexCode + FFF5EE + + + + colourName + Thistle + hexCode + D8BFD8 + + + + colourName + Watermelon Pink + hexCode + E37383 + + + + diff --git a/Palette/App/Palette/Colour Plists/PurpleColour.plist b/Palette/App/Palette/Colour Plists/PurpleColour.plist new file mode 100644 index 0000000..dbab690 --- /dev/null +++ b/Palette/App/Palette/Colour Plists/PurpleColour.plist @@ -0,0 +1,217 @@ + + + + + + + colourName + Amaranth + hexCode + 9F2B68 + + + + colourName + Bright Purple + hexCode + BF40BF + + + + colourName + Burgundy + hexCode + 800020 + + + + colourName + Byzantium + hexCode + 702963 + + + + colourName + Dark Pink + hexCode + AA336A + + + + colourName + Dark Purple + hexCode + 301934 + + + + colourName + Eggplant + hexCode + 483248 + + + + colourName + Iris + hexCode + 5D3FD3 + + + + colourName + Lavender + hexCode + E6E6FA + + + + colourName + Light Purple + hexCode + CBC3E3 + + + + colourName + Light Violet + hexCode + CF9FFF + + + + colourName + Lilac + hexCode + AA98A9 + + + + colourName + Mauve + hexCode + E0B0FF + + + + colourName + Mauve Taupe + hexCode + 915F6D + + + + colourName + Mulberry + hexCode + 770737 + + + + colourName + + hexCode + + + + + colourName + Orchid + hexCode + DA70D6 + + + + colourName + Pastel Purple + hexCode + C3B1E1 + + + + colourName + + hexCode + + + + + colourName + Periwinkle + hexCode + CCCCFF + + + + colourName + Plum + hexCode + 673147 + + + + colourName + Puce + hexCode + A95C68 + + + + colourName + Purple + hexCode + 800080 + + + + colourName + Quartz + hexCode + 51414F + + + + colourName + Red Purple + hexCode + 953553 + + + + colourName + Thistle + hexCode + D8BFD8 + + + + colourName + Tyrian Purple + hexCode + 630330 + + + + colourName + Violet + hexCode + 7F00FF + + + + colourName + Wine + hexCode + 722F37 + + + + colourName + Wisteria + hexCode + BDB5D5 + + + + diff --git a/Palette/App/Palette/Colour Plists/RedColour.plist b/Palette/App/Palette/Colour Plists/RedColour.plist new file mode 100644 index 0000000..35ec1e7 --- /dev/null +++ b/Palette/App/Palette/Colour Plists/RedColour.plist @@ -0,0 +1,266 @@ + + + + + + + colourName + Blood Red + hexCode + 880808 + + + + colourName + Brick Red + hexCode + AA4A44 + + + + colourName + Bright Red + hexCode + EE4B2B + + + + colourName + Burgundy + hexCode + 800020 + + + + colourName + Burnt Sienna + hexCode + E97451 + + + + colourName + Cadmium Red + hexCode + D22B2B + + + + colourName + Cardinal Red + hexCode + C41E3A + + + + colourName + Carmine + hexCode + D70040 + + + + colourName + Cerise + hexCode + DE3163 + + + + colourName + Coral Pink + hexCode + F88379 + + + + colourName + Crimson + hexCode + DC143C + + + + colourName + Dark Red + hexCode + 8B0000 + + + + colourName + Falu Red + hexCode + 7B1818 + + + + colourName + Garnet + hexCode + 9A2A2A + + + + colourName + Mahogany + hexCode + C04000 + + + + colourName + Maroon + hexCode + 800000 + + + + colourName + Marsala + hexCode + 986868 + + + + colourName + Mulberry + hexCode + 770737 + + + + colourName + Neon Red + hexCode + FF3131 + + + + colourName + Oxblood + hexCode + 4A0404 + + + + colourName + Poppy + hexCode + E35335 + + + + colourName + Raspberry + hexCode + E30B5C + + + + colourName + Red + hexCode + FF0000 + + + + colourName + Red Brown + hexCode + A52A2A + + + + colourName + Red Ochre + hexCode + 913831 + + + + colourName + Red Orange + hexCode + FF4433 + + + + colourName + Rose Red + hexCode + C21E56 + + + + colourName + Ruby Red + hexCode + E0115F + + + + colourName + Salmon + hexCode + FA8072 + + + + colourName + Scarlet + hexCode + FF2400 + + + + colourName + Sunset Orange + hexCode + FA5F55 + + + + colourName + + hexCode + + + + + colourName + Terra Cotta + hexCode + E3735E + + + + colourName + Tuscan Red + hexCode + 7C3030 + + + + colourName + + hexCode + + + + + colourName + Venetian Red + hexCode + A42A04 + + + + colourName + Vermillion + hexCode + E34234 + + + + diff --git a/Palette/App/Palette/Colour Plists/SystemColour.plist b/Palette/App/Palette/Colour Plists/SystemColour.plist new file mode 100644 index 0000000..cfbdc44 --- /dev/null +++ b/Palette/App/Palette/Colour Plists/SystemColour.plist @@ -0,0 +1,70 @@ + + + + + + + colourName + Blue + hexCode + 027AFF + + + + colourName + Green + hexCode + 35C759 + + + + colourName + Indigo + hexCode + 5957D5 + + + + colourName + Orange + hexCode + FF9500 + + + + colourName + Pink + hexCode + FF2E55 + + + + colourName + Purple + hexCode + AF52DE + + + + colourName + Red + hexCode + FF3C2F + + + + colourName + Teal + hexCode + 5BC9FA + + + + colourName + Yellow + hexCode + FFCC01 + + + + diff --git a/Palette/App/Palette/Colour Plists/WhiteColour.plist b/Palette/App/Palette/Colour Plists/WhiteColour.plist new file mode 100644 index 0000000..246eecf --- /dev/null +++ b/Palette/App/Palette/Colour Plists/WhiteColour.plist @@ -0,0 +1,105 @@ + + + + + + + colourName + Alabaster + hexCode + EDEADE + + + + colourName + Beige + hexCode + F5F5DC + + + + colourName + Bone White + hexCode + F9F6EE + + + + colourName + Cornsilk + hexCode + FFF8DC + + + + colourName + Cream + hexCode + FFFDD0 + + + + colourName + Eggshell + hexCode + F0EAD6 + + + + colourName + Ivory + hexCode + FFFFF0 + + + + colourName + Linen + hexCode + E9DCC9 + + + + colourName + Off White + hexCode + FAF9F6 + + + + colourName + Parchment + hexCode + FCF5E5 + + + + colourName + Peach + hexCode + FFE5B4 + + + + colourName + Pearl + hexCode + E2DFD2 + + + + colourName + Seashell + hexCode + FFF5EE + + + + colourName + Vanilla + hexCode + F3E5AB + + + + diff --git a/Palette/App/Palette/Colour Plists/YellowColour.plist b/Palette/App/Palette/Colour Plists/YellowColour.plist new file mode 100644 index 0000000..33debc5 --- /dev/null +++ b/Palette/App/Palette/Colour Plists/YellowColour.plist @@ -0,0 +1,266 @@ + + + + + + + colourName + Almond + hexCode + EADDCA + + + + colourName + Amber + hexCode + FFBF00 + + + + colourName + Apricot + hexCode + FBCEB1 + + + + colourName + Beige + hexCode + F5F5DC + + + + colourName + Brass + hexCode + E1C16E + + + + colourName + Bright Yellow + hexCode + FFEA00 + + + + colourName + Cadmium Yellow + hexCode + FDDA0D + + + + colourName + Canary Yellow + hexCode + FFFF8F + + + + colourName + Chartreuse + hexCode + DFFF00 + + + + colourName + Citrine + hexCode + E4D00A + + + + colourName + Cornsilk + hexCode + FFF8DC + + + + colourName + Cream + hexCode + FFFDD0 + + + + colourName + Dark Yellow + hexCode + 8B8000 + + + + colourName + Desert + hexCode + FAD5A5 + + + + colourName + Ecru + hexCode + C2B280 + + + + colourName + Flax + hexCode + EEDC82 + + + + colourName + Gamboge + hexCode + E49B0F + + + + colourName + Gold + hexCode + FFD700 + + + + colourName + Golden Yellow + hexCode + FFC000 + + + + colourName + Goldenrod + hexCode + DAA520 + + + + colourName + Icterine + hexCode + FCF55F + + + + colourName + Ivory + hexCode + FFFFF0 + + + + colourName + Jasmine + hexCode + F8DE7E + + + + colourName + Khaki + hexCode + F0E68C + + + + colourName + Lemon Yellow + hexCode + FAFA33 + + + + colourName + Maize + hexCode + FBEC5D + + + + colourName + Mango + hexCode + F4BB44 + + + + colourName + Mustard Yellow + hexCode + FFDB58 + + + + colourName + Naples Yellow + hexCode + FADA5E + + + + colourName + Navajo White + hexCode + FFDEAD + + + + colourName + Pastel Yellow + hexCode + FFFAA0 + + + + colourName + Saffron + hexCode + F4C430 + + + + colourName + Vanilla + hexCode + F3E5AB + + + + colourName + Vegas Gold + hexCode + C4B454 + + + + colourName + Wheat + hexCode + F5DEB3 + + + + colourName + Yellow + hexCode + FFFF00 + + + + colourName + Yellow Orange + hexCode + FFAA33 + + + + diff --git a/Palette/App/Palette/Colours/BlackColourViewController.h b/Palette/App/Palette/Colours/BlackColourViewController.h new file mode 100644 index 0000000..175cfaf --- /dev/null +++ b/Palette/App/Palette/Colours/BlackColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface BlackColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/BlackColourViewController.m b/Palette/App/Palette/Colours/BlackColourViewController.m new file mode 100644 index 0000000..11e88bc --- /dev/null +++ b/Palette/App/Palette/Colours/BlackColourViewController.m @@ -0,0 +1,236 @@ +#import "BlackColourViewController.h" + +@implementation BlackColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"BlackColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Colours/BlueColourViewController.h b/Palette/App/Palette/Colours/BlueColourViewController.h new file mode 100644 index 0000000..38c62e8 --- /dev/null +++ b/Palette/App/Palette/Colours/BlueColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface BlueColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/BlueColourViewController.m b/Palette/App/Palette/Colours/BlueColourViewController.m new file mode 100644 index 0000000..f91ff66 --- /dev/null +++ b/Palette/App/Palette/Colours/BlueColourViewController.m @@ -0,0 +1,236 @@ +#import "BlueColourViewController.h" + +@implementation BlueColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"BlueColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Colours/BrownColourViewController.h b/Palette/App/Palette/Colours/BrownColourViewController.h new file mode 100644 index 0000000..5e704d6 --- /dev/null +++ b/Palette/App/Palette/Colours/BrownColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface BrownColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/BrownColourViewController.m b/Palette/App/Palette/Colours/BrownColourViewController.m new file mode 100644 index 0000000..73a78c9 --- /dev/null +++ b/Palette/App/Palette/Colours/BrownColourViewController.m @@ -0,0 +1,236 @@ +#import "BrownColourViewController.h" + +@implementation BrownColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"BrownColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Colours/ColourSectionViewController.h b/Palette/App/Palette/Colours/ColourSectionViewController.h new file mode 100644 index 0000000..07d59ef --- /dev/null +++ b/Palette/App/Palette/Colours/ColourSectionViewController.h @@ -0,0 +1,23 @@ +#import +#import "TYTabPagerBar.h" +#import "TYPagerController.h" +#import "SystemColourViewController.h" +#import "MultiColourViewController.h" +#import "BlackColourViewController.h" +#import "BlueColourViewController.h" +#import "BrownColourViewController.h" +#import "GreyColourViewController.h" +#import "GreenColourViewController.h" +#import "OrangeColourViewController.h" +#import "PinkColourViewController.h" +#import "PurpleColourViewController.h" +#import "RedColourViewController.h" +#import "WhiteColourViewController.h" +#import "YellowColourViewController.h" + +@interface ColourSectionViewController : UIViewController +@property (nonatomic, retain) TYTabPagerBar *tabBar; +@property (nonatomic, retain) TYPagerController *pagerController; +@property (nonatomic, strong) NSArray *datas; +@end + diff --git a/Palette/App/Palette/Colours/ColourSectionViewController.m b/Palette/App/Palette/Colours/ColourSectionViewController.m new file mode 100644 index 0000000..5585742 --- /dev/null +++ b/Palette/App/Palette/Colours/ColourSectionViewController.m @@ -0,0 +1,148 @@ +#import "ColourSectionViewController.h" + +@implementation ColourSectionViewController + +-(void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + self.navigationItem.title = @"Colours"; + self.navigationController.navigationBar.prefersLargeTitles = NO; + +} + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + + [self addTabPageBar]; + [self addPagerController]; + [self loadData]; +} + + +- (void)addTabPageBar { + _tabBar = [[TYTabPagerBar alloc]init]; + _tabBar.backgroundColor = UIColor.clearColor; + _tabBar.layout.barStyle = TYPagerBarStyleCoverView; + _tabBar.layout.progressColor = [UIColor colorNamed:@"Accent"]; + _tabBar.layout.selectedTextColor = UIColor.whiteColor; + _tabBar.layout.normalTextColor = UIColor.labelColor; + _tabBar.layout.adjustContentCellsCenter = YES; + _tabBar.dataSource = self; + _tabBar.delegate = self; + [_tabBar registerClass:[TYTabPagerBarCell class] forCellWithReuseIdentifier:[TYTabPagerBarCell cellIdentifier]]; + [self.view addSubview:_tabBar]; +} + + +- (void)addPagerController { + _pagerController = [[TYPagerController alloc]init]; + _pagerController.layout.prefetchItemCount = 1; + _pagerController.layout.addVisibleItemOnlyWhenScrollAnimatedEnd = YES; + _pagerController.dataSource = self; + _pagerController.delegate = self; + _pagerController.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self addChildViewController:_pagerController]; + [self.view addSubview:_pagerController.view]; +} + + +- (void)viewWillLayoutSubviews { + [super viewWillLayoutSubviews]; + _tabBar.frame = CGRectMake(0, CGRectGetMaxY(self.navigationController.navigationBar.frame) + 5, CGRectGetWidth(self.view.frame), 36); + _pagerController.view.frame = CGRectMake(0, CGRectGetMaxY(_tabBar.frame), CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)- CGRectGetMaxY(_tabBar.frame)); +} + + +- (void)loadData { + _datas = [[NSArray alloc] initWithObjects:@"System Colour", @"Multi Colour", @"Shades of Black", @"Shades of Blue", @"Shades of Brown", @"Shades of Grey", @"Shades of Green", @"Shades of Orange", @"Shades of Pink", @"Shades of Purple", @"Shades of Red", @"Shades of White", @"Shades of Yellow", nil]; + [self reloadData]; +} + + +- (NSInteger)numberOfItemsInPagerTabBar { + return _datas.count; +} + + +- (UICollectionViewCell *)pagerTabBar:(TYTabPagerBar *)pagerTabBar cellForItemAtIndex:(NSInteger)index { + UICollectionViewCell *cell = [pagerTabBar dequeueReusableCellWithReuseIdentifier:[TYTabPagerBarCell cellIdentifier] forIndex:index]; + cell.titleLabel.text = _datas[index]; + return cell; +} + + +- (CGFloat)pagerTabBar:(TYTabPagerBar *)pagerTabBar widthForItemAtIndex:(NSInteger)index { + NSString *title = _datas[index]; + return [pagerTabBar cellWidthForTitle:title]; +} + +- (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar didSelectItemAtIndex:(NSInteger)index { + [_pagerController scrollToControllerAtIndex:index animate:YES]; +} + + +- (NSInteger)numberOfControllersInPagerController { + return _datas.count; +} + + +- (UIViewController *)pagerController:(TYPagerController *)pagerController controllerForIndex:(NSInteger)index prefetching:(BOOL)prefetching { + if (index == 0) { + SystemColourViewController *systemVC = [[SystemColourViewController alloc]init]; + return systemVC; + } else if (index == 1) { + MultiColourViewController *multiVC = [[MultiColourViewController alloc] init]; + return multiVC; + } else if (index == 2) { + BlackColourViewController *customVC = [[BlackColourViewController alloc] init]; + return customVC; + } else if (index == 3) { + BlueColourViewController *customVC = [[BlueColourViewController alloc] init]; + return customVC; + } else if (index == 4) { + BrownColourViewController *customVC = [[BrownColourViewController alloc] init]; + return customVC; + } else if (index == 5) { + GreyColourViewController *customVC = [[GreyColourViewController alloc] init]; + return customVC; + } else if (index == 6) { + GreenColourViewController *customVC = [[GreenColourViewController alloc] init]; + return customVC; + } else if (index == 7) { + OrangeColourViewController *customVC = [[OrangeColourViewController alloc] init]; + return customVC; + } else if (index == 8) { + PinkColourViewController *customVC = [[PinkColourViewController alloc] init]; + return customVC; + } else if (index == 9) { + PurpleColourViewController *customVC = [[PurpleColourViewController alloc] init]; + return customVC; + } else if (index == 10) { + RedColourViewController *customVC = [[RedColourViewController alloc] init]; + return customVC; + } else if (index == 11) { + WhiteColourViewController *customVC = [[WhiteColourViewController alloc] init]; + return customVC; + } else { + YellowColourViewController *customVC = [[YellowColourViewController alloc] init]; + return customVC; + } +} + + +- (void)pagerController:(TYPagerController *)pagerController transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated { + [_tabBar scrollToItemFromIndex:fromIndex toIndex:toIndex animate:animated]; +} + +-(void)pagerController:(TYPagerController *)pagerController transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress { + [_tabBar scrollToItemFromIndex:fromIndex toIndex:toIndex progress:progress]; +} + +- (void)reloadData { + [_tabBar reloadData]; + [_pagerController reloadData]; +} + + +@end diff --git a/Palette/App/Palette/Colours/GreenColourViewController.h b/Palette/App/Palette/Colours/GreenColourViewController.h new file mode 100644 index 0000000..840e17a --- /dev/null +++ b/Palette/App/Palette/Colours/GreenColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface GreenColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/GreenColourViewController.m b/Palette/App/Palette/Colours/GreenColourViewController.m new file mode 100644 index 0000000..46590c8 --- /dev/null +++ b/Palette/App/Palette/Colours/GreenColourViewController.m @@ -0,0 +1,236 @@ +#import "GreenColourViewController.h" + +@implementation GreenColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"GreenColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Colours/GreyColourViewController.h b/Palette/App/Palette/Colours/GreyColourViewController.h new file mode 100644 index 0000000..f3d7a63 --- /dev/null +++ b/Palette/App/Palette/Colours/GreyColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface GreyColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/GreyColourViewController.m b/Palette/App/Palette/Colours/GreyColourViewController.m new file mode 100644 index 0000000..2b24ca5 --- /dev/null +++ b/Palette/App/Palette/Colours/GreyColourViewController.m @@ -0,0 +1,236 @@ +#import "GreyColourViewController.h" + +@implementation GreyColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"GreyColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Colours/MultiColourViewController.h b/Palette/App/Palette/Colours/MultiColourViewController.h new file mode 100644 index 0000000..1f35566 --- /dev/null +++ b/Palette/App/Palette/Colours/MultiColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface MultiColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/MultiColourViewController.m b/Palette/App/Palette/Colours/MultiColourViewController.m new file mode 100644 index 0000000..b0c141d --- /dev/null +++ b/Palette/App/Palette/Colours/MultiColourViewController.m @@ -0,0 +1,235 @@ +#import "MultiColourViewController.h" + +@implementation MultiColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"MultiColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} +@end diff --git a/Palette/App/Palette/Colours/OrangeColourViewController.h b/Palette/App/Palette/Colours/OrangeColourViewController.h new file mode 100644 index 0000000..c75c83d --- /dev/null +++ b/Palette/App/Palette/Colours/OrangeColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface OrangeColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/OrangeColourViewController.m b/Palette/App/Palette/Colours/OrangeColourViewController.m new file mode 100644 index 0000000..eceba0c --- /dev/null +++ b/Palette/App/Palette/Colours/OrangeColourViewController.m @@ -0,0 +1,236 @@ +#import "OrangeColourViewController.h" + +@implementation OrangeColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"OrangeColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Colours/PinkColourViewController.h b/Palette/App/Palette/Colours/PinkColourViewController.h new file mode 100644 index 0000000..c7c0038 --- /dev/null +++ b/Palette/App/Palette/Colours/PinkColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface PinkColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/PinkColourViewController.m b/Palette/App/Palette/Colours/PinkColourViewController.m new file mode 100644 index 0000000..f9a7536 --- /dev/null +++ b/Palette/App/Palette/Colours/PinkColourViewController.m @@ -0,0 +1,236 @@ +#import "PinkColourViewController.h" + +@implementation PinkColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"PinkColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Colours/PurpleColourViewController.h b/Palette/App/Palette/Colours/PurpleColourViewController.h new file mode 100644 index 0000000..677e87e --- /dev/null +++ b/Palette/App/Palette/Colours/PurpleColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface PurpleColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/PurpleColourViewController.m b/Palette/App/Palette/Colours/PurpleColourViewController.m new file mode 100644 index 0000000..da763dc --- /dev/null +++ b/Palette/App/Palette/Colours/PurpleColourViewController.m @@ -0,0 +1,236 @@ +#import "PurpleColourViewController.h" + +@implementation PurpleColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"PurpleColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Colours/RedColourViewController.h b/Palette/App/Palette/Colours/RedColourViewController.h new file mode 100644 index 0000000..010aa59 --- /dev/null +++ b/Palette/App/Palette/Colours/RedColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface RedColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/RedColourViewController.m b/Palette/App/Palette/Colours/RedColourViewController.m new file mode 100644 index 0000000..98c7cef --- /dev/null +++ b/Palette/App/Palette/Colours/RedColourViewController.m @@ -0,0 +1,236 @@ +#import "RedColourViewController.h" + +@implementation RedColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"RedColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Colours/SystemColourViewController.h b/Palette/App/Palette/Colours/SystemColourViewController.h new file mode 100644 index 0000000..8115b7b --- /dev/null +++ b/Palette/App/Palette/Colours/SystemColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface SystemColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/SystemColourViewController.m b/Palette/App/Palette/Colours/SystemColourViewController.m new file mode 100644 index 0000000..b6cf481 --- /dev/null +++ b/Palette/App/Palette/Colours/SystemColourViewController.m @@ -0,0 +1,236 @@ +#import "SystemColourViewController.h" + +@implementation SystemColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"SystemColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Colours/WhiteColourViewController.h b/Palette/App/Palette/Colours/WhiteColourViewController.h new file mode 100644 index 0000000..0dffba9 --- /dev/null +++ b/Palette/App/Palette/Colours/WhiteColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface WhiteColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/WhiteColourViewController.m b/Palette/App/Palette/Colours/WhiteColourViewController.m new file mode 100644 index 0000000..0929bd8 --- /dev/null +++ b/Palette/App/Palette/Colours/WhiteColourViewController.m @@ -0,0 +1,236 @@ +#import "WhiteColourViewController.h" + +@implementation WhiteColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"WhiteColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Colours/YellowColourViewController.h b/Palette/App/Palette/Colours/YellowColourViewController.h new file mode 100644 index 0000000..8d4cb4e --- /dev/null +++ b/Palette/App/Palette/Colours/YellowColourViewController.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" +#import "ColourCell.h" +#import "FCAlertView.h" +#import "AddCollectionViewController.h" + +@interface YellowColourViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Colours/YellowColourViewController.m b/Palette/App/Palette/Colours/YellowColourViewController.m new file mode 100644 index 0000000..aa41a36 --- /dev/null +++ b/Palette/App/Palette/Colours/YellowColourViewController.m @@ -0,0 +1,236 @@ +#import "YellowColourViewController.h" + +@implementation YellowColourViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + [self layoutTableView]; + +} + + +-(void)layoutTableView { + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"YellowColour" ofType: @"plist"]]; + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = (NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"colourName"]; + cell.hexLabel.text = [NSString stringWithFormat:@"HEX #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + [self presentViewController:collectionVC animated:YES completion:nil]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/Palette/App/Palette/Constraints/ConstraintExtension.h b/Palette/App/Palette/Constraints/ConstraintExtension.h new file mode 100644 index 0000000..e90ec61 --- /dev/null +++ b/Palette/App/Palette/Constraints/ConstraintExtension.h @@ -0,0 +1,20 @@ +#import + +@interface UIView (extension) + +-(void)top:(nullable NSLayoutAnchor *)top leading:(nullable NSLayoutAnchor *)leading bottom:(nullable NSLayoutAnchor *)bottom trailing:(nullable NSLayoutAnchor *)trailing padding:(UIEdgeInsets)insets; +-(void)top:(nullable NSLayoutAnchor *)top padding:(CGFloat)size; +-(void)leading:(nullable NSLayoutAnchor *)leading padding:(CGFloat)size; +-(void)trailing:(nullable NSLayoutAnchor *)trailing padding:(CGFloat)size; +-(void)bottom:(nullable NSLayoutAnchor *)bottom padding:(CGFloat)size; +-(void)size:(CGSize)size; +-(void)width:(CGFloat)size; +-(void)height:(CGFloat)size; +-(void)x:(nullable NSLayoutAnchor *)centerX; +-(void)y:(nullable NSLayoutAnchor *)centerY; +-(void)x:(nullable NSLayoutAnchor *)centerX padding:(CGFloat)size; +-(void)y:(nullable NSLayoutAnchor *)centerY padding:(CGFloat)size; +-(void)x:(nullable NSLayoutAnchor *)centerX y:(nullable NSLayoutAnchor *)centerY; +-(void)fill; + +@end diff --git a/Palette/App/Palette/Constraints/ConstraintExtension.m b/Palette/App/Palette/Constraints/ConstraintExtension.m new file mode 100644 index 0000000..cbdb804 --- /dev/null +++ b/Palette/App/Palette/Constraints/ConstraintExtension.m @@ -0,0 +1,128 @@ +#import "ConstraintExtension.h" + +@implementation UIView (extension) + +-(void)top:(nullable NSLayoutAnchor *)top leading:(nullable NSLayoutAnchor *)leading bottom:(nullable NSLayoutAnchor *)bottom trailing:(nullable NSLayoutAnchor *)trailing padding:(UIEdgeInsets)insets { + + self.translatesAutoresizingMaskIntoConstraints = NO; + + if (top) { + [self.topAnchor constraintEqualToAnchor:top constant:insets.top].active = YES; + } + + if (leading) { + [self.leadingAnchor constraintEqualToAnchor:leading constant:insets.left].active = YES; + } + + if (trailing) { + [self.trailingAnchor constraintEqualToAnchor:trailing constant:insets.right].active = YES; + } + + if (bottom) { + [self.bottomAnchor constraintEqualToAnchor:bottom constant:insets.bottom].active = YES; + } + +} + + +-(void)top:(nullable NSLayoutAnchor *)top padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (top) { + [self.topAnchor constraintEqualToAnchor:top constant:size].active = YES; + } +} + + +-(void)leading:(nullable NSLayoutAnchor *)leading padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (leading) { + [self.leadingAnchor constraintEqualToAnchor:leading constant:size].active = YES; + } +} + + +-(void)trailing:(nullable NSLayoutAnchor *)trailing padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (trailing) { + [self.trailingAnchor constraintEqualToAnchor:trailing constant:size].active = YES; + } +} + + +-(void)bottom:(nullable NSLayoutAnchor *)bottom padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (bottom) { + [self.bottomAnchor constraintEqualToAnchor:bottom constant:size].active = YES; + } +} + + +-(void)size:(CGSize)size { + + self.translatesAutoresizingMaskIntoConstraints = NO; + + if (size.width != 0) { + [self.widthAnchor constraintEqualToConstant:size.width].active = YES; + } + + if (size.height != 0) { + [self.heightAnchor constraintEqualToConstant:size.height].active = YES; + } + +} + + +-(void)width:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.widthAnchor constraintEqualToConstant:size].active = YES; +} + + +-(void)height:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.heightAnchor constraintEqualToConstant:size].active = YES; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX y:(nullable NSLayoutAnchor *)centerY { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX].active = true; + [[self centerYAnchor] constraintEqualToAnchor:centerY].active = true; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX].active = true; +} + + +-(void)y:(nullable NSLayoutAnchor *)centerY { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerYAnchor] constraintEqualToAnchor:centerY].active = true; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX constant:size].active = true; +} + + +-(void)y:(nullable NSLayoutAnchor *)centerY padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerYAnchor] constraintEqualToAnchor:centerY constant:size].active = true; +} + + +-(void)fill { + + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.topAnchor constraintEqualToAnchor:self.superview.topAnchor].active = YES; + [self.leadingAnchor constraintEqualToAnchor:self.superview.leadingAnchor].active = YES; + [self.trailingAnchor constraintEqualToAnchor:self.superview.trailingAnchor].active = YES; + [self.bottomAnchor constraintEqualToAnchor:self.superview.bottomAnchor].active = YES; + +} + +@end diff --git a/Palette/App/Palette/Constraints/Marcos.h b/Palette/App/Palette/Constraints/Marcos.h new file mode 100644 index 0000000..4078b96 --- /dev/null +++ b/Palette/App/Palette/Constraints/Marcos.h @@ -0,0 +1,2 @@ +#define iPhone_XR_XS_11Pro ([[UIScreen mainScreen] bounds].size.height == 896) // iPhone XR, XS Max, 11 Pro Max +#define iPhone_12_Pro_Max ([[UIScreen mainScreen] bounds].size.height == 926) // iPhone 12 Pro Max \ No newline at end of file diff --git a/Palette/App/Palette/FavouriteViewController.h b/Palette/App/Palette/FavouriteViewController.h new file mode 100644 index 0000000..127f594 --- /dev/null +++ b/Palette/App/Palette/FavouriteViewController.h @@ -0,0 +1,7 @@ +#import +#import "ColourCell.h" + +@interface FavouriteViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@end + diff --git a/Palette/App/Palette/FavouriteViewController.m b/Palette/App/Palette/FavouriteViewController.m new file mode 100644 index 0000000..0e0848b --- /dev/null +++ b/Palette/App/Palette/FavouriteViewController.m @@ -0,0 +1,138 @@ +#import "FavouriteViewController.h" + +static NSMutableDictionary *mutableDict; +static NSMutableArray *allDataArray; + + static void deleteDataForID(NSString *idToRemove){ + + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Favourites.plist", aDocumentsDirectory]; + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:prefPath]; + mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [mutableDict removeObjectForKey:idToRemove]; + [mutableDict writeToFile:prefPath atomically:YES]; + +} + + +@implementation FavouriteViewController + + +-(void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + self.navigationItem.title = @"Themes"; + self.navigationController.navigationBar.prefersLargeTitles = YES; + + UIBarButtonItem *createButton = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"folder.fill.badge.plus"] style:UIBarButtonItemStylePlain target:self action:@selector(createThemeFolder)]; + self.navigationItem.rightBarButtonItem = createButton; + +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Favourites.plist", aDocumentsDirectory]; + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:prefPath]; + mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + allDataArray = [NSMutableArray new]; + for(NSString *key in mutableDict){ + [allDataArray addObject:mutableDict[key]]; + } + + NSLog(@"%@",allDataArray); + + [self layoutTableView]; +} + + +-(void)layoutTableView { + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return allDataArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + + cell.nameLabel.text = allDataArray[indexPath.row][@"BackgroundColour"]; + + NSData *colorData = allDataArray[indexPath.row][@"Icon Colour"]; + UIColor *testColour = [NSKeyedUnarchiver unarchiveObjectWithData:colorData]; + + cell.colourView.backgroundColor = testColour; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 90; +} + + +-(void)deleteButtonTappedForCell:(UITableViewCell *)cell { + NSIndexPath *indexPath = [self.tableView indexPathForCell:cell]; + + deleteDataForID(allDataArray[indexPath.row][@"id"]); +} + + +-(void)createThemeFolder { + + + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/Favourites.plist", aDocumentsDirectory]; + + + UIColor *testColour = UIColor.blueColor; + + NSData *colorData = [NSKeyedArchiver archivedDataWithRootObject:testColour]; + + //long long savedStateCount = (long long)([[NSDate date] timeIntervalSince1970] * 1000.0); + NSString *withID = [NSString stringWithFormat:@"%lld", (long long)([[NSDate date] timeIntervalSince1970] * 1000.0)]; + NSDictionary *data = @{@"id" : withID, @"Icon Colour" : colorData, @"BackgroundColour" : @"Cool", @"Icon Size" : @"sup"}; + [mutableDict setValue:data forKey:withID]; + [mutableDict writeToFile:prefPath atomically:YES]; + + + //deleteDataForID(allDataArray[0][@"id"]); + + +} + + +@end diff --git a/Palette/App/Palette/Gradients/GradientsViewController.h b/Palette/App/Palette/Gradients/GradientsViewController.h new file mode 100644 index 0000000..0953e97 --- /dev/null +++ b/Palette/App/Palette/Gradients/GradientsViewController.h @@ -0,0 +1,10 @@ +#import +#import "ConstraintExtension.h" +#import "GradientCell.h" +#import "FCAlertView.h" + +@interface GradientsViewController : UIViewController +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSArray *colourArray; +@end + diff --git a/Palette/App/Palette/Gradients/GradientsViewController.m b/Palette/App/Palette/Gradients/GradientsViewController.m new file mode 100644 index 0000000..23cd140 --- /dev/null +++ b/Palette/App/Palette/Gradients/GradientsViewController.m @@ -0,0 +1,231 @@ +#import "GradientsViewController.h" + +@implementation GradientsViewController + +-(void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + self.navigationItem.title = @"Gradients"; + self.navigationController.navigationBar.prefersLargeTitles = YES; + +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + + self.colourArray = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource: @"GradientColour" ofType: @"plist"]]; + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[GradientCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.view addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.colourArray.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + GradientCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + UIColor *primraryColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"primraryHexCode"]]; + UIColor *secondaryColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"secondaryHexCode"]]; + + cell.gradient.colors = @[(id)primraryColour.CGColor, (id)secondaryColour.CGColor]; + + cell.firstPreview.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"primraryHexCode"]]; + cell.secondPreview.backgroundColor = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"secondaryHexCode"]]; + cell.firstLabel.text = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"primraryHexCode"]]; + cell.secondLabel.text = [NSString stringWithFormat:@"#%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"secondaryHexCode"]]; + + return cell; + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat width = self.view.frame.size.width /2 -15; + return CGSizeMake(width, width); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,10,0,10); // top, left, bottom, right +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *firstColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"primraryHexCode"]]; + + const CGFloat *_components1 = CGColorGetComponents(firstColour.CGColor); + CGFloat red1 = _components1[0]; + CGFloat green1 = _components1[1]; + CGFloat blue1 = _components1[2]; + + NSString *redString1 = [NSString stringWithFormat:@"%d", (int) (red1 * 255.0)]; + NSString *greenString1 = [NSString stringWithFormat:@"%d", (int) (green1 * 255)]; + NSString *blueString1 = [NSString stringWithFormat:@"%d", (int) (blue1 * 255)]; + + + UIColor *secondColour = [self colorWithHexString:(NSString*)[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"secondaryHexCode"]]; + + const CGFloat *_components2 = CGColorGetComponents(secondColour.CGColor); + CGFloat red2 = _components2[0]; + CGFloat green2 = _components2[1]; + CGFloat blue2 = _components2[2]; + + NSString *redString2 = [NSString stringWithFormat:@"%d", (int) (red2 * 255.0)]; + NSString *greenString2 = [NSString stringWithFormat:@"%d", (int) (green2 * 255)]; + NSString *blueString2 = [NSString stringWithFormat:@"%d", (int) (blue2 * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"First Colour: #%@ \nSecond Colour: #%@",[[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"primraryHexCode"], [[self.colourArray objectAtIndex:indexPath.row] objectForKey:@"secondaryHexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The gradient colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"First Colour: rgb(%@, %@, %@) \nSecond Colour: rgb(%@, %@, %@)",redString1, greenString1, blueString1, redString2, greenString2, blueString2]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The gradient colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"First Colour: UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0) \nSecond Colour: UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString1, greenString1, blueString1, redString2, greenString2, blueString2]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The gradient colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"First Colour: Color(red: %@/255, green: %@/255, blue: %@/255) \nSecond Colour: Color(red: %@/255, green: %@/255, blue: %@/255)", redString1, greenString1, blueString1, redString2, greenString2, blueString2]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The gradient colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"First Colour: [UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00]; \nSecond Colour: [UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString1, greenString1, blueString1, redString2, greenString2, blueString2]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The gradient colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + + +- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath { + + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; + +} + + +- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath { + + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; + +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +@end diff --git a/Palette/App/Palette/Info.plist b/Palette/App/Palette/Info.plist new file mode 100644 index 0000000..865ebda --- /dev/null +++ b/Palette/App/Palette/Info.plist @@ -0,0 +1,66 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Palette/App/Palette/My Collection/MyCollectionViewController.h b/Palette/App/Palette/My Collection/MyCollectionViewController.h new file mode 100644 index 0000000..28cd730 --- /dev/null +++ b/Palette/App/Palette/My Collection/MyCollectionViewController.h @@ -0,0 +1,11 @@ +#import +#import "ColourCell.h" +#import "FCAlertView.h" +#import "ConstraintExtension.h" + +@interface MyCollectionViewController : UIViewController +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UITableView *tableView; +@end + diff --git a/Palette/App/Palette/My Collection/MyCollectionViewController.m b/Palette/App/Palette/My Collection/MyCollectionViewController.m new file mode 100644 index 0000000..6c6a7e3 --- /dev/null +++ b/Palette/App/Palette/My Collection/MyCollectionViewController.m @@ -0,0 +1,374 @@ +#import "MyCollectionViewController.h" + +static NSMutableDictionary *mutableDict; +static NSMutableArray *allDataArray; + +static void deleteDataForID(NSString *idToRemove){ + + //NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + //NSString *prefPath = [NSString stringWithFormat:@"%@/MyCollection.plist", aDocumentsDirectory]; + NSString *prefPath = @"/var/mobile/Library/Preferences/PaletteCollections.plist"; + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:prefPath]; + mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [mutableDict removeObjectForKey:idToRemove]; + [mutableDict writeToFile:prefPath atomically:YES]; + +} + +@implementation MyCollectionViewController + +-(void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + self.navigationItem.title = @"My Collection"; + self.navigationController.navigationBar.prefersLargeTitles = YES; + +} + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + + //NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + //NSString *prefPath = [NSString stringWithFormat:@"%@/MyCollection.plist", aDocumentsDirectory]; + NSString *prefPath = @"/var/mobile/Library/Preferences/PaletteCollections.plist"; + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:prefPath]; + mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + allDataArray = [NSMutableArray new]; + for(NSString *key in mutableDict){ + [allDataArray addObject:mutableDict[key]]; + } + + [self layoutTitleAndSubtitle]; + [self checkCollectionCount]; + [self layoutTableView]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveCollectionNotification:) name:@"NewCollectionNotification" object:nil]; +} + + +-(void)layoutTitleAndSubtitle { + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.font = [UIFont systemFontOfSize:24 weight:UIFontWeightHeavy]; + self.titleLabel.numberOfLines = 2; + self.titleLabel.text = @"No Collection"; + self.titleLabel.alpha = 0; + [self.view addSubview:self.titleLabel]; + + [self.titleLabel x:self.view.centerXAnchor y:self.view.centerYAnchor]; + [self.titleLabel leading:self.view.leadingAnchor padding:20]; + [self.titleLabel trailing:self.view.trailingAnchor padding:-20]; + + + self.subtitleLabel = [[UILabel alloc] init]; + self.subtitleLabel.textAlignment = NSTextAlignmentCenter; + self.subtitleLabel.textColor = UIColor.labelColor; + self.subtitleLabel.font = [UIFont systemFontOfSize:16]; + self.subtitleLabel.numberOfLines = 3; + self.subtitleLabel.text = @"Browse through some colours and add them to your collection"; + self.subtitleLabel.alpha = 0; + [self.view addSubview:self.subtitleLabel]; + + [self.subtitleLabel x:self.view.centerXAnchor]; + [self.subtitleLabel top:self.titleLabel.bottomAnchor padding:15]; + [self.subtitleLabel leading:self.view.leadingAnchor padding:20]; + [self.subtitleLabel trailing:self.view.trailingAnchor padding:-20]; +} + + +- (void)receiveCollectionNotification:(NSNotification *) notification { + + if ([[notification name] isEqualToString:@"NewCollectionNotification"]) { + [self refreshTableView]; + } + +} + + +-(void)checkCollectionCount { + + NSString *notifCnt = [NSString stringWithFormat:@"%ld", allDataArray.count]; + + if ([notifCnt isEqualToString:@"0"]) { + self.titleLabel.alpha = 1; + self.subtitleLabel.alpha = 1; + } else { + self.titleLabel.alpha = 0; + self.subtitleLabel.alpha = 0; + } +} + + +-(void)refreshTableView { + + //NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + //NSString *prefPath = [NSString stringWithFormat:@"%@/MyCollection.plist", aDocumentsDirectory]; + NSString *prefPath = @"/var/mobile/Library/Preferences/PaletteCollections.plist"; + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:prefPath]; + mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + allDataArray = [NSMutableArray new]; + for(NSString *key in mutableDict){ + [allDataArray addObject:mutableDict[key]]; + } + + [self.tableView reloadData]; + + [self performSelector:@selector(checkCollectionCount) withObject:nil afterDelay:0.2]; + +} + + +-(void)layoutTableView { + + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return allDataArray.count;; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + cell.colourView.backgroundColor = [self colorWithHexString:(NSString*)[[allDataArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + cell.nameLabel.text = allDataArray[indexPath.row][@"colourName"]; + cell.hexLabel.text = allDataArray[indexPath.row][@"hexCode"]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[allDataArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + cell.rgbLabel.text = [NSString stringWithFormat:@"RGB(%@, %@, %@)", redString, greenString, blueString]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 150; +} + + +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { + if (editingStyle == UITableViewCellEditingStyleDelete) { + deleteDataForID(allDataArray[indexPath.row][@"id"]); + [self refreshTableView]; + } +} + + +- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath { + + UIContextualAction *clearAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:nil handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) { + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + + deleteDataForID(allDataArray[indexPath.row][@"id"]); + [self refreshTableView]; + + [tableView setEditing:NO animated:YES]; + + completionHandler(YES); + }]; + + UIImage *transparentImage = [UIImage imageNamed:@"transparent"]; + UIImage *trashImage = [UIImage imageNamed:@"trash"]; + CGSize sacleSize = CGSizeMake(50, 50); + UIGraphicsBeginImageContextWithOptions(sacleSize, NO, 0.0); + [trashImage drawInRect:CGRectMake(0, 0, sacleSize.width, sacleSize.height)]; + UIImage * resizedTrashImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + clearAction.image = resizedTrashImage; + clearAction.backgroundColor = [UIColor colorWithPatternImage:transparentImage]; + + UISwipeActionsConfiguration *configuration = [UISwipeActionsConfiguration configurationWithActions:@[clearAction]]; + + return configuration; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + UIColor *selectedColour = [self colorWithHexString:(NSString*)[[allDataArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[[allDataArray objectAtIndex:indexPath.row] objectForKey:@"hexCode"]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + [self presentViewController:view animated:YES completion:nil]; + +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + FCAlertView *alert = [[FCAlertView alloc] init]; + [alert showAlertWithTitle:title withSubtitle:subtitle withCustomImage:nil withDoneButtonTitle:nil andButtons:nil]; + alert.alertBackgroundColor = [UIColor colorNamed:@"Alert"]; + alert.titleColor = UIColor.systemGreenColor; + alert.subTitleColor = UIColor.labelColor; + [alert makeAlertTypeSuccess]; + alert.blurBackground = YES; + alert.autoHideSeconds = 2; + alert.dismissOnOutsideTouch = YES; + alert.bounceAnimations = YES; + alert.animateAlertInFromTop = YES; + alert.animateAlertOutToBottom = YES; + alert.hideAllButtons = YES; +} + +@end + diff --git a/Palette/App/Palette/SectionTabs/TYPagerController.h b/Palette/App/Palette/SectionTabs/TYPagerController.h new file mode 100755 index 0000000..5e5be1d --- /dev/null +++ b/Palette/App/Palette/SectionTabs/TYPagerController.h @@ -0,0 +1,86 @@ +#import +#import "TYPagerViewLayout.h" + +NS_ASSUME_NONNULL_BEGIN + +@class TYPagerController; +@protocol TYPagerControllerDataSource + +// viewController's count in pagerController +- (NSInteger)numberOfControllersInPagerController; + +/* 1.viewController at index in pagerController + 2.if prefetching is YES,the controller is preload,not display. + 3.if controller will display,will call viewWillAppear. + 4.you can register && dequeue controller, usage like tableView + */ +- (UIViewController *)pagerController:(TYPagerController *)pagerController controllerForIndex:(NSInteger)index prefetching:(BOOL)prefetching; + +@end + +@protocol TYPagerControllerDelegate + +@optional + +// Display customization +// the same to viewWillAppear, also can use viewController's viewWillAppear +- (void)pagerController:(TYPagerController *)pagerController viewWillAppear:(UIViewController *)viewController forIndex:(NSInteger)index; +- (void)pagerController:(TYPagerController *)pagerController viewDidAppear:(UIViewController *)viewController forIndex:(NSInteger)index; + +// Disappear customization +// the same to viewWillDisappear, also can use viewController's viewWillDisappear +- (void)pagerController:(TYPagerController *)pagerController viewWillDisappear:(UIViewController *)viewController forIndex:(NSInteger)index; +- (void)pagerController:(TYPagerController *)pagerController viewDidDisappear:(UIViewController *)viewController forIndex:(NSInteger)index; + +// Transition animation customization + +- (void)pagerController:(TYPagerController *)pagerController transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated; + +- (void)pagerController:(TYPagerController *)pagerController transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress; + + +// ScrollViewDelegate + +- (void)pagerControllerDidScroll:(TYPagerController *)pagerController; +- (void)pagerControllerWillBeginScrolling:(TYPagerController *)pagerController animate:(BOOL)animate; +- (void)pagerControllerDidEndScrolling:(TYPagerController *)pagerController animate:(BOOL)animate; + +@end + +@interface TYPagerController : UIViewController + +@property (nonatomic, weak, nullable) id dataSource; +@property (nonatomic, weak, nullable) id delegate; +// pagerController's layout,don't set layout's dataSource to other +@property (nonatomic, strong, readonly) TYPagerViewLayout *layout; +@property (nonatomic, weak, readonly) UIScrollView *scrollView; + +@property (nonatomic, assign, readonly) NSInteger countOfControllers; +@property (nonatomic, assign, readonly) NSInteger curIndex;// default -1 + +@property (nonatomic, strong, nullable, readonly) NSArray *visibleControllers; + +@property (nonatomic, assign) BOOL automaticallySystemManagerViewAppearanceMethods;// default YES.if YES system auto call view Appearance Methods(eg. viewWillAppear...) + +@property (nonatomic, assign) UIEdgeInsets contentInset; + +//if not visible, prefecth, cache view at index, return nil +- (UIViewController *_Nullable)controllerForIndex:(NSInteger)index; + +// register && dequeue's usage like tableView +- (void)registerClass:(Class)Class forControllerWithReuseIdentifier:(NSString *)identifier; +- (void)registerNib:(UINib *)nib forControllerWithReuseIdentifier:(NSString *)identifier; +- (UIViewController *)dequeueReusableControllerWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; + +// scroll to index +- (void)scrollToControllerAtIndex:(NSInteger)index animate:(BOOL)animate; + +// update data and layout,but don't reset propertys(curIndex,visibleDatas,prefechDatas) +- (void)updateData; + +// reload data and reset propertys +- (void)reloadData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Palette/App/Palette/SectionTabs/TYPagerController.m b/Palette/App/Palette/SectionTabs/TYPagerController.m new file mode 100755 index 0000000..b610a82 --- /dev/null +++ b/Palette/App/Palette/SectionTabs/TYPagerController.m @@ -0,0 +1,273 @@ +#import "TYPagerController.h" + +@interface TYPagerController () { + // private + struct { + unsigned int viewWillAppearForIndex :1; + unsigned int viewDidAppearForIndex :1; + unsigned int viewWillDisappearForIndex :1; + unsigned int viewDidDisappearForIndex :1; + + unsigned int transitionFromIndexToIndex :1; + unsigned int transitionFromIndexToIndexProgress :1; + unsigned int viewDidScroll: 1; + unsigned int viewWillBeginScrolling: 1; + unsigned int viewDidEndScrolling: 1; + }_delegateFlags; +} + +// Data +@property (nonatomic, strong) TYPagerViewLayout *layout; + +@end + + +@implementation TYPagerController + +- (TYPagerViewLayout *)layout { + if (!_layout) { + UIScrollView *scrollView = [[UIScrollView alloc]init]; + TYPagerViewLayout *layout = [[TYPagerViewLayout alloc]initWithScrollView:scrollView]; + layout.dataSource = self; + layout.delegate = self; + layout.adjustScrollViewInset = YES; + _layout = layout; + } + return _layout; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + if (self = [super initWithCoder:aDecoder]) { + _automaticallySystemManagerViewAppearanceMethods = YES; + } + return self; +} + +- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { + if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { + _automaticallySystemManagerViewAppearanceMethods = YES; + } + return self; +} + +#pragma mark - life cycle + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + self.view.backgroundColor = [UIColor whiteColor]; + // prevent sysytem automaticallyAdjustsScrollViewInsets + [self addFixAutoAdjustInsetScrollView]; + [self.view addSubview:self.layout.scrollView]; +} + +- (void)addFixAutoAdjustInsetScrollView { + UIView *view = [[UIView alloc]init]; + [self.view addSubview:view]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + _layout.scrollView.frame = UIEdgeInsetsInsetRect(self.view.bounds,_contentInset); +} + +- (void)viewWillLayoutSubviews +{ + [super viewWillLayoutSubviews]; + _layout.scrollView.frame = UIEdgeInsetsInsetRect(self.view.bounds,_contentInset); +} + +#pragma mark - getter && setter + +- (void)setDelegate:(id)delegate +{ + _delegate = delegate; + + _delegateFlags.viewWillAppearForIndex = [delegate respondsToSelector:@selector(pagerController:viewWillAppear:forIndex:)]; + _delegateFlags.viewDidAppearForIndex = [delegate respondsToSelector:@selector(pagerController:viewDidAppear:forIndex:)]; + _delegateFlags.viewWillDisappearForIndex = [delegate respondsToSelector:@selector(pagerController:viewWillDisappear:forIndex:)]; + _delegateFlags.viewDidDisappearForIndex = [delegate respondsToSelector:@selector(pagerController:viewDidDisappear:forIndex:)]; + + _delegateFlags.transitionFromIndexToIndex = [delegate respondsToSelector:@selector(pagerController:transitionFromIndex:toIndex:animated:)]; + _delegateFlags.transitionFromIndexToIndexProgress = [delegate respondsToSelector:@selector(pagerController:transitionFromIndex:toIndex:progress:)]; + + _delegateFlags.viewDidScroll = [delegate respondsToSelector:@selector(pagerControllerDidScroll:)]; + _delegateFlags.viewWillBeginScrolling = [delegate respondsToSelector:@selector(pagerControllerWillBeginScrolling:animate:)]; + _delegateFlags.viewDidEndScrolling = [delegate respondsToSelector:@selector(pagerControllerDidEndScrolling:animate:)]; +} + +- (NSInteger)curIndex { + return _layout.curIndex; +} + +- (NSInteger)countOfControllers { + return _layout.countOfPagerItems; +} + +- (NSArray *)visibleControllers { + return _layout.visibleItems; +} + +- (UIScrollView *)scrollView { + return _layout.scrollView; +} + +- (void)setContentInset:(UIEdgeInsets)contentInset { + _contentInset = contentInset; + [self.view setNeedsLayout]; +} + +- (BOOL)shouldAutomaticallyForwardAppearanceMethods { + return _automaticallySystemManagerViewAppearanceMethods; +} + +- (void)childViewController:(UIViewController *)childViewController BeginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated { + if (!_automaticallySystemManagerViewAppearanceMethods) { + [childViewController beginAppearanceTransition:isAppearing animated:animated]; + } +} + +- (void)childViewControllerEndAppearanceTransition:(UIViewController *)childViewController { + if (!_automaticallySystemManagerViewAppearanceMethods) { + [childViewController endAppearanceTransition]; + } +} + +#pragma mark - public method + +- (UIViewController *)controllerForIndex:(NSInteger)index { + return [_layout itemForIndex:index]; +} + +- (void)scrollToControllerAtIndex:(NSInteger)index animate:(BOOL)animate { + [_layout scrollToItemAtIndex:index animate:animate]; +} + +- (void)updateData { + [_layout updateData]; +} + +- (void)reloadData { + [_layout reloadData]; +} + +- (void)registerClass:(Class)Class forControllerWithReuseIdentifier:(NSString *)identifier { + [_layout registerClass:Class forItemWithReuseIdentifier:identifier]; +} +- (void)registerNib:(UINib *)nib forControllerWithReuseIdentifier:(NSString *)identifier { + [_layout registerNib:nib forItemWithReuseIdentifier:identifier]; +} +- (UIViewController *)dequeueReusableControllerWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index { + return [_layout dequeueReusableItemWithReuseIdentifier:identifier forIndex:index]; +} + +#pragma mark - private + +- (void)willBeginScrollingAnimate:(BOOL)animate { + if (_delegateFlags.viewWillBeginScrolling) { + [_delegate pagerControllerWillBeginScrolling:self animate:animate]; + } +} + +- (void)didEndScrollingAnimate:(BOOL)animate { + if (_delegateFlags.viewDidEndScrolling) { + [_delegate pagerControllerDidEndScrolling:self animate:animate]; + } +} + +#pragma mark - TYPagerViewLayoutDataSource + +- (NSInteger)numberOfItemsInPagerViewLayout { + return [_dataSource numberOfControllersInPagerController]; +} + +- (id)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout itemForIndex:(NSInteger)index prefetching:(BOOL)prefetching { + return [_dataSource pagerController:self controllerForIndex:index prefetching:prefetching]; +} +- (UIView *)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout viewForItem:(id)item atIndex:(NSInteger)index { + UIViewController *viewController = item; + return viewController.view; +} + +- (UIViewController *)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout viewControllerForItem:(id)item atIndex:(NSInteger)index { + return item; +} + +- (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout addVisibleItem:(id)item atIndex:(NSInteger)index { + UIViewController *viewController = item; + if (_delegateFlags.viewWillAppearForIndex) { + [_delegate pagerController:self viewWillAppear:viewController forIndex:index]; + } + // addChildViewController + [self addChildViewController:viewController]; + [self childViewController:viewController BeginAppearanceTransition:YES animated:YES]; + [pagerViewLayout.scrollView addSubview:viewController.view]; + [self childViewControllerEndAppearanceTransition:viewController]; + [viewController didMoveToParentViewController:self]; + if (_delegateFlags.viewDidAppearForIndex) { + [_delegate pagerController:self viewDidAppear:viewController forIndex:index]; + } +} + +- (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout removeInVisibleItem:(id)item atIndex:(NSInteger)index { + UIViewController *viewController = item; + if (_delegateFlags.viewWillDisappearForIndex) { + [_delegate pagerController:self viewWillDisappear:viewController forIndex:index]; + } + // removeChildViewController + [viewController willMoveToParentViewController:nil]; + [self childViewController:viewController BeginAppearanceTransition:NO animated:YES]; + [viewController.view removeFromSuperview]; + [self childViewControllerEndAppearanceTransition:viewController]; + [viewController removeFromParentViewController]; + if (_delegateFlags.viewDidDisappearForIndex) { + [_delegate pagerController:self viewDidDisappear:viewController forIndex:index]; + } +} + +#pragma mark - TYPagerViewLayoutDelegate + +- (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated { + if (_delegateFlags.transitionFromIndexToIndex) { + [_delegate pagerController:self transitionFromIndex:fromIndex toIndex:toIndex animated:animated]; + } +} + +- (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress { + if (_delegateFlags.transitionFromIndexToIndexProgress) { + [_delegate pagerController:self transitionFromIndex:fromIndex toIndex:toIndex progress:progress]; + } +} + +- (void)pagerViewLayoutDidScroll:(TYPagerViewLayout *)pagerViewLayout { + if (_delegateFlags.viewDidScroll) { + [_delegate pagerControllerDidScroll:self]; + } +} + +- (void)pagerViewLayoutWillBeginDragging:(TYPagerViewLayout *)pagerViewLayout { + [self willBeginScrollingAnimate:YES]; +} + +- (void)pagerViewLayoutWillBeginScrollToView:(TYPagerViewLayout *)pagerViewLayout animate:(BOOL)animate { + [self willBeginScrollingAnimate:animate]; +} + +- (void)pagerViewLayoutDidEndDecelerating:(TYPagerViewLayout *)pagerViewLayout { + [self didEndScrollingAnimate:YES]; +} + +- (void)pagerViewLayoutDidEndScrollToView:(TYPagerViewLayout *)pagerViewLayout animate:(BOOL)animate { + [self didEndScrollingAnimate:animate]; +} + +- (void)pagerViewLayoutDidEndScrollingAnimation:(TYPagerViewLayout *)pagerViewLayout { + [self didEndScrollingAnimate:YES]; +} + +- (void)dealloc +{ + _layout = nil; +} + +@end diff --git a/Palette/App/Palette/SectionTabs/TYPagerViewLayout.h b/Palette/App/Palette/SectionTabs/TYPagerViewLayout.h new file mode 100644 index 0000000..a7238ad --- /dev/null +++ b/Palette/App/Palette/SectionTabs/TYPagerViewLayout.h @@ -0,0 +1,126 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSObject (TY_PagerReuseIdentify) +// resueId +@property (nonatomic, strong, readonly, nullable) NSString *ty_pagerReuseIdentify; + +@end + +@class TYPagerViewLayout; +@protocol TYPagerViewLayoutDataSource + +- (NSInteger)numberOfItemsInPagerViewLayout; + +// if item is preload, prefetch will YES +- (id)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout itemForIndex:(NSInteger)index prefetching:(BOOL)prefetching; + +// return item's view +- (UIView *)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout viewForItem:(id)item atIndex:(NSInteger)index; + +// see TYPagerView&&TYPagerController, add&&remove item ,must implement scrollView addSubView item's view +- (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout addVisibleItem:(id)item atIndex:(NSInteger)index; +- (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout removeInVisibleItem:(id)item atIndex:(NSInteger)index; + +@optional + +// if have not viewController return nil. +- (UIViewController *)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout viewControllerForItem:(id)item atIndex:(NSInteger)index; + +@end + +@protocol TYPagerViewLayoutDelegate + +@optional + +// Transition animation customization + +// if you implement ↓↓↓transitionFromIndex:toIndex:progress:,only tap change index will call this, you can set progressAnimateEnabel NO that not call progress method +- (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated; + +// if you implement the method,also you need implement ↑↑↑transitionFromIndex:toIndex:animated:,deal with tap change index animate +- (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress; + +// ScrollViewDelegate + +- (void)pagerViewLayoutDidScroll:(TYPagerViewLayout *)pagerViewLayout; +- (void)pagerViewLayoutWillBeginScrollToView:(TYPagerViewLayout *)pagerViewLayout animate:(BOOL)animate; +- (void)pagerViewLayoutDidEndScrollToView:(TYPagerViewLayout *)pagerViewLayout animate:(BOOL)animate; +- (void)pagerViewLayoutWillBeginDragging:(TYPagerViewLayout *)pagerViewLayout; +- (void)pagerViewLayoutDidEndDragging:(TYPagerViewLayout *)pagerViewLayout willDecelerate:(BOOL)decelerate; +- (void)pagerViewLayoutWillBeginDecelerating:(TYPagerViewLayout *)pagerViewLayout; +- (void)pagerViewLayoutDidEndDecelerating:(TYPagerViewLayout *)pagerViewLayout; +- (void)pagerViewLayoutDidEndScrollingAnimation:(TYPagerViewLayout *)pagerViewLayout; + +@end + +@interface TYPagerViewLayout<__covariant ItemType> : NSObject + +@property (nonatomic, weak, nullable) id dataSource; +@property (nonatomic, weak, nullable) id delegate; + +// strong,will control the delegate,don't set delegate on other place. +@property (nonatomic, strong, readonly) UIScrollView *scrollView; +// if viewcontroller's automaticallyAdjustsScrollViewInsets YES ,will cause frame problems, you can set YES, default YES +@property (nonatomic, assign) BOOL adjustScrollViewInset; + +@property (nonatomic, assign, readonly) NSInteger countOfPagerItems; +@property (nonatomic, assign, readonly) NSInteger curIndex;// default -1 + +@property (nonatomic, strong, readonly) NSCache *memoryCache;; // will cache pagerView,you can set countLimit +@property (nonatomic, assign) BOOL autoMemoryCache; // default YES + +@property (nonatomic, assign) NSInteger prefetchItemCount;// preload left and right item's count , default 0 +// because when superview add subview(have tableView) will call relodData,if set Yes will optimize. default NO +@property (nonatomic, assign) BOOL prefetchItemWillAddToSuperView; + +@property (nonatomic, assign, readonly) NSRange prefetchRange; +@property (nonatomic, assign, readonly) NSRange visibleRange; + +@property (nonatomic, strong, nullable, readonly) NSArray * visibleIndexs; +@property (nonatomic, strong, nullable, readonly) NSArray * visibleItems; + +// default YES, if NO,will not call delegate transitionFromIndex:toIndex:progress:,but will call transitionFromIndex:toIndex: +@property (nonatomic, assign) BOOL progressAnimateEnabel; + +// default NO, when scroll visible range change will add item.If YES add item only when scroll animate end, suggest set prefetchItemCount 1 or more +@property (nonatomic, assign) BOOL addVisibleItemOnlyWhenScrollAnimatedEnd; + +// default 0.5,when scroll progress percent will change index, only progressAnimateEnabel is NO or don't implement delegate transitionFromIndex: toIndex: progress: +@property (nonatomic, assign) CGFloat changeIndexWhenScrollProgress; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +/** + initializer will strong scrollView,and control delegate,don't set delegate on other place. + */ +- (instancetype)initWithScrollView:(UIScrollView *)scrollView NS_DESIGNATED_INITIALIZER; // strong scrollView + +- (ItemType _Nullable)itemForIndex:(NSInteger)idx; + +- (UIView *)viewForItem:(ItemType)item atIndex:(NSInteger)index; +// if have not viewController return nil. +- (UIViewController *_Nullable)viewControllerForItem:(id)item atIndex:(NSInteger)index; + +// view's frame at index +- (CGRect)frameForItemAtIndex:(NSInteger)index; + +// register && dequeue's usage like tableView +- (void)registerClass:(Class)Class forItemWithReuseIdentifier:(NSString *)identifier; +- (void)registerNib:(UINib *)nib forItemWithReuseIdentifier:(NSString *)identifier; +- (ItemType)dequeueReusableItemWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; + +// scroll to index +- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate; + +// update data and layout,the same to relaodData,but don't reset propertys(curIndex,visibleDatas,prefechDatas) +- (void)updateData; + +// reload data and reset propertys +- (void)reloadData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Palette/App/Palette/SectionTabs/TYPagerViewLayout.m b/Palette/App/Palette/SectionTabs/TYPagerViewLayout.m new file mode 100644 index 0000000..c32867c --- /dev/null +++ b/Palette/App/Palette/SectionTabs/TYPagerViewLayout.m @@ -0,0 +1,813 @@ +#import "TYPagerViewLayout.h" +#import + +@interface TYAutoPurgeCache : NSCache +@end + +@implementation TYAutoPurgeCache + +- (nonnull instancetype)init { + if (self = [super init]) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeAllObjects) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +} +@end + +static char ty_pagerReuseIdentifyKey; + +@implementation NSObject (TY_PagerReuseIdentify) + +- (NSString *)ty_pagerReuseIdentify { + return objc_getAssociatedObject(self, &ty_pagerReuseIdentifyKey); +} + +- (void)setTy_pagerReuseIdentify:(NSString *)ty_pagerReuseIdentify { + objc_setAssociatedObject(self, &ty_pagerReuseIdentifyKey, ty_pagerReuseIdentify, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +@end + +typedef NS_ENUM(NSUInteger, TYPagerScrollingDirection) { + TYPagerScrollingLeft, + TYPagerScrollingRight, +}; + +NS_INLINE CGRect frameForItemAtIndex(NSInteger index, CGRect frame) +{ + return CGRectMake(index * CGRectGetWidth(frame), 0, CGRectGetWidth(frame), CGRectGetHeight(frame)); +} + +// caculate visilble range in offset +NS_INLINE NSRange visibleRangWithOffset(CGFloat offset,CGFloat width, NSInteger maxIndex) +{ + if (width <= 0) { + return NSMakeRange(0, 0); + } + NSInteger startIndex = offset/width; + NSInteger endIndex = ceil((offset + width)/width); + + if (startIndex < 0) { + startIndex = 0; + } else if (startIndex > maxIndex) { + startIndex = maxIndex; + } + + if (endIndex > maxIndex) { + endIndex = maxIndex; + } + + NSUInteger length = endIndex - startIndex; + if (length > 5) { + length = 5; + } + return NSMakeRange(startIndex, length); +} + +NS_INLINE NSRange prefetchRangeWithVisibleRange(NSRange visibleRange,NSInteger prefetchItemCount, NSInteger countOfPagerItems) { + if (prefetchItemCount <= 0) { + return NSMakeRange(0, 0); + } + NSInteger leftIndex = MAX((NSInteger)visibleRange.location - prefetchItemCount, 0); + NSInteger rightIndex = MIN(visibleRange.location+visibleRange.length+prefetchItemCount, countOfPagerItems); + return NSMakeRange(leftIndex, rightIndex - leftIndex); +} + +static const NSInteger kMemoryCountLimit = 16; + +@interface TYPagerViewLayout () { + // Private + BOOL _needLayoutContent; + BOOL _scrollAnimated; + BOOL _isTapScrollMoved; + CGFloat _preOffsetX; + NSInteger _firstScrollToIndex; + BOOL _didReloadData; + BOOL _didLayoutSubViews; + + struct { + unsigned int addVisibleItem :1; + unsigned int removeInVisibleItem :1; + }_dataSourceFlags; + + struct { + unsigned int transitionFromIndexToIndex :1; + unsigned int transitionFromIndexToIndexProgress :1; + unsigned int pagerViewLayoutDidScroll: 1; + }_delegateFlags; + +} + +// UI + +@property (nonatomic, strong) UIScrollView *scrollView; + +// Data + +@property (nonatomic, assign) NSInteger countOfPagerItems; +@property (nonatomic, assign) NSInteger curIndex; + +@property (nonatomic, strong) NSCache *memoryCache; + +@property (nonatomic, assign) NSRange visibleRange; +@property (nonatomic, assign) NSRange prefetchRange; + +@property (nonatomic, strong) NSDictionary *visibleIndexItems; +@property (nonatomic, strong) NSDictionary *prefetchIndexItems; + +//reuse Class and nib +@property (nonatomic, strong) NSMutableDictionary *reuseIdentifyClassOrNib; +// reuse items +@property (nonatomic, strong) NSMutableDictionary *reuseIdentifyItems; + +@end + +static NSString * kScrollViewFrameObserverKey = @"scrollView.frame"; + +@implementation TYPagerViewLayout + +#pragma mark - init + +- (instancetype)initWithScrollView:(UIScrollView *)scrollView { + if (self = [super init]) { + NSParameterAssert(scrollView!=nil); + _scrollView = scrollView; + + [self configurePropertys]; + + [self configureScrollView]; + + [self addScrollViewObservers]; + } + return self; +} + +#pragma mark - configure + +- (void)configurePropertys { + _curIndex = -1; + _preOffsetX = 0; + _changeIndexWhenScrollProgress = 0.5; + _didReloadData = NO; + _didLayoutSubViews = NO; + _firstScrollToIndex = 0; + _prefetchItemWillAddToSuperView = NO; + _addVisibleItemOnlyWhenScrollAnimatedEnd = NO; + _progressAnimateEnabel = YES; + _adjustScrollViewInset = YES; + _scrollAnimated = YES; + _autoMemoryCache = YES; +} + +- (void)configureScrollView { + _scrollView.showsHorizontalScrollIndicator = NO; + _scrollView.showsVerticalScrollIndicator = NO; + _scrollView.pagingEnabled = YES; + _scrollView.delegate = self; +} + +- (void)resetPropertys { + [self clearMemoryCache]; + [self removeVisibleItems]; + _scrollAnimated = NO; + _curIndex = -1; + _preOffsetX = 0; +} + +#pragma mark - getter setter + +- (NSArray *)visibleItems { + return _visibleIndexItems.allValues; +} + +- (NSArray *)visibleIndexs { + return _visibleIndexItems.allKeys; +} + +- (NSMutableDictionary *)reuseIdentifyItems { + if (!_reuseIdentifyItems) { + _reuseIdentifyItems = [NSMutableDictionary dictionary]; + } + return _reuseIdentifyItems; +} + +- (NSMutableDictionary *)reuseIdentifyClassOrNib { + if (!_reuseIdentifyClassOrNib) { + _reuseIdentifyClassOrNib = [NSMutableDictionary dictionary]; + } + return _reuseIdentifyClassOrNib; +} + +- (NSCache *)memoryCache { + if (!_memoryCache) { + _memoryCache = [[TYAutoPurgeCache alloc]init]; + _memoryCache.countLimit = kMemoryCountLimit; + } + return _memoryCache; +} + +- (void)setAutoMemoryCache:(BOOL)autoMemoryCache { + _autoMemoryCache = autoMemoryCache; + if(!_autoMemoryCache && _memoryCache){ + [_memoryCache removeAllObjects]; + _memoryCache = nil; + } +} + +- (void)setPrefetchItemCount:(NSInteger)prefetchItemCount { + _prefetchItemCount = prefetchItemCount; + if (prefetchItemCount <= 0 && _prefetchIndexItems) { + _prefetchIndexItems = nil; + } +} + +- (void)setDataSource:(id)dataSource { + _dataSource = dataSource; + _dataSourceFlags.addVisibleItem = [dataSource respondsToSelector:@selector(pagerViewLayout:addVisibleItem:atIndex:)]; + _dataSourceFlags.removeInVisibleItem = [dataSource respondsToSelector:@selector(pagerViewLayout:removeInVisibleItem:atIndex:)]; +} + +- (void)setDelegate:(id)delegate { + _delegate = delegate; + _delegateFlags.transitionFromIndexToIndex = [delegate respondsToSelector:@selector(pagerViewLayout:transitionFromIndex:toIndex:animated:)]; + _delegateFlags.transitionFromIndexToIndexProgress = [delegate respondsToSelector:@selector(pagerViewLayout:transitionFromIndex:toIndex:progress:)]; + _delegateFlags.pagerViewLayoutDidScroll = [delegate respondsToSelector:@selector(pagerViewLayoutDidScroll:)]; +} + +#pragma mark - public + +- (void)reloadData { + [self resetPropertys]; + + [self updateData]; +} + +// update don't reset propertys(curIndex) +- (void)updateData { + [self clearMemoryCache]; + _didReloadData = YES; + _countOfPagerItems = [_dataSource numberOfItemsInPagerViewLayout]; + [self setNeedLayout]; +} + +/** + scroll to item at index + */ +- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate { + if (index < 0 || index >= _countOfPagerItems) { + if (!_didReloadData && index >= 0) { + _firstScrollToIndex = index; + } + return; + } + + if (!_didLayoutSubViews && CGRectIsEmpty(_scrollView.frame)) { + _firstScrollToIndex = index; + } + + [self scrollViewWillScrollToView:_scrollView animate:animate]; + [_scrollView setContentOffset:CGPointMake(index * CGRectGetWidth(_scrollView.frame),0) animated:NO]; + [self scrollViewDidScrollToView:_scrollView animate:animate]; +} + +- (id)itemForIndex:(NSInteger)idx { + NSNumber *index = @(idx); + // 1.from visibleViews + id visibleItem = [_visibleIndexItems objectForKey:index]; + if (!visibleItem && _prefetchItemCount > 0) { + // 2.from prefetch + visibleItem = [_prefetchIndexItems objectForKey:index]; + } + if (!visibleItem) { + // 3.from cache + visibleItem = [self cacheItemForKey:index]; + } + return visibleItem; +} + +- (UIView *)viewForItem:(id)item atIndex:(NSInteger)index { + UIView *view = [_dataSource pagerViewLayout:self viewForItem:item atIndex:index]; + return view; +} + +- (UIViewController *)viewControllerForItem:(id)item atIndex:(NSInteger)index { + if ([_dataSource respondsToSelector:@selector(pagerViewLayout:viewControllerForItem:atIndex:)]) { + return [_dataSource pagerViewLayout:self viewControllerForItem:item atIndex:index]; + } + return nil; +} + +- (CGRect)frameForItemAtIndex:(NSInteger)index { + CGRect frame = frameForItemAtIndex(index, _scrollView.frame); + if (_adjustScrollViewInset) { + frame.size.height -= _scrollView.contentInset.top; + } + return frame; +} + +#pragma mark - register && dequeue + +- (void)registerClass:(Class)Class forItemWithReuseIdentifier:(NSString *)identifier { + [self.reuseIdentifyClassOrNib setObject:Class forKey:identifier]; +} + +- (void)registerNib:(UINib *)nib forItemWithReuseIdentifier:(NSString *)identifier { + [self.reuseIdentifyClassOrNib setObject:nib forKey:identifier]; +} + +- (id)dequeueReusableItemWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index { + NSAssert(_reuseIdentifyClassOrNib.count != 0, @"you don't register any identifiers!"); + NSObject *item = [self.reuseIdentifyItems objectForKey:identifier]; + if (item) { + [self.reuseIdentifyItems removeObjectForKey:identifier]; + return item; + } + id itemClassOrNib = [self.reuseIdentifyClassOrNib objectForKey:identifier]; + if (!itemClassOrNib) { + NSString *error = [NSString stringWithFormat:@"you don't register this identifier->%@",identifier]; + NSAssert(NO, error); + NSLog(@"%@", error); + return nil; + } + + if (class_isMetaClass(object_getClass(itemClassOrNib))) { + // is class + item = [[((Class)itemClassOrNib) alloc]init]; + }else if ([itemClassOrNib isKindOfClass:[UINib class]]) { + // is nib + item =[((UINib *)itemClassOrNib)instantiateWithOwner:nil options:nil].firstObject; + } + if (!item){ + NSString *error = [NSString stringWithFormat:@"you register identifier->%@ is not class or nib!",identifier]; + NSAssert(NO, error); + NSLog(@"%@", error); + return nil; + } + [item setTy_pagerReuseIdentify:identifier]; + UIView *view = [_dataSource pagerViewLayout:self viewForItem:item atIndex:index]; + view.frame = [self frameForItemAtIndex:index]; + return item; +} + +- (void)enqueueReusableItem:(NSObject *)reuseItem prefetchRange:(NSRange)prefetchRange atIndex:(NSInteger)index{ + if (reuseItem.ty_pagerReuseIdentify.length == 0 || NSLocationInRange(index, prefetchRange)) { + return; + } + [self.reuseIdentifyItems setObject:reuseItem forKey:reuseItem.ty_pagerReuseIdentify]; +} + +#pragma mark - layout content + +- (void)setNeedLayout { + // 1. get count Of pager Items + if (_countOfPagerItems <= 0) { + _countOfPagerItems = [_dataSource numberOfItemsInPagerViewLayout]; + } + _needLayoutContent = YES; + if (_curIndex >= _countOfPagerItems) { + _curIndex = _countOfPagerItems - 1; + } + + BOOL needLayoutSubViews = NO; + if (!_didLayoutSubViews && !CGRectIsEmpty(_scrollView.frame) && _firstScrollToIndex < _countOfPagerItems) { + _didLayoutSubViews = YES; + needLayoutSubViews = YES; + } + + // 2.set contentSize and offset + CGFloat contentWidth = CGRectGetWidth(_scrollView.frame); + _scrollView.contentSize = CGSizeMake(_countOfPagerItems * contentWidth, 0); + _scrollView.contentOffset = CGPointMake(MAX(needLayoutSubViews ? _firstScrollToIndex : _curIndex, 0)*contentWidth, _scrollView.contentOffset.y); + + // 3.layout content + if (_curIndex < 0 || needLayoutSubViews) { + [self scrollViewDidScroll:_scrollView]; + }else { + [self layoutIfNeed]; + } +} + +- (void)layoutIfNeed { + if (CGRectIsEmpty(_scrollView.frame)) { + return; + } + // 1.caculate visible range + CGFloat offsetX = _scrollView.contentOffset.x; + NSRange visibleRange = visibleRangWithOffset(offsetX, CGRectGetWidth(_scrollView.frame), _countOfPagerItems); + if (NSEqualRanges(_visibleRange, visibleRange) && !_needLayoutContent) { + // visible range not change + return; + } + _visibleRange = visibleRange; + _needLayoutContent = NO; + + BOOL afterPrefetchIfNoVisibleItems = !_visibleIndexItems; + if (!afterPrefetchIfNoVisibleItems) { + // 2.prefetch left and right Items + [self addPrefetchItemsOutOfVisibleRange:_visibleRange]; + } + // 3.remove invisible Items + [self removeVisibleItemsOutOfVisibleRange:_visibleRange]; + // 4.add visiible Items + [self addVisibleItemsInVisibleRange:_visibleRange]; + if (afterPrefetchIfNoVisibleItems) { + [self addPrefetchItemsOutOfVisibleRange:_visibleRange]; + } +} + +#pragma mark - remove && add visibleViews + +- (void)removeVisibleItems { + [_scrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; + _visibleIndexItems = nil; + _prefetchIndexItems = nil; + if (_reuseIdentifyItems) { + [_reuseIdentifyItems removeAllObjects]; + } +} + +- (void)removeVisibleItemsOutOfVisibleRange:(NSRange)visibleRange { + [_visibleIndexItems enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id item, BOOL * stop) { + NSInteger index = [key integerValue]; + if (!NSLocationInRange(index, visibleRange)) { + // out of visible + [self removeInvisibleItem:item atIndex:index]; + } + }]; +} + +- (void)removeInvisibleItem:(id)invisibleItem atIndex:(NSInteger)index{ + UIView *invisibleView = [self viewForItem:invisibleItem atIndex:index]; + if (!invisibleView.superview) { + return; + } + if (_dataSourceFlags.removeInVisibleItem) { + [_dataSource pagerViewLayout:self removeInVisibleItem:invisibleItem atIndex:index]; + }else { + NSAssert(NO, @"must implememt datasource pagerViewLayout:removeInVisibleItem:atIndex:!"); + } + + NSObject *reuseItem = invisibleItem; + if (_reuseIdentifyClassOrNib.count > 0 && reuseItem.ty_pagerReuseIdentify.length > 0) { + // reuse + [self enqueueReusableItem:reuseItem prefetchRange:_prefetchRange atIndex:index]; + }else { + [self cacheItem:invisibleItem forKey:@(index)]; + } +} + +- (void)addVisibleItemsInVisibleRange:(NSRange)visibleRange { + NSMutableDictionary *visibleIndexItems = [NSMutableDictionary dictionary]; + // add visible views + for (NSInteger idx = visibleRange.location ; idx < visibleRange.location + visibleRange.length; ++idx) { + // from visibleViews,prefetch,cache + id visibleItem = [self itemForIndex:idx]; + if (!visibleItem && (!_addVisibleItemOnlyWhenScrollAnimatedEnd || visibleRange.length == 1)) { + // ↑↑↑ if _addVisibleItemOnlyWhenScrollAnimatedEnd is NO ,scroll visible range change will add item from dataSource, else is YES only scroll animate end(visibleRange.length == 1) will add item from dataSource + visibleItem = [_dataSource pagerViewLayout:self itemForIndex:idx prefetching:NO]; + } + if (visibleItem) { + [self addVisibleItem:visibleItem atIndex:idx]; + visibleIndexItems[@(idx)] = visibleItem; + } + } + + if (visibleIndexItems.count > 0) { + _visibleIndexItems = [visibleIndexItems copy]; + }else { + _visibleIndexItems = nil; + } +} + +- (void)addVisibleItem:(id)visibleItem atIndex:(NSInteger)index{ + if (!visibleItem) { + NSAssert(visibleItem != nil, @"visibleView must not nil!"); + return; + } + UIView *view = [self viewForItem:visibleItem atIndex:index]; + if (view.superview && view.superview != _scrollView) { + [view removeFromSuperview]; + } + CGRect frame = [self frameForItemAtIndex:index]; + if (!CGRectEqualToRect(view.frame, frame)) { + view.frame = frame; + } + if (!_prefetchItemWillAddToSuperView && view.superview) { + return; + } + + if (_prefetchItemWillAddToSuperView && view.superview) { + UIViewController *viewController = [self viewControllerForItem:visibleItem atIndex:index]; + if (!viewController || viewController.parentViewController) { + return; + } + } + + if (_dataSourceFlags.addVisibleItem) { + [_dataSource pagerViewLayout:self addVisibleItem:visibleItem atIndex:index]; + }else { + NSAssert(NO, @"must implement datasource pagerViewLayout:addVisibleItem:frame:atIndex:!"); + } +} + +- (void)addPrefetchItemsOutOfVisibleRange:(NSRange)visibleRange{ + if (_prefetchItemCount <= 0) { + return; + } + NSRange prefetchRange = prefetchRangeWithVisibleRange(visibleRange, _prefetchItemCount, _countOfPagerItems); + if (visibleRange.length == 1) { + // ↑↑↑mean: scroll animate end + NSMutableDictionary *prefetchIndexItems = [NSMutableDictionary dictionary]; + // add prefetch items + for (NSInteger index = prefetchRange.location; index < NSMaxRange(prefetchRange); ++index) { + id prefetchItem = nil; + if (NSLocationInRange(index, visibleRange)) { + prefetchItem = [_visibleIndexItems objectForKey:@(index)]; + }else { + prefetchItem = [self prefetchInvisibleItemAtIndex:index]; + } + if (prefetchItem) { + [prefetchIndexItems setObject:prefetchItem forKey:@(index)]; + } + } + + BOOL haveReuseIdentifyClassOrNib = _reuseIdentifyClassOrNib.count > 0; + if (haveReuseIdentifyClassOrNib || _prefetchItemWillAddToSuperView) { + [_prefetchIndexItems enumerateKeysAndObjectsUsingBlock:^(NSNumber * key, id obj, BOOL * stop) { + NSInteger index = [key integerValue]; + if (haveReuseIdentifyClassOrNib) { + // resuse item + [self enqueueReusableItem:obj prefetchRange:prefetchRange atIndex:index]; + } + if (_prefetchItemWillAddToSuperView && !NSLocationInRange(index, prefetchRange)) { + // remove prefetch item to superView + UIView *view = [self viewForItem:obj atIndex:index]; + if (view.superview == _scrollView && ![_visibleIndexItems objectForKey:key]) { + [view removeFromSuperview]; + } + } + }]; + } + if (prefetchIndexItems.count > 0) { + _prefetchRange = prefetchRange; + _prefetchIndexItems = [prefetchIndexItems copy]; + }else { + _prefetchRange = NSMakeRange(0, 0); + _prefetchIndexItems = nil; + } + }else if (NSIntersectionRange(visibleRange, _prefetchRange).length == 0) { + // visible and prefetch intersection, remove all prefetchItems + if (_prefetchItemWillAddToSuperView) { + [_prefetchIndexItems enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id obj, BOOL *stop) { + UIView *view = [self viewForItem:obj atIndex:[key integerValue]]; + if (view.superview == _scrollView && ![_visibleIndexItems objectForKey:key]) { + [view removeFromSuperview]; + } + }]; + } + _prefetchRange = NSMakeRange(0, 0); + _prefetchIndexItems = nil; + } +} + +- (UIView *)prefetchInvisibleItemAtIndex:(NSInteger)index { + id prefetchItem = [_prefetchIndexItems objectForKey:@(index)]; + if (!prefetchItem) { + prefetchItem = [_visibleIndexItems objectForKey:@(index)]; + } + if (!prefetchItem) { + prefetchItem = [self cacheItemForKey:@(index)]; + } + if (!prefetchItem) { + prefetchItem = [_dataSource pagerViewLayout:self itemForIndex:index prefetching:YES]; + UIView *view = [self viewForItem:prefetchItem atIndex:index]; + CGRect frame = [self frameForItemAtIndex:index]; + if (!CGRectEqualToRect(view.frame, frame)) { + view.frame = frame; + } + if (_prefetchItemWillAddToSuperView && view.superview != _scrollView) { + [_scrollView addSubview:view]; + } + } + return prefetchItem; +} + +#pragma mark - caculate index + +- (void)caculateIndexWithOffsetX:(CGFloat)offsetX direction:(TYPagerScrollingDirection)direction{ + if (CGRectIsEmpty(_scrollView.frame)) { + return; + } + if (_countOfPagerItems <= 0) { + _curIndex = -1; + return; + } + // scrollView width + CGFloat width = CGRectGetWidth(_scrollView.frame); + NSInteger index = 0; + // when scroll to progress(changeIndexWhenScrollProgress) will change index + double percentChangeIndex = _changeIndexWhenScrollProgress; + if (_changeIndexWhenScrollProgress >= 1.0 || [self progressCaculateEnable]) { + percentChangeIndex = 0.999999999; + } + + // caculate cur index + if (direction == TYPagerScrollingLeft) { + index = ceil(offsetX/width-percentChangeIndex); + }else { + index = floor(offsetX/width+percentChangeIndex); + } + + if (index < 0) { + index = 0; + }else if (index >= _countOfPagerItems) { + index = _countOfPagerItems-1; + } + if (index == _curIndex) { + // if index not same,change index + return; + } + + NSInteger fromIndex = MAX(_curIndex, 0); + _curIndex = index; + if (_delegateFlags.transitionFromIndexToIndex /*&& ![self progressCaculateEnable]*/) { + [_delegate pagerViewLayout:self transitionFromIndex:fromIndex toIndex:_curIndex animated:_scrollAnimated]; + } + _scrollAnimated = YES; +} + +- (void)caculateIndexByProgressWithOffsetX:(CGFloat)offsetX direction:(TYPagerScrollingDirection)direction{ + if (CGRectIsEmpty(_scrollView.frame)) { + return; + } + if (_countOfPagerItems <= 0) { + _curIndex = -1; + return; + } + CGFloat width = CGRectGetWidth(_scrollView.frame); + CGFloat floadIndex = offsetX/width; + NSInteger floorIndex = floor(floadIndex); + if (floorIndex < 0 || floorIndex >= _countOfPagerItems || floadIndex > _countOfPagerItems-1) { + return; + } + + CGFloat progress = offsetX/width-floorIndex; + NSInteger fromIndex = 0, toIndex = 0; + if (direction == TYPagerScrollingLeft) { + fromIndex = floorIndex; + toIndex = MIN(_countOfPagerItems -1, fromIndex + 1); + if (fromIndex == toIndex && toIndex == _countOfPagerItems-1) { + fromIndex = _countOfPagerItems-2; + progress = 1.0; + } + }else { + toIndex = floorIndex; + fromIndex = MIN(_countOfPagerItems-1, toIndex +1); + progress = 1.0 - progress; + } + + if (_delegateFlags.transitionFromIndexToIndexProgress) { + [_delegate pagerViewLayout:self transitionFromIndex:fromIndex toIndex:toIndex progress:progress]; + } +} + +- (BOOL)progressCaculateEnable { + return _delegateFlags.transitionFromIndexToIndexProgress && _progressAnimateEnabel && !_isTapScrollMoved; +} + +#pragma mark - memoryCache + +- (void)clearMemoryCache { + if (_autoMemoryCache && _memoryCache) { + [_memoryCache removeAllObjects]; + } +} + +- (void)cacheItem:(id)item forKey:(NSNumber *)key { + if (_autoMemoryCache && key) { + UIView *cacheItem = [self.memoryCache objectForKey:key]; + if (cacheItem && cacheItem == item) { + return; + } + [self.memoryCache setObject:item forKey:key]; + } +} + +- (id)cacheItemForKey:(NSNumber *)key { + if (_autoMemoryCache && _memoryCache && key) { + return [_memoryCache objectForKey:key]; + } + return nil; +} + +#pragma mark - UIScrollViewDelegate + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + if (!scrollView.superview) { + return; + } + // get scrolling direction + CGFloat offsetX = scrollView.contentOffset.x; + TYPagerScrollingDirection direction = offsetX >= _preOffsetX ? TYPagerScrollingLeft : TYPagerScrollingRight; + + // caculate index and progress + if ([self progressCaculateEnable]) { + [self caculateIndexByProgressWithOffsetX:offsetX direction:direction]; + } + [self caculateIndexWithOffsetX:offsetX direction:direction]; + + // layout items + [self layoutIfNeed]; + _isTapScrollMoved = NO; + + if (_delegateFlags.pagerViewLayoutDidScroll) { + [_delegate pagerViewLayoutDidScroll:self]; + } +} + +- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView +{ + _preOffsetX = scrollView.contentOffset.x; + if ([_delegate respondsToSelector:@selector(pagerViewLayoutWillBeginDragging:)]) { + [_delegate pagerViewLayoutWillBeginDragging:self]; + } +} + +- (void)scrollViewWillScrollToView:(UIScrollView *)scrollView animate:(BOOL)animate { + _preOffsetX = scrollView.contentOffset.x; + _isTapScrollMoved = YES; + _scrollAnimated = animate; + if ([_delegate respondsToSelector:@selector(pagerViewLayoutWillBeginScrollToView:animate:)]) { + [_delegate pagerViewLayoutWillBeginScrollToView:self animate:animate]; + } +} + +- (void)scrollViewDidScrollToView:(UIScrollView *)scrollView animate:(BOOL)animate { + if ([_delegate respondsToSelector:@selector(pagerViewLayoutDidEndScrollToView:animate:)]) { + [_delegate pagerViewLayoutDidEndScrollToView:self animate:animate]; + } +} + +- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { + if ([_delegate respondsToSelector:@selector(pagerViewLayoutDidEndDragging:willDecelerate:)]) { + [_delegate pagerViewLayoutDidEndDragging:self willDecelerate:decelerate]; + } +} + +- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { + if ([_delegate respondsToSelector:@selector(pagerViewLayoutWillBeginDecelerating:)]) { + [_delegate pagerViewLayoutWillBeginDecelerating:self]; + } +} + +- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { + if ([_delegate respondsToSelector:@selector(pagerViewLayoutDidEndDecelerating:)]) { + [_delegate pagerViewLayoutDidEndDecelerating:self]; + } +} + +- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { + if ([_delegate respondsToSelector:@selector(pagerViewLayoutDidEndScrollingAnimation:)]) { + [_delegate pagerViewLayoutDidEndScrollingAnimation:self]; + } +} + +#pragma mark - Observer + +- (void)addScrollViewObservers { + [self addObserver:self forKeyPath:kScrollViewFrameObserverKey options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + if ([keyPath isEqualToString:kScrollViewFrameObserverKey]) { + CGRect newFrame = [[change objectForKey:NSKeyValueChangeNewKey]CGRectValue]; + CGRect oldFrame = [[change objectForKey:NSKeyValueChangeOldKey]CGRectValue]; + BOOL needLayoutContent = !CGRectEqualToRect(newFrame, oldFrame); + if (needLayoutContent) { + [self setNeedLayout]; + } + } +} + +- (void)removeScrollViewObservers { + [self removeObserver:self forKeyPath:kScrollViewFrameObserverKey context:nil]; +} + +- (void)dealloc { + [self removeScrollViewObservers]; + _scrollView.delegate = nil; + _scrollView = nil; + if (_reuseIdentifyItems) { + [_reuseIdentifyItems removeAllObjects]; + } + if (_reuseIdentifyClassOrNib) { + [_reuseIdentifyClassOrNib removeAllObjects]; + } + [self clearMemoryCache]; +} + +@end diff --git a/Palette/App/Palette/SectionTabs/TYTabPagerBar.h b/Palette/App/Palette/SectionTabs/TYTabPagerBar.h new file mode 100644 index 0000000..726d8f2 --- /dev/null +++ b/Palette/App/Palette/SectionTabs/TYTabPagerBar.h @@ -0,0 +1,74 @@ +#import +#import "TYTabPagerBarLayout.h" + +NS_ASSUME_NONNULL_BEGIN + +@class TYTabPagerBar; +@protocol TYTabPagerBarDataSource + +- (NSInteger)numberOfItemsInPagerTabBar; + +- (UICollectionViewCell *)pagerTabBar:(TYTabPagerBar *)pagerTabBar cellForItemAtIndex:(NSInteger)index; + +@end + +@protocol TYTabPagerBarDelegate + +@optional + +// configure layout +- (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar configureLayout:(TYTabPagerBarLayout *)layout; + +// if cell wdith is not variable,you can set layout.cellWidth. otherwise ,you can implement this return cell width. cell width not contain cell edge +- (CGFloat)pagerTabBar:(TYTabPagerBar *)pagerTabBar widthForItemAtIndex:(NSInteger)index; + +// did select cell item +- (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar didSelectItemAtIndex:(NSInteger)index; + +// transition frome cell to cell with animated +- (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar transitionFromeCell:(UICollectionViewCell * _Nullable)fromCell toCell:(UICollectionViewCell * _Nullable)toCell animated:(BOOL)animated; + +// transition frome cell to cell with progress +- (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar transitionFromeCell:(UICollectionViewCell * _Nullable)fromCell toCell:(UICollectionViewCell * _Nullable)toCell progress:(CGFloat)progress; + +@end + +@interface TYTabPagerBar : UIView + +@property (nonatomic, weak, readonly) UICollectionView *collectionView; +@property (nonatomic, strong) UIView *progressView; +// automatically resized to self.bounds +@property (nonatomic, strong) UIView *backgroundView; + +@property (nonatomic, weak, nullable) id dataSource; + +@property (nonatomic, weak, nullable) id delegate; + +@property (nonatomic, strong) TYTabPagerBarLayout *layout; + +@property (nonatomic, assign) BOOL autoScrollItemToCenter; + +@property (nonatomic, assign, readonly) NSInteger countOfItems; + +@property (nonatomic, assign, readonly) NSInteger curIndex; + +@property (nonatomic, assign) UIEdgeInsets contentInset; + +- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier; +- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier; + +- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; + +- (void)reloadData; + +- (void)scrollToItemFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animate:(BOOL)animate; +- (void)scrollToItemFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress; +- (void)scrollToItemAtIndex:(NSInteger)index atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated; + +- (CGFloat)cellWidthForTitle:(NSString * _Nullable)title; +- (CGRect)cellFrameWithIndex:(NSInteger)index; +- (nullable UICollectionViewCell *)cellForIndex:(NSInteger)index; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Palette/App/Palette/SectionTabs/TYTabPagerBar.m b/Palette/App/Palette/SectionTabs/TYTabPagerBar.m new file mode 100644 index 0000000..84e0401 --- /dev/null +++ b/Palette/App/Palette/SectionTabs/TYTabPagerBar.m @@ -0,0 +1,307 @@ +#import "TYTabPagerBar.h" + +@interface TYTabPagerBar () { + struct { + unsigned int transitionFromeCellAnimated :1; + unsigned int transitionFromeCellProgress :1; + unsigned int widthForItemAtIndex :1; + }_delegateFlags; + TYTabPagerBarLayout *_layout; +} + +// UI +@property (nonatomic, weak) UICollectionView *collectionView; + +// Data + +@property (nonatomic, assign) NSInteger countOfItems; + +@property (nonatomic, assign) NSInteger curIndex; + +@property (nonatomic, assign) BOOL isFirstLayout; +@property (nonatomic, assign) BOOL didLayoutSubViews; + +@end + +@implementation TYTabPagerBar + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + _isFirstLayout = YES; + _didLayoutSubViews = NO; + _autoScrollItemToCenter = YES; + self.backgroundColor = [UIColor clearColor]; + [self addFixAutoAdjustInsetScrollView]; + [self addCollectionView]; + [self addUnderLineView]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + if (self = [super initWithCoder:aDecoder]) { + _isFirstLayout = YES; + _didLayoutSubViews = NO; + _autoScrollItemToCenter = YES; + self.backgroundColor = [UIColor clearColor]; + [self addFixAutoAdjustInsetScrollView]; + [self addCollectionView]; + [self addUnderLineView]; + } + return self; +} + +- (void)addFixAutoAdjustInsetScrollView { + UIView *view = [[UIView alloc]init]; + [self addSubview:view]; +} + +- (void)addCollectionView { + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init]; + layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; + UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:UIEdgeInsetsInsetRect(self.bounds, _contentInset) collectionViewLayout:layout]; + collectionView.backgroundColor = [UIColor clearColor]; + collectionView.showsHorizontalScrollIndicator = NO; + collectionView.showsVerticalScrollIndicator = NO; + if ([collectionView respondsToSelector:@selector(setPrefetchingEnabled:)]) { + collectionView.prefetchingEnabled = NO; + } + collectionView.delegate = self; + collectionView.dataSource = self; + [self addSubview:collectionView]; + _collectionView = collectionView; +} + +- (void)addUnderLineView { + UIView *progressView = [[UIView alloc]init]; + progressView.backgroundColor = [UIColor redColor]; + [_collectionView addSubview:progressView]; + _progressView = progressView; +} + +#pragma mark - getter setter + +- (void)setProgressView:(UIView *)progressView { + if (_progressView == progressView) { + return; + } + if (_progressView) { + [_progressView removeFromSuperview]; + } + if (_layout && _layout.barStyle == TYPagerBarStyleCoverView) { + progressView.layer.zPosition = -1; + [_collectionView insertSubview: progressView atIndex:0]; + }else { + [_collectionView addSubview:progressView]; + } + if (_layout && self.superview) { + [_layout layoutSubViews]; + } +} + +- (void)setBackgroundView:(UIView *)backgroundView { + if (_backgroundView) { + [_backgroundView removeFromSuperview]; + } + _backgroundView = backgroundView; + backgroundView.frame = self.bounds; + [self insertSubview:backgroundView atIndex:0]; +} + +- (void)setDelegate:(id)delegate { + _delegate = delegate; + _delegateFlags.transitionFromeCellAnimated = [delegate respondsToSelector:@selector(pagerTabBar:transitionFromeCell:toCell:animated:)]; + _delegateFlags.transitionFromeCellProgress = [delegate respondsToSelector:@selector(pagerTabBar:transitionFromeCell:toCell:progress:)]; + _delegateFlags.widthForItemAtIndex = [delegate respondsToSelector:@selector(pagerTabBar:widthForItemAtIndex:)]; +} + +- (void)setLayout:(TYTabPagerBarLayout *)layout { + BOOL updateLayout = _layout && _layout != layout; + _layout = layout; + if (updateLayout) { + [self reloadData]; + } +} + +- (TYTabPagerBarLayout *)layout { + if (!_layout) { + _layout = [[TYTabPagerBarLayout alloc]initWithPagerTabBar:self]; + } + return _layout; +} + +#pragma mark - public + +- (void)reloadData { + _countOfItems = [_dataSource numberOfItemsInPagerTabBar]; + if (_curIndex >= _countOfItems) { + _curIndex = _countOfItems - 1; + } + if ([_delegate respondsToSelector:@selector(pagerTabBar:configureLayout:)]) { + [_delegate pagerTabBar:self configureLayout:self.layout]; + } + [self.layout layoutIfNeed]; + [_collectionView reloadData]; + [self.layout adjustContentCellsCenterInBar]; + [self.layout layoutSubViews]; +} + +- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier { + [_collectionView registerClass:Class forCellWithReuseIdentifier:identifier]; +} + +- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier { + [_collectionView registerNib:nib forCellWithReuseIdentifier:identifier]; +} + +- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index { + UICollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; + return cell; +} + +- (CGRect)cellFrameWithIndex:(NSInteger)index +{ + if (index < 0) { + return CGRectZero; + } + if (index >= _countOfItems) { + return CGRectZero; + } + UICollectionViewLayoutAttributes * cellAttrs = [_collectionView layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; + if (!cellAttrs) { + return CGRectZero; + } + return cellAttrs.frame; +} + +- (UICollectionViewCell *)cellForIndex:(NSInteger)index +{ + if (index >= _countOfItems) { + return nil; + } + return (UICollectionViewCell *)[_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; +} + +- (void)scrollToItemFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animate:(BOOL)animate { + if (toIndex < _countOfItems && toIndex >= 0 && fromIndex < _countOfItems && fromIndex >= 0) { + _curIndex = toIndex; + [self transitionFromIndex:fromIndex toIndex:toIndex animated:animate]; + if (_autoScrollItemToCenter) { + if (!_didLayoutSubViews) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self scrollToItemAtIndex:toIndex atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:animate]; + }); + }else { + [self scrollToItemAtIndex:toIndex atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:animate]; + } + } + } +} + +- (void)scrollToItemFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress { + if (toIndex < _countOfItems && toIndex >= 0 && fromIndex < _countOfItems && fromIndex >= 0) { + [self transitionFromIndex:fromIndex toIndex:toIndex progress:progress]; + } +} + +- (void)scrollToItemAtIndex:(NSInteger)index atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated { + [_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0] atScrollPosition:scrollPosition animated:animated]; +} + +- (CGFloat)cellWidthForTitle:(NSString *)title { + if (!title) { + return CGSizeZero.width; + } + //iOS 7 + CGRect frame = [title boundingRectWithSize:CGSizeMake(1000, 1000) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{ NSFontAttributeName:self.layout.selectedTextFont} context:nil]; + return CGSizeMake(ceil(frame.size.width), ceil(frame.size.height) + 1).width; +} + +#pragma mark - UICollectionViewDataSource + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + _countOfItems = [_dataSource numberOfItemsInPagerTabBar]; + return _countOfItems; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + UICollectionViewCell *cell = [_dataSource pagerTabBar:self cellForItemAtIndex:indexPath.item]; + [self.layout transitionFromCell:(indexPath.item == _curIndex ? nil : cell) toCell:(indexPath.item == _curIndex ? cell : nil) animate:NO]; + return cell; +} + +#pragma mark - UICollectionViewDelegateFlowLayout + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath +{ + if ([_delegate respondsToSelector:@selector(pagerTabBar:didSelectItemAtIndex:)]) { + [_delegate pagerTabBar:self didSelectItemAtIndex:indexPath.item]; + } +} + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath +{ + if (self.layout.cellWidth > 0) { + return CGSizeMake(self.layout.cellWidth+self.layout.cellEdging*2, CGRectGetHeight(_collectionView.frame)); + }else if(_delegateFlags.widthForItemAtIndex){ + CGFloat width = [_delegate pagerTabBar:self widthForItemAtIndex:indexPath.item]+self.layout.cellEdging*2; + return CGSizeMake(width, CGRectGetHeight(_collectionView.frame)); + }else { + NSAssert(NO, @"you must return cell width!"); + } + return CGSizeZero; +} + +#pragma mark - transition cell + +- (void)transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated +{ + UICollectionViewCell *fromCell = [self cellForIndex:fromIndex]; + UICollectionViewCell *toCell = [self cellForIndex:toIndex]; + if (_delegateFlags.transitionFromeCellAnimated) { + [_delegate pagerTabBar:self transitionFromeCell:fromCell toCell:toCell animated:animated]; + }else { + [self.layout transitionFromCell:fromCell toCell:toCell animate:animated]; + } + [self.layout setUnderLineFrameWithIndex:toIndex animated:fromCell && animated ? animated: NO]; +} + +- (void)transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress +{ + UICollectionViewCell *fromCell = [self cellForIndex:fromIndex]; + UICollectionViewCell *toCell = [self cellForIndex:toIndex]; + if (_delegateFlags.transitionFromeCellProgress) { + [_delegate pagerTabBar:self transitionFromeCell:fromCell toCell:toCell progress:progress]; + }else { + [self.layout transitionFromCell:fromCell toCell:toCell progress:progress]; + } + [self.layout setUnderLineFrameWithfromIndex:fromIndex toIndex:toIndex progress:progress]; +} + +-(void)layoutSubviews { + [super layoutSubviews]; + _backgroundView.frame = self.bounds; + CGRect frame = UIEdgeInsetsInsetRect(self.bounds, _contentInset); + BOOL needUpdateLayout = (frame.size.height > 0 && _collectionView.frame.size.height != frame.size.height) || (frame.size.width > 0 && _collectionView.frame.size.width != frame.size.width); + _collectionView.frame = frame; + if (!_didLayoutSubViews && !CGRectIsEmpty(_collectionView.frame)) { + _didLayoutSubViews = YES; + } + if (needUpdateLayout) { + [_layout invalidateLayout]; + } + if (frame.size.height > 0 && frame.size.width > 0) { + [_layout adjustContentCellsCenterInBar]; + } + _isFirstLayout = NO; + [_layout layoutSubViews]; +} + +- (void)dealloc { + _collectionView.dataSource = nil; + _collectionView.delegate = nil; +} + +@end diff --git a/Palette/App/Palette/SectionTabs/TYTabPagerBarCell.h b/Palette/App/Palette/SectionTabs/TYTabPagerBarCell.h new file mode 100755 index 0000000..4b0b7ab --- /dev/null +++ b/Palette/App/Palette/SectionTabs/TYTabPagerBarCell.h @@ -0,0 +1,17 @@ +#import +NS_ASSUME_NONNULL_BEGIN +@protocol TYTabPagerBarCellProtocol + +/** + font ,textColor will use TYTabPagerBarLayout's textFont,textColor + */ +@property (nonatomic, strong, readonly) UILabel *titleLabel; + +@end + +@interface TYTabPagerBarCell : UICollectionViewCell +@property (nonatomic, weak,readonly) UILabel *titleLabel; + ++ (NSString *)cellIdentifier; +@end +NS_ASSUME_NONNULL_END diff --git a/Palette/App/Palette/SectionTabs/TYTabPagerBarCell.m b/Palette/App/Palette/SectionTabs/TYTabPagerBarCell.m new file mode 100755 index 0000000..ff6384c --- /dev/null +++ b/Palette/App/Palette/SectionTabs/TYTabPagerBarCell.m @@ -0,0 +1,45 @@ +#import "TYTabPagerBarCell.h" + +@interface TYTabPagerBarCell () +@property (nonatomic, weak) UILabel *titleLabel; +@end + +@implementation TYTabPagerBarCell + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + [self addTabTitleLabel]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder +{ + if (self = [super initWithCoder:aDecoder]) { + [self addTabTitleLabel]; + } + return self; +} + +- (void)addTabTitleLabel +{ + UILabel *titleLabel = [[UILabel alloc]init]; + titleLabel.font = [UIFont systemFontOfSize:15]; + titleLabel.textColor = [UIColor darkTextColor]; + titleLabel.textAlignment = NSTextAlignmentCenter; + [self.contentView addSubview:titleLabel]; + _titleLabel = titleLabel; +} + ++ (NSString *)cellIdentifier { + return @"TYTabPagerBarCell"; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + _titleLabel.frame = self.contentView.bounds; +} + +@end diff --git a/Palette/App/Palette/SectionTabs/TYTabPagerBarLayout.h b/Palette/App/Palette/SectionTabs/TYTabPagerBarLayout.h new file mode 100644 index 0000000..7d56d64 --- /dev/null +++ b/Palette/App/Palette/SectionTabs/TYTabPagerBarLayout.h @@ -0,0 +1,76 @@ +#import +#import "TYTabPagerBarCell.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, TYPagerBarStyle) { + TYPagerBarStyleNoneView, + TYPagerBarStyleProgressView, + TYPagerBarStyleProgressBounceView, + TYPagerBarStyleProgressElasticView, + TYPagerBarStyleCoverView, +}; + +@class TYTabPagerBar; +@interface TYTabPagerBarLayout : NSObject + +@property (nonatomic, weak, readonly) TYTabPagerBar *pagerTabBar; +@property (nonatomic, assign, readonly) CGFloat selectFontScale; + +// set barStyle will reset propertys, so you should first time set it, +@property (nonatomic, assign) TYPagerBarStyle barStyle; // default TYPagerBarStyleProgressElasticView + +@property (nonatomic, assign) UIEdgeInsets sectionInset; + +// progress view +@property (nonatomic, assign) CGFloat progressHeight; // default 2 +@property (nonatomic, assign) CGFloat progressWidth; //if > 0 progress width is equal,else progress width is cell width +@property (nonatomic, strong, nullable) UIColor *progressColor; + +@property (nonatomic, assign) CGFloat progressRadius; // height/2 +@property (nonatomic, assign) CGFloat progressBorderWidth; +@property (nonatomic, strong, nullable) UIColor *progressBorderColor; + +@property (nonatomic, assign) CGFloat progressHorEdging; // default 6, if < 0 width + edge ,if >0 width - edge +@property (nonatomic, assign) CGFloat progressVerEdging; // default 0, cover style is 3. + +// cell frame +@property (nonatomic, assign) CGFloat cellWidth; // default 0, if > 0 cells width is equal,else if = 0 cell will call delegate +@property (nonatomic, assign) CGFloat cellSpacing; // default 2,cell space +@property (nonatomic, assign) CGFloat cellEdging; // default 0,cell left right edge +@property (nonatomic, assign) BOOL adjustContentCellsCenter;// default NO, cells center if contentSize < bar's width ,will set sectionInset + +// TYTabPagerBarCellProtocol -> cell's label +@property (nonatomic, strong) UIFont *normalTextFont; // default 15 +@property (nonatomic, strong) UIFont *selectedTextFont; // default 17 +@property (nonatomic, strong) UIColor *normalTextColor; // default 51.51.51 +@property (nonatomic, strong) UIColor *selectedTextColor; // default white +@property (nonatomic, assign) BOOL textColorProgressEnable; // default YES + +// animate duration +@property (nonatomic, assign) CGFloat animateDuration; // default 0.3 + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +- (instancetype)initWithPagerTabBar:(TYTabPagerBar *)pagerTabBar NS_DESIGNATED_INITIALIZER; + +- (void)layoutIfNeed; + +- (void)invalidateLayout; + +- (void)layoutSubViews; + +- (void)adjustContentCellsCenterInBar; + +// override +- (void)transitionFromCell:(UICollectionViewCell *_Nullable)fromCell toCell:(UICollectionViewCell *_Nullable)toCell animate:(BOOL)animate; + +- (void)transitionFromCell:(UICollectionViewCell *_Nullable)fromCell toCell:(UICollectionViewCell *_Nullable)toCell progress:(CGFloat)progress; + +- (void)setUnderLineFrameWithIndex:(NSInteger)index animated:(BOOL)animated; + +- (void)setUnderLineFrameWithfromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress; +@end + +NS_ASSUME_NONNULL_END diff --git a/Palette/App/Palette/SectionTabs/TYTabPagerBarLayout.m b/Palette/App/Palette/SectionTabs/TYTabPagerBarLayout.m new file mode 100644 index 0000000..019ef9b --- /dev/null +++ b/Palette/App/Palette/SectionTabs/TYTabPagerBarLayout.m @@ -0,0 +1,334 @@ +#import "TYTabPagerBarLayout.h" +#import "TYTabPagerBar.h" + +@interface TYTabPagerBarLayout () + +@property (nonatomic, weak) TYTabPagerBar *pagerTabBar; + +@property (nonatomic, assign) CGFloat selectFontScale; + +@end + +#define kUnderLineViewHeight 2 + +@implementation TYTabPagerBarLayout + +- (instancetype)initWithPagerTabBar:(TYTabPagerBar *)pagerTabBar { + if (self = [super init]) { + _pagerTabBar = pagerTabBar; + [self configurePropertys]; + self.barStyle = TYPagerBarStyleProgressElasticView; + } + return self; +} + +- (void)configurePropertys { + _cellSpacing = 2; + _cellEdging = 3; + _cellWidth = 0; + _progressHorEdging = 6; + _progressWidth = 0; + _animateDuration = 0.25; + + _normalTextFont = [UIFont systemFontOfSize:15]; + _selectedTextFont = [UIFont systemFontOfSize:18]; + _normalTextColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1]; + _selectedTextColor = [UIColor redColor]; + _textColorProgressEnable = YES; + //_adjustContentCellsCenter = YES; +} + +#pragma mark - geter setter + +- (void)setProgressRadius:(CGFloat)progressRadius { + _progressRadius = progressRadius; + _pagerTabBar.progressView.layer.cornerRadius = progressRadius; +} + +- (void)setProgressBorderWidth:(CGFloat)progressBorderWidth { + _progressBorderWidth = progressBorderWidth; + _pagerTabBar.progressView.layer.borderWidth = progressBorderWidth; +} + +- (void)setProgressBorderColor:(UIColor *)progressBorderColor { + _progressBorderColor = progressBorderColor; + if (!_progressColor) { + _pagerTabBar.progressView.backgroundColor = [UIColor clearColor]; + } + _pagerTabBar.progressView.layer.borderColor = progressBorderColor.CGColor; +} + +- (void)setProgressColor:(UIColor *)progressColor { + _progressColor = progressColor; + _pagerTabBar.progressView.backgroundColor = progressColor; +} + +- (void)setProgressHeight:(CGFloat)progressHeight { + _progressHeight = progressHeight; + CGRect frame = _pagerTabBar.progressView.frame; + CGFloat height = CGRectGetHeight(_pagerTabBar.collectionView.frame); + frame.origin.y = _barStyle == TYPagerBarStyleCoverView ? (height - _progressHeight)/2:(height - _progressHeight - _progressVerEdging); + frame.size.height = progressHeight; + _pagerTabBar.progressView.frame = frame; +} + +- (UIEdgeInsets)sectionInset { + if (!UIEdgeInsetsEqualToEdgeInsets(_sectionInset, UIEdgeInsetsZero) || _barStyle != TYPagerBarStyleCoverView) { + return _sectionInset; + } + if (_barStyle == TYPagerBarStyleCoverView && _adjustContentCellsCenter) { + return _sectionInset; + } + CGFloat horEdging = -_progressHorEdging+_cellSpacing; + return UIEdgeInsetsMake(0, horEdging, 0, horEdging); +} + +- (void)setAdjustContentCellsCenter:(BOOL)adjustContentCellsCenter { + BOOL change = _adjustContentCellsCenter != adjustContentCellsCenter; + _adjustContentCellsCenter = adjustContentCellsCenter; + if (change && _pagerTabBar.superview) { + [_pagerTabBar setNeedsLayout]; + } +} + +- (void)setBarStyle:(TYPagerBarStyle)barStyle +{ + if (barStyle == _barStyle) { + return; + } + if (_barStyle == TYPagerBarStyleCoverView) { + self.progressBorderWidth = 0; + self.progressBorderColor = nil; + } + _barStyle = barStyle; + switch (barStyle) { + case TYPagerBarStyleProgressView: + self.progressWidth = 0; + self.progressHorEdging = 6; + self.progressVerEdging = 0; + self.progressHeight = kUnderLineViewHeight; + break; + case TYPagerBarStyleProgressBounceView: + case TYPagerBarStyleProgressElasticView: + self.progressWidth = 30; + self.progressVerEdging = 0; + self.progressHorEdging = 0; + self.progressHeight = kUnderLineViewHeight; + break; + case TYPagerBarStyleCoverView: + self.progressWidth = 0; + self.progressHorEdging = -self.progressHeight/4; + self.progressVerEdging = 3; + break; + default: + break; + } + _pagerTabBar.progressView.hidden = barStyle == TYPagerBarStyleNoneView; + if (barStyle == TYPagerBarStyleCoverView) { + _progressRadius = 0; + _pagerTabBar.progressView.layer.zPosition = -1; + [_pagerTabBar.progressView removeFromSuperview]; + [_pagerTabBar.collectionView insertSubview: _pagerTabBar.progressView atIndex:0]; + }else { + self.progressRadius = _progressHeight/2; + if (_pagerTabBar.progressView.layer.zPosition == -1) { + _pagerTabBar.progressView.layer.zPosition = 0; + [_pagerTabBar.progressView removeFromSuperview]; + [_pagerTabBar.collectionView addSubview:_pagerTabBar.progressView]; + } + + } +} + +#pragma mark - public + +- (void)layoutIfNeed { + UICollectionViewFlowLayout *collectionLayout = (UICollectionViewFlowLayout *)_pagerTabBar.collectionView.collectionViewLayout; + collectionLayout.minimumLineSpacing = _cellSpacing; + collectionLayout.minimumInteritemSpacing = _cellSpacing; + _selectFontScale = self.normalTextFont.pointSize/(self.selectedTextFont ? self.selectedTextFont.pointSize:self.normalTextFont.pointSize); + collectionLayout.sectionInset = _sectionInset; +} + +- (void)invalidateLayout { + [_pagerTabBar.collectionView.collectionViewLayout invalidateLayout]; +} + +- (void)adjustContentCellsCenterInBar { + if (!_adjustContentCellsCenter || !_pagerTabBar.superview) { + return; + } + CGRect frame = self.pagerTabBar.collectionView.frame; + if (CGRectIsEmpty(frame)) { + return; + } + + UICollectionViewFlowLayout *collectionLayout = (UICollectionViewFlowLayout *)_pagerTabBar.collectionView.collectionViewLayout; + CGSize contentSize = collectionLayout.collectionViewContentSize; + NSArray *layoutAttribulte = [collectionLayout layoutAttributesForElementsInRect:CGRectMake(0, 0, MAX(contentSize.width, CGRectGetWidth(frame)), MAX(contentSize.height,CGRectGetHeight(frame)))]; + if (layoutAttribulte.count == 0) { + return; + } + + UICollectionViewLayoutAttributes *firstAttribute = layoutAttribulte.firstObject; + UICollectionViewLayoutAttributes *lastAttribute = layoutAttribulte.lastObject; + CGFloat left = CGRectGetMinX(firstAttribute.frame); + CGFloat right = CGRectGetMaxX(lastAttribute.frame); + if (right - left > CGRectGetWidth(self.pagerTabBar.frame)) { + return; + } + CGFloat sapce = (CGRectGetWidth(self.pagerTabBar.frame) - (right - left))/2; + _sectionInset = UIEdgeInsetsMake(_sectionInset.top, sapce, _sectionInset.bottom, sapce); + collectionLayout.sectionInset = _sectionInset; +} + +- (CGRect)cellFrameWithIndex:(NSInteger)index { + return [_pagerTabBar cellFrameWithIndex:index]; +} + +#pragma mark - cell + +- (void)transitionFromCell:(UICollectionViewCell *)fromCell toCell:(UICollectionViewCell *)toCell animate:(BOOL)animate { + if (_pagerTabBar.countOfItems == 0) { + return; + } + void (^animateBlock)() = ^{ + if (fromCell) { + fromCell.titleLabel.font = _normalTextFont; + fromCell.titleLabel.textColor = _normalTextColor; + fromCell.transform = CGAffineTransformMakeScale(_selectFontScale, _selectFontScale); + } + if (toCell) { + toCell.titleLabel.font = _normalTextFont; + toCell.titleLabel.textColor = _selectedTextColor ? _selectedTextColor : _normalTextColor; + toCell.transform = CGAffineTransformIdentity; + } + }; + if (animate) { + [UIView animateWithDuration:_animateDuration animations:^{ + animateBlock(); + }]; + }else{ + animateBlock(); + } + +} + +- (void)transitionFromCell:(UICollectionViewCell *)fromCell toCell:(UICollectionViewCell *)toCell progress:(CGFloat)progress { + if (_pagerTabBar.countOfItems == 0 || !_textColorProgressEnable) { + return; + } + CGFloat currentTransform = (1.0 - _selectFontScale)*progress; + fromCell.transform = CGAffineTransformMakeScale(1.0-currentTransform, 1.0-currentTransform); + toCell.transform = CGAffineTransformMakeScale(_selectFontScale+currentTransform, _selectFontScale+currentTransform); + + if (_normalTextColor == _selectedTextColor || !_selectedTextColor) { + return; + } + + CGFloat narR=0,narG=0,narB=0,narA=1; + [_normalTextColor getRed:&narR green:&narG blue:&narB alpha:&narA]; + CGFloat selR=0,selG=0,selB=0,selA=1; + [_selectedTextColor getRed:&selR green:&selG blue:&selB alpha:&selA]; + CGFloat detalR = narR - selR ,detalG = narG - selG,detalB = narB - selB,detalA = narA - selA; + + fromCell.titleLabel.textColor = [UIColor colorWithRed:selR+detalR*progress green:selG+detalG*progress blue:selB+detalB*progress alpha:selA+detalA*progress]; + toCell.titleLabel.textColor = [UIColor colorWithRed:narR-detalR*progress green:narG-detalG*progress blue:narB-detalB*progress alpha:narA-detalA*progress]; +} + +#pragma mark - progress View + +// set up progress view frame +- (void)setUnderLineFrameWithIndex:(NSInteger)index animated:(BOOL)animated +{ + UIView *progressView = _pagerTabBar.progressView; + if (progressView.isHidden || _pagerTabBar.countOfItems == 0) { + return; + } + + CGRect cellFrame = [self cellFrameWithIndex:index]; + CGFloat progressHorEdging = _progressWidth > 0 ? (cellFrame.size.width - _progressWidth)/2 : _progressHorEdging; + CGFloat progressX = cellFrame.origin.x+progressHorEdging; + CGFloat progressY = _barStyle == TYPagerBarStyleCoverView ? (cellFrame.size.height - _progressHeight)/2:(cellFrame.size.height - _progressHeight - _progressVerEdging); + CGFloat width = cellFrame.size.width-2*progressHorEdging; + + if (animated) { + [UIView animateWithDuration:_animateDuration animations:^{ + progressView.frame = CGRectMake(progressX, progressY, width, _progressHeight); + }]; + }else { + progressView.frame = CGRectMake(progressX, progressY, width, _progressHeight); + } +} + +- (void)setUnderLineFrameWithfromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress +{ + UIView *progressView = _pagerTabBar.progressView; + if (progressView.isHidden || _pagerTabBar.countOfItems == 0) { + return; + } + + CGRect fromCellFrame = [self cellFrameWithIndex:fromIndex]; + CGRect toCellFrame = [self cellFrameWithIndex:toIndex]; + + CGFloat progressFromEdging = _progressWidth > 0 ? (fromCellFrame.size.width - _progressWidth)/2 : _progressHorEdging; + CGFloat progressToEdging = _progressWidth > 0 ? (toCellFrame.size.width - _progressWidth)/2 : _progressHorEdging; + CGFloat progressY = _barStyle == TYPagerBarStyleCoverView ? (toCellFrame.size.height - _progressHeight)/2:(toCellFrame.size.height - _progressHeight - _progressVerEdging); + CGFloat progressX = 0, width = 0; + + if (_barStyle == TYPagerBarStyleProgressBounceView) { + if (fromCellFrame.origin.x < toCellFrame.origin.x) { + if (progress <= 0.5) { + progressX = fromCellFrame.origin.x + progressFromEdging; + width = (toCellFrame.size.width-progressToEdging+progressFromEdging+_cellSpacing)*2*progress + fromCellFrame.size.width-2*progressFromEdging; + }else { + progressX = fromCellFrame.origin.x + progressFromEdging + (fromCellFrame.size.width-progressFromEdging+progressToEdging+_cellSpacing)*(progress-0.5)*2; + width = CGRectGetMaxX(toCellFrame)-progressToEdging - progressX; + } + }else { + if (progress <= 0.5) { + progressX = fromCellFrame.origin.x + progressFromEdging - (toCellFrame.size.width-progressToEdging+progressFromEdging+_cellSpacing)*2*progress; + width = CGRectGetMaxX(fromCellFrame) - progressFromEdging - progressX; + }else { + progressX = toCellFrame.origin.x + progressToEdging; + width = (fromCellFrame.size.width-progressFromEdging+progressToEdging + _cellSpacing)*(1-progress)*2 + toCellFrame.size.width - 2*progressToEdging; + } + } + }else if (_barStyle == TYPagerBarStyleProgressElasticView) { + if (fromCellFrame.origin.x < toCellFrame.origin.x) { + if (progress <= 0.5) { + progressX = fromCellFrame.origin.x + progressFromEdging + (fromCellFrame.size.width-2*progressFromEdging)*progress; + width = (toCellFrame.size.width-progressToEdging+progressFromEdging+_cellSpacing)*2*progress - (toCellFrame.size.width-2*progressToEdging)*progress + fromCellFrame.size.width-2*progressFromEdging-(fromCellFrame.size.width-2*progressFromEdging)*progress; + }else { + progressX = fromCellFrame.origin.x + progressFromEdging + (fromCellFrame.size.width-2*progressFromEdging)*0.5 + (fromCellFrame.size.width-progressFromEdging - (fromCellFrame.size.width-2*progressFromEdging)*0.5 +progressToEdging+_cellSpacing)*(progress-0.5)*2; + width = CGRectGetMaxX(toCellFrame)-progressToEdging - progressX - (toCellFrame.size.width-2*progressToEdging)*(1-progress); + } + }else { + if (progress <= 0.5) { + progressX = fromCellFrame.origin.x + progressFromEdging - (toCellFrame.size.width-(toCellFrame.size.width-2*progressToEdging)/2-progressToEdging+progressFromEdging+_cellSpacing)*2*progress; + width = CGRectGetMaxX(fromCellFrame) - (fromCellFrame.size.width-2*progressFromEdging)*progress - progressFromEdging - progressX; + }else { + progressX = toCellFrame.origin.x + progressToEdging+(toCellFrame.size.width-2*progressToEdging)*(1-progress); + width = (fromCellFrame.size.width-progressFromEdging+progressToEdging-(fromCellFrame.size.width-2*progressFromEdging)/2 + _cellSpacing)*(1-progress)*2 + toCellFrame.size.width - 2*progressToEdging - (toCellFrame.size.width-2*progressToEdging)*(1-progress); + } + } + }else { + progressX = (toCellFrame.origin.x+progressToEdging-(fromCellFrame.origin.x+progressFromEdging))*progress+fromCellFrame.origin.x+progressFromEdging; + width = (toCellFrame.size.width-2*progressToEdging)*progress + (fromCellFrame.size.width-2*progressFromEdging)*(1-progress); + } + + progressView.frame = CGRectMake(progressX,progressY, width, _progressHeight); +} + +- (void)layoutSubViews { + if (CGRectIsEmpty(_pagerTabBar.frame)) { + return; + } + if (_barStyle == TYPagerBarStyleCoverView) { + self.progressHeight = CGRectGetHeight(_pagerTabBar.collectionView.frame) -self.progressVerEdging*2; + self.progressRadius = _progressRadius > 0 ? _progressRadius : self.progressHeight/2; + } + [self setUnderLineFrameWithIndex:_pagerTabBar.curIndex animated:NO]; +} + +@end diff --git a/Palette/App/Palette/main.m b/Palette/App/Palette/main.m new file mode 100644 index 0000000..dba295e --- /dev/null +++ b/Palette/App/Palette/main.m @@ -0,0 +1,11 @@ +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + NSString * appDelegateClassName; + @autoreleasepool { + // Setup code that might create autoreleased objects goes here. + appDelegateClassName = NSStringFromClass([AppDelegate class]); + } + return UIApplicationMain(argc, argv, nil, appDelegateClassName); +} diff --git a/Palette/App/layout/DEBIAN/control b/Palette/App/layout/DEBIAN/control new file mode 100644 index 0000000..21b70b2 --- /dev/null +++ b/Palette/App/layout/DEBIAN/control @@ -0,0 +1,9 @@ +Package: com.titand3v.palette +Name: Palette +Version: 1.0 +Architecture: iphoneos-arm +Description: Browse application info. +Maintainer: TitanD3v +Author: TitanD3v +Section: Utilities +Depends: firmware (>= 14.0) diff --git a/Palette/App/layout/DEBIAN/postinst b/Palette/App/layout/DEBIAN/postinst new file mode 100755 index 0000000..d10668c --- /dev/null +++ b/Palette/App/layout/DEBIAN/postinst @@ -0,0 +1,2 @@ +#!/bin/bash +uicache -p /Applications/Palette.app diff --git a/Palette/Makefile b/Palette/Makefile new file mode 100644 index 0000000..aeac13c --- /dev/null +++ b/Palette/Makefile @@ -0,0 +1,14 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0 + +FINALPACKAGE = 1 +DEBUG = 0 + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += App Tweak Prefs + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Palette/Prefs/Makefile b/Palette/Prefs/Makefile new file mode 100644 index 0000000..a7b85e9 --- /dev/null +++ b/Palette/Prefs/Makefile @@ -0,0 +1,15 @@ +BUNDLE_NAME = PalettePrefs + +$(BUNDLE_NAME)_FILES = $(wildcard *.m) +$(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles +$(BUNDLE_NAME)_FRAMEWORKS = UIKit +$(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences OnBoardingKit +$(BUNDLE_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(BUNDLE_NAME)_LIBRARIES = TitanD3vUniversal + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/bundle.mk + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) + $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/PalettePrefs.plist$(ECHO_END) diff --git a/Palette/Prefs/PALPrimraryListController.h b/Palette/Prefs/PALPrimraryListController.h new file mode 100644 index 0000000..a5d8b77 --- /dev/null +++ b/Palette/Prefs/PALPrimraryListController.h @@ -0,0 +1,29 @@ +#import +#import + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1;; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + + +@interface PALPrimraryListController : TDPrimraryController { + OBWelcomeController *onboardingController; + OBWelcomeController *updateController; +} + +@end diff --git a/Palette/Prefs/PALPrimraryListController.m b/Palette/Prefs/PALPrimraryListController.m new file mode 100644 index 0000000..7ba231a --- /dev/null +++ b/Palette/Prefs/PALPrimraryListController.m @@ -0,0 +1,118 @@ +#include "PALPrimraryListController.h" + +@implementation PALPrimraryListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Primrary" target:self]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[TDPrefsManager sharedInstance] initWithBundleID:@"com.TitanD3v.PalettePrefs" tweakName:@"Palette" prefsBundle:@"PalettePrefs.bundle"]; + + [[TDPrefsManager sharedInstance] bannerTitle:@"Palette" subtitle:@"Coded with 🤍" devName:@"TitanD3v" coverImagePath:@"/Assets/Banner/cover-image.png" showCoverImage:YES iconPath:@"" iconTint:YES]; + + [[TDPrefsManager sharedInstance] changelogPlistPath:@"/Assets/Changelog/changelog.plist" currentVersion:@"Version 1.0"]; + + [[TDPrefsManager sharedInstance] useAssetsFromLibrary:YES]; + +} + + +-(void)presentTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + onboardingController = [[OBWelcomeController alloc] initWithTitle:@"User Guide" detailText:@"A walk through tutorial how to use Palette" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PalettePrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]]; + + [onboardingController addBulletedListItemWithTitle:@"Your time" description:@"Please take a few minutes of your time to read through to get started." image:[UIImage systemImageNamed:@"timer"]]; + + [onboardingController addBulletedListItemWithTitle:@"Main page" description:@"On the main page, there's menu icon on the navigation bar it will present the drawer when tapped. You will find the social media details, changelog, backup/restore, tweak list, profile and crew list." image:[UIImage systemImageNamed:@"square.stack.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Report a bug" description:@"If you are experiencing a bug or any other issues, you can report a bug from this page below the close button, it will bring up the Bug Report page. You can select the categories, write description about a bug, attach a .txt file, photo, provide URL link for the pastebin or any pasteboard website also you can attach all of them if you want. Once you submit a bug report and our team will be in touch with you within 48 hours. If you haven't heard anything from us and please don't hesitate to get in touch with us through social media." image:[UIImage systemImageNamed:@"ant.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Gesture" description:@"Select your preferred gesture for status bar to invoke colour picker." image:[UIImage systemImageNamed:@"hand.tap.fill"]]; + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [onboardingController.buttonTray addButton:dismissButton]; + + onboardingController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:onboardingController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [onboardingController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + onboardingController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [onboardingController.buttonTray addCaptionText:@"Thank you for installing Palette"]; + + onboardingController.modalPresentationStyle = UIModalPresentationPageSheet; + onboardingController.modalInPresentation = YES; + [self presentViewController:onboardingController animated:YES completion:nil]; + + UIView *reportView = [[UIView alloc] init]; + reportView.backgroundColor = UIColor.clearColor; + [onboardingController.buttonTray addSubview:reportView]; + + reportView.translatesAutoresizingMaskIntoConstraints = NO; + [reportView.topAnchor constraintEqualToAnchor:dismissButton.bottomAnchor constant:10].active = YES; + [[reportView centerXAnchor] constraintEqualToAnchor:onboardingController.buttonTray.centerXAnchor].active = true; + [reportView.widthAnchor constraintEqualToConstant:140].active = YES; + [reportView.heightAnchor constraintEqualToConstant:40].active = YES; + + + UIImageView *bugImage = [[UIImageView alloc] init]; + bugImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + bugImage.tintColor = [[TDAppearance sharedInstance] tintColour]; + [reportView addSubview:bugImage]; + + bugImage.translatesAutoresizingMaskIntoConstraints = NO; + [bugImage.leadingAnchor constraintEqualToAnchor:reportView.leadingAnchor constant:10].active = YES; + [[bugImage centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + [bugImage.widthAnchor constraintEqualToConstant:30].active = YES; + [bugImage.heightAnchor constraintEqualToConstant:30].active = YES; + + + UILabel *reportLabel = [[UILabel alloc] init]; + reportLabel.text = @"Report a bug"; + reportLabel.textColor = [[TDAppearance sharedInstance] tintColour]; + reportLabel.textAlignment = NSTextAlignmentLeft; + [reportView addSubview:reportLabel]; + + reportLabel.translatesAutoresizingMaskIntoConstraints = NO; + [reportLabel.leadingAnchor constraintEqualToAnchor:bugImage.trailingAnchor constant:5].active = YES; + [[reportLabel centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + + [reportView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentReportBugVC)]]; + +} + + +-(void)dismissTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentReportBugVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; + + TDReportBugViewController *bugVC = [[TDReportBugViewController alloc] init]; + bugVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [self presentViewController:bugVC animated:YES completion:nil]; +} + +@end diff --git a/Palette/Prefs/Resources/Assets/Banner/banner-icon.png b/Palette/Prefs/Resources/Assets/Banner/banner-icon.png new file mode 100644 index 0000000..f1c2acc Binary files /dev/null and b/Palette/Prefs/Resources/Assets/Banner/banner-icon.png differ diff --git a/Palette/Prefs/Resources/Assets/Banner/cover-image.png b/Palette/Prefs/Resources/Assets/Banner/cover-image.png new file mode 100644 index 0000000..591e9e9 Binary files /dev/null and b/Palette/Prefs/Resources/Assets/Banner/cover-image.png differ diff --git a/Palette/Prefs/Resources/Assets/Cell/prefs-icon@2x.png b/Palette/Prefs/Resources/Assets/Cell/prefs-icon@2x.png new file mode 100644 index 0000000..1b7f0e3 Binary files /dev/null and b/Palette/Prefs/Resources/Assets/Cell/prefs-icon@2x.png differ diff --git a/Palette/Prefs/Resources/Assets/Cell/prefs-icon@3x.png b/Palette/Prefs/Resources/Assets/Cell/prefs-icon@3x.png new file mode 100644 index 0000000..3261e53 Binary files /dev/null and b/Palette/Prefs/Resources/Assets/Cell/prefs-icon@3x.png differ diff --git a/Palette/Prefs/Resources/Assets/Changelog/changelog.plist b/Palette/Prefs/Resources/Assets/Changelog/changelog.plist new file mode 100644 index 0000000..5552c96 --- /dev/null +++ b/Palette/Prefs/Resources/Assets/Changelog/changelog.plist @@ -0,0 +1,22 @@ + + + + + + + Date + 20th June 2021 + Version + v1.0 + ChangelogDescription + + Initial Release... + + updateCategories + + 0 + + + + + \ No newline at end of file diff --git a/Palette/Prefs/Resources/Info.plist b/Palette/Prefs/Resources/Info.plist new file mode 100644 index 0000000..6c201ae --- /dev/null +++ b/Palette/Prefs/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + PalettePrefs + CFBundleIdentifier + com.titand3v.paletteprefs + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + PALPrimraryListController + + diff --git a/Palette/Prefs/Resources/Primrary.plist b/Palette/Prefs/Resources/Primrary.plist new file mode 100644 index 0000000..8e1231f --- /dev/null +++ b/Palette/Prefs/Resources/Primrary.plist @@ -0,0 +1,92 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable + + + + cellClass + TDEnableCell + default + + key + togglePalette + disabledTitle + Disable Palette + enabledTitle + Enable Palette + disabledColour + B92F2F + enabledColour + 43EB1F + disabledIconPath + Assets/example-icon.png + enabledIconPath + Assets/example-icon.png + defaults + com.TitanD3v.PalettePrefs + PostNotification + com.TitanD3v.PalettePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Gesture + + + + cell + PSLinkListCell + cellClass + TDListCell + title + Status Bar + subtitle + Gesture + default + 0 + detail + TDListController + key + paletteGesture + validValues + + 0 + 1 + 2 + 3 + + validTitles + + Double Tap + Triple Tap + Swipe Left + Swipe Right + + iconName + button + defaults + com.TitanD3v.PalettePrefs + PostNotification + com.TitanD3v.PalettePrefs.settingschanged + + + + title + + + diff --git a/Palette/Prefs/entry.plist b/Palette/Prefs/entry.plist new file mode 100644 index 0000000..7df9ced --- /dev/null +++ b/Palette/Prefs/entry.plist @@ -0,0 +1,21 @@ + + + + + entry + + bundle + PalettePrefs + cell + PSLinkCell + detail + PALPrimraryListController + icon + Assets/Cell/prefs-icon.png + isController + + label + Palette + + + diff --git a/Palette/Tweak/AddCollectionViewController.h b/Palette/Tweak/AddCollectionViewController.h new file mode 100644 index 0000000..64e544f --- /dev/null +++ b/Palette/Tweak/AddCollectionViewController.h @@ -0,0 +1,12 @@ +#import + +@interface AddCollectionViewController : UIViewController +@property (nonatomic, retain) UIButton *cancelButton; +@property (nonatomic, retain) UIButton *addButton; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UITextField *textField; +@property (nonatomic, retain) NSMutableDictionary *mutableDict; +@property (nonatomic, retain) NSString *hexCode; +@end + diff --git a/Palette/Tweak/AddCollectionViewController.m b/Palette/Tweak/AddCollectionViewController.m new file mode 100644 index 0000000..110117c --- /dev/null +++ b/Palette/Tweak/AddCollectionViewController.m @@ -0,0 +1,176 @@ +#import "AddCollectionViewController.h" + +@implementation AddCollectionViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.cancelButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [self.cancelButton addTarget:self action:@selector(dismissVC) forControlEvents:UIControlEventTouchUpInside]; + [self.cancelButton setTitle:@"Cancel" forState:UIControlStateNormal]; + [self.cancelButton setTitleColor:[UIColor colorWithRed: 0.43 green: 0.83 blue: 0.98 alpha: 1.00] forState:UIControlStateNormal]; + [self.view addSubview:self.cancelButton]; + + [self.cancelButton top:self.view.topAnchor padding:16]; + [self.cancelButton leading:self.view.leadingAnchor padding:20]; + + + self.addButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [self.addButton addTarget:self action:@selector(addCollection) forControlEvents:UIControlEventTouchUpInside]; + [self.addButton setTitle:@"Add" forState:UIControlStateNormal]; + [self.addButton setTitleColor:[UIColor colorWithRed: 0.43 green: 0.83 blue: 0.98 alpha: 1.00] forState:UIControlStateNormal]; + self.addButton.hidden = YES; + [self.view addSubview:self.addButton]; + + [self.addButton top:self.view.topAnchor padding:16]; + [self.addButton trailing:self.view.trailingAnchor padding:-20]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + self.iconImage.image = [[UIImage systemImageNamed:@"heart.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.iconImage.tintColor = [UIColor colorWithRed: 0.43 green: 0.83 blue: 0.98 alpha: 1.00]; + [self.view addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(80, 80)]; + [self.iconImage top:self.addButton.bottomAnchor padding:25]; + [self.iconImage x:self.view.centerXAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.font = [UIFont systemFontOfSize:25 weight:UIFontWeightSemibold]; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.text = @"Collection Name"; + self.titleLabel.numberOfLines = 2; + [self.view addSubview:self.titleLabel]; + + [self.titleLabel top:self.iconImage.bottomAnchor padding:30]; + [self.titleLabel leading:self.view.leadingAnchor padding:20]; + [self.titleLabel trailing:self.view.trailingAnchor padding:-20]; + [self.titleLabel x:self.view.centerXAnchor]; + + + self.textField = [[UITextField alloc] init]; + self.textField.borderStyle = UITextBorderStyleRoundedRect; + self.textField.font = [UIFont systemFontOfSize:15]; + self.textField.placeholder = @"Enter collection name..."; + self.textField.autocorrectionType = UITextAutocorrectionTypeNo; + self.textField.keyboardType = UIKeyboardTypeDefault; + self.textField.textColor = UIColor.labelColor; + self.textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; + self.textField.delegate = self; + self.textField.tintColor = [UIColor colorWithRed: 0.43 green: 0.83 blue: 0.98 alpha: 1.00]; + [self.textField addTarget:self action:@selector(textFieldDidChange:)forControlEvents:UIControlEventEditingChanged]; + [self.view addSubview:self.textField]; + + [self.textField height:40]; + [self.textField top:self.titleLabel.bottomAnchor padding:30]; + [self.textField leading:self.view.leadingAnchor padding:20]; + [self.textField trailing:self.view.trailingAnchor padding:-20]; + [self.textField x:self.view.centerXAnchor]; + + [self.textField becomeFirstResponder]; + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.view.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.12 alpha: 1.00]; + self.textField.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + } else { + self.view.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.textField.backgroundColor = UIColor.whiteColor; + } +} + + +- (void)textFieldDidChange:(id)sender { + + if (self.textField.text && self.textField.text.length > 0) { + self.addButton.hidden = NO; + } else { + self.addButton.hidden = YES; + } + +} + + +- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + + if (self.textField.text && self.textField.text.length > 0) { + self.addButton.hidden = NO; + } else { + self.addButton.hidden = YES; + } + + return YES; +} + + +- (BOOL)textFieldShouldEndEditing:(UITextField *)textField { + + if (self.textField.text && self.textField.text.length > 0) { + self.addButton.hidden = NO; + } else { + self.addButton.hidden = YES; + } + + return YES; +} + + +-(void)addCollection { + + [self.textField resignFirstResponder]; + + NSString *prefPath = @"/var/mobile/Library/Preferences/PaletteCollections.plist"; + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:prefPath]; + self.mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + NSString *withID = [NSString stringWithFormat:@"%lld", (long long)([[NSDate date] timeIntervalSince1970] * 1000.0)]; + NSDictionary *data = @{@"id" : withID, @"colourName" : self.textField.text, @"hexCode" : self.hexCode}; + [self.mutableDict setValue:data forKey:withID]; + [self.mutableDict writeToFile:prefPath atomically:YES]; + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Saved!" message:[NSString stringWithFormat:@"%@ have been added to your collection", self.textField.text] preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self dismissVC2]; + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + +} + + +- (void)dismissVC { + + [self.textField resignFirstResponder]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +- (void)dismissVC2 { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +- (void)traitCollectionDidChange:(UITraitCollection *) previousTraitCollection { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.view.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.12 alpha: 1.00]; + self.textField.backgroundColor = [UIColor colorWithRed: 0.17 green: 0.17 blue: 0.18 alpha: 1.00]; + } else { + self.view.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00]; + self.textField.backgroundColor = UIColor.whiteColor; + } +} + + +@end + + + + + + diff --git a/Palette/Tweak/Makefile b/Palette/Tweak/Makefile new file mode 100644 index 0000000..7337174 --- /dev/null +++ b/Palette/Tweak/Makefile @@ -0,0 +1,16 @@ +export ARCHS = arm64 arm64e +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +TWEAK_NAME = Palette + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Palette/Tweak/Palette.plist b/Palette/Tweak/Palette.plist new file mode 100644 index 0000000..10dc654 --- /dev/null +++ b/Palette/Tweak/Palette.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard" ); }; } diff --git a/Palette/Tweak/Palette.xm b/Palette/Tweak/Palette.xm new file mode 100644 index 0000000..c416884 --- /dev/null +++ b/Palette/Tweak/Palette.xm @@ -0,0 +1,220 @@ +#import +#import "AddCollectionViewController.h" + +static NSString *BID = @"com.TitanD3v.PalettePrefs"; +static BOOL togglePalette; +NSInteger paletteGesture; + +@interface _UIStatusBar : UIView +- (NSString *)hexStringFromColor:(UIColor *)color; +-(void)showActionMenuWithColour:(UIColor *)selectedColour; +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle; +-(void)showAddCollectionWithHexCode:(NSString *)colourString; +@end + +UIColorPickerViewController *colourPickerVC; +UIColor *tempColour; + + +%group Palette +%hook _UIStatusBar + +-(void)willMoveToSuperview:(UIView *)newViews { + %orig(newViews); + + if (paletteGesture == 0) { + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(presentColourPicker)]; + tapGesture.numberOfTapsRequired = 2; + [self addGestureRecognizer:tapGesture]; + } else if (paletteGesture == 1) { + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(presentColourPicker)]; + tapGesture.numberOfTapsRequired = 3; + [self addGestureRecognizer:tapGesture]; + } else if (paletteGesture == 2) { + UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(presentColourPicker)]; + swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; + [self addGestureRecognizer:swipeLeft]; + } else if (paletteGesture == 3) { + UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(presentColourPicker)]; + swipeRight.direction = UISwipeGestureRecognizerDirectionRight; + [self addGestureRecognizer:swipeRight]; + } + +} + + +%new +-(void)presentColourPicker { + + colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + colourPickerVC.modalInPresentation = YES; + colourPickerVC.selectedColor = [UIColor colorWithRed: 0.43 green: 0.83 blue: 0.98 alpha: 1.00]; + UIViewController *controller = [[UIApplication sharedApplication] keyWindow].rootViewController; + [controller presentViewController:colourPickerVC animated:YES completion:nil]; + +} + + +%new +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + tempColour = viewController.selectedColor; + [self showActionMenuWithColour:tempColour]; +} + + +%new +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + tempColour = viewController.selectedColor; + NSLog(@"Colour picker selected %@", [self hexStringFromColor:tempColour]); + +} + + +%new +- (NSString *)hexStringFromColor:(UIColor *)color { + const CGFloat *components = CGColorGetComponents(color.CGColor); + + CGFloat r = components[0]; + CGFloat g = components[1]; + CGFloat b = components[2]; + + return [NSString stringWithFormat:@"%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255)]; +} + + +%new +-(void)showActionMenuWithColour:(UIColor *)selectedColour { + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + + const CGFloat *_components = CGColorGetComponents(selectedColour.CGColor); + CGFloat red = _components[0]; + CGFloat green = _components[1]; + CGFloat blue = _components[2]; + + NSString *redString = [NSString stringWithFormat:@"%d", (int) (red * 255.0)]; + NSString *greenString = [NSString stringWithFormat:@"%d", (int) (green * 255)]; + NSString *blueString = [NSString stringWithFormat:@"%d", (int) (blue * 255)]; + + + UIAlertController *view = [UIAlertController alertControllerWithTitle:@"" message:@"Select which colour code you want to copy to clipboard or add to your collection." preferredStyle:UIAlertControllerStyleActionSheet]; + + UIAlertAction *addAction = [UIAlertAction actionWithTitle:@"Add to Collection" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + NSString *colourString = [NSString stringWithFormat:@"%@",[self hexStringFromColor:selectedColour]]; + [self showAddCollectionWithHexCode:colourString]; + + }]; + + + UIAlertAction *hexAction = [UIAlertAction actionWithTitle:@"Copy HEX Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"#%@",[self hexStringFromColor:selectedColour]]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for HEX was saved to your clipboard"]; + }]; + + + UIAlertAction *rgbAction = [UIAlertAction actionWithTitle:@"Copy RGB Values" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"rgb(%@, %@, %@)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for RGB was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Swift)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"UIColor(red: %@.0/255.0, green: %@.0/255.0, blue: %@/255.0, alpha: 1.0)",redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Swift was saved to your clipboard"]; + }]; + + + UIAlertAction *swiftuiAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (SwiftUI)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"Color(red: %@/255, green: %@/255, blue: %@/255)", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for SwiftUI was saved to your clipboard"]; + }]; + + + UIAlertAction *objcAction = [UIAlertAction actionWithTitle:@"Copy UIColor Values (Objective-C)" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + pasteboard.string = [NSString stringWithFormat:@"[UIColor colorWithRed:%@/255.0 green: %@/255.0 blue: %@/255.0 alpha: 1.00];", redString, greenString, blueString]; + [self showAlertWithTitle:@"Saved!" subtitle:@"The colour values for Objective-C was saved to your clipboard"]; + }]; + + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + [view dismissViewControllerAnimated:YES completion:nil]; + }]; + + + [view addAction:addAction]; + [view addAction:hexAction]; + [view addAction:rgbAction]; + [view addAction:swiftAction]; + [view addAction:swiftuiAction]; + [view addAction:objcAction]; + [view addAction:cancelAction]; + view.view.tintColor = [UIColor colorWithRed: 0.43 green: 0.83 blue: 0.98 alpha: 1.00]; + UIViewController *controller = [[UIApplication sharedApplication] keyWindow].rootViewController; + [controller presentViewController:view animated:YES completion:nil]; + + +} + + +%new +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + }]; + + [alert addAction:defaultAction]; + alert.view.tintColor = [UIColor colorWithRed: 0.43 green: 0.83 blue: 0.98 alpha: 1.00]; + UIViewController *controller = [[UIApplication sharedApplication] keyWindow].rootViewController; + [controller presentViewController:alert animated:YES completion:nil]; + +} + + +%new +-(void)showAddCollectionWithHexCode:(NSString *)colourString { + + AddCollectionViewController *collectionVC = [[AddCollectionViewController alloc] init]; + collectionVC.modalInPresentation = YES; + collectionVC.hexCode = colourString; + UIViewController *controller = [[UIApplication sharedApplication] keyWindow].rootViewController; + [controller presentViewController:collectionVC animated:YES completion:nil]; + +} + +%end +%end + + + + +void SettingsChanged() { + + togglePalette = [[TDTweakManager sharedInstance] boolForKey:@"togglePalette" defaultValue:YES ID:BID]; + paletteGesture = [[TDTweakManager sharedInstance] intForKey:@"paletteGesture" defaultValue:0 ID:BID]; + +} + +%ctor { + + NSString * path = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0]; + if ([path containsString:@"/Application"] || [path containsString:@"SpringBoard.app"]) { + + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)SettingsChanged, CFSTR("com.TitanD3v.PalettePrefs.settingschanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + SettingsChanged(); + + if (togglePalette) { + %init(Palette); + } + + } +} diff --git a/Palette/Tweak/Tutorial/Tutorial.xm b/Palette/Tweak/Tutorial/Tutorial.xm new file mode 100644 index 0000000..0c940f4 --- /dev/null +++ b/Palette/Tweak/Tutorial/Tutorial.xm @@ -0,0 +1,110 @@ +#import + +static NSString *BIDD = @"com.TitanD3v.PalettePrefs"; +static BOOL togglePalettee; +static BOOL showSBTutorial; + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + +@interface SpringBoard : UIView +-(void)presentPaletteTutorialVC; +@end + + +OBWelcomeController *tutorialController; + + +%group Tutorial +%hook SpringBoard + +- (void)applicationDidFinishLaunching:(id)application { + %orig; + + if ((togglePalettee) && (showSBTutorial)) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self presentPaletteTutorialVC]; + }); + } +} + +%new +-(void)presentPaletteTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + tutorialController = [[OBWelcomeController alloc] initWithTitle:@"Palette" detailText:@"Tutorial" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PalettePrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]]; + tutorialController.view.tintColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + + [tutorialController addBulletedListItemWithTitle:@"Gesture" description:@"Use your preferred gesture on the status bar to invoke Palette's colour picker." image:[UIImage systemImageNamed:@"hand.tap.fill"]]; + + [tutorialController addBulletedListItemWithTitle:@"Warning!!!" description:@"When you finished selecting the colour or using the eyedrop tool then make sure you press on the close button then it will show more options afterwards so you can copy the colour code or add them to your collection. Don't swipe down to dismiss the colour picker unless you actually want to dismiss it. Otherwise press the close button." image:[UIImage systemImageNamed:@"exclamationmark.circle.fill"]]; + + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissPaletteTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [tutorialController.buttonTray addButton:dismissButton]; + + tutorialController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:tutorialController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [tutorialController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + tutorialController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [tutorialController.buttonTray addCaptionText:@"Thank you for installing Palette"]; + + tutorialController.modalPresentationStyle = UIModalPresentationPageSheet; + tutorialController.modalInPresentation = YES; + [[%c(SBIconController) sharedInstance] presentViewController:tutorialController animated:YES completion:nil]; + +} + +%new +-(void)dismissPaletteTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [tutorialController dismissViewControllerAnimated:YES completion:nil]; + [[TDTweakManager sharedInstance] setBool:NO forKey:@"showSBTutorial" ID:BIDD]; +} +%end +%end + + +void SettingsChanged2() { + + togglePalettee = [[TDTweakManager sharedInstance] boolForKey:@"togglePalette" defaultValue:YES ID:BIDD]; + showSBTutorial = [[TDTweakManager sharedInstance] boolForKey:@"showSBTutorial" defaultValue:YES ID:BIDD]; + +} + +%ctor { + NSString * path = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0]; + if ([path containsString:@"/Application"] || [path containsString:@"SpringBoard.app"]) { + + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)SettingsChanged2, CFSTR("com.TitanD3v.PalettePrefs.settingschanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + SettingsChanged2(); + %init(Tutorial); + } +} diff --git a/Palette/control b/Palette/control new file mode 100644 index 0000000..9f113d0 --- /dev/null +++ b/Palette/control @@ -0,0 +1,11 @@ +Package: com.titand3v.palette +Name: Palette +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal +Version: 1.0 +Section: Tweaks +Description: Add colours to your colelction +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/palette/index.html +Icon: https://titand3v.github.io/depictions/palette/assets/icon.png diff --git a/Palette/layout/DEBIAN/postinst b/Palette/layout/DEBIAN/postinst new file mode 100755 index 0000000..52fbea0 --- /dev/null +++ b/Palette/layout/DEBIAN/postinst @@ -0,0 +1,8 @@ +echo "" +echo "" +echo "Thank you for installing Palette 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/Paradise/.DS_Store b/Paradise/.DS_Store new file mode 100644 index 0000000..4e729c6 Binary files /dev/null and b/Paradise/.DS_Store differ diff --git a/Paradise/App/.DS_Store b/Paradise/App/.DS_Store new file mode 100644 index 0000000..a0b11fe Binary files /dev/null and b/Paradise/App/.DS_Store differ diff --git a/Paradise/App/Makefile b/Paradise/App/Makefile new file mode 100644 index 0000000..8db48ee --- /dev/null +++ b/Paradise/App/Makefile @@ -0,0 +1,20 @@ +TARGET = iphone:clang:latest:14.0 +INSTALL_TARGET_PROCESSES = Paradise +ARCHS = arm64 arm64e + +FINALPACKAGE = 1 +DEBUG = 0 + +include $(THEOS)/makefiles/common.mk + +XCODEPROJ_NAME = Paradise +Paradise_XCODE_SCHEME = Paradise +Paradise_CODESIGN_FLAGS = -SParadise.entitlements +Paradise_XCODE_PROJECT = Paradise.xcodeproj +Paradise_LIBRARIES = MobileGestalt + +include $(THEOS_MAKE_PATH)/xcodeproj.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete diff --git a/Paradise/App/Paradise.entitlements b/Paradise/App/Paradise.entitlements new file mode 100644 index 0000000..ff71897 --- /dev/null +++ b/Paradise/App/Paradise.entitlements @@ -0,0 +1,44 @@ + + + + + platform-application + + com.apple.private.security.no-container + + com.apple.private.skip-library-validation + + get-task-allow + + com.apple.security.iokit-user-client-class + + AGXCommandQueue + AGXDevice + AGXDeviceUserClient + AGXSharedUserClient + AppleCredentialManagerUserClient + AppleJPEGDriverUserClient + ApplePPMUserClient + AppleSPUHIDDeviceUserClient + AppleSPUHIDDriverUserClient + IOAccelContext + IOAccelContext2 + IOAccelDevice + IOAccelDevice2 + IOAccelSharedUserClient + IOAccelSharedUserClient2 + IOAccelSubmitter2 + IOHIDEventServiceFastPathUserClient + IOHIDLibUserClient + IOMobileFramebufferUserClient + IOReportUserClient + IOSurfaceAcceleratorClient + IOSurfaceRootUserClient + RootDomainUserClient + + com.apple.security.exception.files.home-relative-path.read-write + + /var/mobile/Library/Preferences/com.TitanD3v.ParadiseApp.plist + + + \ No newline at end of file diff --git a/Paradise/App/Paradise.xcodeproj/project.pbxproj b/Paradise/App/Paradise.xcodeproj/project.pbxproj new file mode 100644 index 0000000..7159564 --- /dev/null +++ b/Paradise/App/Paradise.xcodeproj/project.pbxproj @@ -0,0 +1,857 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 5A1676972631661300387CE5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A1676962631661300387CE5 /* AppDelegate.m */; }; + 5A16769A2631661300387CE5 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A1676992631661300387CE5 /* SceneDelegate.m */; }; + 5A16769D2631661300387CE5 /* TabViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A16769C2631661300387CE5 /* TabViewController.m */; }; + 5A1676A02631661300387CE5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5A16769E2631661300387CE5 /* Main.storyboard */; }; + 5A1676A22631661700387CE5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5A1676A12631661700387CE5 /* Assets.xcassets */; }; + 5A1676A52631661700387CE5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5A1676A32631661700387CE5 /* LaunchScreen.storyboard */; }; + 5A1676A82631661700387CE5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A1676A72631661700387CE5 /* main.m */; }; + 5A1676B22631661700387CE5 /* ParadiseTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A1676B12631661700387CE5 /* ParadiseTests.m */; }; + 5A1676BD2631661700387CE5 /* ParadiseUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A1676BC2631661700387CE5 /* ParadiseUITests.m */; }; + 5A1676D826316C7300387CE5 /* EditorViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A1676D726316C7300387CE5 /* EditorViewController.m */; settings = {COMPILER_FLAGS = "-Wno-deprecated-declarations -Wno-implicit-retain-self"; }; }; + 5A1676DE26316C7B00387CE5 /* ThemesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A1676DD26316C7B00387CE5 /* ThemesViewController.m */; }; + 5A1676E32631733700387CE5 /* AppearanceColour.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5A1676E22631733700387CE5 /* AppearanceColour.xcassets */; }; + 5A1676EC26317FA400387CE5 /* ThemesCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A1676EA26317FA400387CE5 /* ThemesCell.m */; }; + 5A7C952B2639D72D0093F0A4 /* IconsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C952A2639D72D0093F0A4 /* IconsViewController.m */; settings = {COMPILER_FLAGS = "-Wno-deprecated-declarations -Wno-implicit-retain-self"; }; }; + 5A7C95332639DF3F0093F0A4 /* Icons.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5A7C95322639DF3F0093F0A4 /* Icons.plist */; }; + 5A7C953C2639E3710093F0A4 /* GlyphCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C953B2639E3710093F0A4 /* GlyphCell.m */; }; + 5A7C95432639E7620093F0A4 /* PreviewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A7C95422639E7620093F0A4 /* PreviewViewController.m */; }; + 5A98E86E2640128F00B53204 /* AccessoriesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E86D2640128F00B53204 /* AccessoriesViewController.m */; }; + 5A98E87E264019A800B53204 /* ColourPickerCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E87D264019A800B53204 /* ColourPickerCell.m */; }; + 5A98E884264019BF00B53204 /* CustomCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A98E883264019BF00B53204 /* CustomCell.m */; }; + 5AA0F93C26739622000CD30F /* TutorialViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AA0F93B26739622000CD30F /* TutorialViewController.m */; }; + 5AA0F9452673968E000CD30F /* TutorialCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AA0F9442673968E000CD30F /* TutorialCell.m */; }; + 5AC7D7CE2635D659008252FE /* ParadiseSegmentControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AC7D7CD2635D659008252FE /* ParadiseSegmentControl.m */; settings = {COMPILER_FLAGS = "-Wno-deprecated-declarations -Wno-implicit-retain-self"; }; }; + 5AC7D7E0263608F4008252FE /* ToolsCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AC7D7DF263608F4008252FE /* ToolsCell.m */; }; + 5AC7D7E62636CB46008252FE /* EditorCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AC7D7E52636CB46008252FE /* EditorCell.m */; }; + 5AC7D7EC2636EA3E008252FE /* ColourCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AC7D7EB2636EA3E008252FE /* ColourCell.m */; }; + 5AE13DC726319A8900E9E3F0 /* AddFolderCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13DC526319A8900E9E3F0 /* AddFolderCell.m */; }; + 5AE13DCF2631A28200E9E3F0 /* LibraryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13DCE2631A28200E9E3F0 /* LibraryViewController.m */; }; + 5AE13DDC2631A7BA00E9E3F0 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13DDB2631A7BA00E9E3F0 /* SettingsViewController.m */; }; + 5AE13DE62631AEE700E9E3F0 /* ConstraintExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13DE52631AEE600E9E3F0 /* ConstraintExtension.m */; }; + 5AE13DEC2631D0FC00E9E3F0 /* CreateThemeFolderVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13DEB2631D0FC00E9E3F0 /* CreateThemeFolderVC.m */; }; + 5AE13DFC26322B4F00E9E3F0 /* AppManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13DFB26322B4F00E9E3F0 /* AppManager.m */; }; + 5AE13E052632305D00E9E3F0 /* LibraryCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13E042632305D00E9E3F0 /* LibraryCell.m */; }; + 5AE13E132632F8F900E9E3F0 /* UITextViewHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13E0D2632F8F900E9E3F0 /* UITextViewHelper.swift */; }; + 5AE13E142632F8F900E9E3F0 /* UITextFieldHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13E0E2632F8F900E9E3F0 /* UITextFieldHelper.swift */; }; + 5AE13E152632F8F900E9E3F0 /* DeviceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13E0F2632F8F900E9E3F0 /* DeviceHelper.swift */; }; + 5AE13E162632F8F900E9E3F0 /* NSLayoutHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13E102632F8F900E9E3F0 /* NSLayoutHelper.swift */; }; + 5AE13E172632F8F900E9E3F0 /* UIButtonHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13E112632F8F900E9E3F0 /* UIButtonHelper.swift */; }; + 5AE13E182632F8F900E9E3F0 /* UILabelHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AE13E122632F8F900E9E3F0 /* UILabelHelper.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 5A1676AE2631661700387CE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5A16768A2631661300387CE5 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5A1676912631661300387CE5; + remoteInfo = Paradise; + }; + 5A1676B92631661700387CE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5A16768A2631661300387CE5 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5A1676912631661300387CE5; + remoteInfo = Paradise; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 5A1676922631661300387CE5 /* Paradise.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Paradise.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5A1676952631661300387CE5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 5A1676962631661300387CE5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 5A1676982631661300387CE5 /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; }; + 5A1676992631661300387CE5 /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; }; + 5A16769B2631661300387CE5 /* TabViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TabViewController.h; sourceTree = ""; }; + 5A16769C2631661300387CE5 /* TabViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TabViewController.m; sourceTree = ""; }; + 5A16769F2631661300387CE5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5A1676A12631661700387CE5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 5A1676A42631661700387CE5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 5A1676A62631661700387CE5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5A1676A72631661700387CE5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 5A1676AD2631661700387CE5 /* ParadiseTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ParadiseTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5A1676B12631661700387CE5 /* ParadiseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ParadiseTests.m; sourceTree = ""; }; + 5A1676B32631661700387CE5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5A1676B82631661700387CE5 /* ParadiseUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ParadiseUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 5A1676BC2631661700387CE5 /* ParadiseUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ParadiseUITests.m; sourceTree = ""; }; + 5A1676BE2631661700387CE5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5A1676D626316C7300387CE5 /* EditorViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EditorViewController.h; sourceTree = ""; }; + 5A1676D726316C7300387CE5 /* EditorViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EditorViewController.m; sourceTree = ""; }; + 5A1676DC26316C7B00387CE5 /* ThemesViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThemesViewController.h; sourceTree = ""; }; + 5A1676DD26316C7B00387CE5 /* ThemesViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ThemesViewController.m; sourceTree = ""; }; + 5A1676E22631733700387CE5 /* AppearanceColour.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = AppearanceColour.xcassets; sourceTree = ""; }; + 5A1676E926317FA400387CE5 /* ThemesCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThemesCell.h; sourceTree = ""; }; + 5A1676EA26317FA400387CE5 /* ThemesCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ThemesCell.m; sourceTree = ""; }; + 5A7C95202639CFB60093F0A4 /* Preferences.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Preferences.h; sourceTree = ""; }; + 5A7C95292639D72D0093F0A4 /* IconsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IconsViewController.h; sourceTree = ""; }; + 5A7C952A2639D72D0093F0A4 /* IconsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IconsViewController.m; sourceTree = ""; }; + 5A7C95322639DF3F0093F0A4 /* Icons.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Icons.plist; sourceTree = ""; }; + 5A7C953A2639E3710093F0A4 /* GlyphCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GlyphCell.h; sourceTree = ""; }; + 5A7C953B2639E3710093F0A4 /* GlyphCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GlyphCell.m; sourceTree = ""; }; + 5A7C95412639E7620093F0A4 /* PreviewViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreviewViewController.h; sourceTree = ""; }; + 5A7C95422639E7620093F0A4 /* PreviewViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreviewViewController.m; sourceTree = ""; }; + 5A98E86C2640128F00B53204 /* AccessoriesViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AccessoriesViewController.h; sourceTree = ""; }; + 5A98E86D2640128F00B53204 /* AccessoriesViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AccessoriesViewController.m; sourceTree = ""; }; + 5A98E87C264019A800B53204 /* ColourPickerCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ColourPickerCell.h; sourceTree = ""; }; + 5A98E87D264019A800B53204 /* ColourPickerCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ColourPickerCell.m; sourceTree = ""; }; + 5A98E882264019BF00B53204 /* CustomCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CustomCell.h; sourceTree = ""; }; + 5A98E883264019BF00B53204 /* CustomCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CustomCell.m; sourceTree = ""; }; + 5AA0F93A26739622000CD30F /* TutorialViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TutorialViewController.h; sourceTree = ""; }; + 5AA0F93B26739622000CD30F /* TutorialViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TutorialViewController.m; sourceTree = ""; }; + 5AA0F9432673968E000CD30F /* TutorialCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TutorialCell.h; sourceTree = ""; }; + 5AA0F9442673968E000CD30F /* TutorialCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TutorialCell.m; sourceTree = ""; }; + 5AC7D7CC2635D659008252FE /* ParadiseSegmentControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParadiseSegmentControl.h; sourceTree = ""; }; + 5AC7D7CD2635D659008252FE /* ParadiseSegmentControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ParadiseSegmentControl.m; sourceTree = ""; }; + 5AC7D7DE263608F4008252FE /* ToolsCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ToolsCell.h; sourceTree = ""; }; + 5AC7D7DF263608F4008252FE /* ToolsCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ToolsCell.m; sourceTree = ""; }; + 5AC7D7E42636CB46008252FE /* EditorCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EditorCell.h; sourceTree = ""; }; + 5AC7D7E52636CB46008252FE /* EditorCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EditorCell.m; sourceTree = ""; }; + 5AC7D7EA2636EA3E008252FE /* ColourCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ColourCell.h; sourceTree = ""; }; + 5AC7D7EB2636EA3E008252FE /* ColourCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ColourCell.m; sourceTree = ""; }; + 5AE13DC426319A8900E9E3F0 /* AddFolderCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AddFolderCell.h; sourceTree = ""; }; + 5AE13DC526319A8900E9E3F0 /* AddFolderCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AddFolderCell.m; sourceTree = ""; }; + 5AE13DCD2631A28200E9E3F0 /* LibraryViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LibraryViewController.h; sourceTree = ""; }; + 5AE13DCE2631A28200E9E3F0 /* LibraryViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LibraryViewController.m; sourceTree = ""; wrapsLines = 0; }; + 5AE13DDA2631A7BA00E9E3F0 /* SettingsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = ""; }; + 5AE13DDB2631A7BA00E9E3F0 /* SettingsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = ""; }; + 5AE13DE42631AEE600E9E3F0 /* ConstraintExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstraintExtension.h; sourceTree = ""; }; + 5AE13DE52631AEE600E9E3F0 /* ConstraintExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConstraintExtension.m; sourceTree = ""; }; + 5AE13DEA2631D0FC00E9E3F0 /* CreateThemeFolderVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CreateThemeFolderVC.h; sourceTree = ""; }; + 5AE13DEB2631D0FC00E9E3F0 /* CreateThemeFolderVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CreateThemeFolderVC.m; sourceTree = ""; }; + 5AE13DFA26322B4F00E9E3F0 /* AppManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppManager.h; sourceTree = ""; }; + 5AE13DFB26322B4F00E9E3F0 /* AppManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppManager.m; sourceTree = ""; }; + 5AE13E032632305D00E9E3F0 /* LibraryCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LibraryCell.h; sourceTree = ""; }; + 5AE13E042632305D00E9E3F0 /* LibraryCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LibraryCell.m; sourceTree = ""; wrapsLines = 0; }; + 5AE13E0C2632F8F800E9E3F0 /* Paradise-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Paradise-Bridging-Header.h"; sourceTree = ""; }; + 5AE13E0D2632F8F900E9E3F0 /* UITextViewHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITextViewHelper.swift; sourceTree = ""; }; + 5AE13E0E2632F8F900E9E3F0 /* UITextFieldHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITextFieldHelper.swift; sourceTree = ""; }; + 5AE13E0F2632F8F900E9E3F0 /* DeviceHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceHelper.swift; sourceTree = ""; }; + 5AE13E102632F8F900E9E3F0 /* NSLayoutHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSLayoutHelper.swift; sourceTree = ""; }; + 5AE13E112632F8F900E9E3F0 /* UIButtonHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIButtonHelper.swift; sourceTree = ""; }; + 5AE13E122632F8F900E9E3F0 /* UILabelHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UILabelHelper.swift; sourceTree = ""; }; + 8B079E982638129300AAF999 /* Macros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Macros.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5A16768F2631661300387CE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A1676AA2631661700387CE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A1676B52631661700387CE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5A1676892631661300387CE5 = { + isa = PBXGroup; + children = ( + 5A1676942631661300387CE5 /* Paradise */, + 5A1676B02631661700387CE5 /* ParadiseTests */, + 5A1676BB2631661700387CE5 /* ParadiseUITests */, + 5A1676932631661300387CE5 /* Products */, + ); + sourceTree = ""; + }; + 5A1676932631661300387CE5 /* Products */ = { + isa = PBXGroup; + children = ( + 5A1676922631661300387CE5 /* Paradise.app */, + 5A1676AD2631661700387CE5 /* ParadiseTests.xctest */, + 5A1676B82631661700387CE5 /* ParadiseUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 5A1676942631661300387CE5 /* Paradise */ = { + isa = PBXGroup; + children = ( + 5A7C95322639DF3F0093F0A4 /* Icons.plist */, + 5A1676952631661300387CE5 /* AppDelegate.h */, + 5A1676962631661300387CE5 /* AppDelegate.m */, + 5A1676982631661300387CE5 /* SceneDelegate.h */, + 5A1676992631661300387CE5 /* SceneDelegate.m */, + 5A16769B2631661300387CE5 /* TabViewController.h */, + 5A16769C2631661300387CE5 /* TabViewController.m */, + 5AA0F93926739614000CD30F /* Tutorial */, + 5AE13DE32631AEE600E9E3F0 /* Constraints */, + 5AE13DF926322B3F00E9E3F0 /* Manager */, + 5AC7D7CB2635D659008252FE /* Segment */, + 5A7C95402639E7620093F0A4 /* Preview */, + 5A1676E726317E7700387CE5 /* Editor */, + 5A98E872264012C700B53204 /* Accessories */, + 5A1676E826317E8300387CE5 /* Themes */, + 5AE13DCC2631A26C00E9E3F0 /* Library */, + 5AE13DD92631A7A100E9E3F0 /* Settings */, + 5A16769E2631661300387CE5 /* Main.storyboard */, + 5A1676A12631661700387CE5 /* Assets.xcassets */, + 5A1676E22631733700387CE5 /* AppearanceColour.xcassets */, + 5A1676A62631661700387CE5 /* Info.plist */, + 5A1676A72631661700387CE5 /* main.m */, + 5A1676A32631661700387CE5 /* LaunchScreen.storyboard */, + ); + path = Paradise; + sourceTree = ""; + }; + 5A1676B02631661700387CE5 /* ParadiseTests */ = { + isa = PBXGroup; + children = ( + 5A1676B12631661700387CE5 /* ParadiseTests.m */, + 5A1676B32631661700387CE5 /* Info.plist */, + ); + path = ParadiseTests; + sourceTree = ""; + }; + 5A1676BB2631661700387CE5 /* ParadiseUITests */ = { + isa = PBXGroup; + children = ( + 5A1676BC2631661700387CE5 /* ParadiseUITests.m */, + 5A1676BE2631661700387CE5 /* Info.plist */, + ); + path = ParadiseUITests; + sourceTree = ""; + }; + 5A1676E726317E7700387CE5 /* Editor */ = { + isa = PBXGroup; + children = ( + 5A1676D626316C7300387CE5 /* EditorViewController.h */, + 5A1676D726316C7300387CE5 /* EditorViewController.m */, + 5AC7D7DE263608F4008252FE /* ToolsCell.h */, + 5AC7D7DF263608F4008252FE /* ToolsCell.m */, + 5AC7D7E42636CB46008252FE /* EditorCell.h */, + 5AC7D7E52636CB46008252FE /* EditorCell.m */, + 5AC7D7EA2636EA3E008252FE /* ColourCell.h */, + 5AC7D7EB2636EA3E008252FE /* ColourCell.m */, + 5A7C953A2639E3710093F0A4 /* GlyphCell.h */, + 5A7C953B2639E3710093F0A4 /* GlyphCell.m */, + 5A7C95292639D72D0093F0A4 /* IconsViewController.h */, + 5A7C952A2639D72D0093F0A4 /* IconsViewController.m */, + ); + path = Editor; + sourceTree = ""; + }; + 5A1676E826317E8300387CE5 /* Themes */ = { + isa = PBXGroup; + children = ( + 5A1676DC26316C7B00387CE5 /* ThemesViewController.h */, + 5A1676DD26316C7B00387CE5 /* ThemesViewController.m */, + 5A1676E926317FA400387CE5 /* ThemesCell.h */, + 5A1676EA26317FA400387CE5 /* ThemesCell.m */, + 5AE13DC426319A8900E9E3F0 /* AddFolderCell.h */, + 5AE13DC526319A8900E9E3F0 /* AddFolderCell.m */, + 5AE13DEA2631D0FC00E9E3F0 /* CreateThemeFolderVC.h */, + 5AE13DEB2631D0FC00E9E3F0 /* CreateThemeFolderVC.m */, + ); + path = Themes; + sourceTree = ""; + }; + 5A7C95402639E7620093F0A4 /* Preview */ = { + isa = PBXGroup; + children = ( + 5A7C95412639E7620093F0A4 /* PreviewViewController.h */, + 5A7C95422639E7620093F0A4 /* PreviewViewController.m */, + ); + path = Preview; + sourceTree = ""; + }; + 5A98E872264012C700B53204 /* Accessories */ = { + isa = PBXGroup; + children = ( + 5A98E86C2640128F00B53204 /* AccessoriesViewController.h */, + 5A98E86D2640128F00B53204 /* AccessoriesViewController.m */, + 5A98E87C264019A800B53204 /* ColourPickerCell.h */, + 5A98E87D264019A800B53204 /* ColourPickerCell.m */, + 5A98E882264019BF00B53204 /* CustomCell.h */, + 5A98E883264019BF00B53204 /* CustomCell.m */, + ); + path = Accessories; + sourceTree = ""; + }; + 5AA0F93926739614000CD30F /* Tutorial */ = { + isa = PBXGroup; + children = ( + 5AA0F93A26739622000CD30F /* TutorialViewController.h */, + 5AA0F93B26739622000CD30F /* TutorialViewController.m */, + 5AA0F9432673968E000CD30F /* TutorialCell.h */, + 5AA0F9442673968E000CD30F /* TutorialCell.m */, + ); + path = Tutorial; + sourceTree = ""; + }; + 5AC7D7CB2635D659008252FE /* Segment */ = { + isa = PBXGroup; + children = ( + 5AC7D7CC2635D659008252FE /* ParadiseSegmentControl.h */, + 5AC7D7CD2635D659008252FE /* ParadiseSegmentControl.m */, + ); + path = Segment; + sourceTree = ""; + }; + 5AE13DCC2631A26C00E9E3F0 /* Library */ = { + isa = PBXGroup; + children = ( + 5AE13E032632305D00E9E3F0 /* LibraryCell.h */, + 5AE13E042632305D00E9E3F0 /* LibraryCell.m */, + 5AE13DCD2631A28200E9E3F0 /* LibraryViewController.h */, + 5AE13DCE2631A28200E9E3F0 /* LibraryViewController.m */, + ); + path = Library; + sourceTree = ""; + }; + 5AE13DD92631A7A100E9E3F0 /* Settings */ = { + isa = PBXGroup; + children = ( + 5AE13DDA2631A7BA00E9E3F0 /* SettingsViewController.h */, + 5AE13DDB2631A7BA00E9E3F0 /* SettingsViewController.m */, + ); + path = Settings; + sourceTree = ""; + }; + 5AE13DE32631AEE600E9E3F0 /* Constraints */ = { + isa = PBXGroup; + children = ( + 5AE13DE42631AEE600E9E3F0 /* ConstraintExtension.h */, + 5AE13DE52631AEE600E9E3F0 /* ConstraintExtension.m */, + 5AE13E0F2632F8F900E9E3F0 /* DeviceHelper.swift */, + 5AE13E102632F8F900E9E3F0 /* NSLayoutHelper.swift */, + 5AE13E112632F8F900E9E3F0 /* UIButtonHelper.swift */, + 5AE13E122632F8F900E9E3F0 /* UILabelHelper.swift */, + 5AE13E0E2632F8F900E9E3F0 /* UITextFieldHelper.swift */, + 5AE13E0D2632F8F900E9E3F0 /* UITextViewHelper.swift */, + 5AE13E0C2632F8F800E9E3F0 /* Paradise-Bridging-Header.h */, + 8B079E982638129300AAF999 /* Macros.h */, + ); + path = Constraints; + sourceTree = ""; + }; + 5AE13DF926322B3F00E9E3F0 /* Manager */ = { + isa = PBXGroup; + children = ( + 5AE13DFA26322B4F00E9E3F0 /* AppManager.h */, + 5AE13DFB26322B4F00E9E3F0 /* AppManager.m */, + 5A7C95202639CFB60093F0A4 /* Preferences.h */, + ); + path = Manager; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5A1676912631661300387CE5 /* Paradise */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5A1676C12631661700387CE5 /* Build configuration list for PBXNativeTarget "Paradise" */; + buildPhases = ( + 5A16768E2631661300387CE5 /* Sources */, + 5A16768F2631661300387CE5 /* Frameworks */, + 5A1676902631661300387CE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Paradise; + productName = Paradise; + productReference = 5A1676922631661300387CE5 /* Paradise.app */; + productType = "com.apple.product-type.application"; + }; + 5A1676AC2631661700387CE5 /* ParadiseTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5A1676C42631661700387CE5 /* Build configuration list for PBXNativeTarget "ParadiseTests" */; + buildPhases = ( + 5A1676A92631661700387CE5 /* Sources */, + 5A1676AA2631661700387CE5 /* Frameworks */, + 5A1676AB2631661700387CE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5A1676AF2631661700387CE5 /* PBXTargetDependency */, + ); + name = ParadiseTests; + productName = ParadiseTests; + productReference = 5A1676AD2631661700387CE5 /* ParadiseTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 5A1676B72631661700387CE5 /* ParadiseUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5A1676C72631661700387CE5 /* Build configuration list for PBXNativeTarget "ParadiseUITests" */; + buildPhases = ( + 5A1676B42631661700387CE5 /* Sources */, + 5A1676B52631661700387CE5 /* Frameworks */, + 5A1676B62631661700387CE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5A1676BA2631661700387CE5 /* PBXTargetDependency */, + ); + name = ParadiseUITests; + productName = ParadiseUITests; + productReference = 5A1676B82631661700387CE5 /* ParadiseUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5A16768A2631661300387CE5 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1230; + TargetAttributes = { + 5A1676912631661300387CE5 = { + CreatedOnToolsVersion = 12.3; + LastSwiftMigration = 1230; + }; + 5A1676AC2631661700387CE5 = { + CreatedOnToolsVersion = 12.3; + TestTargetID = 5A1676912631661300387CE5; + }; + 5A1676B72631661700387CE5 = { + CreatedOnToolsVersion = 12.3; + TestTargetID = 5A1676912631661300387CE5; + }; + }; + }; + buildConfigurationList = 5A16768D2631661300387CE5 /* Build configuration list for PBXProject "Paradise" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5A1676892631661300387CE5; + productRefGroup = 5A1676932631661300387CE5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5A1676912631661300387CE5 /* Paradise */, + 5A1676AC2631661700387CE5 /* ParadiseTests */, + 5A1676B72631661700387CE5 /* ParadiseUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5A1676902631661300387CE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5A1676A52631661700387CE5 /* LaunchScreen.storyboard in Resources */, + 5A1676E32631733700387CE5 /* AppearanceColour.xcassets in Resources */, + 5A1676A22631661700387CE5 /* Assets.xcassets in Resources */, + 5A7C95332639DF3F0093F0A4 /* Icons.plist in Resources */, + 5A1676A02631661300387CE5 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A1676AB2631661700387CE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A1676B62631661700387CE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5A16768E2631661300387CE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5AE13DEC2631D0FC00E9E3F0 /* CreateThemeFolderVC.m in Sources */, + 5A16769D2631661300387CE5 /* TabViewController.m in Sources */, + 5AE13E172632F8F900E9E3F0 /* UIButtonHelper.swift in Sources */, + 5A7C952B2639D72D0093F0A4 /* IconsViewController.m in Sources */, + 5AC7D7EC2636EA3E008252FE /* ColourCell.m in Sources */, + 5A1676972631661300387CE5 /* AppDelegate.m in Sources */, + 5A1676DE26316C7B00387CE5 /* ThemesViewController.m in Sources */, + 5AC7D7E62636CB46008252FE /* EditorCell.m in Sources */, + 5AE13DCF2631A28200E9E3F0 /* LibraryViewController.m in Sources */, + 5AE13DFC26322B4F00E9E3F0 /* AppManager.m in Sources */, + 5A7C953C2639E3710093F0A4 /* GlyphCell.m in Sources */, + 5A1676A82631661700387CE5 /* main.m in Sources */, + 5AE13E182632F8F900E9E3F0 /* UILabelHelper.swift in Sources */, + 5AA0F93C26739622000CD30F /* TutorialViewController.m in Sources */, + 5A98E87E264019A800B53204 /* ColourPickerCell.m in Sources */, + 5A98E884264019BF00B53204 /* CustomCell.m in Sources */, + 5A98E86E2640128F00B53204 /* AccessoriesViewController.m in Sources */, + 5AE13E052632305D00E9E3F0 /* LibraryCell.m in Sources */, + 5A7C95432639E7620093F0A4 /* PreviewViewController.m in Sources */, + 5AE13E162632F8F900E9E3F0 /* NSLayoutHelper.swift in Sources */, + 5AC7D7E0263608F4008252FE /* ToolsCell.m in Sources */, + 5AE13DE62631AEE700E9E3F0 /* ConstraintExtension.m in Sources */, + 5AE13E142632F8F900E9E3F0 /* UITextFieldHelper.swift in Sources */, + 5AC7D7CE2635D659008252FE /* ParadiseSegmentControl.m in Sources */, + 5A1676EC26317FA400387CE5 /* ThemesCell.m in Sources */, + 5A1676D826316C7300387CE5 /* EditorViewController.m in Sources */, + 5AE13E132632F8F900E9E3F0 /* UITextViewHelper.swift in Sources */, + 5AE13E152632F8F900E9E3F0 /* DeviceHelper.swift in Sources */, + 5AE13DDC2631A7BA00E9E3F0 /* SettingsViewController.m in Sources */, + 5AA0F9452673968E000CD30F /* TutorialCell.m in Sources */, + 5A16769A2631661300387CE5 /* SceneDelegate.m in Sources */, + 5AE13DC726319A8900E9E3F0 /* AddFolderCell.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A1676A92631661700387CE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5A1676B22631661700387CE5 /* ParadiseTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5A1676B42631661700387CE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5A1676BD2631661700387CE5 /* ParadiseUITests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 5A1676AF2631661700387CE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5A1676912631661300387CE5 /* Paradise */; + targetProxy = 5A1676AE2631661700387CE5 /* PBXContainerItemProxy */; + }; + 5A1676BA2631661700387CE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5A1676912631661300387CE5 /* Paradise */; + targetProxy = 5A1676B92631661700387CE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 5A16769E2631661300387CE5 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5A16769F2631661300387CE5 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 5A1676A32631661700387CE5 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5A1676A42631661700387CE5 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5A1676BF2631661700387CE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 5A1676C02631661700387CE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5A1676C22631661700387CE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = Paradise/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.TitanD3v.Paradise; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Paradise/Constraints/Paradise-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Debug; + }; + 5A1676C32631661700387CE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = Paradise/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.TitanD3v.Paradise; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Paradise/Constraints/Paradise-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + }; + name = Release; + }; + 5A1676C52631661700387CE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = ParadiseTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.TitanD3v.ParadiseTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Paradise.app/Paradise"; + }; + name = Debug; + }; + 5A1676C62631661700387CE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = ParadiseTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.TitanD3v.ParadiseTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Paradise.app/Paradise"; + }; + name = Release; + }; + 5A1676C82631661700387CE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = ParadiseUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.TitanD3v.ParadiseUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Paradise; + }; + name = Debug; + }; + 5A1676C92631661700387CE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7W4LY2JZ25; + INFOPLIST_FILE = ParadiseUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.TitanD3v.ParadiseUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Paradise; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5A16768D2631661300387CE5 /* Build configuration list for PBXProject "Paradise" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5A1676BF2631661700387CE5 /* Debug */, + 5A1676C02631661700387CE5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5A1676C12631661700387CE5 /* Build configuration list for PBXNativeTarget "Paradise" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5A1676C22631661700387CE5 /* Debug */, + 5A1676C32631661700387CE5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5A1676C42631661700387CE5 /* Build configuration list for PBXNativeTarget "ParadiseTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5A1676C52631661700387CE5 /* Debug */, + 5A1676C62631661700387CE5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5A1676C72631661700387CE5 /* Build configuration list for PBXNativeTarget "ParadiseUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5A1676C82631661700387CE5 /* Debug */, + 5A1676C92631661700387CE5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5A16768A2631661300387CE5 /* Project object */; +} diff --git a/Paradise/App/Paradise.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Paradise/App/Paradise.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Paradise/App/Paradise.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcuserdata/Prysm.xcuserdatad/UserInterfaceState.xcuserstate b/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcuserdata/Prysm.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..d32657d Binary files /dev/null and b/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcuserdata/Prysm.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcuserdata/dylan4char.xcuserdatad/UserInterfaceState.xcuserstate b/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcuserdata/dylan4char.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..158269b Binary files /dev/null and b/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcuserdata/dylan4char.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcuserdata/sgwc.xcuserdatad/UserInterfaceState.xcuserstate b/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcuserdata/sgwc.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..dc111e9 Binary files /dev/null and b/Paradise/App/Paradise.xcodeproj/project.xcworkspace/xcuserdata/sgwc.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Paradise/App/Paradise.xcodeproj/xcuserdata/Prysm.xcuserdatad/xcschemes/xcschememanagement.plist b/Paradise/App/Paradise.xcodeproj/xcuserdata/Prysm.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..8ebd75d --- /dev/null +++ b/Paradise/App/Paradise.xcodeproj/xcuserdata/Prysm.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + Paradise.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/Paradise/App/Paradise.xcodeproj/xcuserdata/dylan4char.xcuserdatad/xcschemes/xcschememanagement.plist b/Paradise/App/Paradise.xcodeproj/xcuserdata/dylan4char.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..8ebd75d --- /dev/null +++ b/Paradise/App/Paradise.xcodeproj/xcuserdata/dylan4char.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + Paradise.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/Paradise/App/Paradise.xcodeproj/xcuserdata/sgwc.xcuserdatad/xcschemes/xcschememanagement.plist b/Paradise/App/Paradise.xcodeproj/xcuserdata/sgwc.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..8ebd75d --- /dev/null +++ b/Paradise/App/Paradise.xcodeproj/xcuserdata/sgwc.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + Paradise.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/Paradise/App/Paradise/Accessories/AccessoriesViewController.h b/Paradise/App/Paradise/Accessories/AccessoriesViewController.h new file mode 100644 index 0000000..1aca85f --- /dev/null +++ b/Paradise/App/Paradise/Accessories/AccessoriesViewController.h @@ -0,0 +1,11 @@ +//#import +//#import "ConstraintExtension.h" +//#import "CustomCell.h" +//#import "ColourPickerCell.h" +// +//@interface AccessoriesViewController : UIViewController +//@property (nonatomic, retain) NSArray *titleArray; +//@property (nonatomic, retain) UITableView *tableView; +//@property (nonatomic, retain) UICollectionView *maskCollectionView; +//@end +// diff --git a/Paradise/App/Paradise/Accessories/AccessoriesViewController.m b/Paradise/App/Paradise/Accessories/AccessoriesViewController.m new file mode 100644 index 0000000..1be5be6 --- /dev/null +++ b/Paradise/App/Paradise/Accessories/AccessoriesViewController.m @@ -0,0 +1,126 @@ +//#import "AccessoriesViewController.h" +// +//@implementation AccessoriesViewController +// +//-(void)viewWillAppear:(BOOL)animated { +// [super viewWillAppear:animated]; +// +// self.navigationItem.title = @"Accessories"; +// self.navigationController.navigationBar.prefersLargeTitles = YES; +// +//} +// +//- (void)viewDidLoad { +// [super viewDidLoad]; +// self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; +// +// [self layoutTableView]; +//} +// +// +//-(void)layoutTableView { +// +// self.titleArray = [[NSArray alloc] initWithObjects:@"Icon Mask", @"Icon Badge", @"Badge Colour", nil]; +// +// self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; +// self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; +// self.tableView.editing = NO; +// self.tableView.backgroundColor = UIColor.clearColor; +// [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; +// self.tableView.showsVerticalScrollIndicator = NO; +// [self.view addSubview:self.tableView]; +// +// self.tableView.dataSource = self; +// self.tableView.delegate = self; +//} +// +// +//-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { +// return 3; +//} +// +// +//-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { +// if (section == 0) { +// return 1; +// } else if (section == 1) { +// return 1; +// } else { +// return 1; +// } +//} +// +// +//- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { +// return 25.0f; +//} +// +// +//- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { +// +// UIView *sectionHeaderView = [[UIView alloc] initWithFrame:CGRectMake(15, 0, tableView.frame.size.width -15, 45)]; +// sectionHeaderView.backgroundColor = UIColor.clearColor; +// sectionHeaderView.clipsToBounds = true; +// +// UILabel *headerLabel = [[UILabel alloc] init]; +// headerLabel.backgroundColor = [UIColor clearColor]; +// headerLabel.textColor = UIColor.labelColor; +// headerLabel.textAlignment = NSTextAlignmentLeft; +// headerLabel.font = [UIFont boldSystemFontOfSize:16]; +// headerLabel.text = [self.titleArray objectAtIndex:section]; +// [sectionHeaderView addSubview:headerLabel]; +// +// [headerLabel leading:sectionHeaderView.leadingAnchor padding:10]; +// [headerLabel y:sectionHeaderView.centerYAnchor]; +// +// return sectionHeaderView; +//} +// +// +//-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { +// +// UIView *selectionView = [UIView new]; +// selectionView.backgroundColor = UIColor.clearColor; +// [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; +// +// //if (indexPath.section == 0) { +// +// CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"customCell"]; +// +// if (cell == nil) { +// cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"customCell"]; +// } +// +// +// UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; +// self.maskCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; +// self.maskCollectionView.backgroundColor = UIColor.clearColor; +// self.maskCollectionView.translatesAutoresizingMaskIntoConstraints = NO; +// self.maskCollectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; +// [self.maskCollectionView setShowsHorizontalScrollIndicator:NO]; +// [self.maskCollectionView setShowsVerticalScrollIndicator:NO]; +// [self.maskCollectionView registerClass:[AddFolderCell class] forCellWithReuseIdentifier:@"addCell"]; +// [self.view addSubview:self.maskCollectionView]; +// +// self.maskCollectionView.delegate = self; +// self.maskCollectionView.dataSource = self; +// +// [self.maskCollectionView top:cell.baseView.topAnchor padding:5]; +// [self.maskCollectionView leading:cell.baseView.leadingAnchor padding:5]; +// [self.maskCollectionView trailing:cell.baseView.trailingAnchor padding:-5]; +// [self.maskCollectionView bottom:cell.baseView.bottomAnchor padding:-5]; +// +// return cell; +// +//// } else { +//// return nil; +//// } +// +//} +// +// +//- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { +// return 150; +//} +// +//@end diff --git a/Paradise/App/Paradise/Accessories/ColourPickerCell.h b/Paradise/App/Paradise/Accessories/ColourPickerCell.h new file mode 100644 index 0000000..cbad94a --- /dev/null +++ b/Paradise/App/Paradise/Accessories/ColourPickerCell.h @@ -0,0 +1,9 @@ +//#import +// +//NS_ASSUME_NONNULL_BEGIN +// +//@interface ColourPickerCell : UIViewController +// +//@end +// +//NS_ASSUME_NONNULL_END diff --git a/Paradise/App/Paradise/Accessories/ColourPickerCell.m b/Paradise/App/Paradise/Accessories/ColourPickerCell.m new file mode 100644 index 0000000..3d20a4f --- /dev/null +++ b/Paradise/App/Paradise/Accessories/ColourPickerCell.m @@ -0,0 +1,24 @@ +//#import "ColourPickerCell.h" +// +//@interface ColourPickerCell () +// +//@end +// +//@implementation ColourPickerCell +// +//- (void)viewDidLoad { +// [super viewDidLoad]; +// // Do any additional setup after loading the view. +//} +// +///* +//#pragma mark - Navigation +// +//// In a storyboard-based application, you will often want to do a little preparation before navigation +//- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { +// // Get the new view controller using [segue destinationViewController]. +// // Pass the selected object to the new view controller. +//} +//*/ +// +//@end diff --git a/Paradise/App/Paradise/Accessories/CustomCell.h b/Paradise/App/Paradise/Accessories/CustomCell.h new file mode 100644 index 0000000..23ed620 --- /dev/null +++ b/Paradise/App/Paradise/Accessories/CustomCell.h @@ -0,0 +1,6 @@ +//#import +//#import "ConstraintExtension.h" +// +//@interface CustomCell : UITableViewCell +//@property (nonatomic, retain) UIView *baseView; +//@end diff --git a/Paradise/App/Paradise/Accessories/CustomCell.m b/Paradise/App/Paradise/Accessories/CustomCell.m new file mode 100644 index 0000000..b4b40c6 --- /dev/null +++ b/Paradise/App/Paradise/Accessories/CustomCell.m @@ -0,0 +1,28 @@ +//#import "CustomCell.h" +// +//@implementation CustomCell +// +//-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { +// +// self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; +// +// if (self) { +// +// self.baseView = [[UIView alloc] init]; +// self.baseView.backgroundColor = [UIColor redColor]; +// self.baseView.layer.cornerRadius = 15; +// self.baseView.layer.cornerCurve = kCACornerCurveContinuous; +// self.baseView.clipsToBounds = true; +// [self.contentView addSubview:self.baseView]; +// +// [self.baseView top:self.topAnchor padding:5]; +// [self.baseView leading:self.leadingAnchor padding:0]; +// [self.baseView trailing:self.trailingAnchor padding:0]; +// [self.baseView bottom:self.bottomAnchor padding:0]; +// +// } +// +// return self; +//} +// +//@end diff --git a/Paradise/App/Paradise/AppDelegate.h b/Paradise/App/Paradise/AppDelegate.h new file mode 100644 index 0000000..d79858b --- /dev/null +++ b/Paradise/App/Paradise/AppDelegate.h @@ -0,0 +1,7 @@ +#import + +@interface AppDelegate : UIResponder + + +@end + diff --git a/Paradise/App/Paradise/AppDelegate.m b/Paradise/App/Paradise/AppDelegate.m new file mode 100644 index 0000000..ee5c42e --- /dev/null +++ b/Paradise/App/Paradise/AppDelegate.m @@ -0,0 +1,33 @@ +#import "AppDelegate.h" + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + + return YES; +} + + +#pragma mark - UISceneSession lifecycle + + +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role]; +} + + +- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet *)sceneSessions { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. +} + + +@end diff --git a/Paradise/App/Paradise/AppearanceColour.xcassets/Accent.colorset/Contents.json b/Paradise/App/Paradise/AppearanceColour.xcassets/Accent.colorset/Contents.json new file mode 100644 index 0000000..cc34a04 --- /dev/null +++ b/Paradise/App/Paradise/AppearanceColour.xcassets/Accent.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.980", + "green" : "0.831", + "red" : "0.427" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.980", + "green" : "0.831", + "red" : "0.427" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/AppearanceColour.xcassets/Cell Background.colorset/Contents.json b/Paradise/App/Paradise/AppearanceColour.xcassets/Cell Background.colorset/Contents.json new file mode 100644 index 0000000..22c4bb0 --- /dev/null +++ b/Paradise/App/Paradise/AppearanceColour.xcassets/Cell Background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/AppearanceColour.xcassets/Containers.colorset/Contents.json b/Paradise/App/Paradise/AppearanceColour.xcassets/Containers.colorset/Contents.json new file mode 100644 index 0000000..9a9aee9 --- /dev/null +++ b/Paradise/App/Paradise/AppearanceColour.xcassets/Containers.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.180", + "green" : "0.169", + "red" : "0.169" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/AppearanceColour.xcassets/Contents.json b/Paradise/App/Paradise/AppearanceColour.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Paradise/App/Paradise/AppearanceColour.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/AppearanceColour.xcassets/Main Background.colorset/Contents.json b/Paradise/App/Paradise/AppearanceColour.xcassets/Main Background.colorset/Contents.json new file mode 100644 index 0000000..b5471af --- /dev/null +++ b/Paradise/App/Paradise/AppearanceColour.xcassets/Main Background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.969", + "green" : "0.949", + "red" : "0.949" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.118", + "green" : "0.110", + "red" : "0.110" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/AccentColor.colorset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/AppIcon.appiconset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..4dc2778 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,100 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "xcode-120.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "xcode-180.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/AppIcon.appiconset/xcode-120.png b/Paradise/App/Paradise/Assets.xcassets/AppIcon.appiconset/xcode-120.png new file mode 100644 index 0000000..45e4b61 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/AppIcon.appiconset/xcode-120.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/AppIcon.appiconset/xcode-180.png b/Paradise/App/Paradise/Assets.xcassets/AppIcon.appiconset/xcode-180.png new file mode 100644 index 0000000..f3e1c42 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/AppIcon.appiconset/xcode-180.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/Contents.json b/Paradise/App/Paradise/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/Gradients/Contents.json b/Paradise/App/Paradise/Assets.xcassets/Gradients/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/Gradients/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/Gradients/gradient.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/Gradients/gradient.imageset/Contents.json new file mode 100644 index 0000000..03682e6 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/Gradients/gradient.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "gradient1.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/Gradients/gradient.imageset/gradient1.png b/Paradise/App/Paradise/Assets.xcassets/Gradients/gradient.imageset/gradient1.png new file mode 100644 index 0000000..82cd2d7 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/Gradients/gradient.imageset/gradient1.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/Splashscreen/Contents.json b/Paradise/App/Paradise/Assets.xcassets/Splashscreen/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/Splashscreen/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/Splashscreen/splashscreen.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/Splashscreen/splashscreen.imageset/Contents.json new file mode 100644 index 0000000..5acbe8d --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/Splashscreen/splashscreen.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "splashscreen.jpg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/Splashscreen/splashscreen.imageset/splashscreen.jpg b/Paradise/App/Paradise/Assets.xcassets/Splashscreen/splashscreen.imageset/splashscreen.jpg new file mode 100644 index 0000000..8ef7ea3 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/Splashscreen/splashscreen.imageset/splashscreen.jpg differ diff --git a/Paradise/App/Paradise/Assets.xcassets/checkmark.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/checkmark.imageset/Contents.json new file mode 100644 index 0000000..300e0eb --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/checkmark.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "filename" : "tick.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/checkmark.imageset/tick.png b/Paradise/App/Paradise/Assets.xcassets/checkmark.imageset/tick.png new file mode 100644 index 0000000..ea9f6ce Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/checkmark.imageset/tick.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/close.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/close.imageset/Contents.json new file mode 100644 index 0000000..147d07b --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/close.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "filename" : "cancel.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/close.imageset/cancel.png b/Paradise/App/Paradise/Assets.xcassets/close.imageset/cancel.png new file mode 100644 index 0000000..9b49c52 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/close.imageset/cancel.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/colourpicker-icon.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/colourpicker-icon.imageset/Contents.json new file mode 100644 index 0000000..9b0b0d8 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/colourpicker-icon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "colourpicker-icon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/colourpicker-icon.imageset/colourpicker-icon.png b/Paradise/App/Paradise/Assets.xcassets/colourpicker-icon.imageset/colourpicker-icon.png new file mode 100644 index 0000000..e1ec157 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/colourpicker-icon.imageset/colourpicker-icon.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/default-preview.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/default-preview.imageset/Contents.json new file mode 100644 index 0000000..0dd81ec --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/default-preview.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "default-preview.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/default-preview.imageset/default-preview.png b/Paradise/App/Paradise/Assets.xcassets/default-preview.imageset/default-preview.png new file mode 100644 index 0000000..97356a1 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/default-preview.imageset/default-preview.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/image-picker.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/image-picker.imageset/Contents.json new file mode 100644 index 0000000..24c474e --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/image-picker.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "image.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/image-picker.imageset/image.png b/Paradise/App/Paradise/Assets.xcassets/image-picker.imageset/image.png new file mode 100644 index 0000000..b5accc6 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/image-picker.imageset/image.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/imagepicker-icon.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/imagepicker-icon.imageset/Contents.json new file mode 100644 index 0000000..f480df3 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/imagepicker-icon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "imagepicker-icon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/imagepicker-icon.imageset/imagepicker-icon.png b/Paradise/App/Paradise/Assets.xcassets/imagepicker-icon.imageset/imagepicker-icon.png new file mode 100644 index 0000000..36b9efe Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/imagepicker-icon.imageset/imagepicker-icon.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/paradise-icon.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/paradise-icon.imageset/Contents.json new file mode 100644 index 0000000..33775db --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/paradise-icon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "header-icon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/paradise-icon.imageset/header-icon.png b/Paradise/App/Paradise/Assets.xcassets/paradise-icon.imageset/header-icon.png new file mode 100644 index 0000000..f28e722 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/paradise-icon.imageset/header-icon.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/preview-icon.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/preview-icon.imageset/Contents.json new file mode 100644 index 0000000..c41b89c --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/preview-icon.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "filename" : "preview.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/preview-icon.imageset/preview.png b/Paradise/App/Paradise/Assets.xcassets/preview-icon.imageset/preview.png new file mode 100644 index 0000000..4fd287d Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/preview-icon.imageset/preview.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8-Plus.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8-Plus.imageset/Contents.json new file mode 100644 index 0000000..b6bd379 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8-Plus.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "preview-wallpaper-8-Plus.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8-Plus.imageset/preview-wallpaper-8-Plus.png b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8-Plus.imageset/preview-wallpaper-8-Plus.png new file mode 100644 index 0000000..eb4c56c Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8-Plus.imageset/preview-wallpaper-8-Plus.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8.imageset/Contents.json new file mode 100644 index 0000000..4a14afb --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "preview-wallpaper-8.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8.imageset/preview-wallpaper-8.png b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8.imageset/preview-wallpaper-8.png new file mode 100644 index 0000000..ffdd05c Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper-8.imageset/preview-wallpaper-8.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper.imageset/Contents.json new file mode 100644 index 0000000..0b0e521 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "preview-wallpaper.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper.imageset/preview-wallpaper.png b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper.imageset/preview-wallpaper.png new file mode 100644 index 0000000..8c13c61 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/preview-wallpaper.imageset/preview-wallpaper.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/preview.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/preview.imageset/Contents.json new file mode 100644 index 0000000..9a374ac --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/preview.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "com.apple.DocumentsApp-large.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/preview.imageset/com.apple.DocumentsApp-large.png b/Paradise/App/Paradise/Assets.xcassets/preview.imageset/com.apple.DocumentsApp-large.png new file mode 100644 index 0000000..e0dd0ab Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/preview.imageset/com.apple.DocumentsApp-large.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/reset.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/reset.imageset/Contents.json new file mode 100644 index 0000000..6a7e6d7 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/reset.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "filename" : "undo-circular-arrow.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/reset.imageset/undo-circular-arrow.png b/Paradise/App/Paradise/Assets.xcassets/reset.imageset/undo-circular-arrow.png new file mode 100644 index 0000000..349df66 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/reset.imageset/undo-circular-arrow.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/resize.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/resize.imageset/Contents.json new file mode 100644 index 0000000..e05a85d --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/resize.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "increase-size-option.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/resize.imageset/increase-size-option.png b/Paradise/App/Paradise/Assets.xcassets/resize.imageset/increase-size-option.png new file mode 100644 index 0000000..55279a3 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/resize.imageset/increase-size-option.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/rotate.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/rotate.imageset/Contents.json new file mode 100644 index 0000000..32ac684 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/rotate.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "refresh-button.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/rotate.imageset/refresh-button.png b/Paradise/App/Paradise/Assets.xcassets/rotate.imageset/refresh-button.png new file mode 100644 index 0000000..db4d340 Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/rotate.imageset/refresh-button.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/save-icon.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/save-icon.imageset/Contents.json new file mode 100644 index 0000000..2621081 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/save-icon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "verification-sign.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/save-icon.imageset/verification-sign.png b/Paradise/App/Paradise/Assets.xcassets/save-icon.imageset/verification-sign.png new file mode 100644 index 0000000..d3f0d4f Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/save-icon.imageset/verification-sign.png differ diff --git a/Paradise/App/Paradise/Assets.xcassets/save-s.imageset/Contents.json b/Paradise/App/Paradise/Assets.xcassets/save-s.imageset/Contents.json new file mode 100644 index 0000000..18b9576 --- /dev/null +++ b/Paradise/App/Paradise/Assets.xcassets/save-s.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "save.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Paradise/App/Paradise/Assets.xcassets/save-s.imageset/save.png b/Paradise/App/Paradise/Assets.xcassets/save-s.imageset/save.png new file mode 100644 index 0000000..3af755a Binary files /dev/null and b/Paradise/App/Paradise/Assets.xcassets/save-s.imageset/save.png differ diff --git a/Paradise/App/Paradise/Base.lproj/LaunchScreen.storyboard b/Paradise/App/Paradise/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/Paradise/App/Paradise/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Paradise/App/Paradise/Base.lproj/Main.storyboard b/Paradise/App/Paradise/Base.lproj/Main.storyboard new file mode 100644 index 0000000..b3f5af9 --- /dev/null +++ b/Paradise/App/Paradise/Base.lproj/Main.storyboard @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Paradise/App/Paradise/Constraints/ConstraintExtension.h b/Paradise/App/Paradise/Constraints/ConstraintExtension.h new file mode 100644 index 0000000..e90ec61 --- /dev/null +++ b/Paradise/App/Paradise/Constraints/ConstraintExtension.h @@ -0,0 +1,20 @@ +#import + +@interface UIView (extension) + +-(void)top:(nullable NSLayoutAnchor *)top leading:(nullable NSLayoutAnchor *)leading bottom:(nullable NSLayoutAnchor *)bottom trailing:(nullable NSLayoutAnchor *)trailing padding:(UIEdgeInsets)insets; +-(void)top:(nullable NSLayoutAnchor *)top padding:(CGFloat)size; +-(void)leading:(nullable NSLayoutAnchor *)leading padding:(CGFloat)size; +-(void)trailing:(nullable NSLayoutAnchor *)trailing padding:(CGFloat)size; +-(void)bottom:(nullable NSLayoutAnchor *)bottom padding:(CGFloat)size; +-(void)size:(CGSize)size; +-(void)width:(CGFloat)size; +-(void)height:(CGFloat)size; +-(void)x:(nullable NSLayoutAnchor *)centerX; +-(void)y:(nullable NSLayoutAnchor *)centerY; +-(void)x:(nullable NSLayoutAnchor *)centerX padding:(CGFloat)size; +-(void)y:(nullable NSLayoutAnchor *)centerY padding:(CGFloat)size; +-(void)x:(nullable NSLayoutAnchor *)centerX y:(nullable NSLayoutAnchor *)centerY; +-(void)fill; + +@end diff --git a/Paradise/App/Paradise/Constraints/ConstraintExtension.m b/Paradise/App/Paradise/Constraints/ConstraintExtension.m new file mode 100644 index 0000000..cbdb804 --- /dev/null +++ b/Paradise/App/Paradise/Constraints/ConstraintExtension.m @@ -0,0 +1,128 @@ +#import "ConstraintExtension.h" + +@implementation UIView (extension) + +-(void)top:(nullable NSLayoutAnchor *)top leading:(nullable NSLayoutAnchor *)leading bottom:(nullable NSLayoutAnchor *)bottom trailing:(nullable NSLayoutAnchor *)trailing padding:(UIEdgeInsets)insets { + + self.translatesAutoresizingMaskIntoConstraints = NO; + + if (top) { + [self.topAnchor constraintEqualToAnchor:top constant:insets.top].active = YES; + } + + if (leading) { + [self.leadingAnchor constraintEqualToAnchor:leading constant:insets.left].active = YES; + } + + if (trailing) { + [self.trailingAnchor constraintEqualToAnchor:trailing constant:insets.right].active = YES; + } + + if (bottom) { + [self.bottomAnchor constraintEqualToAnchor:bottom constant:insets.bottom].active = YES; + } + +} + + +-(void)top:(nullable NSLayoutAnchor *)top padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (top) { + [self.topAnchor constraintEqualToAnchor:top constant:size].active = YES; + } +} + + +-(void)leading:(nullable NSLayoutAnchor *)leading padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (leading) { + [self.leadingAnchor constraintEqualToAnchor:leading constant:size].active = YES; + } +} + + +-(void)trailing:(nullable NSLayoutAnchor *)trailing padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (trailing) { + [self.trailingAnchor constraintEqualToAnchor:trailing constant:size].active = YES; + } +} + + +-(void)bottom:(nullable NSLayoutAnchor *)bottom padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (bottom) { + [self.bottomAnchor constraintEqualToAnchor:bottom constant:size].active = YES; + } +} + + +-(void)size:(CGSize)size { + + self.translatesAutoresizingMaskIntoConstraints = NO; + + if (size.width != 0) { + [self.widthAnchor constraintEqualToConstant:size.width].active = YES; + } + + if (size.height != 0) { + [self.heightAnchor constraintEqualToConstant:size.height].active = YES; + } + +} + + +-(void)width:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.widthAnchor constraintEqualToConstant:size].active = YES; +} + + +-(void)height:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.heightAnchor constraintEqualToConstant:size].active = YES; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX y:(nullable NSLayoutAnchor *)centerY { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX].active = true; + [[self centerYAnchor] constraintEqualToAnchor:centerY].active = true; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX].active = true; +} + + +-(void)y:(nullable NSLayoutAnchor *)centerY { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerYAnchor] constraintEqualToAnchor:centerY].active = true; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX constant:size].active = true; +} + + +-(void)y:(nullable NSLayoutAnchor *)centerY padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerYAnchor] constraintEqualToAnchor:centerY constant:size].active = true; +} + + +-(void)fill { + + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.topAnchor constraintEqualToAnchor:self.superview.topAnchor].active = YES; + [self.leadingAnchor constraintEqualToAnchor:self.superview.leadingAnchor].active = YES; + [self.trailingAnchor constraintEqualToAnchor:self.superview.trailingAnchor].active = YES; + [self.bottomAnchor constraintEqualToAnchor:self.superview.bottomAnchor].active = YES; + +} + +@end diff --git a/Paradise/App/Paradise/Constraints/DeviceHelper.swift b/Paradise/App/Paradise/Constraints/DeviceHelper.swift new file mode 100644 index 0000000..dbdbab8 --- /dev/null +++ b/Paradise/App/Paradise/Constraints/DeviceHelper.swift @@ -0,0 +1,355 @@ +import UIKit +enum UIDeviceSize { + case i3_5Inch + case i4Inch + case i4_7Inch + case i5_5Inch + case i5_8Inch + case i6_1Inch + case i5_4Inch + case i6_5Inch + case i6_7Inch + case i7_9Inch + case i9_7Inch + case i10_5Inch + case i11_Inch + case i12_9Inch + case unknown +} + +let deviceSize : UIDeviceSize = { + let w: Double = Double(UIScreen.main.bounds.width) + let h: Double = Double(UIScreen.main.bounds.height) + let screenHeight: Double = max(w, h) + let deviceType = UIDevice().type + switch screenHeight { + case 480: + return .i3_5Inch + case 568: + return .i4Inch + case 667: + return UIScreen.main.scale == 3.0 ? .i5_5Inch : .i4_7Inch + case 736: + return .i5_5Inch + case 812: + switch deviceType { + case .iPhone12Mini: + return .i5_4Inch + default: + return .i5_8Inch + } + case 844: + return .i6_1Inch + case 896: + switch deviceType { + case .iPhoneXSMax: + return .i6_5Inch + default: + return .i6_1Inch + } + case 926: + return .i6_7Inch + case 1024: + switch UIDevice().type { + case .iPadMini,.iPadMini2,.iPadMini3,.iPadMini4: + return .i7_9Inch + case .iPadPro10_5: + return .i10_5Inch + default: + return .i9_7Inch + } + case 1112: + return .i10_5Inch + case 1194: + return .i11_Inch + case 1366: + return .i12_9Inch + default: + return .unknown + } + +}() + +// This Model and Extention has been taken from the Answer by +// Alessandro Ornano : https://stackoverflow.com/a/46234519/6330448 +// Feel free to update it +public enum Model : String { + +//Simulator +case simulator = "simulator/sandbox", + +//iPod +iPod1 = "iPod 1", +iPod2 = "iPod 2", +iPod3 = "iPod 3", +iPod4 = "iPod 4", +iPod5 = "iPod 5", +iPod6 = "iPod 6", +iPod7 = "iPod 7", + +//iPad +iPad2 = "iPad 2", +iPad3 = "iPad 3", +iPad4 = "iPad 4", +iPadAir = "iPad Air ", +iPadAir2 = "iPad Air 2", +iPadAir3 = "iPad Air 3", +iPadAir4 = "iPad Air 4", +iPad5 = "iPad 5", //iPad 2017 +iPad6 = "iPad 6", //iPad 2018 +iPad7 = "iPad 7", //iPad 2019 +iPad8 = "iPad 8", //iPad 2020 + +//iPad Mini +iPadMini = "iPad Mini", +iPadMini2 = "iPad Mini 2", +iPadMini3 = "iPad Mini 3", +iPadMini4 = "iPad Mini 4", +iPadMini5 = "iPad Mini 5", + +//iPad Pro +iPadPro9_7 = "iPad Pro 9.7\"", +iPadPro10_5 = "iPad Pro 10.5\"", +iPadPro11 = "iPad Pro 11\"", +iPadPro2_11 = "iPad Pro 11\" 2nd gen", +iPadPro12_9 = "iPad Pro 12.9\"", +iPadPro2_12_9 = "iPad Pro 2 12.9\"", +iPadPro3_12_9 = "iPad Pro 3 12.9\"", +iPadPro4_12_9 = "iPad Pro 4 12.9\"", + +//iPhone +iPhone4 = "iPhone 4", +iPhone4S = "iPhone 4S", +iPhone5 = "iPhone 5", +iPhone5S = "iPhone 5S", +iPhone5C = "iPhone 5C", +iPhone6 = "iPhone 6", +iPhone6Plus = "iPhone 6 Plus", +iPhone6S = "iPhone 6S", +iPhone6SPlus = "iPhone 6S Plus", +iPhoneSE = "iPhone SE", +iPhone7 = "iPhone 7", +iPhone7Plus = "iPhone 7 Plus", +iPhone8 = "iPhone 8", +iPhone8Plus = "iPhone 8 Plus", +iPhoneX = "iPhone X", +iPhoneXS = "iPhone XS", +iPhoneXSMax = "iPhone XS Max", +iPhoneXR = "iPhone XR", +iPhone11 = "iPhone 11", +iPhone11Pro = "iPhone 11 Pro", +iPhone11ProMax = "iPhone 11 Pro Max", +iPhoneSE2 = "iPhone SE 2nd gen", +iPhone12Mini = "iPhone 12 Mini", +iPhone12 = "iPhone 12", +iPhone12Pro = "iPhone 12 Pro", +iPhone12ProMax = "iPhone 12 Pro Max", + +// Apple Watch +AppleWatch1 = "Apple Watch 1gen", +AppleWatchS1 = "Apple Watch Series 1", +AppleWatchS2 = "Apple Watch Series 2", +AppleWatchS3 = "Apple Watch Series 3", +AppleWatchS4 = "Apple Watch Series 4", +AppleWatchS5 = "Apple Watch Series 5", +AppleWatchSE = "Apple Watch Special Edition", +AppleWatchS6 = "Apple Watch Series 6", + +//Apple TV +AppleTV1 = "Apple TV 1gen", +AppleTV2 = "Apple TV 2gen", +AppleTV3 = "Apple TV 3gen", +AppleTV4 = "Apple TV 4gen", +AppleTV_4K = "Apple TV 4K", + +unrecognized = "?unrecognized?" +} + +// #-#-#-#-#-#-#-#-#-#-#-#-# +// MARK: UIDevice extensions +// #-#-#-#-#-#-#-#-#-#-#-#-# + +public extension UIDevice { + +var type: Model { + var systemInfo = utsname() + uname(&systemInfo) + let modelCode = withUnsafePointer(to: &systemInfo.machine) { + $0.withMemoryRebound(to: CChar.self, capacity: 1) { + ptr in String.init(validatingUTF8: ptr) + } + } + + let modelMap : [String: Model] = [ + + //Simulator + "i386" : .simulator, + "x86_64" : .simulator, + + //iPod + "iPod1,1" : .iPod1, + "iPod2,1" : .iPod2, + "iPod3,1" : .iPod3, + "iPod4,1" : .iPod4, + "iPod5,1" : .iPod5, + "iPod7,1" : .iPod6, + "iPod9,1" : .iPod7, + + //iPad + "iPad2,1" : .iPad2, + "iPad2,2" : .iPad2, + "iPad2,3" : .iPad2, + "iPad2,4" : .iPad2, + "iPad3,1" : .iPad3, + "iPad3,2" : .iPad3, + "iPad3,3" : .iPad3, + "iPad3,4" : .iPad4, + "iPad3,5" : .iPad4, + "iPad3,6" : .iPad4, + "iPad6,11" : .iPad5, //iPad 2017 + "iPad6,12" : .iPad5, + "iPad7,5" : .iPad6, //iPad 2018 + "iPad7,6" : .iPad6, + "iPad7,11" : .iPad7, //iPad 2019 + "iPad7,12" : .iPad7, + "iPad11,6" : .iPad8, //iPad 2020 + "iPad11,7" : .iPad8, + + //iPad Mini + "iPad2,5" : .iPadMini, + "iPad2,6" : .iPadMini, + "iPad2,7" : .iPadMini, + "iPad4,4" : .iPadMini2, + "iPad4,5" : .iPadMini2, + "iPad4,6" : .iPadMini2, + "iPad4,7" : .iPadMini3, + "iPad4,8" : .iPadMini3, + "iPad4,9" : .iPadMini3, + "iPad5,1" : .iPadMini4, + "iPad5,2" : .iPadMini4, + "iPad11,1" : .iPadMini5, + "iPad11,2" : .iPadMini5, + + //iPad Pro + "iPad6,3" : .iPadPro9_7, + "iPad6,4" : .iPadPro9_7, + "iPad7,3" : .iPadPro10_5, + "iPad7,4" : .iPadPro10_5, + "iPad6,7" : .iPadPro12_9, + "iPad6,8" : .iPadPro12_9, + "iPad7,1" : .iPadPro2_12_9, + "iPad7,2" : .iPadPro2_12_9, + "iPad8,1" : .iPadPro11, + "iPad8,2" : .iPadPro11, + "iPad8,3" : .iPadPro11, + "iPad8,4" : .iPadPro11, + "iPad8,9" : .iPadPro2_11, + "iPad8,10" : .iPadPro2_11, + "iPad8,5" : .iPadPro3_12_9, + "iPad8,6" : .iPadPro3_12_9, + "iPad8,7" : .iPadPro3_12_9, + "iPad8,8" : .iPadPro3_12_9, + "iPad8,11" : .iPadPro4_12_9, + "iPad8,12" : .iPadPro4_12_9, + + //iPad Air + "iPad4,1" : .iPadAir, + "iPad4,2" : .iPadAir, + "iPad4,3" : .iPadAir, + "iPad5,3" : .iPadAir2, + "iPad5,4" : .iPadAir2, + "iPad11,3" : .iPadAir3, + "iPad11,4" : .iPadAir3, + "iPad13,1" : .iPadAir4, + "iPad13,2" : .iPadAir4, + + + //iPhone + "iPhone3,1" : .iPhone4, + "iPhone3,2" : .iPhone4, + "iPhone3,3" : .iPhone4, + "iPhone4,1" : .iPhone4S, + "iPhone5,1" : .iPhone5, + "iPhone5,2" : .iPhone5, + "iPhone5,3" : .iPhone5C, + "iPhone5,4" : .iPhone5C, + "iPhone6,1" : .iPhone5S, + "iPhone6,2" : .iPhone5S, + "iPhone7,1" : .iPhone6Plus, + "iPhone7,2" : .iPhone6, + "iPhone8,1" : .iPhone6S, + "iPhone8,2" : .iPhone6SPlus, + "iPhone8,4" : .iPhoneSE, + "iPhone9,1" : .iPhone7, + "iPhone9,3" : .iPhone7, + "iPhone9,2" : .iPhone7Plus, + "iPhone9,4" : .iPhone7Plus, + "iPhone10,1" : .iPhone8, + "iPhone10,4" : .iPhone8, + "iPhone10,2" : .iPhone8Plus, + "iPhone10,5" : .iPhone8Plus, + "iPhone10,3" : .iPhoneX, + "iPhone10,6" : .iPhoneX, + "iPhone11,2" : .iPhoneXS, + "iPhone11,4" : .iPhoneXSMax, + "iPhone11,6" : .iPhoneXSMax, + "iPhone11,8" : .iPhoneXR, + "iPhone12,1" : .iPhone11, + "iPhone12,3" : .iPhone11Pro, + "iPhone12,5" : .iPhone11ProMax, + "iPhone12,8" : .iPhoneSE2, + "iPhone13,1" : .iPhone12Mini, + "iPhone13,2" : .iPhone12, + "iPhone13,3" : .iPhone12Pro, + "iPhone13,4" : .iPhone12ProMax, + + // Apple Watch + "Watch1,1" : .AppleWatch1, + "Watch1,2" : .AppleWatch1, + "Watch2,6" : .AppleWatchS1, + "Watch2,7" : .AppleWatchS1, + "Watch2,3" : .AppleWatchS2, + "Watch2,4" : .AppleWatchS2, + "Watch3,1" : .AppleWatchS3, + "Watch3,2" : .AppleWatchS3, + "Watch3,3" : .AppleWatchS3, + "Watch3,4" : .AppleWatchS3, + "Watch4,1" : .AppleWatchS4, + "Watch4,2" : .AppleWatchS4, + "Watch4,3" : .AppleWatchS4, + "Watch4,4" : .AppleWatchS4, + "Watch5,1" : .AppleWatchS5, + "Watch5,2" : .AppleWatchS5, + "Watch5,3" : .AppleWatchS5, + "Watch5,4" : .AppleWatchS5, + "Watch5,9" : .AppleWatchSE, + "Watch5,10" : .AppleWatchSE, + "Watch5,11" : .AppleWatchSE, + "Watch5,12" : .AppleWatchSE, + "Watch6,1" : .AppleWatchS6, + "Watch6,2" : .AppleWatchS6, + "Watch6,3" : .AppleWatchS6, + "Watch6,4" : .AppleWatchS6, + + //Apple TV + "AppleTV1,1" : .AppleTV1, + "AppleTV2,1" : .AppleTV2, + "AppleTV3,1" : .AppleTV3, + "AppleTV3,2" : .AppleTV3, + "AppleTV5,3" : .AppleTV4, + "AppleTV6,2" : .AppleTV_4K + ] + + if let model = modelMap[String.init(validatingUTF8: modelCode!)!] { + if model == .simulator { + if let simModelCode = ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] { + if let simModel = modelMap[String.init(validatingUTF8: simModelCode)!] { + return simModel + } + } + } + return model + } + return Model.unrecognized + } +} diff --git a/Paradise/App/Paradise/Constraints/Macros.h b/Paradise/App/Paradise/Constraints/Macros.h new file mode 100644 index 0000000..03b6d81 --- /dev/null +++ b/Paradise/App/Paradise/Constraints/Macros.h @@ -0,0 +1,11 @@ +#define MAIN_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width +#define MAIN_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height + +#define iPhone_SE ([[UIScreen mainScreen] bounds].size.height == 568) // iPhone SE +#define iPhone_6_8 ([[UIScreen mainScreen] bounds].size.height == 667) // iPhone 6, 6s, 7 and 8 +#define iPhone_6_8_Plus ([[UIScreen mainScreen] bounds].size.height == 736) // iPhone 6, 6s, 7 and 8 Plus +#define iPhone_X_XS_11Pro ([[UIScreen mainScreen] bounds].size.height == 812) // iPhone X, XS, 11 Pro +#define iPhone_XR_XS_11Pro ([[UIScreen mainScreen] bounds].size.height == 896) // iPhone XR, XS Max, 11 Pro Max +#define iPhone_12_Pro ([[UIScreen mainScreen] bounds].size.height == 844) // iPhone 12 & 12 Pro +#define iPhone_12_mini ([[UIScreen mainScreen] bounds].size.height == 780) // iPhone 12 mini +#define iPhone_12_Pro_Max ([[UIScreen mainScreen] bounds].size.height == 926) // iPhone 12 Pro Max diff --git a/Paradise/App/Paradise/Constraints/NSLayoutHelper.swift b/Paradise/App/Paradise/Constraints/NSLayoutHelper.swift new file mode 100644 index 0000000..2539096 --- /dev/null +++ b/Paradise/App/Paradise/Constraints/NSLayoutHelper.swift @@ -0,0 +1,55 @@ +import UIKit +@IBDesignable class NSLayoutHelper : NSLayoutConstraint { + @IBInspectable var iPhone4s: CGFloat = 0.0 { + didSet { deviceConstant(.i3_5Inch,value:iPhone4s) } + } + @IBInspectable var iPhoneSE: CGFloat = 0.0 { + didSet { deviceConstant(.i4Inch,value:iPhoneSE) } + } + @IBInspectable var iPhoneSE2G: CGFloat = 0.0 { + didSet { deviceConstant(.i4_7Inch,value:iPhoneSE2G) } + } + @IBInspectable var iPhone8Plus: CGFloat = 0.0 { + didSet { deviceConstant(.i5_5Inch,value:iPhone8Plus) } + } + @IBInspectable var iPhone11Pro: CGFloat = 0.0 { + didSet { deviceConstant(.i5_8Inch,value:iPhone11Pro) } + } + @IBInspectable var iPhone11: CGFloat = 0.0 { + didSet { deviceConstant(.i6_1Inch,value:iPhone11) } + } + @IBInspectable var iPhone11Max: CGFloat = 0.0 { + didSet { deviceConstant(.i6_5Inch,value:iPhone11Max) } + } + @IBInspectable var iPhone12Mini: CGFloat = 0.0 { + didSet { deviceConstant(.i5_4Inch,value:iPhone12Mini) } + } + @IBInspectable var iPhone12: CGFloat = 0.0 { + didSet { deviceConstant(.i6_1Inch,value:iPhone12) } + } + @IBInspectable var iPhone12ProMax: CGFloat = 0.0 { + didSet { deviceConstant(.i6_7Inch,value:iPhone12ProMax) } + } + @IBInspectable var iPadMini: CGFloat = 0.0 { + didSet { deviceConstant(.i7_9Inch,value:iPadMini) } + } + @IBInspectable var iPadPro9_7: CGFloat = 0.0 { + didSet { deviceConstant(.i9_7Inch,value:iPadPro9_7) } + } + @IBInspectable var iPadPro10_5: CGFloat = 0.0 { + didSet { deviceConstant(.i10_5Inch,value:iPadPro10_5) } + } + @IBInspectable var iPadPro11: CGFloat = 0.0 { + didSet { deviceConstant(.i11_Inch,value:iPadPro11) } + } + @IBInspectable var iPadPro12_9: CGFloat = 0.0 { + didSet { deviceConstant(.i12_9Inch,value:iPadPro12_9) } + } + // Helpers + open func deviceConstant(_ device:UIDeviceSize,value:CGFloat) { + if deviceSize == device { + constant = value + } + } +} + diff --git a/Paradise/App/Paradise/Constraints/Paradise-Bridging-Header.h b/Paradise/App/Paradise/Constraints/Paradise-Bridging-Header.h new file mode 100644 index 0000000..1b2cb5d --- /dev/null +++ b/Paradise/App/Paradise/Constraints/Paradise-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + diff --git a/Paradise/App/Paradise/Constraints/UIButtonHelper.swift b/Paradise/App/Paradise/Constraints/UIButtonHelper.swift new file mode 100644 index 0000000..ac0143f --- /dev/null +++ b/Paradise/App/Paradise/Constraints/UIButtonHelper.swift @@ -0,0 +1,55 @@ +import UIKit + +@IBDesignable class UIButtonHelper : UIButton { + @IBInspectable var iPhone4s: CGFloat = 0.0 { + didSet { deviceFont(.i3_5Inch,value:iPhone4s) } + } + @IBInspectable var iPhoneSE: CGFloat = 0.0 { + didSet { deviceFont(.i4Inch,value:iPhoneSE) } + } + @IBInspectable var iPhoneSE2G: CGFloat = 0.0 { + didSet { deviceFont(.i4_7Inch,value:iPhoneSE2G) } + } + @IBInspectable var iPhone8Plus: CGFloat = 0.0 { + didSet { deviceFont(.i5_5Inch,value:iPhone8Plus) } + } + @IBInspectable var iPhone11Pro: CGFloat = 0.0 { + didSet { deviceFont(.i5_8Inch,value:iPhone11Pro) } + } + @IBInspectable var iPhone11: CGFloat = 0.0 { + didSet { deviceFont(.i6_1Inch,value:iPhone11) } + } + @IBInspectable var iPhone11Max: CGFloat = 0.0 { + didSet { deviceFont(.i6_5Inch,value:iPhone11Max) } + } + @IBInspectable var iPhone12Mini: CGFloat = 0.0 { + didSet { deviceFont(.i5_4Inch,value:iPhone12Mini) } + } + @IBInspectable var iPhone12: CGFloat = 0.0 { + didSet { deviceFont(.i6_1Inch,value:iPhone12) } + } + @IBInspectable var iPhone12ProMax: CGFloat = 0.0 { + didSet { deviceFont(.i6_7Inch,value:iPhone12ProMax) } + } + @IBInspectable var iPadMini: CGFloat = 0.0 { + didSet { deviceFont(.i7_9Inch,value:iPadMini) } + } + @IBInspectable var iPadPro9_7: CGFloat = 0.0 { + didSet { deviceFont(.i9_7Inch,value:iPadPro9_7) } + } + @IBInspectable var iPadPro10_5: CGFloat = 0.0 { + didSet { deviceFont(.i10_5Inch,value:iPadPro10_5) } + } + @IBInspectable var iPadPro12_9: CGFloat = 0.0 { + didSet { deviceFont(.i12_9Inch,value:iPadPro12_9) } + } + // Helpers + open func deviceFont(_ device:UIDeviceSize,value:CGFloat) { + if deviceSize == device { + if let font = titleLabel?.font { + titleLabel?.font = UIFont(descriptor: font.fontDescriptor, size: value) + layoutIfNeeded() + } + } + } +} diff --git a/Paradise/App/Paradise/Constraints/UILabelHelper.swift b/Paradise/App/Paradise/Constraints/UILabelHelper.swift new file mode 100644 index 0000000..d64bca3 --- /dev/null +++ b/Paradise/App/Paradise/Constraints/UILabelHelper.swift @@ -0,0 +1,53 @@ +import UIKit + +@IBDesignable class UILabelHelper : UILabel { + @IBInspectable var iPhone4s: CGFloat = 0.0 { + didSet { deviceFont(.i3_5Inch,value:iPhone4s) } + } + @IBInspectable var iPhoneSE: CGFloat = 0.0 { + didSet { deviceFont(.i4Inch,value:iPhoneSE) } + } + @IBInspectable var iPhoneSE2G: CGFloat = 0.0 { + didSet { deviceFont(.i4_7Inch,value:iPhoneSE2G) } + } + @IBInspectable var iPhone8Plus: CGFloat = 0.0 { + didSet { deviceFont(.i5_5Inch,value:iPhone8Plus) } + } + @IBInspectable var iPhone11Pro: CGFloat = 0.0 { + didSet { deviceFont(.i5_8Inch,value:iPhone11Pro) } + } + @IBInspectable var iPhone11: CGFloat = 0.0 { + didSet { deviceFont(.i6_1Inch,value:iPhone11) } + } + @IBInspectable var iPhone11Max: CGFloat = 0.0 { + didSet { deviceFont(.i6_5Inch,value:iPhone11Max) } + } + @IBInspectable var iPhone12Mini: CGFloat = 0.0 { + didSet { deviceFont(.i5_4Inch,value:iPhone12Mini) } + } + @IBInspectable var iPhone12: CGFloat = 0.0 { + didSet { deviceFont(.i6_1Inch,value:iPhone12) } + } + @IBInspectable var iPhone12ProMax: CGFloat = 0.0 { + didSet { deviceFont(.i6_7Inch,value:iPhone12ProMax) } + } + @IBInspectable var iPadMini: CGFloat = 0.0 { + didSet { deviceFont(.i7_9Inch,value:iPadMini) } + } + @IBInspectable var iPadPro9_7: CGFloat = 0.0 { + didSet { deviceFont(.i9_7Inch,value:iPadPro9_7) } + } + @IBInspectable var iPadPro10_5: CGFloat = 0.0 { + didSet { deviceFont(.i10_5Inch,value:iPadPro10_5) } + } + @IBInspectable var iPadPro12_9: CGFloat = 0.0 { + didSet { deviceFont(.i12_9Inch,value:iPadPro12_9) } + } + // Helpers + open func deviceFont(_ device:UIDeviceSize,value:CGFloat) { + if deviceSize == device { + font = UIFont(descriptor: font.fontDescriptor, size: value) + layoutIfNeeded() + } + } +} diff --git a/Paradise/App/Paradise/Constraints/UITextFieldHelper.swift b/Paradise/App/Paradise/Constraints/UITextFieldHelper.swift new file mode 100644 index 0000000..29bee37 --- /dev/null +++ b/Paradise/App/Paradise/Constraints/UITextFieldHelper.swift @@ -0,0 +1,56 @@ +import UIKit + +@IBDesignable class UITextfieldHelper : UITextField { + @IBInspectable var iPhone4s: CGFloat = 0.0 { + didSet { deviceFont(.i3_5Inch,value:iPhone4s) } + } + @IBInspectable var iPhoneSE: CGFloat = 0.0 { + didSet { deviceFont(.i4Inch,value:iPhoneSE) } + } + @IBInspectable var iPhoneSE2G: CGFloat = 0.0 { + didSet { deviceFont(.i4_7Inch,value:iPhoneSE2G) } + } + @IBInspectable var iPhone8Plus: CGFloat = 0.0 { + didSet { deviceFont(.i5_5Inch,value:iPhone8Plus) } + } + @IBInspectable var iPhone11Pro: CGFloat = 0.0 { + didSet { deviceFont(.i5_8Inch,value:iPhone11Pro) } + } + @IBInspectable var iPhone11: CGFloat = 0.0 { + didSet { deviceFont(.i6_1Inch,value:iPhone11) } + } + @IBInspectable var iPhone11Max: CGFloat = 0.0 { + didSet { deviceFont(.i6_5Inch,value:iPhone11Max) } + } + @IBInspectable var iPhone12Mini: CGFloat = 0.0 { + didSet { deviceFont(.i5_4Inch,value:iPhone12Mini) } + } + @IBInspectable var iPhone12: CGFloat = 0.0 { + didSet { deviceFont(.i6_1Inch,value:iPhone12) } + } + @IBInspectable var iPhone12ProMax: CGFloat = 0.0 { + didSet { deviceFont(.i6_7Inch,value:iPhone12ProMax) } + } + @IBInspectable var iPadMini: CGFloat = 0.0 { + didSet { deviceFont(.i7_9Inch,value:iPadMini) } + } + @IBInspectable var iPadPro9_7: CGFloat = 0.0 { + didSet { deviceFont(.i9_7Inch,value:iPadPro9_7) } + } + @IBInspectable var iPadPro10_5: CGFloat = 0.0 { + didSet { deviceFont(.i10_5Inch,value:iPadPro10_5) } + } + @IBInspectable var iPadPro12_9: CGFloat = 0.0 { + didSet { deviceFont(.i12_9Inch,value:iPadPro12_9) } + } + // Helpers + open func deviceFont(_ device:UIDeviceSize,value:CGFloat) { + if deviceSize == device { + if let font = font { + self.font = UIFont(descriptor: font.fontDescriptor, size: value) + layoutIfNeeded() + } + } + + } +} diff --git a/Paradise/App/Paradise/Constraints/UITextViewHelper.swift b/Paradise/App/Paradise/Constraints/UITextViewHelper.swift new file mode 100644 index 0000000..b49edc2 --- /dev/null +++ b/Paradise/App/Paradise/Constraints/UITextViewHelper.swift @@ -0,0 +1,55 @@ +import UIKit + +@IBDesignable class UITextViewHelper : UITextView { + @IBInspectable var iPhone4s: CGFloat = 0.0 { + didSet { deviceFont(.i3_5Inch,value:iPhone4s) } + } + @IBInspectable var iPhoneSE: CGFloat = 0.0 { + didSet { deviceFont(.i4Inch,value:iPhoneSE) } + } + @IBInspectable var iPhoneSE2G: CGFloat = 0.0 { + didSet { deviceFont(.i4_7Inch,value:iPhoneSE2G) } + } + @IBInspectable var iPhone8Plus: CGFloat = 0.0 { + didSet { deviceFont(.i5_5Inch,value:iPhone8Plus) } + } + @IBInspectable var iPhone11Pro: CGFloat = 0.0 { + didSet { deviceFont(.i5_8Inch,value:iPhone11Pro) } + } + @IBInspectable var iPhone11: CGFloat = 0.0 { + didSet { deviceFont(.i6_1Inch,value:iPhone11) } + } + @IBInspectable var iPhone11Max: CGFloat = 0.0 { + didSet { deviceFont(.i6_5Inch,value:iPhone11Max) } + } + @IBInspectable var iPhone12Mini: CGFloat = 0.0 { + didSet { deviceFont(.i5_4Inch,value:iPhone12Mini) } + } + @IBInspectable var iPhone12: CGFloat = 0.0 { + didSet { deviceFont(.i6_1Inch,value:iPhone12) } + } + @IBInspectable var iPhone12ProMax: CGFloat = 0.0 { + didSet { deviceFont(.i6_7Inch,value:iPhone12ProMax) } + } + @IBInspectable var iPadMini: CGFloat = 0.0 { + didSet { deviceFont(.i7_9Inch,value:iPadMini) } + } + @IBInspectable var iPadPro9_7: CGFloat = 0.0 { + didSet { deviceFont(.i9_7Inch,value:iPadPro9_7) } + } + @IBInspectable var iPadPro10_5: CGFloat = 0.0 { + didSet { deviceFont(.i10_5Inch,value:iPadPro10_5) } + } + @IBInspectable var iPadPro12_9: CGFloat = 0.0 { + didSet { deviceFont(.i12_9Inch,value:iPadPro12_9) } + } + // Helpers + open func deviceFont(_ device:UIDeviceSize,value:CGFloat) { + if deviceSize == device { + if let font = font { + self.font = UIFont(descriptor: font.fontDescriptor, size: value) + layoutIfNeeded() + } + } + } +} diff --git a/Paradise/App/Paradise/Editor/ColourCell.h b/Paradise/App/Paradise/Editor/ColourCell.h new file mode 100644 index 0000000..2e57fe7 --- /dev/null +++ b/Paradise/App/Paradise/Editor/ColourCell.h @@ -0,0 +1,9 @@ +#import +#import "ConstraintExtension.h" + +@interface ColourCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UIView *colourView; +@property (nonatomic, retain) UILabel *titleLabel; +@end diff --git a/Paradise/App/Paradise/Editor/ColourCell.m b/Paradise/App/Paradise/Editor/ColourCell.m new file mode 100644 index 0000000..60a6984 --- /dev/null +++ b/Paradise/App/Paradise/Editor/ColourCell.m @@ -0,0 +1,62 @@ +#import "ColourCell.h" + +@implementation ColourCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 20; + + self.clipsToBounds = true; + self.layer.cornerRadius = 20; + + self.baseView = [[UIView alloc] init]; + self.baseView.layer.cornerRadius = 20; + self.baseView.backgroundColor = [UIColor colorNamed:@"Main Background"]; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFill; + self.iconImage.clipsToBounds = true; + self.iconImage.tintColor = UIColor.labelColor; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(30, 30)]; + [self.iconImage top:self.baseView.topAnchor padding:10]; + [self.iconImage leading:self.baseView.leadingAnchor padding:10]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.font = [UIFont systemFontOfSize:14]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.numberOfLines = 2; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel x:self.baseView.centerXAnchor]; + [self.titleLabel leading:self.baseView.leadingAnchor padding:5]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-5]; + [self.titleLabel bottom:self.baseView.bottomAnchor padding:-10]; + + + self.colourView = [[UIView alloc] init]; + self.colourView.layer.cornerRadius = 5; + self.colourView.layer.cornerCurve = kCACornerCurveContinuous; + self.colourView.clipsToBounds = true; + [self.baseView addSubview:self.colourView]; + + [self.colourView size:CGSizeMake(40, 40)]; + [self.colourView x:self.baseView.centerXAnchor]; + [self.colourView bottom:self.titleLabel.topAnchor padding:-15]; + + } + return self; +} + +@end diff --git a/Paradise/App/Paradise/Editor/EditorCell.h b/Paradise/App/Paradise/Editor/EditorCell.h new file mode 100644 index 0000000..db58de3 --- /dev/null +++ b/Paradise/App/Paradise/Editor/EditorCell.h @@ -0,0 +1,9 @@ +#import +#import "ConstraintExtension.h" + +@interface EditorCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UIImageView *previewImage; +@property (nonatomic, retain) UILabel *titleLabel; +@end diff --git a/Paradise/App/Paradise/Editor/EditorCell.m b/Paradise/App/Paradise/Editor/EditorCell.m new file mode 100644 index 0000000..54d2cd8 --- /dev/null +++ b/Paradise/App/Paradise/Editor/EditorCell.m @@ -0,0 +1,62 @@ +#import "EditorCell.h" + +@implementation EditorCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 20; + + self.clipsToBounds = true; + self.layer.cornerRadius = 20; + + self.baseView = [[UIView alloc] init]; + self.baseView.layer.cornerRadius = 20; + self.baseView.backgroundColor = [UIColor colorNamed:@"Main Background"]; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFill; + self.iconImage.clipsToBounds = true; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(30, 30)]; + [self.iconImage top:self.baseView.topAnchor padding:10]; + [self.iconImage leading:self.baseView.leadingAnchor padding:10]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.font = [UIFont systemFontOfSize:14]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.numberOfLines = 2; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel x:self.baseView.centerXAnchor]; + [self.titleLabel leading:self.baseView.leadingAnchor padding:5]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-5]; + [self.titleLabel bottom:self.baseView.bottomAnchor padding:-10]; + + + self.previewImage = [[UIImageView alloc] init]; + self.previewImage.layer.cornerRadius = 5; + self.previewImage.layer.cornerCurve = kCACornerCurveContinuous; + self.previewImage.clipsToBounds = true; + self.previewImage.tintColor = UIColor.labelColor; + [self.baseView addSubview:self.previewImage]; + + [self.previewImage size:CGSizeMake(40, 40)]; + [self.previewImage x:self.baseView.centerXAnchor]; + [self.previewImage bottom:self.titleLabel.topAnchor padding:-15]; + + } + return self; +} + +@end diff --git a/Paradise/App/Paradise/Editor/EditorViewController.h b/Paradise/App/Paradise/Editor/EditorViewController.h new file mode 100644 index 0000000..feb945b --- /dev/null +++ b/Paradise/App/Paradise/Editor/EditorViewController.h @@ -0,0 +1,46 @@ +#import +#import "Preferences.h" +#import "ConstraintExtension.h" +#import "Macros.h" +#import "ParadiseSegmentControl.h" +#import "ToolsCell.h" +#import "EditorCell.h" +#import "ColourCell.h" +#import "IconsViewController.h" +#import "PreviewViewController.h" +#import "TutorialViewController.h" +#import "AppManager.h" + +@interface EditorViewController : UIViewController { + float iconSize; + CAGradientLayer *gradient; + NSInteger colourPickerIndex; + UIPanGestureRecognizer *panGesture; + UIPinchGestureRecognizer *pinchGesture; + UIRotationGestureRecognizer *rotateGesture; + UIImage *tempImage; + UIColor *tempColour; +} + +@property (weak, nonatomic) IBOutlet UIView *topbarView; +@property (nonatomic, retain) UIButton *moreButton; +@property (nonatomic, retain) UIButton *saveButton; +@property (nonatomic, retain) UILabel *appLabel; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIView *toolsView; +@property (nonatomic, retain) UIButton *resetTransformButton; +@property (nonatomic, retain) UIView *segmentView; +@property (nonatomic, retain) ParadiseSegmentControl *segmentControl; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *editorArray; +@property (nonatomic, retain) UIImageView *backgroundImage; +@property (nonatomic, retain) UIView *gradientView; +@property (nonatomic, retain) UIView *iconContainerView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UIColor *primraryColour; +@property (nonatomic, retain) UIColor *secondaryColour; +@property (nonatomic, retain) UIImagePickerController *backgroundImagePickerController; +@property (nonatomic, retain) UIImagePickerController *iconImagePickerController; + +@end diff --git a/Paradise/App/Paradise/Editor/EditorViewController.m b/Paradise/App/Paradise/Editor/EditorViewController.m new file mode 100644 index 0000000..c45249e --- /dev/null +++ b/Paradise/App/Paradise/Editor/EditorViewController.m @@ -0,0 +1,956 @@ +#import "EditorViewController.h" + +@implementation EditorViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + [self configDeviceSize]; + [self layoutMenuBar]; + [self layoutIconEditor]; + [self layoutToolView]; + [self layoutCollectionView]; + [self layoutTableView]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveRefreshAppDetailsNotification:) name:@"RefreshAppDetailsNotification" object:nil]; + + showTutorial = [[AppManager sharedInstance] boolForKey:@"showTutorial" defaultValue:YES]; + + if (showTutorial) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self presentTutorialVC]; + }); + } +} + + +- (void)receiveRefreshAppDetailsNotification:(NSNotification *) notification { + + if ([[notification name] isEqualToString:@"RefreshAppDetailsNotification"]) { + + loadPrefs(); + self.appLabel.text = appName; + + } + +} + + +-(void)configDeviceSize { + + if (iPhone_6_8) { + iconSize = 230; + } else if (iPhone_6_8_Plus) { + iconSize = 250; + } else if (iPhone_X_XS_11Pro) { + iconSize = 275; + } else if (iPhone_XR_XS_11Pro) { + iconSize = 275; + } else if (iPhone_12_Pro) { + iconSize = 275; + } else if (iPhone_12_mini) { + iconSize = 230; + } else if (iPhone_12_Pro_Max) { + iconSize = 320; + } + +} + + +-(void)layoutMenuBar { + + loadPrefs(); + + self.moreButton = [[UIButton alloc] init]; + UIImage *moreImage = [[UIImage systemImageNamed:@"rectangle.grid.1x2.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [self.moreButton setImage:moreImage forState:UIControlStateNormal]; + self.moreButton.tintColor = UIColor.whiteColor; + self.moreButton.backgroundColor = [UIColor colorNamed:@"Accent"]; + self.moreButton.layer.cornerRadius = 20; + self.moreButton.menu = [self toolMenuManagement]; + self.moreButton.showsMenuAsPrimaryAction = true; + [self.topbarView addSubview:self.moreButton]; + + [self.moreButton size:CGSizeMake(60, 40)]; + [self.moreButton leading:self.topbarView.leadingAnchor padding:15]; + [self.moreButton y:self.topbarView.centerYAnchor]; + + + self.saveButton = [[UIButton alloc] init]; + [self.saveButton addTarget:self action:@selector(saveIconTheme) forControlEvents:UIControlEventTouchUpInside]; + UIImage *saveImage = [[UIImage systemImageNamed:@"paperplane.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [self.saveButton setImage:saveImage forState:UIControlStateNormal]; + self.saveButton.tintColor = UIColor.whiteColor; + self.saveButton.backgroundColor = [UIColor colorNamed:@"Accent"]; + self.saveButton.layer.cornerRadius = 20; + [self.topbarView addSubview:self.saveButton]; + + [self.saveButton size:CGSizeMake(60, 40)]; + [self.saveButton trailing:self.topbarView.trailingAnchor padding:-15]; + [self.saveButton y:self.topbarView.centerYAnchor]; + + + self.appLabel = [[UILabel alloc] init]; + self.appLabel.textAlignment = NSTextAlignmentCenter; + self.appLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold]; + self.appLabel.textColor = UIColor.labelColor; + self.appLabel.text = appName; + [self.topbarView addSubview:self.appLabel]; + + [self.appLabel x:self.topbarView.centerXAnchor]; + [self.appLabel y:self.topbarView.centerYAnchor]; + [self.appLabel leading:self.moreButton.trailingAnchor padding:15]; + [self.appLabel trailing:self.saveButton.leadingAnchor padding:-15]; + +} + + +-(void)layoutIconEditor { + + self.iconView = [[UIView alloc] init]; + self.iconView.backgroundColor = [UIColor colorNamed:@"Containers"]; + self.iconView.layer.cornerRadius = 25; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + self.iconView.clipsToBounds = true; + [self.view addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(iconSize, iconSize)]; + [self.iconView x:self.view.centerXAnchor]; + [self.iconView top:self.topbarView.bottomAnchor padding:20]; + + + self.backgroundImage = [[UIImageView alloc] init]; + self.backgroundImage.contentMode = UIViewContentModeScaleAspectFill; + [self.iconView addSubview:self.backgroundImage]; + [self.backgroundImage fill]; + //self.backgroundImage.image = [UIImage imageNamed:@"preview"]; + + + self.iconContainerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, iconSize, iconSize)]; + [self.iconView addSubview:self.iconContainerView]; + + + self.gradientView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, iconSize, iconSize)]; + self.gradientView.alpha = 0; + [self.iconContainerView addSubview:self.gradientView]; + + + self.primraryColour = UIColor.whiteColor; + self.secondaryColour = UIColor.systemTealColor; + + gradient = [CAGradientLayer layer]; + gradient.frame = self.gradientView.bounds; + gradient.colors = @[(id)self.primraryColour.CGColor, (id)self.secondaryColour.CGColor]; + [self.gradientView.layer insertSublayer:gradient atIndex:0]; + + + self.iconImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 130, 130)]; + // self.iconImage.image = [[UIImage imageNamed:@"paradise-icon"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.iconImage.image = [UIImage imageNamed:@"paradise-icon"]; + self.iconImage.center = self.iconContainerView.center; + self.iconImage.tintColor = [UIColor colorNamed:@"Accent"]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.iconView addSubview:self.iconImage]; + [self addMovementGesturesToView:self.iconImage]; +} + + +-(void)layoutToolView { + + self.toolsView = [[UIView alloc] init]; + self.toolsView.backgroundColor = [UIColor colorNamed:@"Containers"]; + self.toolsView.layer.cornerRadius = 25; + self.toolsView.layer.cornerCurve = kCACornerCurveContinuous; + self.toolsView.layer.maskedCorners = 3; + self.toolsView.clipsToBounds = true; + [self.view addSubview:self.toolsView]; + + [self.toolsView top:self.iconView.bottomAnchor padding:20]; + [self.toolsView leading:self.view.leadingAnchor padding:0]; + [self.toolsView trailing:self.view.trailingAnchor padding:0]; + [self.toolsView bottom:self.view.bottomAnchor padding:0]; + + + self.resetTransformButton = [[UIButton alloc] init]; + [self.resetTransformButton addTarget:self action:@selector(resetIconTransformPressed) forControlEvents:UIControlEventTouchUpInside]; + UIImage *resetImage = [[UIImage imageNamed:@"reset"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [self.resetTransformButton setImage:resetImage forState:UIControlStateNormal]; + self.resetTransformButton.tintColor = UIColor.systemRedColor; + self.resetTransformButton.alpha = 0; + [self.view addSubview:self.resetTransformButton]; + + [self.resetTransformButton size:CGSizeMake(25, 25)]; + [self.resetTransformButton trailing:self.view.trailingAnchor padding:-10]; + [self.resetTransformButton bottom:self.toolsView.topAnchor padding:-10]; + + + self.segmentView = [[UIView alloc] init]; + self.segmentView.backgroundColor = [UIColor colorNamed:@"Main Background"]; + self.segmentView.layer.cornerRadius = 20; + self.segmentView.clipsToBounds = true; + [self.toolsView addSubview:self.segmentView]; + + [self.segmentView size:CGSizeMake(254, 40)]; + [self.segmentView top:self.toolsView.topAnchor padding:10]; + [self.segmentView x:self.toolsView.centerXAnchor]; + + + self.segmentControl = [[ParadiseSegmentControl alloc] initWithStringsArray:@[@"Editor", @"Icon Tools"]]; + self.segmentControl.frame = CGRectMake(2, 2, 250, 36); + self.segmentControl.cornerRadius = 18; + self.segmentControl.backgroundColor = UIColor.clearColor; + self.segmentControl.labelTextColorInsideSlider = UIColor.labelColor; + self.segmentControl.labelTextColorOutsideSlider = UIColor.labelColor; + self.segmentControl.sliderColor = [UIColor colorNamed:@"Containers"]; + [self.segmentView addSubview:self.segmentControl]; + + + [self.segmentControl setPressedHandler:^(NSUInteger index) { + + if (index == 0) { + + [UIView animateWithDuration:0.3 animations:^{ + self.collectionView.alpha = 1; + self.tableView.alpha = 0; + }]; + + } else if (index == 1) { + + [UIView animateWithDuration:0.3 animations:^{ + self.collectionView.alpha = 0; + self.tableView.alpha = 1; + }]; + } + + }]; +} + + +-(void)layoutCollectionView { + + self.editorArray = [[NSArray alloc] initWithObjects:@"Icons", @"Icon Image", @"Icon Colour", @"Background Image", @"Background Colour", @"BG Top Gradient", @"BG Bottom Gradient", nil]; + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[EditorCell class] forCellWithReuseIdentifier:@"Cell1"]; + [self.collectionView registerClass:[ColourCell class] forCellWithReuseIdentifier:@"Cell2"]; + [self.toolsView addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + [self.collectionView top:self.segmentView.bottomAnchor padding:10]; + [self.collectionView leading:self.toolsView.leadingAnchor padding:0]; + [self.collectionView trailing:self.toolsView.trailingAnchor padding:0]; + [self.collectionView bottom:self.toolsView.bottomAnchor padding:-10]; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.editorArray.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + if (indexPath.row == 0) { + + EditorCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell1" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.iconImage.image = [UIImage imageNamed:@"imagepicker-icon"]; + cell.titleLabel.text = [self.editorArray objectAtIndex:indexPath.row]; + cell.previewImage.contentMode = UIViewContentModeScaleAspectFit; + + if (tempImage != nil) { + cell.previewImage.image = tempImage; + cell.previewImage.tintColor = [UIColor colorNamed:@"Accent"]; + } else { + cell.previewImage.image = [UIImage imageNamed:@"paradise-icon"]; + } + + return cell; + + } else if (indexPath.row == 1) { + + EditorCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell1" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.iconImage.image = [UIImage imageNamed:@"imagepicker-icon"]; + cell.titleLabel.text = [self.editorArray objectAtIndex:indexPath.row]; + cell.previewImage.contentMode = UIViewContentModeScaleAspectFill; + cell.previewImage.image = [UIImage imageNamed:@"default-preview"]; + + return cell; + + } else if (indexPath.row == 3) { + + EditorCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell1" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.iconImage.image = [UIImage imageNamed:@"imagepicker-icon"]; + cell.titleLabel.text = [self.editorArray objectAtIndex:indexPath.row]; + cell.previewImage.contentMode = UIViewContentModeScaleAspectFill; + cell.previewImage.image = [UIImage imageNamed:@"default-preview"]; + + return cell; + + } else { + + ColourCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell2" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.iconImage.image = [UIImage imageNamed:@"colourpicker-icon"]; + cell.titleLabel.text = [self.editorArray objectAtIndex:indexPath.row]; + + if (indexPath.row == 2) { + cell.colourView.backgroundColor = [UIColor colorNamed:@"Accent"]; + } else if (indexPath.row == 4) { + cell.colourView.backgroundColor = [UIColor colorNamed:@"Containers"]; + } else if (indexPath.row == 5) { + cell.colourView.backgroundColor = self.primraryColour; + } else if (indexPath.row == 6) { + cell.colourView.backgroundColor = self.secondaryColour; + } + + return cell; + + } + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat width = self.view.frame.size.width /2 -15; + return CGSizeMake(width, 110); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,10,0,10); // top, left, bottom, right +} + + +- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath { + + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; + +} + + +- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath { + + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; + +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + if (indexPath.row == 0) { + + IconsViewController *iconVC = [self.storyboard instantiateViewControllerWithIdentifier:@"IconsViewController"]; + iconVC.iconDelegate = self; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:iconVC]; + [self presentViewController:navController animated:YES completion:nil]; + + } else if (indexPath.row == 1) { + + [self iconImagePicker]; + + } else if (indexPath.row == 2) { + + colourPickerIndex = 0; + [self presentColorPickerVC]; + + } else if (indexPath.row == 3) { + + [self backgroundImagePicker]; + + } else if (indexPath.row == 4) { + + self.gradientView.alpha = 0; + self.backgroundImage.image = nil; + colourPickerIndex = 1; + [self presentColorPickerVC]; + + } else if (indexPath.row == 5) { + + colourPickerIndex = 2; + self.gradientView.alpha = 1; + self.backgroundImage.image = nil; + [self presentColorPickerVC]; + + } else if (indexPath.row == 6) { + + self.gradientView.alpha = 1; + self.backgroundImage.image = nil; + colourPickerIndex = 3; + [self presentColorPickerVC]; + } + +} + + +-(void)layoutTableView { + + self.tableView = [[UITableView alloc] initWithFrame:CGRectZero]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + self.tableView.alpha = 0; + [self.toolsView addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + [self.tableView top:self.segmentView.bottomAnchor padding:10]; + [self.tableView leading:self.toolsView.leadingAnchor padding:10]; + [self.tableView trailing:self.toolsView.trailingAnchor padding:-10]; + [self.tableView bottom:self.toolsView.bottomAnchor padding:-10]; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 2; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ToolsCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[ToolsCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + NSArray *titleArray = [[NSArray alloc] initWithObjects:@"Resize", @"Rotate", nil]; + NSArray *imageArray = [[NSArray alloc] initWithObjects:@"resize", @"rotate", nil]; + cell.toolsDelegate = self; + cell.iconImage.image = [[UIImage imageNamed:[imageArray objectAtIndex:indexPath.row]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + cell.titleLabel.text = [titleArray objectAtIndex:indexPath.row]; + + cell.slider.tag = indexPath.row; + [cell.slider addTarget:self action:@selector(iconToolsSliderChanged:) forControlEvents:UIControlEventValueChanged]; + + if (indexPath.row == 0) { + cell.slider.minimumValue = 20; + cell.slider.maximumValue = 350; + cell.slider.continuous = YES; + cell.slider.value = 130; + } else if (indexPath.row == 1) { + cell.slider.continuous = YES; + cell.slider.value = 0; + } + + return cell; + +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 90; +} + + +-(void)iconToolsSliderChanged:(UISlider*)sender { + + ToolsCell *cell = (ToolsCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:sender.tag inSection:0]]; + + NSIndexPath *indexPath = [self.tableView indexPathForCell:cell]; + + if (indexPath.row == 0) { + [self.iconImage setFrame:CGRectMake(0, 0, cell.slider.value, cell.slider.value)]; + self.iconImage.center = self.iconContainerView.center; + } else if (indexPath.row == 1) { + self.iconImage.transform = CGAffineTransformMakeRotation(cell.slider.value * 2*M_PI); + } + +} + + +- (void)resetToolsForCell:(UITableViewCell *)cell { + NSIndexPath *indexPath = [self.tableView indexPathForCell:cell]; + ToolsCell *cells = (ToolsCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + + if (indexPath.row == 0) { + + [self.iconImage setFrame:CGRectMake(0, 0, 130, 130)]; + self.iconImage.center = self.iconContainerView.center; + cells.slider.value = 130; + + } else if (indexPath.row == 1) { + + self.iconImage.transform = CGAffineTransformIdentity; + cells.slider.value = 0; + } + +} + + +- (void)addMovementGesturesToView:(UIView *)view { + view.userInteractionEnabled = YES; + + if (!panGesture) { + panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; + panGesture.delegate = self; + panGesture.cancelsTouchesInView = NO; + [view addGestureRecognizer:panGesture]; + + pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)]; + pinchGesture.delegate = self; + pinchGesture.cancelsTouchesInView = NO; + [view addGestureRecognizer:pinchGesture]; + + rotateGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotateGesture:)]; + rotateGesture.delegate = self; + rotateGesture.cancelsTouchesInView = NO; + [view addGestureRecognizer:rotateGesture]; + } + +} + + +- (void)handlePanGesture:(UIPanGestureRecognizer *)panGesture { + CGPoint translation = [panGesture translationInView:panGesture.view.superview]; + + if (UIGestureRecognizerStateBegan == panGesture.state || UIGestureRecognizerStateChanged == panGesture.state) { + + [UIView animateWithDuration:0.3 animations:^{ + self.resetTransformButton.alpha = 1; + }]; + + panGesture.view.center = CGPointMake(panGesture.view.center.x + translation.x, panGesture.view.center.y + translation.y); + + [panGesture setTranslation:CGPointZero inView:self.view]; + } + +} + + +- (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinchGesture { + + if (UIGestureRecognizerStateBegan == pinchGesture.state || UIGestureRecognizerStateChanged == pinchGesture.state) { + + [UIView animateWithDuration:0.3 animations:^{ + self.resetTransformButton.alpha = 1; + }]; + + float currentScale = [[pinchGesture.view.layer valueForKeyPath:@"transform.scale.x"] floatValue]; + + float minScale = 0.5; + float maxScale = 4.0; + float zoomSpeed = .5; + + float deltaScale = pinchGesture.scale; + + deltaScale = ((deltaScale - 1) * zoomSpeed) + 1; + + deltaScale = MIN(deltaScale, maxScale / currentScale); + deltaScale = MAX(deltaScale, minScale / currentScale); + + CGAffineTransform zoomTransform = CGAffineTransformScale(pinchGesture.view.transform, deltaScale, deltaScale); + pinchGesture.view.transform = zoomTransform; + + pinchGesture.scale = 1; + } +} + + +- (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotateGesture { + if (UIGestureRecognizerStateBegan == rotateGesture.state || UIGestureRecognizerStateChanged == rotateGesture.state) { + [UIView animateWithDuration:0.3 animations:^{ + self.resetTransformButton.alpha = 1; + }]; + rotateGesture.view.transform = CGAffineTransformRotate(rotateGesture.view.transform, rotateGesture.rotation); + rotateGesture.rotation = 0; + } +} + + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { + return YES; +} + + +-(void)backgroundImagePicker { + + self.gradientView.alpha = 0; + + self.backgroundImagePickerController = [[UIImagePickerController alloc] init]; + self.backgroundImagePickerController.delegate = self; + self.backgroundImagePickerController.allowsEditing = false; + self.backgroundImagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [self presentViewController:self.backgroundImagePickerController animated:YES completion:nil]; + +} + + +-(void)iconImagePicker { + + self.iconImagePickerController = [[UIImagePickerController alloc] init]; + self.iconImagePickerController.delegate = self; + self.iconImagePickerController.allowsEditing = false; + self.iconImagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [self presentViewController:self.iconImagePickerController animated:YES completion:nil]; + +} + + +-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(nonnull NSDictionary *)info { + + if (picker == self.backgroundImagePickerController) { + + self.backgroundImage.image = info[UIImagePickerControllerOriginalImage]; + NSIndexPath *_indexPath = [NSIndexPath indexPathForItem:3 inSection:0]; + EditorCell *cell = (EditorCell *)[self.collectionView cellForItemAtIndexPath:_indexPath]; + cell.previewImage.image = info[UIImagePickerControllerOriginalImage]; + + } else if (picker == self.iconImagePickerController) { + self.iconImage.image = info[UIImagePickerControllerOriginalImage]; + tempImage = info[UIImagePickerControllerOriginalImage]; + + NSIndexPath *_indexPath = [NSIndexPath indexPathForItem:1 inSection:0]; + EditorCell *cell = (EditorCell *)[self.collectionView cellForItemAtIndexPath:_indexPath]; + cell.previewImage.image = info[UIImagePickerControllerOriginalImage]; + } + + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentColorPickerVC { + + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + if (colourPickerIndex == 0) { + colourPickerVC.selectedColor = self.iconImage.tintColor; + } else if (colourPickerIndex == 1) { + colourPickerVC.selectedColor = self.iconView.backgroundColor; + } else if (colourPickerIndex == 2) { + colourPickerVC.selectedColor = self.primraryColour; + } else if (colourPickerIndex == 3) { + colourPickerVC.selectedColor = self.secondaryColour; + } + [self presentViewController:colourPickerVC animated:YES completion:nil]; +} + + +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + + UIColor *cpSelectedColour = viewController.selectedColor; + + if (colourPickerIndex == 0) { + self.iconImage.tintColor = cpSelectedColour; + //self.backgroundColourPreview.backgroundColor = cpSelectedColour; + } else if (colourPickerIndex == 1) { + self.iconView.backgroundColor = cpSelectedColour; + //self.iconColourView.backgroundColor = cpSelectedColour; + } else if (colourPickerIndex == 2) { + self.primraryColour = cpSelectedColour; + //self.primraryColourPreview.backgroundColor = cpSelectedColour; + gradient.colors = @[(id)self.primraryColour.CGColor, (id)self.secondaryColour.CGColor]; + } else if (colourPickerIndex == 3) { + self.secondaryColour = cpSelectedColour; + //self.secondaryColourPreview.backgroundColor = cpSelectedColour; + gradient.colors = @[(id)self.primraryColour.CGColor, (id)self.secondaryColour.CGColor]; + } + +} + + +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + + UIColor *cpSelectedColour = viewController.selectedColor; + + if (colourPickerIndex == 0) { + + self.iconImage.tintColor = cpSelectedColour; + //self.backgroundColourPreview.backgroundColor = cpSelectedColour; + NSIndexPath *_indexPath1 = [NSIndexPath indexPathForItem:0 inSection:0]; + EditorCell *cell1 = (EditorCell *)[self.collectionView cellForItemAtIndexPath:_indexPath1]; + cell1.previewImage.tintColor = cpSelectedColour; + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + ColourCell *cell2 = (ColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath2]; + cell2.colourView.backgroundColor = cpSelectedColour; + tempColour = cpSelectedColour; + + } else if (colourPickerIndex == 1) { + + self.iconView.backgroundColor = cpSelectedColour; + NSIndexPath *_indexPath1 = [NSIndexPath indexPathForItem:0 inSection:0]; + EditorCell *cell1 = (EditorCell *)[self.collectionView cellForItemAtIndexPath:_indexPath1]; + cell1.previewImage.tintColor = cpSelectedColour; + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:4 inSection:0]; + ColourCell *cell2 = (ColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath2]; + cell2.colourView.backgroundColor = cpSelectedColour; + + } else if (colourPickerIndex == 2) { + + self.primraryColour = cpSelectedColour; + gradient.colors = @[(id)self.primraryColour.CGColor, (id)self.secondaryColour.CGColor]; + + self.iconView.backgroundColor = cpSelectedColour; + NSIndexPath *_indexPath = [NSIndexPath indexPathForItem:5 inSection:0]; + ColourCell *cell = (ColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + + } else if (colourPickerIndex == 3) { + + self.secondaryColour = cpSelectedColour; + gradient.colors = @[(id)self.primraryColour.CGColor, (id)self.secondaryColour.CGColor]; + + self.iconView.backgroundColor = cpSelectedColour; + NSIndexPath *_indexPath = [NSIndexPath indexPathForItem:6 inSection:0]; + ColourCell *cell = (ColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + } + +} + + +-(void)resetIconTransformPressed { + + panGesture = nil; + + [self.iconImage removeFromSuperview]; + + [UIView animateWithDuration:0.3 animations:^{ + self.resetTransformButton.alpha = 0; + }]; + + [self addIconImage]; + +} + + +-(void)addIconImage { + + self.iconImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 130, 130)]; + if (tempImage != nil) { + self.iconImage.image = tempImage; + } else { + self.iconImage.image = [UIImage imageNamed:@"paradise-icon"]; + } + self.iconImage.center = self.iconContainerView.center; + self.iconImage.tintColor = tempColour; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.iconView addSubview:self.iconImage]; + [self addMovementGesturesToView:self.iconImage]; + +} + + +-(UIMenu *)toolMenuManagement { + + UIAction *previewAction = [UIAction actionWithTitle:@"Preview" image:[UIImage systemImageNamed:@"eye.fill"] identifier:nil handler:^(UIAction *action) { + [self previewIcon]; + }]; + + UIAction *saveAction = [UIAction actionWithTitle:@"Save Icon Theme" image:[UIImage systemImageNamed:@"paperplane.fill"] identifier:nil handler:^(UIAction *action) { + [self saveIconTheme]; + }]; + + UIAction *exportAction = [UIAction actionWithTitle:@"Export" image:[UIImage systemImageNamed:@"square.and.arrow.up.fill"] identifier:nil handler:^(UIAction *action) { + [self exportIcon]; + }]; + + UIAction *photoAction = [UIAction actionWithTitle:@"Save to Photo Library" image:[UIImage systemImageNamed:@"photo.fill.on.rectangle.fill"] identifier:nil handler:^(UIAction *action) { + [self saveIconToPhotoAlbum]; + }]; + + UIAction *tutorialAction = [UIAction actionWithTitle:@"Show Tutorial" image:[UIImage systemImageNamed:@"questionmark.circle.fill"] identifier:nil handler:^(UIAction *action) { + [self presentTutorialVC]; + }]; + + // UIAction *templateAction = [UIAction actionWithTitle:@"Save Template" image:[UIImage systemImageNamed:@"square.fill"] identifier:nil handler:^(UIAction *action) { + // + // }]; + + UIAction *resetAction = [UIAction actionWithTitle:@"Reset Icon" image:[UIImage systemImageNamed:@"trash.fill"] identifier:nil handler:^(UIAction *action) { + [self resetIconEditor]; + }]; + resetAction.attributes = UIMenuElementAttributesDestructive; + + //saveAction.attributes = UIMenuElementAttributesDestructive; // UIMenuElementAttributesDisabled + + return [UIMenu menuWithTitle:@"Icon Settings" children:@[previewAction, saveAction, exportAction, photoAction, tutorialAction, resetAction]]; +} + + +-(void)previewIcon { + + PreviewViewController *previewVC = [[PreviewViewController alloc] init]; + previewVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [self presentViewController:previewVC animated:YES completion:nil]; + + UIGraphicsBeginImageContextWithOptions(self.iconView.frame.size, NO, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); + [self.iconView.layer renderInContext:context]; + UIImage *contextImage = UIGraphicsGetImageFromCurrentImageContext(); + + previewVC.previewImage.image = contextImage; + +} + + +-(void)saveIconTheme { + + loadPrefs(); + + self.iconView.layer.cornerRadius = 0; + + UIGraphicsBeginImageContextWithOptions(self.iconView.frame.size, NO, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); + [self.iconView.layer renderInContext:context]; + UIImage *contextImage = UIGraphicsGetImageFromCurrentImageContext(); + + NSString *imageSubdirectory = [NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/", themeFolderName]; + + NSString *iconName = [NSString stringWithFormat:@"%@-large.png", bundleID]; + + NSString *filePath = [imageSubdirectory stringByAppendingPathComponent:iconName]; + + NSData *imageData = UIImagePNGRepresentation(contextImage); + [imageData writeToFile:filePath atomically:YES]; + + [self showAlertWithTitle:@"Successfully" message:@"Your icon have been saved to the theme folder you selected, you can apply icons theme by using theme engine and respring is required if you aren't using snowboard."]; + [self performSelector:@selector(resetCornerRadius) withObject:nil afterDelay:0.2]; +} + + +-(void)saveIconToPhotoAlbum { + + self.iconView.layer.cornerRadius = 0; + + UIGraphicsBeginImageContextWithOptions(self.iconView.frame.size, NO, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); + [self.iconView.layer renderInContext:context]; + UIImage *contextImage = UIGraphicsGetImageFromCurrentImageContext(); + UIImageWriteToSavedPhotosAlbum(contextImage, nil, nil, nil); + + [self showAlertWithTitle:@"Successfully" message:@"Your icon was saved to your photo library."]; + [self performSelector:@selector(resetCornerRadius) withObject:nil afterDelay:0.2]; +} + + +-(void)exportIcon { + + self.iconView.layer.cornerRadius = 0; + + UIGraphicsBeginImageContextWithOptions(self.iconView.frame.size, NO, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); + [self.iconView.layer renderInContext:context]; + UIImage *contextImage = UIGraphicsGetImageFromCurrentImageContext(); + + NSString *title = @"Paradise"; + NSArray *dataToShare = @[contextImage, title]; + + UIActivityViewController *controller = [[UIActivityViewController alloc]initWithActivityItems:dataToShare applicationActivities:nil]; + controller.excludedActivityTypes = @[UIActivityTypeAirDrop]; + [self presentViewController:controller animated:YES completion:nil]; + + + [controller setCompletionWithItemsHandler:^(UIActivityType _Nullable activityType, BOOL completed, NSArray * _Nullable returnedItems, NSError * _Nullable activityError) { + + if (activityType == nil) { + self.iconView.layer.cornerRadius = 25; + } else { + self.iconView.layer.cornerRadius = 25; + } + }]; + +} + + +-(void)resetIconEditor { + + self.iconView.backgroundColor = [UIColor colorNamed:@"Containers"]; + self.backgroundImage.image = nil; + self.gradientView.alpha = 0; + self.primraryColour = UIColor.whiteColor; + self.secondaryColour = UIColor.systemTealColor; + gradient.colors = @[(id)self.primraryColour.CGColor, (id)self.secondaryColour.CGColor]; + tempImage = nil; + tempColour = [UIColor colorNamed:@"Accent"]; + + [self resetIconTransformPressed]; + [self.collectionView reloadData]; + +} + + +-(void)resetCornerRadius { + self.iconView.layer.cornerRadius = 25; +} + + +-(void)showAlertWithTitle:(NSString *)title message:(NSString *)message { + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + }]; + + [alertController addAction:dismissAction]; + [self presentViewController:alertController animated:YES completion:nil]; + +} + + +-(void)sendDataToEditor:(UIImage*)image { + + self.iconImage.image = image; + tempImage = image; + + NSIndexPath *_indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; + EditorCell *cell = (EditorCell *)[self.collectionView cellForItemAtIndexPath:_indexPath]; + cell.previewImage.image = image; + cell.previewImage.tintColor = tempColour; +} + + +-(void)presentTutorialVC { + + TutorialViewController *tutorialVC = [[TutorialViewController alloc] init]; + tutorialVC.modalInPresentation = YES; + [self presentViewController:tutorialVC animated:YES completion:nil]; +} + + +@end diff --git a/Paradise/App/Paradise/Editor/GlyphCell.h b/Paradise/App/Paradise/Editor/GlyphCell.h new file mode 100644 index 0000000..262df2b --- /dev/null +++ b/Paradise/App/Paradise/Editor/GlyphCell.h @@ -0,0 +1,6 @@ +#import + +@interface GlyphCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@end diff --git a/Paradise/App/Paradise/Editor/GlyphCell.m b/Paradise/App/Paradise/Editor/GlyphCell.m new file mode 100644 index 0000000..753cde4 --- /dev/null +++ b/Paradise/App/Paradise/Editor/GlyphCell.m @@ -0,0 +1,30 @@ +#import "GlyphCell.h" + +@implementation GlyphCell + + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] initWithFrame:self.contentView.bounds]; + self.baseView.clipsToBounds = YES; + [self.contentView addSubview:self.baseView]; + + + self.iconImage = [[UIImageView alloc] init]; + [self.contentView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.contentView.centerXAnchor].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.contentView.centerYAnchor].active = YES; + + } + return self; +} + + +@end diff --git a/Paradise/App/Paradise/Editor/IconsViewController.h b/Paradise/App/Paradise/Editor/IconsViewController.h new file mode 100644 index 0000000..bf3f64e --- /dev/null +++ b/Paradise/App/Paradise/Editor/IconsViewController.h @@ -0,0 +1,14 @@ +#import +#import "ConstraintExtension.h" +#import "GlyphCell.h" + +@protocol senddataProtocol +-(void)sendDataToEditor:(UIImage*)image; +@end + + +@interface IconsViewController : UIViewController +@property (nonatomic,assign) id iconDelegate; +@property (nonatomic, retain) UICollectionView *symbolCollectionView; +@end + diff --git a/Paradise/App/Paradise/Editor/IconsViewController.m b/Paradise/App/Paradise/Editor/IconsViewController.m new file mode 100644 index 0000000..8648fd8 --- /dev/null +++ b/Paradise/App/Paradise/Editor/IconsViewController.m @@ -0,0 +1,92 @@ +#import "IconsViewController.h" + +@implementation IconsViewController +@synthesize iconDelegate; + +-(void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + self.navigationItem.title = @"Icons"; + self.navigationController.navigationBar.prefersLargeTitles = YES; + + UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(dismissVC)]; + self.navigationItem.leftBarButtonItem = cancelButton; + +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + [self layoutSymbolCollectionView]; + +} + + +- (NSArray *)iconsArray { + NSMutableDictionary *iconsDict = [NSMutableDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"Icons" ofType:@"plist"]]; + return [iconsDict objectForKey:@"iconsList"]; +} + + +-(void)layoutSymbolCollectionView { + + UICollectionViewFlowLayout *iconLayout = [[UICollectionViewFlowLayout alloc] init]; + self.symbolCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:iconLayout]; + self.symbolCollectionView.backgroundColor = UIColor.clearColor; + self.symbolCollectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.symbolCollectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.symbolCollectionView setShowsHorizontalScrollIndicator:NO]; + [self.symbolCollectionView setShowsVerticalScrollIndicator:NO]; + [self.symbolCollectionView registerClass:[GlyphCell class] forCellWithReuseIdentifier:@"GlyphCell"]; + [self.view addSubview:self.symbolCollectionView]; + + self.symbolCollectionView.delegate = self; + self.symbolCollectionView.dataSource = self; + + [self.symbolCollectionView top:self.view.topAnchor padding:0]; + [self.symbolCollectionView leading:self.view.leadingAnchor padding:10]; + [self.symbolCollectionView trailing:self.view.trailingAnchor padding:-10]; + [self.symbolCollectionView bottom:self.view.bottomAnchor padding:-10]; + +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return [[self iconsArray] count]; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + GlyphCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"GlyphCell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.iconImage.image = [[UIImage systemImageNamed:[[self iconsArray] objectAtIndex:indexPath.row]]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + cell.iconImage.tintColor = UIColor.labelColor; + cell.iconImage.contentMode = UIViewContentModeScaleAspectFit; + + return cell; + +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + [iconDelegate sendDataToEditor:[UIImage systemImageNamed:[[self iconsArray] objectAtIndex:indexPath.row]]]; + [self dismissVC]; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + + return CGSizeMake(50, 50); + +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +@end diff --git a/Paradise/App/Paradise/Editor/ToolsCell.h b/Paradise/App/Paradise/Editor/ToolsCell.h new file mode 100644 index 0000000..f22340e --- /dev/null +++ b/Paradise/App/Paradise/Editor/ToolsCell.h @@ -0,0 +1,17 @@ +#import +#import "ConstraintExtension.h" + +@protocol ToolsButtonDelegate +@optional +- (void)resetToolsForCell:(UITableViewCell *)cell; +@end + +@interface ToolsCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIButton *resetButton; +@property (nonatomic, retain) UISlider *slider; +@property (nonatomic, weak) id toolsDelegate; +@end + diff --git a/Paradise/App/Paradise/Editor/ToolsCell.m b/Paradise/App/Paradise/Editor/ToolsCell.m new file mode 100644 index 0000000..9e45726 --- /dev/null +++ b/Paradise/App/Paradise/Editor/ToolsCell.m @@ -0,0 +1,71 @@ +#import "ToolsCell.h" + +@implementation ToolsCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor colorNamed:@"Main Background"]; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:5]; + [self.baseView leading:self.leadingAnchor padding:5]; + [self.baseView trailing:self.trailingAnchor padding:-5]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.tintColor = UIColor.labelColor; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(15, 15)]; + [self.iconImage top:self.baseView.topAnchor padding:10]; + [self.iconImage leading:self.baseView.leadingAnchor padding:10]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.font = [UIFont systemFontOfSize:14]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel y:self.iconImage.centerYAnchor]; + [self.titleLabel leading:self.iconImage.trailingAnchor padding:8]; + + + self.resetButton = [[UIButton alloc] init]; + [self.resetButton addTarget:self action:@selector(resetButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + UIImage *btnImage = [UIImage imageNamed:@"reset"]; + [self.resetButton setImage:btnImage forState:UIControlStateNormal]; + self.resetButton.tintColor = UIColor.systemRedColor; + [self.baseView addSubview:self.resetButton]; + + [self.resetButton size:CGSizeMake(20, 20)]; + [self.resetButton top:self.baseView.topAnchor padding:10]; + [self.resetButton trailing:self.baseView.trailingAnchor padding:-10]; + + + self.slider = [[UISlider alloc] init]; + [self.baseView addSubview:self.slider]; + + [self.slider leading:self.baseView.leadingAnchor padding:10]; + [self.slider trailing:self.baseView.trailingAnchor padding:-10]; + [self.slider bottom:self.baseView.bottomAnchor padding:-10]; + + } + + return self; +} + + +- (void)resetButtonPressed:(id)sender { + [self.toolsDelegate resetToolsForCell:self]; +} + +@end diff --git a/Paradise/App/Paradise/Icons.plist b/Paradise/App/Paradise/Icons.plist new file mode 100644 index 0000000..62f4b1f --- /dev/null +++ b/Paradise/App/Paradise/Icons.plist @@ -0,0 +1,2579 @@ + + + + + iconsList + + 0.circle + 0.circle.fill + 0.square + 0.square.fill + 00.circle + 00.circle.fill + 00.square + 00.square.fill + 01.circle + 01.circle.fill + 01.square + 01.square.fill + 02.circle + 02.circle.fill + 02.square + 02.square.fill + 03.circle + 03.circle.fill + 03.square + 03.square.fill + 04.circle + 04.circle.fill + 04.square + 04.square.fill + 05.circle + 05.circle.fill + 05.square + 05.square.fill + 06.circle + 06.circle.fill + 06.square + 06.square.fill + 07.circle + 07.circle.fill + 07.square + 07.square.fill + 08.circle + 08.circle.fill + 08.square + 08.square.fill + 09.circle + 09.circle.fill + 09.square + 09.square.fill + 1.circle + 1.circle.fill + 1.magnifyingglass + 1.square + 1.square.fill + 10.circle + 10.circle.fill + 10.square + 10.square.fill + 11.circle + 11.circle.fill + 11.square + 11.square.fill + 12.circle + 12.circle.fill + 12.square + 12.square.fill + 13.circle + 13.circle.fill + 13.square + 13.square.fill + 14.circle + 14.circle.fill + 14.square + 14.square.fill + 15.circle + 15.circle.fill + 15.square + 15.square.fill + 16.circle + 16.circle.fill + 16.square + 16.square.fill + 17.circle + 17.circle.fill + 17.square + 17.square.fill + 18.circle + 18.circle.fill + 18.square + 18.square.fill + 19.circle + 19.circle.fill + 19.square + 19.square.fill + 2.circle + 2.circle.fill + 2.square + 2.square.fill + 20.circle + 20.circle.fill + 20.square + 20.square.fill + 21.circle + 21.circle.fill + 21.square + 21.square.fill + 22.circle + 22.circle.fill + 22.square + 22.square.fill + 23.circle + 23.circle.fill + 23.square + 23.square.fill + 24.circle + 24.circle.fill + 24.square + 24.square.fill + 25.circle + 25.circle.fill + 25.square + 25.square.fill + 26.circle + 26.circle.fill + 26.square + 26.square.fill + 27.circle + 27.circle.fill + 27.square + 27.square.fill + 28.circle + 28.circle.fill + 28.square + 28.square.fill + 29.circle + 29.circle.fill + 29.square + 29.square.fill + 3.circle + 3.circle.fill + 3.square + 3.square.fill + 30.circle + 30.circle.fill + 30.square + 30.square.fill + 31.circle + 31.circle.fill + 31.square + 31.square.fill + 32.circle + 32.circle.fill + 32.square + 32.square.fill + 33.circle + 33.circle.fill + 33.square + 33.square.fill + 34.circle + 34.circle.fill + 34.square + 34.square.fill + 35.circle + 35.circle.fill + 35.square + 35.square.fill + 36.circle + 36.circle.fill + 36.square + 36.square.fill + 37.circle + 37.circle.fill + 37.square + 37.square.fill + 38.circle + 38.circle.fill + 38.square + 38.square.fill + 39.circle + 39.circle.fill + 39.square + 39.square.fill + 4.alt.circle + 4.alt.circle.fill + 4.alt.square + 4.alt.square.fill + 4.circle + 4.circle.fill + 4.square + 4.square.fill + 40.circle + 40.circle.fill + 40.square + 40.square.fill + 41.circle + 41.circle.fill + 41.square + 41.square.fill + 42.circle + 42.circle.fill + 42.square + 42.square.fill + 43.circle + 43.circle.fill + 43.square + 43.square.fill + 44.circle + 44.circle.fill + 44.square + 44.square.fill + 45.circle + 45.circle.fill + 45.square + 45.square.fill + 46.circle + 46.circle.fill + 46.square + 46.square.fill + 47.circle + 47.circle.fill + 47.square + 47.square.fill + 48.circle + 48.circle.fill + 48.square + 48.square.fill + 49.circle + 49.circle.fill + 49.square + 49.square.fill + 4k.tv + 4k.tv.fill + 5.circle + 5.circle.fill + 5.square + 5.square.fill + 50.circle + 50.circle.fill + 50.square + 50.square.fill + 6.alt.circle + 6.alt.circle.fill + 6.alt.square + 6.alt.square.fill + 6.circle + 6.circle.fill + 6.square + 6.square.fill + 7.circle + 7.circle.fill + 7.square + 7.square.fill + 8.circle + 8.circle.fill + 8.square + 8.square.fill + 9.alt.circle + 9.alt.circle.fill + 9.alt.square + 9.alt.square.fill + 9.circle + 9.circle.fill + 9.square + 9.square.fill + a.circle + a.circle.fill + a.magnify + a.square + a.square.fill + abc + airplane + airplane.circle + airplane.circle.fill + airplayaudio + airplayvideo + airpod.left + airpod.right + airpodpro.left + airpodpro.right + airpods + airpodspro + airport.express + airport.extreme + airport.extreme.tower + alarm + alarm.fill + alt + amplifier + ant + ant.circle + ant.circle.fill + ant.fill + antenna.radiowaves.left.and.right + app + app.badge + app.badge.fill + app.fill + app.gift + app.gift.fill + appclip + applelogo + applescript + applescript.fill + appletv + appletv.fill + applewatch + applewatch.radiowaves.left.and.right + applewatch.slash + applewatch.watchface + apps.ipad + apps.ipad.landscape + apps.iphone + apps.iphone.badge.plus + apps.iphone.landscape + archivebox + archivebox.circle + archivebox.circle.fill + archivebox.fill + arkit + arrow.2.squarepath + arrow.3.trianglepath + arrow.backward + arrow.backward.circle + arrow.backward.circle.fill + arrow.backward.square + arrow.backward.square.fill + arrow.clockwise + arrow.clockwise.circle + arrow.clockwise.circle.fill + arrow.clockwise.heart + arrow.clockwise.heart.fill + arrow.clockwise.icloud + arrow.clockwise.icloud.fill + arrow.counterclockwise + arrow.counterclockwise.circle + arrow.counterclockwise.circle.fill + arrow.counterclockwise.icloud + arrow.counterclockwise.icloud.fill + arrow.down + arrow.down.app + arrow.down.app.fill + arrow.down.backward + arrow.down.backward.circle + arrow.down.backward.circle.fill + arrow.down.backward.square + arrow.down.backward.square.fill + arrow.down.circle + arrow.down.circle.fill + arrow.down.doc + arrow.down.doc.fill + arrow.down.forward + arrow.down.forward.and.arrow.up.backward + arrow.down.forward.and.arrow.up.backward.circle + arrow.down.forward.and.arrow.up.backward.circle.fill + arrow.down.forward.circle + arrow.down.forward.circle.fill + arrow.down.forward.square + arrow.down.forward.square.fill + arrow.down.heart + arrow.down.heart.fill + arrow.down.left + arrow.down.left.circle + arrow.down.left.circle.fill + arrow.down.left.square + arrow.down.left.square.fill + arrow.down.left.video + arrow.down.left.video.fill + arrow.down.right + arrow.down.right.and.arrow.up.left + arrow.down.right.and.arrow.up.left.circle + arrow.down.right.and.arrow.up.left.circle.fill + arrow.down.right.circle + arrow.down.right.circle.fill + arrow.down.right.square + arrow.down.right.square.fill + arrow.down.square + arrow.down.square.fill + arrow.down.to.line + arrow.down.to.line.alt + arrow.forward + arrow.forward.circle + arrow.forward.circle.fill + arrow.forward.square + arrow.forward.square.fill + arrow.left + arrow.left.and.right + arrow.left.and.right.circle + arrow.left.and.right.circle.fill + arrow.left.and.right.righttriangle.left.righttriangle.right + arrow.left.and.right.righttriangle.left.righttriangle.right.fill + arrow.left.and.right.square + arrow.left.and.right.square.fill + arrow.left.arrow.right + arrow.left.arrow.right.circle + arrow.left.arrow.right.circle.fill + arrow.left.arrow.right.square + arrow.left.arrow.right.square.fill + arrow.left.circle + arrow.left.circle.fill + arrow.left.square + arrow.left.square.fill + arrow.left.to.line + arrow.left.to.line.alt + arrow.rectanglepath + arrow.right + arrow.right.circle + arrow.right.circle.fill + arrow.right.doc.on.clipboard + arrow.right.square + arrow.right.square.fill + arrow.right.to.line + arrow.right.to.line.alt + arrow.triangle.2.circlepath + arrow.triangle.2.circlepath.camera + arrow.triangle.2.circlepath.camera.fill + arrow.triangle.2.circlepath.circle + arrow.triangle.2.circlepath.circle.fill + arrow.triangle.2.circlepath.doc.on.clipboard + arrow.triangle.branch + arrow.triangle.capsulepath + arrow.triangle.merge + arrow.triangle.pull + arrow.triangle.swap + arrow.triangle.turn.up.right.circle + arrow.triangle.turn.up.right.circle.fill + arrow.triangle.turn.up.right.diamond + arrow.triangle.turn.up.right.diamond.fill + arrow.turn.down.left + arrow.turn.down.right + arrow.turn.left.down + arrow.turn.left.up + arrow.turn.right.down + arrow.turn.right.up + arrow.turn.up.forward.iphone + arrow.turn.up.forward.iphone.fill + arrow.turn.up.left + arrow.turn.up.right + arrow.up + arrow.up.and.down + arrow.up.and.down.and.arrow.left.and.right + arrow.up.and.down.circle + arrow.up.and.down.circle.fill + arrow.up.and.down.righttriangle.up.fill.righttriangle.down.fill + arrow.up.and.down.righttriangle.up.righttriangle.down + arrow.up.and.down.square + arrow.up.and.down.square.fill + arrow.up.and.person.rectangle.portrait + arrow.up.and.person.rectangle.turn.left + arrow.up.and.person.rectangle.turn.right + arrow.up.arrow.down + arrow.up.arrow.down.circle + arrow.up.arrow.down.circle.fill + arrow.up.arrow.down.square + arrow.up.arrow.down.square.fill + arrow.up.backward + arrow.up.backward.and.arrow.down.forward + arrow.up.backward.and.arrow.down.forward.circle + arrow.up.backward.and.arrow.down.forward.circle.fill + arrow.up.backward.circle + arrow.up.backward.circle.fill + arrow.up.backward.square + arrow.up.backward.square.fill + arrow.up.bin + arrow.up.bin.fill + arrow.up.circle + arrow.up.circle.fill + arrow.up.doc + arrow.up.doc.fill + arrow.up.doc.on.clipboard + arrow.up.forward + arrow.up.forward.app + arrow.up.forward.app.fill + arrow.up.forward.circle + arrow.up.forward.circle.fill + arrow.up.forward.square + arrow.up.forward.square.fill + arrow.up.heart + arrow.up.heart.fill + arrow.up.left + arrow.up.left.and.arrow.down.right + arrow.up.left.and.arrow.down.right.circle + arrow.up.left.and.arrow.down.right.circle.fill + arrow.up.left.and.down.right.and.arrow.up.right.and.down.left + arrow.up.left.and.down.right.magnifyingglass + arrow.up.left.circle + arrow.up.left.circle.fill + arrow.up.left.square + arrow.up.left.square.fill + arrow.up.message + arrow.up.message.fill + arrow.up.right + arrow.up.right.and.arrow.down.left.rectangle + arrow.up.right.and.arrow.down.left.rectangle.fill + arrow.up.right.circle + arrow.up.right.circle.fill + arrow.up.right.square + arrow.up.right.square.fill + arrow.up.right.video + arrow.up.right.video.fill + arrow.up.square + arrow.up.square.fill + arrow.up.to.line + arrow.up.to.line.alt + arrow.uturn.backward + arrow.uturn.backward.circle + arrow.uturn.backward.circle.badge.ellipsis + arrow.uturn.backward.circle.fill + arrow.uturn.backward.square + arrow.uturn.backward.square.fill + arrow.uturn.down + arrow.uturn.down.circle + arrow.uturn.down.circle.fill + arrow.uturn.down.square + arrow.uturn.down.square.fill + arrow.uturn.forward + arrow.uturn.forward.circle + arrow.uturn.forward.circle.fill + arrow.uturn.forward.square + arrow.uturn.forward.square.fill + arrow.uturn.left + arrow.uturn.left.circle + arrow.uturn.left.circle.badge.ellipsis + arrow.uturn.left.circle.fill + arrow.uturn.left.square + arrow.uturn.left.square.fill + arrow.uturn.right + arrow.uturn.right.circle + arrow.uturn.right.circle.fill + arrow.uturn.right.square + arrow.uturn.right.square.fill + arrow.uturn.up + arrow.uturn.up.circle + arrow.uturn.up.circle.fill + arrow.uturn.up.square + arrow.uturn.up.square.fill + arrowshape.bounce.forward + arrowshape.bounce.forward.fill + arrowshape.bounce.right + arrowshape.bounce.right.fill + arrowshape.turn.up.backward + arrowshape.turn.up.backward.2 + arrowshape.turn.up.backward.2.circle + arrowshape.turn.up.backward.2.circle.fill + arrowshape.turn.up.backward.2.fill + arrowshape.turn.up.backward.circle + arrowshape.turn.up.backward.circle.fill + arrowshape.turn.up.backward.fill + arrowshape.turn.up.forward + arrowshape.turn.up.forward.circle + arrowshape.turn.up.forward.circle.fill + arrowshape.turn.up.forward.fill + arrowshape.turn.up.left + arrowshape.turn.up.left.2 + arrowshape.turn.up.left.2.circle + arrowshape.turn.up.left.2.circle.fill + arrowshape.turn.up.left.2.fill + arrowshape.turn.up.left.circle + arrowshape.turn.up.left.circle.fill + arrowshape.turn.up.left.fill + arrowshape.turn.up.right + arrowshape.turn.up.right.circle + arrowshape.turn.up.right.circle.fill + arrowshape.turn.up.right.fill + arrowshape.zigzag.forward + arrowshape.zigzag.forward.fill + arrowshape.zigzag.right + arrowshape.zigzag.right.fill + arrowtriangle.backward + arrowtriangle.backward.circle + arrowtriangle.backward.circle.fill + arrowtriangle.backward.fill + arrowtriangle.backward.square + arrowtriangle.backward.square.fill + arrowtriangle.down + arrowtriangle.down.circle + arrowtriangle.down.circle.fill + arrowtriangle.down.fill + arrowtriangle.down.square + arrowtriangle.down.square.fill + arrowtriangle.forward + arrowtriangle.forward.circle + arrowtriangle.forward.circle.fill + arrowtriangle.forward.fill + arrowtriangle.forward.square + arrowtriangle.forward.square.fill + arrowtriangle.left + arrowtriangle.left.and.line.vertical.and.arrowtriangle.right + arrowtriangle.left.circle + arrowtriangle.left.circle.fill + arrowtriangle.left.fill + arrowtriangle.left.fill.and.line.vertical.and.arrowtriangle.right.fill + arrowtriangle.left.square + arrowtriangle.left.square.fill + arrowtriangle.right + arrowtriangle.right.and.line.vertical.and.arrowtriangle.left + arrowtriangle.right.circle + arrowtriangle.right.circle.fill + arrowtriangle.right.fill + arrowtriangle.right.fill.and.line.vertical.and.arrowtriangle.left.fill + arrowtriangle.right.square + arrowtriangle.right.square.fill + arrowtriangle.up + arrowtriangle.up.circle + arrowtriangle.up.circle.fill + arrowtriangle.up.fill + arrowtriangle.up.square + arrowtriangle.up.square.fill + aspectratio + aspectratio.fill + asterisk.circle + asterisk.circle.fill + at + at.badge.minus + at.badge.plus + at.circle + at.circle.fill + atom + australsign.circle + australsign.circle.fill + australsign.square + australsign.square.fill + b.circle + b.circle.fill + b.square + b.square.fill + backward + backward.end + backward.end.alt + backward.end.alt.fill + backward.end.fill + backward.fill + backward.frame + backward.frame.fill + badge.plus.radiowaves.forward + badge.plus.radiowaves.right + bag + bag.badge.minus + bag.badge.plus + bag.circle + bag.circle.fill + bag.fill + bag.fill.badge.minus + bag.fill.badge.plus + bahtsign.circle + bahtsign.circle.fill + bahtsign.square + bahtsign.square.fill + bandage + bandage.fill + banknote + banknote.fill + barcode + barcode.viewfinder + barometer + battery.0 + battery.100 + battery.100.bolt + battery.25 + bed.double + bed.double.fill + bell + bell.badge + bell.badge.fill + bell.circle + bell.circle.fill + bell.fill + bell.slash + bell.slash.circle + bell.slash.circle.fill + bell.slash.fill + bicycle + bicycle.circle + bicycle.circle.fill + binoculars + binoculars.fill + bitcoinsign.circle + bitcoinsign.circle.fill + bitcoinsign.square + bitcoinsign.square.fill + bold + bold.italic.underline + bold.underline + bolt + bolt.badge.a + bolt.badge.a.fill + bolt.car + bolt.car.fill + bolt.circle + bolt.circle.fill + bolt.fill + bolt.fill.batteryblock + bolt.fill.batteryblock.fill + bolt.heart + bolt.heart.fill + bolt.horizontal + bolt.horizontal.circle + bolt.horizontal.circle.fill + bolt.horizontal.fill + bolt.horizontal.icloud + bolt.horizontal.icloud.fill + bolt.slash + bolt.slash.circle + bolt.slash.circle.fill + bolt.slash.fill + bonjour + book + book.circle + book.circle.fill + book.closed + book.closed.fill + book.fill + bookmark + bookmark.circle + bookmark.circle.fill + bookmark.fill + bookmark.slash + bookmark.slash.fill + books.vertical + books.vertical.fill + briefcase + briefcase.fill + bubble.left + bubble.left.and.bubble.right + bubble.left.and.bubble.right.fill + bubble.left.fill + bubble.middle.bottom + bubble.middle.bottom.fill + bubble.middle.top + bubble.middle.top.fill + bubble.right + bubble.right.fill + building + building.2 + building.2.crop.circle + building.2.crop.circle.fill + building.2.fill + building.columns + building.columns.fill + building.fill + burn + burst + burst.fill + bus + bus.doubledecker + bus.doubledecker.fill + bus.fill + c.circle + c.circle.fill + c.square + c.square.fill + calendar + calendar.badge.clock + calendar.badge.exclamationmark + calendar.badge.minus + calendar.badge.plus + calendar.circle + calendar.circle.fill + camera + camera.aperture + camera.badge.ellipsis + camera.circle + camera.circle.fill + camera.fill + camera.fill.badge.ellipsis + camera.filters + camera.metering.center.weighted + camera.metering.center.weighted.average + camera.metering.matrix + camera.metering.multispot + camera.metering.none + camera.metering.partial + camera.metering.spot + camera.metering.unknown + camera.on.rectangle + camera.on.rectangle.fill + camera.viewfinder + candybarphone + capslock + capslock.fill + capsule + capsule.fill + capsule.portrait + capsule.portrait.fill + captions.bubble + captions.bubble.fill + car + car.2 + car.2.fill + car.circle + car.circle.fill + car.fill + cart + cart.badge.minus + cart.badge.plus + cart.fill + cart.fill.badge.minus + cart.fill.badge.plus + case + case.fill + cedisign.circle + cedisign.circle.fill + cedisign.square + cedisign.square.fill + centsign.circle + centsign.circle.fill + centsign.square + centsign.square.fill + chart.bar + chart.bar.doc.horizontal + chart.bar.doc.horizontal.fill + chart.bar.fill + chart.bar.xaxis + chart.pie + chart.pie.fill + checkerboard.rectangle + checkmark + checkmark.circle + checkmark.circle.fill + checkmark.icloud + checkmark.icloud.fill + checkmark.rectangle + checkmark.rectangle.fill + checkmark.rectangle.portrait + checkmark.rectangle.portrait.fill + checkmark.seal + checkmark.seal.fill + checkmark.shield + checkmark.shield.fill + checkmark.square + checkmark.square.fill + chevron.backward + chevron.backward.2 + chevron.backward.circle + chevron.backward.circle.fill + chevron.backward.square + chevron.backward.square.fill + chevron.compact.down + chevron.compact.left + chevron.compact.right + chevron.compact.up + chevron.down + chevron.down.circle + chevron.down.circle.fill + chevron.down.square + chevron.down.square.fill + chevron.forward + chevron.forward.2 + chevron.forward.circle + chevron.forward.circle.fill + chevron.forward.square + chevron.forward.square.fill + chevron.left + chevron.left.2 + chevron.left.circle + chevron.left.circle.fill + chevron.left.slash.chevron.right + chevron.left.square + chevron.left.square.fill + chevron.right + chevron.right.2 + chevron.right.circle + chevron.right.circle.fill + chevron.right.square + chevron.right.square.fill + chevron.up + chevron.up.chevron.down + chevron.up.circle + chevron.up.circle.fill + chevron.up.square + chevron.up.square.fill + circle + circle.bottomhalf.fill + circle.circle + circle.circle.fill + circle.dashed + circle.dashed.inset.fill + circle.fill + circle.fill.square.fill + circle.grid.2x2 + circle.grid.2x2.fill + circle.grid.3x3 + circle.grid.3x3.fill + circle.grid.cross + circle.grid.cross.down.fill + circle.grid.cross.fill + circle.grid.cross.left.fill + circle.grid.cross.right.fill + circle.grid.cross.up.fill + circle.lefthalf.fill + circle.righthalf.fill + circle.square + circle.tophalf.fill + circlebadge + circlebadge.2 + circlebadge.2.fill + circlebadge.fill + circles.hexagongrid + circles.hexagongrid.fill + circles.hexagonpath + circles.hexagonpath.fill + clear + clear.fill + clock + clock.arrow.circlepath + clock.fill + cloud + cloud.bolt + cloud.bolt.fill + cloud.bolt.rain + cloud.bolt.rain.fill + cloud.drizzle + cloud.drizzle.fill + cloud.fill + cloud.fog + cloud.fog.fill + cloud.hail + cloud.hail.fill + cloud.heavyrain + cloud.heavyrain.fill + cloud.moon + cloud.moon.bolt + cloud.moon.bolt.fill + cloud.moon.fill + cloud.moon.rain + cloud.moon.rain.fill + cloud.rain + cloud.rain.fill + cloud.sleet + cloud.sleet.fill + cloud.snow + cloud.snow.fill + cloud.sun + cloud.sun.bolt + cloud.sun.bolt.fill + cloud.sun.fill + cloud.sun.rain + cloud.sun.rain.fill + coloncurrencysign.circle + coloncurrencysign.circle.fill + coloncurrencysign.square + coloncurrencysign.square.fill + comb + comb.fill + command + command.circle + command.circle.fill + command.square + command.square.fill + cone + cone.fill + contextualmenu.and.cursorarrow + control + cpu + creditcard + creditcard.circle + creditcard.circle.fill + creditcard.fill + crop + crop.rotate + cross + cross.case + cross.case.fill + cross.circle + cross.circle.fill + cross.fill + crown + crown.fill + cruzeirosign.circle + cruzeirosign.circle.fill + cruzeirosign.square + cruzeirosign.square.fill + cube + cube.fill + cube.transparent + cube.transparent.fill + curlybraces + curlybraces.square + curlybraces.square.fill + cursorarrow + cursorarrow.and.square.on.square.dashed + cursorarrow.click + cursorarrow.click.2 + cursorarrow.click.badge.clock + cursorarrow.motionlines + cursorarrow.motionlines.click + cursorarrow.rays + cursorarrow.square + cylinder + cylinder.fill + cylinder.split.1x2 + cylinder.split.1x2.fill + d.circle + d.circle.fill + d.square + d.square.fill + decrease.indent + decrease.quotelevel + delete.left + delete.left.fill + delete.right + delete.right.fill + deskclock + deskclock.fill + desktopcomputer + dial.max + dial.max.fill + dial.min + dial.min.fill + diamond + diamond.fill + die.face.1 + die.face.1.fill + die.face.2 + die.face.2.fill + die.face.3 + die.face.3.fill + die.face.4 + die.face.4.fill + die.face.5 + die.face.5.fill + die.face.6 + die.face.6.fill + display + display.2 + display.trianglebadge.exclamationmark + divide + divide.circle + divide.circle.fill + divide.square + divide.square.fill + doc + doc.append + doc.append.fill + doc.badge.ellipsis + doc.badge.gearshape + doc.badge.gearshape.fill + doc.badge.plus + doc.circle + doc.circle.fill + doc.fill + doc.fill.badge.ellipsis + doc.fill.badge.plus + doc.on.clipboard + doc.on.clipboard.fill + doc.on.doc + doc.on.doc.fill + doc.plaintext + doc.plaintext.fill + doc.richtext + doc.richtext.fill + doc.text + doc.text.below.ecg + doc.text.below.ecg.fill + doc.text.fill + doc.text.fill.viewfinder + doc.text.magnifyingglass + doc.text.viewfinder + doc.zipper + dock.arrow.down.rectangle + dock.arrow.up.rectangle + dock.rectangle + dollarsign.circle + dollarsign.circle.fill + dollarsign.square + dollarsign.square.fill + dongsign.circle + dongsign.circle.fill + dongsign.square + dongsign.square.fill + dot.arrowtriangles.up.right.down.left.circle + dot.circle.and.cursorarrow + dot.radiowaves.forward + dot.radiowaves.left.and.right + dot.radiowaves.right + dot.square + dot.square.fill + dot.squareshape + dot.squareshape.fill + dot.squareshape.split.2x2 + dpad + dpad.down.fill + dpad.fill + dpad.left.fill + dpad.right.fill + dpad.up.fill + drop + drop.fill + drop.triangle + drop.triangle.fill + e.circle + e.circle.fill + e.square + e.square.fill + ear + ear.badge.checkmark + ear.fill + ear.trianglebadge.exclamationmark + earpods + eject + eject.circle + eject.circle.fill + eject.fill + ellipsis + ellipsis.bubble + ellipsis.bubble.fill + ellipsis.circle + ellipsis.circle.fill + ellipsis.rectangle + ellipsis.rectangle.fill + envelope + envelope.arrow.triangle.branch + envelope.arrow.triangle.branch.fill + envelope.badge + envelope.badge.fill + envelope.badge.shield.leadinghalf.fill + envelope.circle + envelope.circle.fill + envelope.fill + envelope.fill.badge.shield.trailinghalf.fill + envelope.open + envelope.open.fill + equal + equal.circle + equal.circle.fill + equal.square + equal.square.fill + escape + esim + esim.fill + eurosign.circle + eurosign.circle.fill + eurosign.square + eurosign.square.fill + exclamationmark + exclamationmark.2 + exclamationmark.3 + exclamationmark.applewatch + exclamationmark.arrow.circlepath + exclamationmark.arrow.triangle.2.circlepath + exclamationmark.bubble + exclamationmark.bubble.fill + exclamationmark.circle + exclamationmark.circle.fill + exclamationmark.icloud + exclamationmark.icloud.fill + exclamationmark.octagon + exclamationmark.octagon.fill + exclamationmark.shield + exclamationmark.shield.fill + exclamationmark.square + exclamationmark.square.fill + exclamationmark.triangle + exclamationmark.triangle.fill + externaldrive + externaldrive.badge.checkmark + externaldrive.badge.icloud + externaldrive.badge.minus + externaldrive.badge.person.crop + externaldrive.badge.plus + externaldrive.badge.timemachine + externaldrive.badge.wifi + externaldrive.badge.xmark + externaldrive.connected.to.line.below + externaldrive.connected.to.line.below.fill + externaldrive.fill + externaldrive.fill.badge.checkmark + externaldrive.fill.badge.icloud + externaldrive.fill.badge.minus + externaldrive.fill.badge.person.crop + externaldrive.fill.badge.plus + externaldrive.fill.badge.timemachine + externaldrive.fill.badge.wifi + externaldrive.fill.badge.xmark + eye + eye.circle + eye.circle.fill + eye.fill + eye.slash + eye.slash.fill + eyebrow + eyedropper + eyedropper.full + eyedropper.halffull + eyeglasses + eyes + eyes.inverse + f.circle + f.circle.fill + f.cursive + f.cursive.circle + f.cursive.circle.fill + f.square + f.square.fill + face.dashed + face.dashed.fill + face.smiling + face.smiling.fill + faceid + faxmachine + fiberchannel + figure.stand + figure.stand.line.dotted.figure.stand + figure.walk + figure.walk.circle + figure.walk.circle.fill + figure.walk.diamond + figure.walk.diamond.fill + figure.wave + figure.wave.circle + figure.wave.circle.fill + filemenu.and.cursorarrow + filemenu.and.selection + film + film.fill + flag + flag.badge.ellipsis + flag.badge.ellipsis.fill + flag.circle + flag.circle.fill + flag.fill + flag.slash + flag.slash.circle + flag.slash.circle.fill + flag.slash.fill + flame + flame.fill + flashlight.off.fill + flashlight.on.fill + flipphone + florinsign.circle + florinsign.circle.fill + florinsign.square + florinsign.square.fill + flowchart + flowchart.fill + fn + folder + folder.badge.gear + folder.badge.minus + folder.badge.person.crop + folder.badge.plus + folder.badge.questionmark + folder.circle + folder.circle.fill + folder.fill + folder.fill.badge.gear + folder.fill.badge.minus + folder.fill.badge.person.crop + folder.fill.badge.plus + folder.fill.badge.questionmark + forward + forward.end + forward.end.alt + forward.end.alt.fill + forward.end.fill + forward.fill + forward.frame + forward.frame.fill + francsign.circle + francsign.circle.fill + francsign.square + francsign.square.fill + function + fx + g.circle + g.circle.fill + g.square + g.square.fill + gamecontroller + gamecontroller.fill + gauge + gauge.badge.minus + gauge.badge.plus + gear + gearshape + gearshape.2 + gearshape.2.fill + gearshape.fill + gift + gift.circle + gift.circle.fill + gift.fill + giftcard + giftcard.fill + globe + gobackward + gobackward.10 + gobackward.15 + gobackward.30 + gobackward.45 + gobackward.60 + gobackward.75 + gobackward.90 + gobackward.minus + goforward + goforward.10 + goforward.15 + goforward.30 + goforward.45 + goforward.60 + goforward.75 + goforward.90 + goforward.plus + graduationcap + graduationcap.fill + greaterthan + greaterthan.circle + greaterthan.circle.fill + greaterthan.square + greaterthan.square.fill + greetingcard + greetingcard.fill + grid + grid.circle + grid.circle.fill + guaranisign.circle + guaranisign.circle.fill + guaranisign.square + guaranisign.square.fill + guitars + guitars.fill + gyroscope + h.circle + h.circle.fill + h.square + h.square.fill + h.square.fill.on.square.fill + h.square.on.square + hammer + hammer.fill + hand.draw + hand.draw.fill + hand.point.down + hand.point.down.fill + hand.point.left + hand.point.left.fill + hand.point.right + hand.point.right.fill + hand.point.up + hand.point.up.braille + hand.point.up.braille.fill + hand.point.up.fill + hand.point.up.left + hand.point.up.left.fill + hand.raised + hand.raised.fill + hand.raised.slash + hand.raised.slash.fill + hand.tap + hand.tap.fill + hand.thumbsdown + hand.thumbsdown.fill + hand.thumbsup + hand.thumbsup.fill + hand.wave + hand.wave.fill + hands.clap + hands.clap.fill + hands.sparkles + hands.sparkles.fill + hare + hare.fill + headphones + headphones.circle + headphones.circle.fill + hearingaid.ear + heart + heart.circle + heart.circle.fill + heart.fill + heart.slash + heart.slash.circle + heart.slash.circle.fill + heart.slash.fill + heart.text.square + heart.text.square.fill + helm + hexagon + hexagon.fill + hifispeaker + hifispeaker.2 + hifispeaker.2.fill + hifispeaker.and.homepod + hifispeaker.and.homepod.fill + hifispeaker.fill + highlighter + homekit + homepod + homepod.2 + homepod.2.fill + homepod.fill + hourglass + hourglass.badge.plus + hourglass.bottomhalf.fill + hourglass.tophalf.fill + house + house.circle + house.circle.fill + house.fill + hryvniasign.circle + hryvniasign.circle.fill + hryvniasign.square + hryvniasign.square.fill + hurricane + i.circle + i.circle.fill + i.square + i.square.fill + icloud + icloud.and.arrow.down + icloud.and.arrow.down.fill + icloud.and.arrow.up + icloud.and.arrow.up.fill + icloud.circle + icloud.circle.fill + icloud.fill + icloud.slash + icloud.slash.fill + increase.indent + increase.quotelevel + indianrupeesign.circle + indianrupeesign.circle.fill + indianrupeesign.square + indianrupeesign.square.fill + infinity + info + info.circle + info.circle.fill + internaldrive + internaldrive.fill + ipad + ipad.homebutton + ipad.homebutton.landscape + ipad.landscape + iphone + iphone.homebutton + iphone.homebutton.radiowaves.left.and.right + iphone.homebutton.slash + iphone.radiowaves.left.and.right + iphone.slash + ipod + ipodshuffle.gen1 + ipodshuffle.gen2 + ipodshuffle.gen3 + ipodshuffle.gen4 + ipodtouch + italic + j.circle + j.circle.fill + j.square + j.square.fill + j.square.fill.on.square.fill + j.square.on.square + k + k.circle + k.circle.fill + k.square + k.square.fill + key + key.fill + key.icloud + key.icloud.fill + keyboard + keyboard.badge.ellipsis + keyboard.chevron.compact.down + keyboard.chevron.compact.left + keyboard.macwindow + keyboard.onehanded.left + keyboard.onehanded.right + kipsign.circle + kipsign.circle.fill + kipsign.square + kipsign.square.fill + l.circle + l.circle.fill + l.joystick + l.joystick.down + l.joystick.down.fill + l.joystick.fill + l.rectangle.roundedbottom + l.rectangle.roundedbottom.fill + l.square + l.square.fill + l1.rectangle.roundedbottom + l1.rectangle.roundedbottom.fill + l2.rectangle.roundedtop + l2.rectangle.roundedtop.fill + ladybug + ladybug.fill + laptopcomputer + laptopcomputer.and.iphone + largecircle.fill.circle + larisign.circle + larisign.circle.fill + larisign.square + larisign.square.fill + lasso + lasso.sparkles + latch.2.case + latch.2.case.fill + lb.rectangle.roundedbottom + lb.rectangle.roundedbottom.fill + leaf + leaf.arrow.triangle.circlepath + leaf.fill + lessthan + lessthan.circle + lessthan.circle.fill + lessthan.square + lessthan.square.fill + level + level.fill + lifepreserver + lifepreserver.fill + light.max + light.min + lightbulb + lightbulb.fill + lightbulb.slash + lightbulb.slash.fill + line.3.crossed.swirl.circle + line.3.crossed.swirl.circle.fill + line.diagonal + line.diagonal.arrow + line.horizontal.2.decrease.circle + line.horizontal.2.decrease.circle.fill + line.horizontal.3 + line.horizontal.3.circle + line.horizontal.3.circle.fill + line.horizontal.3.decrease + line.horizontal.3.decrease.circle + line.horizontal.3.decrease.circle.fill + line.horizontal.star.fill.line.horizontal + lineweight + link + link.badge.plus + link.circle + link.circle.fill + link.icloud + link.icloud.fill + lirasign.circle + lirasign.circle.fill + lirasign.square + lirasign.square.fill + list.and.film + list.bullet + list.bullet.below.rectangle + list.bullet.indent + list.bullet.rectangle + list.dash + list.number + list.star + list.triangle + livephoto + livephoto.badge.a + livephoto.play + livephoto.slash + location + location.circle + location.circle.fill + location.fill + location.fill.viewfinder + location.north + location.north.fill + location.north.line + location.north.line.fill + location.slash + location.slash.fill + location.viewfinder + lock + lock.circle + lock.circle.fill + lock.doc + lock.doc.fill + lock.fill + lock.icloud + lock.icloud.fill + lock.open + lock.open.fill + lock.rectangle + lock.rectangle.fill + lock.rectangle.on.rectangle + lock.rectangle.on.rectangle.fill + lock.rectangle.stack + lock.rectangle.stack.fill + lock.rotation + lock.rotation.open + lock.shield + lock.shield.fill + lock.slash + lock.slash.fill + lock.square + lock.square.fill + lock.square.stack + lock.square.stack.fill + loupe + lt.rectangle.roundedtop + lt.rectangle.roundedtop.fill + lungs + lungs.fill + m.circle + m.circle.fill + m.square + m.square.fill + macmini + macmini.fill + macpro.gen1 + macpro.gen2 + macpro.gen2.fill + macpro.gen3 + macpro.gen3.server + macwindow + macwindow.badge.plus + macwindow.on.rectangle + magnifyingglass + magnifyingglass.circle + magnifyingglass.circle.fill + mail + mail.and.text.magnifyingglass + mail.fill + mail.stack + mail.stack.fill + manatsign.circle + manatsign.circle.fill + manatsign.square + manatsign.square.fill + map + map.fill + mappin + mappin.and.ellipse + mappin.circle + mappin.circle.fill + mappin.slash + megaphone + megaphone.fill + memories + memories.badge.minus + memories.badge.plus + memorychip + menubar.arrow.down.rectangle + menubar.arrow.up.rectangle + menubar.dock.rectangle + menubar.dock.rectangle.badge.record + menubar.rectangle + message + message.circle + message.circle.fill + message.fill + metronome + metronome.fill + mic + mic.circle + mic.circle.fill + mic.fill + mic.slash + mic.slash.fill + millsign.circle + millsign.circle.fill + millsign.square + millsign.square.fill + minus + minus.circle + minus.circle.fill + minus.diamond + minus.diamond.fill + minus.magnifyingglass + minus.plus.batteryblock + minus.plus.batteryblock.fill + minus.rectangle + minus.rectangle.fill + minus.rectangle.portrait + minus.rectangle.portrait.fill + minus.slash.plus + minus.square + minus.square.fill + moon + moon.circle + moon.circle.fill + moon.fill + moon.stars + moon.stars.fill + moon.zzz + moon.zzz.fill + mosaic + mosaic.fill + mount + mount.fill + mouth + mouth.fill + move.3d + multiply + multiply.circle + multiply.circle.fill + multiply.square + multiply.square.fill + music.mic + music.note + music.note.house + music.note.house.fill + music.note.list + music.quarternote.3 + mustache + mustache.fill + n.circle + n.circle.fill + n.square + n.square.fill + nairasign.circle + nairasign.circle.fill + nairasign.square + nairasign.square.fill + network + newspaper + newspaper.fill + nose + nose.fill + nosign + note + note.text + note.text.badge.plus + number + number.circle + number.circle.fill + number.square + number.square.fill + o.circle + o.circle.fill + o.square + o.square.fill + octagon + octagon.fill + opticaldisc + opticaldiscdrive + opticaldiscdrive.fill + option + oval + oval.fill + oval.portrait + oval.portrait.fill + p.circle + p.circle.fill + p.square + p.square.fill + paintbrush + paintbrush.fill + paintbrush.pointed + paintbrush.pointed.fill + paintpalette + paintpalette.fill + pano + pano.fill + paperclip + paperclip.badge.ellipsis + paperclip.circle + paperclip.circle.fill + paperplane + paperplane.circle + paperplane.circle.fill + paperplane.fill + paragraphsign + pause + pause.circle + pause.circle.fill + pause.fill + pause.rectangle + pause.rectangle.fill + pc + pencil + pencil.and.outline + pencil.circle + pencil.circle.fill + pencil.slash + pencil.tip + pencil.tip.crop.circle + pencil.tip.crop.circle.badge.arrow.forward + pencil.tip.crop.circle.badge.minus + pencil.tip.crop.circle.badge.plus + percent + person + person.2 + person.2.circle + person.2.circle.fill + person.2.fill + person.2.square.stack + person.2.square.stack.fill + person.3 + person.3.fill + person.and.arrow.left.and.arrow.right + person.badge.minus + person.badge.plus + person.circle + person.circle.fill + person.crop.circle + person.crop.circle.badge.checkmark + person.crop.circle.badge.exclamationmark + person.crop.circle.badge.minus + person.crop.circle.badge.plus + person.crop.circle.badge.questionmark + person.crop.circle.badge.xmark + person.crop.circle.fill + person.crop.circle.fill.badge.checkmark + person.crop.circle.fill.badge.exclamationmark + person.crop.circle.fill.badge.minus + person.crop.circle.fill.badge.plus + person.crop.circle.fill.badge.questionmark + person.crop.circle.fill.badge.xmark + person.crop.rectangle + person.crop.rectangle.fill + person.crop.square + person.crop.square.fill + person.crop.square.fill.and.at.rectangle + person.fill + person.fill.and.arrow.left.and.arrow.right + person.fill.badge.minus + person.fill.badge.plus + person.fill.checkmark + person.fill.questionmark + person.fill.turn.down + person.fill.turn.left + person.fill.turn.right + person.fill.viewfinder + person.fill.xmark + person.icloud + person.icloud.fill + personalhotspot + perspective + pesetasign.circle + pesetasign.circle.fill + pesetasign.square + pesetasign.square.fill + pesosign.circle + pesosign.circle.fill + pesosign.square + pesosign.square.fill + phone + phone.arrow.down.left + phone.arrow.right + phone.arrow.up.right + phone.badge.plus + phone.bubble.left + phone.bubble.left.fill + phone.circle + phone.circle.fill + phone.connection + phone.down + phone.down.circle + phone.down.circle.fill + phone.down.fill + phone.fill + phone.fill.arrow.down.left + phone.fill.arrow.right + phone.fill.arrow.up.right + phone.fill.badge.plus + phone.fill.connection + photo + photo.fill + photo.fill.on.rectangle.fill + photo.on.rectangle + photo.on.rectangle.angled + photo.tv + pianokeys + pianokeys.inverse + pills + pills.fill + pin + pin.circle + pin.circle.fill + pin.fill + pin.slash + pin.slash.fill + pip + pip.enter + pip.exit + pip.fill + pip.remove + pip.swap + placeholdertext.fill + play + play.circle + play.circle.fill + play.fill + play.rectangle + play.rectangle.fill + play.slash + play.slash.fill + playpause + playpause.fill + plus + plus.app + plus.app.fill + plus.bubble + plus.bubble.fill + plus.circle + plus.circle.fill + plus.diamond + plus.diamond.fill + plus.magnifyingglass + plus.message + plus.message.fill + plus.rectangle + plus.rectangle.fill + plus.rectangle.fill.on.folder.fill + plus.rectangle.fill.on.rectangle.fill + plus.rectangle.on.folder + plus.rectangle.on.rectangle + plus.rectangle.portrait + plus.rectangle.portrait.fill + plus.slash.minus + plus.square + plus.square.fill + plus.square.fill.on.square.fill + plus.square.on.square + plus.viewfinder + plusminus + plusminus.circle + plusminus.circle.fill + point.fill.topleft.down.curvedto.point.fill.bottomright.up + point.topleft.down.curvedto.point.bottomright.up + power + poweroff + poweron + powersleep + printer + printer.dotmatrix + printer.dotmatrix.fill + printer.dotmatrix.fill.and.paper.fill + printer.fill + printer.fill.and.paper.fill + projective + purchased + purchased.circle + purchased.circle.fill + puzzlepiece + puzzlepiece.fill + pyramid + pyramid.fill + q.circle + q.circle.fill + q.square + q.square.fill + qrcode + qrcode.viewfinder + questionmark + questionmark.circle + questionmark.circle.fill + questionmark.diamond + questionmark.diamond.fill + questionmark.folder + questionmark.folder.fill + questionmark.square + questionmark.square.dashed + questionmark.square.fill + questionmark.video + questionmark.video.fill + quote.bubble + quote.bubble.fill + r.circle + r.circle.fill + r.joystick + r.joystick.down + r.joystick.down.fill + r.joystick.fill + r.rectangle.roundedbottom + r.rectangle.roundedbottom.fill + r.square + r.square.fill + r.square.fill.on.square.fill + r.square.on.square + r1.rectangle.roundedbottom + r1.rectangle.roundedbottom.fill + r2.rectangle.roundedtop + r2.rectangle.roundedtop.fill + radio + radio.fill + rays + rb.rectangle.roundedbottom + rb.rectangle.roundedbottom.fill + record.circle + record.circle.fill + recordingtape + rectangle + rectangle.3.offgrid + rectangle.3.offgrid.bubble.left + rectangle.3.offgrid.bubble.left.fill + rectangle.3.offgrid.fill + rectangle.and.arrow.up.right.and.arrow.down.left + rectangle.and.arrow.up.right.and.arrow.down.left.slash + rectangle.and.paperclip + rectangle.and.pencil.and.ellipsis + rectangle.and.text.magnifyingglass + rectangle.arrowtriangle.2.inward + rectangle.arrowtriangle.2.outward + rectangle.badge.checkmark + rectangle.badge.minus + rectangle.badge.plus + rectangle.badge.xmark + rectangle.bottomthird.inset.fill + rectangle.center.inset.fill + rectangle.compress.vertical + rectangle.connected.to.line.below + rectangle.dashed + rectangle.dashed.and.paperclip + rectangle.dashed.badge.record + rectangle.expand.vertical + rectangle.fill + rectangle.fill.badge.checkmark + rectangle.fill.badge.minus + rectangle.fill.badge.plus + rectangle.fill.badge.xmark + rectangle.fill.on.rectangle.angled.fill + rectangle.fill.on.rectangle.fill + rectangle.fill.on.rectangle.fill.circle + rectangle.fill.on.rectangle.fill.circle.fill + rectangle.fill.on.rectangle.fill.slash.fill + rectangle.grid.1x2 + rectangle.grid.1x2.fill + rectangle.grid.2x2 + rectangle.grid.2x2.fill + rectangle.grid.3x2 + rectangle.grid.3x2.fill + rectangle.inset.bottomleft.fill + rectangle.inset.bottomright.fill + rectangle.inset.fill + rectangle.inset.topleft.fill + rectangle.inset.topright.fill + rectangle.lefthalf.fill + rectangle.lefthalf.inset.fill + rectangle.lefthalf.inset.fill.arrow.left + rectangle.leftthird.inset.fill + rectangle.on.rectangle + rectangle.on.rectangle.angled + rectangle.on.rectangle.slash + rectangle.portrait + rectangle.portrait.arrowtriangle.2.inward + rectangle.portrait.arrowtriangle.2.outward + rectangle.portrait.fill + rectangle.righthalf.fill + rectangle.righthalf.inset.fill + rectangle.righthalf.inset.fill.arrow.right + rectangle.rightthird.inset.fill + rectangle.roundedbottom + rectangle.roundedbottom.fill + rectangle.roundedtop + rectangle.roundedtop.fill + rectangle.slash + rectangle.slash.fill + rectangle.split.1x2 + rectangle.split.1x2.fill + rectangle.split.2x1 + rectangle.split.2x1.fill + rectangle.split.2x2 + rectangle.split.2x2.fill + rectangle.split.3x1 + rectangle.split.3x1.fill + rectangle.split.3x3 + rectangle.split.3x3.fill + rectangle.stack + rectangle.stack.badge.minus + rectangle.stack.badge.person.crop + rectangle.stack.badge.plus + rectangle.stack.fill + rectangle.stack.fill.badge.minus + rectangle.stack.fill.badge.person.crop + rectangle.stack.fill.badge.plus + rectangle.stack.person.crop + rectangle.stack.person.crop.fill + repeat + repeat.1 + restart + restart.circle + return + rhombus + rhombus.fill + rosette + rotate.3d + rotate.left + rotate.left.fill + rotate.right + rotate.right.fill + rt.rectangle.roundedtop + rt.rectangle.roundedtop.fill + rublesign.circle + rublesign.circle.fill + rublesign.square + rublesign.square.fill + ruler + ruler.fill + rupeesign.circle + rupeesign.circle.fill + rupeesign.square + rupeesign.square.fill + s.circle + s.circle.fill + s.square + s.square.fill + safari + safari.fill + scale.3d + scalemass + scalemass.fill + scanner + scanner.fill + scissors + scissors.badge.ellipsis + scope + scribble + scribble.variable + scroll + scroll.fill + sdcard + sdcard.fill + seal + seal.fill + selection.pin.in.out + server.rack + shadow + shekelsign.circle + shekelsign.circle.fill + shekelsign.square + shekelsign.square.fill + shield + shield.fill + shield.lefthalf.fill + shield.lefthalf.fill.slash + shield.slash + shield.slash.fill + shift + shift.fill + shippingbox + shippingbox.fill + shuffle + sidebar.leading + sidebar.left + sidebar.right + sidebar.squares.leading + sidebar.squares.left + sidebar.squares.right + sidebar.squares.trailing + sidebar.trailing + signature + signpost.left + signpost.left.fill + signpost.right + signpost.right.fill + simcard + simcard.2 + simcard.2.fill + simcard.fill + skew + slash.circle + slash.circle.fill + sleep + slider.horizontal.3 + slider.horizontal.below.rectangle + slider.horizontal.below.square.fill.and.square + slider.vertical.3 + slowmo + smallcircle.circle + smallcircle.circle.fill + smallcircle.fill.circle + smallcircle.fill.circle.fill + smoke + smoke.fill + snow + sparkle + sparkles + sparkles.rectangle.stack + sparkles.rectangle.stack.fill + sparkles.square.fill.on.square + speaker + speaker.fill + speaker.slash + speaker.slash.circle + speaker.slash.circle.fill + speaker.slash.fill + speaker.wave.1 + speaker.wave.1.fill + speaker.wave.2 + speaker.wave.2.circle + speaker.wave.2.circle.fill + speaker.wave.2.fill + speaker.wave.3 + speaker.wave.3.fill + speaker.zzz + speaker.zzz.fill + speedometer + sportscourt + sportscourt.fill + square + square.2.stack.3d + square.2.stack.3d.bottom.fill + square.2.stack.3d.top.fill + square.3.stack.3d + square.3.stack.3d.bottom.fill + square.3.stack.3d.middle.fill + square.3.stack.3d.top.fill + square.and.arrow.down + square.and.arrow.down.fill + square.and.arrow.down.on.square + square.and.arrow.down.on.square.fill + square.and.arrow.up + square.and.arrow.up.fill + square.and.arrow.up.on.square + square.and.arrow.up.on.square.fill + square.and.at.rectangle + square.and.line.vertical.and.square + square.and.line.vertical.and.square.fill + square.and.pencil + square.bottomhalf.fill + square.circle + square.circle.fill + square.dashed + square.dashed.inset.fill + square.fill + square.fill.and.line.vertical.and.square + square.fill.and.line.vertical.square.fill + square.fill.on.circle.fill + square.fill.on.square + square.fill.on.square.fill + square.fill.text.grid.1x2 + square.grid.2x2 + square.grid.2x2.fill + square.grid.3x1.below.line.grid.1x2 + square.grid.3x1.fill.below.line.grid.1x2 + square.grid.3x1.folder.badge.plus + square.grid.3x1.folder.fill.badge.plus + square.grid.3x2 + square.grid.3x2.fill + square.grid.3x3 + square.grid.3x3.bottomleft.fill + square.grid.3x3.bottommiddle.fill + square.grid.3x3.bottomright.fill + square.grid.3x3.fill + square.grid.3x3.fill.square + square.grid.3x3.middle.fill + square.grid.3x3.middleleft.fill + square.grid.3x3.middleright.fill + square.grid.3x3.topleft.fill + square.grid.3x3.topmiddle.fill + square.grid.3x3.topright.fill + square.grid.4x3.fill + square.lefthalf.fill + square.on.circle + square.on.square + square.on.square.dashed + square.on.square.squareshape.controlhandles + square.righthalf.fill + square.slash + square.slash.fill + square.split.1x2 + square.split.1x2.fill + square.split.2x1 + square.split.2x1.fill + square.split.2x2 + square.split.2x2.fill + square.split.bottomrightquarter + square.split.bottomrightquarter.fill + square.split.diagonal + square.split.diagonal.2x2 + square.split.diagonal.2x2.fill + square.split.diagonal.fill + square.stack + square.stack.3d.down.forward + square.stack.3d.down.forward.fill + square.stack.3d.down.right + square.stack.3d.down.right.fill + square.stack.3d.forward.dottedline + square.stack.3d.forward.dottedline.fill + square.stack.3d.up + square.stack.3d.up.badge.a + square.stack.3d.up.badge.a.fill + square.stack.3d.up.fill + square.stack.3d.up.slash + square.stack.3d.up.slash.fill + square.stack.fill + square.tophalf.fill + squares.below.rectangle + squareshape + squareshape.controlhandles.on.squareshape.controlhandles + squareshape.dashed.squareshape + squareshape.fill + squareshape.split.2x2 + squareshape.split.2x2.dotted + squareshape.split.3x3 + squareshape.squareshape.dashed + star + star.circle + star.circle.fill + star.fill + star.leadinghalf.fill + star.slash + star.slash.fill + star.square + star.square.fill + staroflife + staroflife.circle + staroflife.circle.fill + staroflife.fill + sterlingsign.circle + sterlingsign.circle.fill + sterlingsign.square + sterlingsign.square.fill + stethoscope + stop + stop.circle + stop.circle.fill + stop.fill + stopwatch + stopwatch.fill + strikethrough + studentdesk + suit.club + suit.club.fill + suit.diamond + suit.diamond.fill + suit.heart + suit.heart.fill + suit.spade + suit.spade.fill + sum + sun.dust + sun.dust.fill + sun.haze + sun.haze.fill + sun.max + sun.max.fill + sun.min + sun.min.fill + sunrise + sunrise.fill + sunset + sunset.fill + swift + switch.2 + t.bubble + t.bubble.fill + t.circle + t.circle.fill + t.square + t.square.fill + tablecells + tablecells.badge.ellipsis + tablecells.badge.ellipsis.fill + tablecells.fill + tag + tag.circle + tag.circle.fill + tag.fill + tag.slash + tag.slash.fill + target + teletype + teletype.answer + teletype.circle + teletype.circle.fill + tengesign.circle + tengesign.circle.fill + tengesign.square + tengesign.square.fill + terminal + terminal.fill + text.aligncenter + text.alignleft + text.alignright + text.and.command.macwindow + text.append + text.badge.checkmark + text.badge.minus + text.badge.plus + text.badge.star + text.badge.xmark + text.below.photo + text.below.photo.fill + text.book.closed + text.book.closed.fill + text.bubble + text.bubble.fill + text.cursor + text.insert + text.justify + text.justifyleft + text.justifyright + text.magnifyingglass + text.quote + text.redaction + textbox + textformat + textformat.123 + textformat.abc + textformat.abc.dottedunderline + textformat.alt + textformat.size + textformat.subscript + textformat.superscript + thermometer + thermometer.snowflake + thermometer.sun + thermometer.sun.fill + ticket + ticket.fill + timelapse + timeline.selection + timer + timer.square + togglepower + tornado + tortoise + tortoise.fill + touchid + tram + tram.circle + tram.circle.fill + tram.fill + tram.tunnel.fill + trash + trash.circle + trash.circle.fill + trash.fill + trash.slash + trash.slash.fill + tray + tray.2 + tray.2.fill + tray.and.arrow.down + tray.and.arrow.down.fill + tray.and.arrow.up + tray.and.arrow.up.fill + tray.circle + tray.circle.fill + tray.fill + tray.full + tray.full.fill + triangle + triangle.circle + triangle.circle.fill + triangle.fill + triangle.lefthalf.fill + triangle.righthalf.fill + tropicalstorm + tugriksign.circle + tugriksign.circle.fill + tugriksign.square + tugriksign.square.fill + tuningfork + turkishlirasign.circle + turkishlirasign.circle.fill + turkishlirasign.square + turkishlirasign.square.fill + tv + tv.and.hifispeaker.fill + tv.circle + tv.circle.fill + tv.fill + tv.music.note + tv.music.note.fill + u.circle + u.circle.fill + u.square + u.square.fill + uiwindow.split.2x1 + umbrella + umbrella.fill + underline + v.circle + v.circle.fill + v.square + v.square.fill + video + video.badge.checkmark + video.badge.plus + video.bubble.left + video.bubble.left.fill + video.circle + video.circle.fill + video.fill + video.fill.badge.checkmark + video.fill.badge.plus + video.slash + video.slash.fill + view.2d + view.3d + viewfinder + viewfinder.circle + viewfinder.circle.fill + w.circle + w.circle.fill + w.square + w.square.fill + wake + wallet.pass + wallet.pass.fill + wand.and.rays + wand.and.rays.inverse + wand.and.stars + wand.and.stars.inverse + wave.3.backward + wave.3.backward.circle + wave.3.backward.circle.fill + wave.3.forward + wave.3.forward.circle + wave.3.forward.circle.fill + wave.3.left + wave.3.left.circle + wave.3.left.circle.fill + wave.3.right + wave.3.right.circle + wave.3.right.circle.fill + waveform + waveform.circle + waveform.circle.fill + waveform.path + waveform.path.badge.minus + waveform.path.badge.plus + waveform.path.ecg + waveform.path.ecg.rectangle + waveform.path.ecg.rectangle.fill + wifi + wifi.exclamationmark + wifi.slash + wind + wind.snow + wonsign.circle + wonsign.circle.fill + wonsign.square + wonsign.square.fill + wrench + wrench.and.screwdriver + wrench.and.screwdriver.fill + wrench.fill + x.circle + x.circle.fill + x.square + x.square.fill + x.squareroot + xmark + xmark.bin + xmark.bin.circle + xmark.bin.circle.fill + xmark.bin.fill + xmark.circle + xmark.circle.fill + xmark.diamond + xmark.diamond.fill + xmark.icloud + xmark.icloud.fill + xmark.octagon + xmark.octagon.fill + xmark.rectangle + xmark.rectangle.fill + xmark.rectangle.portrait + xmark.rectangle.portrait.fill + xmark.seal + xmark.seal.fill + xmark.shield + xmark.shield.fill + xmark.square + xmark.square.fill + xserve + y.circle + y.circle.fill + y.square + y.square.fill + yensign.circle + yensign.circle.fill + yensign.square + yensign.square.fill + z.circle + z.circle.fill + z.square + z.square.fill + zl.rectangle.roundedtop + zl.rectangle.roundedtop.fill + zr.rectangle.roundedtop + zr.rectangle.roundedtop.fill + zzz + + + \ No newline at end of file diff --git a/Paradise/App/Paradise/Info.plist b/Paradise/App/Paradise/Info.plist new file mode 100644 index 0000000..82a4e4b --- /dev/null +++ b/Paradise/App/Paradise/Info.plist @@ -0,0 +1,68 @@ + + + + + NSPhotoLibraryUsageDescription + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + SceneDelegate + UISceneStoryboardFile + Main + + + + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Paradise/App/Paradise/Library/LibraryCell.h b/Paradise/App/Paradise/Library/LibraryCell.h new file mode 100644 index 0000000..6a8249a --- /dev/null +++ b/Paradise/App/Paradise/Library/LibraryCell.h @@ -0,0 +1,15 @@ +//#import +//#import "ConstraintExtension.h" +// +//@protocol LibraryButtonDelegate +//@optional +//- (void)deleteLibraryForCell:(UICollectionViewCell *)cell; +//@end +// +//@interface LibraryCell : UICollectionViewCell +//@property (nonatomic, retain) UIView *baseView; +//@property (nonatomic, retain) UIImageView *previewImage; +//@property (nonatomic, retain) UILabel *titleLabel; +//@property (nonatomic, retain) UIButton *deleteButton; +//@property (nonatomic, weak) id libraryDelegate; +//@end diff --git a/Paradise/App/Paradise/Library/LibraryCell.m b/Paradise/App/Paradise/Library/LibraryCell.m new file mode 100644 index 0000000..287d202 --- /dev/null +++ b/Paradise/App/Paradise/Library/LibraryCell.m @@ -0,0 +1,64 @@ +//#import "LibraryCell.h" +// +//@implementation LibraryCell +// +//- (instancetype)initWithFrame:(CGRect)frame { +// +// self = [super initWithFrame:frame]; +// if (self) { +// +// self.layer.cornerRadius = 20; +// +// self.clipsToBounds = true; +// self.layer.cornerRadius = 20; +// +// self.baseView = [[UIView alloc] init]; +// self.baseView.layer.cornerRadius = 20; +// self.baseView.backgroundColor = [UIColor colorNamed:@"Cell Background"]; +// self.baseView.clipsToBounds = true; +// self.baseView.layer.cornerCurve = kCACornerCurveContinuous; +// [self.contentView addSubview:self.baseView]; +// +// [self.baseView fill]; +// +// +// self.previewImage = [[UIImageView alloc] init]; +// self.previewImage.contentMode = UIViewContentModeScaleAspectFill; +// [self.baseView addSubview:self.previewImage]; +// +// [self.previewImage fill]; +// +// +// self.deleteButton = [[UIButton alloc] init]; +// [self.deleteButton addTarget:self action:@selector(deleteButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; +// UIImage *btnImage = [UIImage systemImageNamed:@"trash.fill"]; +// [self.deleteButton setImage:btnImage forState:UIControlStateNormal]; +// self.deleteButton.tintColor = UIColor.systemRedColor; +// [self.baseView addSubview:self.deleteButton]; +// +// [self.deleteButton top:self.baseView.topAnchor padding:10]; +// [self.deleteButton trailing:self.baseView.trailingAnchor padding:-10]; +// [self.deleteButton size:CGSizeMake(30, 30)]; +// +// +// self.titleLabel = [[UILabel alloc] init]; +// self.titleLabel.font = [UIFont boldSystemFontOfSize:14]; +// self.titleLabel.textAlignment = NSTextAlignmentCenter; +// self.titleLabel.textColor = UIColor.whiteColor; +// [self.baseView addSubview:self.titleLabel]; +// +// [self.titleLabel bottom:self.baseView.bottomAnchor padding: -10]; +// [self.titleLabel x:self.baseView.centerXAnchor]; +// [self.titleLabel leading:self.baseView.leadingAnchor padding:5]; +// [self.titleLabel trailing:self.baseView.trailingAnchor padding:-5]; +// +// } +// return self; +//} +// +// +//- (void)deleteButtonPressed:(id)sender { +// [self.libraryDelegate deleteLibraryForCell:self]; +//} +// +//@end diff --git a/Paradise/App/Paradise/Library/LibraryViewController.h b/Paradise/App/Paradise/Library/LibraryViewController.h new file mode 100644 index 0000000..9e21077 --- /dev/null +++ b/Paradise/App/Paradise/Library/LibraryViewController.h @@ -0,0 +1,7 @@ +//#import +//#import "LibraryCell.h" +// +//@interface LibraryViewController : UIViewController +//@property (nonatomic, retain) UICollectionView *collectionView; +//@end +// diff --git a/Paradise/App/Paradise/Library/LibraryViewController.m b/Paradise/App/Paradise/Library/LibraryViewController.m new file mode 100644 index 0000000..56713b1 --- /dev/null +++ b/Paradise/App/Paradise/Library/LibraryViewController.m @@ -0,0 +1,113 @@ +//#import "LibraryViewController.h" +// +//@implementation LibraryViewController +// +//-(void)viewWillAppear:(BOOL)animated { +// [super viewWillAppear:animated]; +// +// self.navigationItem.title = @"Templates"; +// self.navigationController.navigationBar.prefersLargeTitles = YES; +// +//} +// +//- (void)viewDidLoad { +// [super viewDidLoad]; +// +// self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; +// +// UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; +// self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; +// self.collectionView.backgroundColor = UIColor.clearColor; +// self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; +// self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; +// [self.collectionView setShowsHorizontalScrollIndicator:NO]; +// [self.collectionView setShowsVerticalScrollIndicator:NO]; +// [self.collectionView registerClass:[LibraryCell class] forCellWithReuseIdentifier:@"Cell"]; +// [self.view addSubview:self.collectionView]; +// +// self.collectionView.delegate = self; +// self.collectionView.dataSource = self; +//} +// +// +//- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { +// return 20; +//} +// +// +//- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { +// +// LibraryCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; +// +// cell.backgroundColor = UIColor.clearColor; +// cell.previewImage.image = [UIImage imageNamed:@"preview"]; +// cell.titleLabel.text = @"Saved :)"; +// cell.libraryDelegate = self; +// +// +// return cell; +// +//} +// +// +//- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { +// CGFloat width = self.view.frame.size.width /2 -15; +// return CGSizeMake(width, width); +//} +// +// +//- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { +// return 10.0; +//} +// +//- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { +// return 10.0; +//} +// +// +//- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { +// return UIEdgeInsetsMake(0,10,0,10); // top, left, bottom, right +//} +// +// +//- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { +// +//} +// +// +//- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath { +// +// UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; +// [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ +// cell.transform = CGAffineTransformMakeScale(0.97, 0.97); +// cell.alpha = 0.5; +// } completion:nil]; +// +//} +// +// +//- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath { +// +// UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; +// [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ +// cell.transform = CGAffineTransformMakeScale(1.0, 1.0); +// cell.alpha = 1; +// } completion:nil]; +// +//} +// +// +//- (void)deleteLibraryForCell:(UICollectionViewCell *)cell { +// NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell]; +// +// if (indexPath.row == 1) { +// self.view.backgroundColor = UIColor.yellowColor; +// } else if (indexPath.row == 3) { +// self.view.backgroundColor = UIColor.greenColor; +// } +// +// +//} +// +// +//@end diff --git a/Paradise/App/Paradise/Manager/AppManager.h b/Paradise/App/Paradise/Manager/AppManager.h new file mode 100644 index 0000000..0efa64e --- /dev/null +++ b/Paradise/App/Paradise/Manager/AppManager.h @@ -0,0 +1,20 @@ +#import + +@interface AppManager : NSObject ++(instancetype)sharedInstance; +-(id)init; + +- (void)setBool:(BOOL)anObject forKey:(id)aKey; +- (void)setObject:(id)anObject forKey:(id)aKey; +- (void)setFloat:(long long)anObject forKey:(id)aKey; +- (void)setInt:(int)anObject forKey:(id)aKey; +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue; +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue; +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue; +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue; +- (bool)boolForKey:(id)aKey; +- (id)objectForKey:(id)aKey; +- (long long)floatForKey:(id)aKey; +- (int)intForKey:(id)aKey; + +@end diff --git a/Paradise/App/Paradise/Manager/AppManager.m b/Paradise/App/Paradise/Manager/AppManager.m new file mode 100644 index 0000000..d2b4754 --- /dev/null +++ b/Paradise/App/Paradise/Manager/AppManager.m @@ -0,0 +1,78 @@ +#import "AppManager.h" + +static NSString *prefPath = @"/var/mobile/Library/Preferences/com.TitanD3v.ParadiseEditor.plist"; +static NSMutableDictionary *settings; + +@implementation AppManager + ++(instancetype)sharedInstance { + static AppManager *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[AppManager alloc] init]; + settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + }); + return sharedInstance; +} + +-(id)init { + return self; +} + +- (void)setBool:(BOOL)anObject forKey:(id)aKey { + [settings setObject:[NSNumber numberWithBool:anObject] forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (void)setObject:(id)anObject forKey:(id)aKey { + [settings setObject:anObject forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (void)setFloat:(long long)anObject forKey:(id)aKey { + [settings setObject:@(anObject) forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (void)setInt:(int)anObject forKey:(id)aKey { + [settings setObject:@(anObject) forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue { + if([settings objectForKey:aKey] == NULL){ + return defaultValue; + } + return [[settings objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue { + return [settings objectForKey:aKey]?:defaultValue; +} + +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue { + return [[settings objectForKey:aKey] longLongValue]?:defaultValue; +} + +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue { + return [[settings objectForKey:aKey] intValue]?:defaultValue; +} + +- (bool)boolForKey:(id)aKey { + return [[settings objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey { + return [settings objectForKey:aKey]; +} + +- (long long)floatForKey:(id)aKey { + return [[settings objectForKey:aKey] longLongValue]; +} + +- (int)intForKey:(id)aKey { + return [[settings objectForKey:aKey] intValue]; +} + +@end diff --git a/Paradise/App/Paradise/Manager/Preferences.h b/Paradise/App/Paradise/Manager/Preferences.h new file mode 100644 index 0000000..fb1e3f5 --- /dev/null +++ b/Paradise/App/Paradise/Manager/Preferences.h @@ -0,0 +1,18 @@ +#import + +static NSMutableDictionary *settings; +static NSString *prefPath = @"/var/mobile/Library/Preferences/com.TitanD3v.ParadiseEditor.plist"; + +static NSString *themeFolderName; +static NSString *bundleID; +static NSString *appName; +static BOOL showTutorial; + +static void loadPrefs() { + settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + + themeFolderName = [settings objectForKey:@"selectedThemesName"]; + bundleID = [settings objectForKey:@"paradiseBundleID"]; + appName = [settings objectForKey:@"paradiseAppName"]; +} diff --git a/Paradise/App/Paradise/Preview/PreviewViewController.h b/Paradise/App/Paradise/Preview/PreviewViewController.h new file mode 100644 index 0000000..0f5453b --- /dev/null +++ b/Paradise/App/Paradise/Preview/PreviewViewController.h @@ -0,0 +1,10 @@ +#import +#import "Macros.h" + +@interface PreviewViewController : UIViewController +@property (nonatomic, retain) UIImageView *wallpaperImage; +@property (nonatomic, retain) UIImageView *previewImage; +@property (nonatomic, retain) UILabel *appLabel; +@property (nonatomic, retain) UIButton *dismissButton; +@end + diff --git a/Paradise/App/Paradise/Preview/PreviewViewController.m b/Paradise/App/Paradise/Preview/PreviewViewController.m new file mode 100644 index 0000000..5d6da26 --- /dev/null +++ b/Paradise/App/Paradise/Preview/PreviewViewController.m @@ -0,0 +1,146 @@ +#import "PreviewViewController.h" + +static float iconSize; +static float iconTop; +static float iconLeading; + +@implementation PreviewViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = UIColor.whiteColor; + + [self layoutWallpaper]; + [self layoutDeviceSize]; + [self layoutPreviewIcon]; + [self layoutDismissButton]; + +} + + +-(void)layoutDeviceSize { + + if (iPhone_6_8) { + + self.wallpaperImage.image = [UIImage imageNamed:@"preview-wallpaper-8"]; + iconSize = 62; + iconTop = 268; + iconLeading = 22; + + } else if (iPhone_6_8_Plus) { + + self.wallpaperImage.image = [UIImage imageNamed:@"preview-wallpaper-8-Plus"]; + iconSize = 68; + iconTop = 297; + iconLeading = 25; + + } else if (iPhone_X_XS_11Pro) { + + self.wallpaperImage.image = [UIImage imageNamed:@"preview-wallpaper"]; + iconSize = 62; + iconTop = 268; + iconLeading = 22; + + } else if (iPhone_XR_XS_11Pro) { + + self.wallpaperImage.image = [UIImage imageNamed:@"preview-wallpaper"]; + iconSize = 68; + iconTop = 297; + iconLeading = 25; + + } else if (iPhone_12_Pro) { + + self.wallpaperImage.image = [UIImage imageNamed:@"preview-wallpaper"]; + iconSize = 62; + iconTop = 268; + iconLeading = 22; + + } else if (iPhone_12_mini) { + + self.wallpaperImage.image = [UIImage imageNamed:@"preview-wallpaper-8-Plus"]; + iconSize = 68; + iconTop = 297; + iconLeading = 25; + + } else if (iPhone_12_Pro_Max) { + + self.wallpaperImage.image = [UIImage imageNamed:@"preview-wallpaper"]; + iconSize = 68; + iconTop = 297; + iconLeading = 25; + + } + +} + + +-(void)layoutWallpaper { + + self.wallpaperImage = [[UIImageView alloc] initWithFrame:self.view.bounds]; + [self.view addSubview:self.wallpaperImage]; + +} + + +-(void)layoutPreviewIcon { + + self.previewImage = [[UIImageView alloc] init]; + self.previewImage.layer.cornerRadius = 14; + self.previewImage.clipsToBounds = true; + [self.view addSubview:self.previewImage]; + + self.previewImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.previewImage.widthAnchor constraintEqualToConstant:iconSize].active = YES; + [self.previewImage.heightAnchor constraintEqualToConstant:iconSize].active = YES; + [self.previewImage.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:iconTop].active = YES; + [self.previewImage.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:iconLeading].active = YES; + + + self.appLabel = [[UILabel alloc] init]; + self.appLabel.textAlignment = NSTextAlignmentCenter; + self.appLabel.textColor = UIColor.whiteColor; + self.appLabel.font = [UIFont systemFontOfSize:13]; + self.appLabel.text = @"Your App"; + [self.view addSubview:self.appLabel]; + + self.appLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.appLabel.topAnchor constraintEqualToAnchor:self.previewImage.bottomAnchor constant:7].active = YES; + [self.appLabel.centerXAnchor constraintEqualToAnchor:self.previewImage.centerXAnchor].active = true; + +} + + +-(void)layoutDismissButton { + + self.dismissButton = [[UIButton alloc] init]; + self.dismissButton.backgroundColor = [UIColor colorNamed:@"Accent"]; + self.dismissButton.layer.cornerRadius = 25; + [self.dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + self.dismissButton.titleLabel.font = [UIFont systemFontOfSize:15]; + [self.dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [self.dismissButton addTarget:self action:@selector(dismissPreviewVC) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:self.dismissButton]; + + self.dismissButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.dismissButton.widthAnchor constraintEqualToConstant:150].active = YES; + [self.dismissButton.heightAnchor constraintEqualToConstant:50].active = YES; + [self.dismissButton.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-20].active = YES; + [[self.dismissButton centerXAnchor] constraintEqualToAnchor:self.view.centerXAnchor].active = true; +} + + +-(void)dismissPreviewVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesEnded:touches withEvent:event]; + if (touches.anyObject.view == self.view) { + [self dismissViewControllerAnimated:YES completion:nil]; + //[[NSNotificationCenter defaultCenter] postNotificationName:@"IconEditorDismissed" object:self]; + } +} + + +@end diff --git a/Paradise/App/Paradise/SceneDelegate.h b/Paradise/App/Paradise/SceneDelegate.h new file mode 100644 index 0000000..a19a1ce --- /dev/null +++ b/Paradise/App/Paradise/SceneDelegate.h @@ -0,0 +1,8 @@ +#import + +@interface SceneDelegate : UIResponder + +@property (strong, nonatomic) UIWindow * window; + +@end + diff --git a/Paradise/App/Paradise/SceneDelegate.m b/Paradise/App/Paradise/SceneDelegate.m new file mode 100644 index 0000000..c1ef7e9 --- /dev/null +++ b/Paradise/App/Paradise/SceneDelegate.m @@ -0,0 +1,81 @@ +#import "SceneDelegate.h" + +@implementation SceneDelegate + + +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { + + [self.window setTintColor:[UIColor colorNamed:@"Accent"]]; + +// UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.window.bounds]; +// imageView.image = [UIImage imageNamed:@"splashscreen"]; +// [self.window.rootViewController.view addSubview:imageView]; +// [self.window.rootViewController.view bringSubviewToFront:imageView]; +// +// [UIView transitionWithView:self.window duration:5.0f options:UIViewAnimationOptionTransitionNone animations:^(void){ +// imageView.alpha = 0.0f; +// +// } completion:^(BOOL finished){ +// [imageView removeFromSuperview]; +// +// }]; + + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + [self refreshAppDetails]; +} + + +- (void)sceneDidDisconnect:(UIScene *)scene { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + [self refreshAppDetails]; + +} + + +- (void)sceneDidBecomeActive:(UIScene *)scene { + + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + [self refreshAppDetails]; + +} + + +- (void)sceneWillResignActive:(UIScene *)scene { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + [self refreshAppDetails]; +} + + +- (void)sceneWillEnterForeground:(UIScene *)scene { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + [self refreshAppDetails]; + + +} + + +- (void)sceneDidEnterBackground:(UIScene *)scene { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + [self refreshAppDetails]; + +} + + +-(void)refreshAppDetails { + [[NSNotificationCenter defaultCenter] postNotificationName:@"RefreshAppDetailsNotification" object:self]; +} + +@end + + + diff --git a/Paradise/App/Paradise/Segment/ParadiseSegmentControl.h b/Paradise/App/Paradise/Segment/ParadiseSegmentControl.h new file mode 100644 index 0000000..654d9c5 --- /dev/null +++ b/Paradise/App/Paradise/Segment/ParadiseSegmentControl.h @@ -0,0 +1,22 @@ +#import + +@interface ParadiseSegmentControl : UIControl + +@property (strong, nonatomic) UIColor *backgroundColor; +@property (strong, nonatomic) UIColor *sliderColor; +@property (strong, nonatomic) UIColor *labelTextColorInsideSlider; +@property (strong, nonatomic) UIColor *labelTextColorOutsideSlider; +@property (strong, nonatomic) UIFont *font; +@property (nonatomic) CGFloat cornerRadius; +@property (nonatomic) CGFloat sliderOffset; + ++ (instancetype)switchWithStringsArray:(NSArray *)strings; +- (instancetype)initWithStringsArray:(NSArray *)strings; +- (instancetype)initWithAttributedStringsArray:(NSArray *)strings; + +- (void)forceSelectedIndex:(NSInteger)index animated:(BOOL)animated; +- (void)setPressedHandler:(void (^)(NSUInteger index))handler; +- (void)setWillBePressedHandler:(void (^)(NSUInteger index))handler; +- (void)selectIndex:(NSInteger)index animated:(BOOL)animated; + +@end diff --git a/Paradise/App/Paradise/Segment/ParadiseSegmentControl.m b/Paradise/App/Paradise/Segment/ParadiseSegmentControl.m new file mode 100644 index 0000000..06af60c --- /dev/null +++ b/Paradise/App/Paradise/Segment/ParadiseSegmentControl.m @@ -0,0 +1,411 @@ +#import "ParadiseSegmentControl.h" + +@interface ParadiseSegmentControl () + +@property (strong, nonatomic) NSMutableArray *labels; +@property (strong, nonatomic) NSMutableArray *onTopLabels; +@property (strong, nonatomic) NSArray *strings; + +@property (strong, nonatomic) void (^handlerBlock)(NSUInteger index); +@property (strong, nonatomic) void (^willBePressedHandlerBlock)(NSUInteger index); + +@property (strong, nonatomic) UIView *backgroundView; +@property (strong, nonatomic) UIView *sliderView; + +@property (nonatomic) NSInteger selectedIndex; + +@end + +@implementation ParadiseSegmentControl + +- (instancetype)init +{ + self = [super init]; + if (self) { + + [NSException raise:@"ParadiseSegmentControlInitException" format:@"Init call is prohibited, use initWithStringsArray: method"]; + } + + return self; +} + ++ (instancetype)switchWithStringsArray:(NSArray *)strings +{ + // to do + return [[ParadiseSegmentControl alloc] initWithStringsArray:strings]; +} + +- (instancetype)initWithStringsArray:(NSArray *)strings +{ + self = [super init]; + + self.strings = strings; + self.cornerRadius = 12.0f; + self.sliderOffset = 1.0f; + + self.backgroundColor = [UIColor colorWithRed:70/255.0 green:70/255.0 blue:70/255.0 alpha:1.0]; + self.sliderColor = [UIColor whiteColor]; + self.labelTextColorInsideSlider = [UIColor blackColor]; + self.labelTextColorOutsideSlider = [UIColor whiteColor]; + + self.backgroundView = [[UIView alloc] init]; + self.backgroundView.backgroundColor = self.backgroundColor; + self.backgroundView.userInteractionEnabled = YES; + [self addSubview:self.backgroundView]; + + self.labels = [[NSMutableArray alloc] init]; + + for (int k = 0; k < [self.strings count]; k++) { + + NSString *string = self.strings[k]; + UILabel *label = [[UILabel alloc] init]; + label.tag = k; + label.text = string; + label.font = self.font; + label.adjustsFontSizeToFitWidth = YES; + label.adjustsLetterSpacingToFitWidth = YES; + label.textAlignment = NSTextAlignmentCenter; + label.textColor = self.labelTextColorOutsideSlider; + [self.backgroundView addSubview:label]; + [self.labels addObject:label]; + + UITapGestureRecognizer *rec = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleRecognizerTap:)]; + [label addGestureRecognizer:rec]; + label.userInteractionEnabled = YES; + } + + self.sliderView = [[UIView alloc] init]; + self.sliderView.backgroundColor = self.sliderColor; + self.sliderView.clipsToBounds = YES; + [self addSubview:self.sliderView]; + + self.onTopLabels = [[NSMutableArray alloc] init]; + + for (NSString *string in self.strings) { + + UILabel *label = [[UILabel alloc] init]; + label.text = string; + label.font = self.font; + label.adjustsFontSizeToFitWidth = YES; + label.adjustsLetterSpacingToFitWidth = YES; + label.textAlignment = NSTextAlignmentCenter; + label.textColor = self.labelTextColorInsideSlider; + [self.sliderView addSubview:label]; + [self.onTopLabels addObject:label]; + } + + UIPanGestureRecognizer *sliderRec = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(sliderMoved:)]; + [self.sliderView addGestureRecognizer:sliderRec]; + + return self; +} + +- (instancetype)initWithAttributedStringsArray:(NSArray *)strings { + self = [super init]; + + self.strings = strings; + self.cornerRadius = 12.0f; + self.sliderOffset = 1.0f; + + self.backgroundColor = [UIColor colorWithRed:70/255.0 green:70/255.0 blue:70/255.0 alpha:1.0]; + self.sliderColor = [UIColor whiteColor]; + self.labelTextColorInsideSlider = [UIColor blackColor]; + self.labelTextColorOutsideSlider = [UIColor whiteColor]; + + self.backgroundView = [[UIView alloc] init]; + + self.backgroundView.backgroundColor = self.backgroundColor; + self.backgroundView.userInteractionEnabled = YES; + [self addSubview:self.backgroundView]; + + self.labels = [[NSMutableArray alloc] init]; + + [self.strings enumerateObjectsUsingBlock:^(NSMutableAttributedString *str, NSUInteger idx, BOOL *stop) { + + [str addAttribute:NSForegroundColorAttributeName + value:self.labelTextColorOutsideSlider + range:NSMakeRange(0, str.length)]; + + UILabel *label = [[UILabel alloc] init]; + label.tag = idx; + label.attributedText = str; + label.textAlignment = NSTextAlignmentCenter; + + [self.backgroundView addSubview:label]; + [self.labels addObject:label]; + + UITapGestureRecognizer *rec = [[UITapGestureRecognizer alloc] initWithTarget:self + action:@selector(handleRecognizerTap:)]; + [label addGestureRecognizer:rec]; + label.userInteractionEnabled = YES; + }]; + + self.sliderView = [[UIView alloc] init]; + self.sliderView.backgroundColor = self.sliderColor; + self.sliderView.clipsToBounds = YES; + [self addSubview:self.sliderView]; + + self.onTopLabels = [[NSMutableArray alloc] init]; + + [self.strings enumerateObjectsUsingBlock:^(NSMutableAttributedString *str, NSUInteger idx, BOOL *stop) { + + [str addAttribute:NSForegroundColorAttributeName + value:self.labelTextColorInsideSlider + range:NSMakeRange(0, str.length)]; + + UILabel *label = [[UILabel alloc] init]; + label.attributedText = str; + label.textAlignment = NSTextAlignmentCenter; + + [self.sliderView addSubview:label]; + [self.onTopLabels addObject:label]; + }]; + + UIPanGestureRecognizer *sliderRec = [[UIPanGestureRecognizer alloc] initWithTarget:self + action:@selector(sliderMoved:)]; + [self.sliderView addGestureRecognizer:sliderRec]; + + return self; +} + +- (void)setPressedHandler:(void (^)(NSUInteger))handler +{ + self.handlerBlock = handler; +} + +- (void)setWillBePressedHandler:(void (^)(NSUInteger))handler +{ + self.willBePressedHandlerBlock = handler; +} + +- (void)forceSelectedIndex:(NSInteger)index animated:(BOOL)animated +{ + if (index > [self.strings count]) { + return; + } + + self.selectedIndex = index; + + if (animated) { + + [self animateChangeToIndex:index callHandler:YES]; + + } else { + + [self changeToIndexWithoutAnimation:index callHandler:YES]; + } +} + +- (void)selectIndex:(NSInteger)index animated:(BOOL)animated +{ + if (index > [self.strings count]) { + return; + } + self.selectedIndex = index; + + if (animated) { + + [self animateChangeToIndex:index callHandler:NO]; + + } else { + + [self changeToIndexWithoutAnimation:index callHandler:NO]; + } +} + +- (void)layoutSubviews +{ + self.backgroundView.layer.cornerRadius = self.cornerRadius; + self.sliderView.layer.cornerRadius = self.cornerRadius - 1; + + self.backgroundView.backgroundColor = self.backgroundColor; + self.sliderView.backgroundColor = self.sliderColor; + + self.backgroundView.frame = [self convertRect:self.frame fromView:self.superview]; + + self.backgroundView.layer.cornerRadius = self.cornerRadius; + self.sliderView.layer.cornerRadius = self.cornerRadius; + + CGFloat sliderWidth = self.frame.size.width / [self.strings count]; + + self.sliderView.frame = CGRectMake(sliderWidth * self.selectedIndex + self.sliderOffset, self.backgroundView.frame.origin.y + self.sliderOffset, sliderWidth - self.sliderOffset * 2, self.frame.size.height - self.sliderOffset * 2); + + for (int i = 0; i < [self.labels count]; i++) { + + UILabel *label = self.labels[i]; + label.frame = CGRectMake(i * sliderWidth, 0, sliderWidth, self.frame.size.height); + if (self.font) { + label.font = self.font; + } + label.textColor = self.labelTextColorOutsideSlider; + } + + for (int j = 0; j < [self.onTopLabels count]; j++) { + + UILabel *label = self.onTopLabels[j]; + label.frame = CGRectMake([self.sliderView convertPoint:CGPointMake(j * sliderWidth, 0) fromView:self.backgroundView].x, - self.sliderOffset, sliderWidth, self.frame.size.height); + if (self.font) { + label.font = self.font; + } + label.textColor = self.labelTextColorInsideSlider; + } +} + +- (void)animateChangeToIndex:(NSUInteger)selectedIndex callHandler:(BOOL)callHandler +{ + + if (self.willBePressedHandlerBlock) { + self.willBePressedHandlerBlock(selectedIndex); + } + + [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{ + + CGFloat sliderWidth = self.frame.size.width / [self.strings count]; + + CGRect oldFrame = self.sliderView.frame; + CGRect newFrame = CGRectMake(sliderWidth * self.selectedIndex + self.sliderOffset, self.backgroundView.frame.origin.y + self.sliderOffset, sliderWidth - self.sliderOffset * 2, self.frame.size.height - self.sliderOffset * 2); + + CGRect offRect = CGRectMake(newFrame.origin.x - oldFrame.origin.x, newFrame.origin.y - oldFrame.origin.y, 0, 0); + + self.sliderView.frame = newFrame; + + for (UILabel *label in self.onTopLabels) { + + label.frame = CGRectMake(label.frame.origin.x - offRect.origin.x, label.frame.origin.y - offRect.origin.y, label.frame.size.width, label.frame.size.height); + } + + } completion:^(BOOL finished) { + + if (self.handlerBlock && callHandler) { + self.handlerBlock(selectedIndex); + } + }]; +} + +- (void)changeToIndexWithoutAnimation:(NSUInteger)selectedIndex callHandler:(BOOL)callHandler +{ + if (self.willBePressedHandlerBlock) { + self.willBePressedHandlerBlock(selectedIndex); + } + + CGFloat sliderWidth = self.frame.size.width / [self.strings count]; + + CGRect oldFrame = self.sliderView.frame; + CGRect newFrame = CGRectMake(sliderWidth * self.selectedIndex + self.sliderOffset, self.backgroundView.frame.origin.y + self.sliderOffset, sliderWidth - self.sliderOffset * 2, self.frame.size.height - self.sliderOffset * 2); + + CGRect offRect = CGRectMake(newFrame.origin.x - oldFrame.origin.x, newFrame.origin.y - oldFrame.origin.y, 0, 0); + + self.sliderView.frame = newFrame; + + for (UILabel *label in self.onTopLabels) { + + label.frame = CGRectMake(label.frame.origin.x - offRect.origin.x, label.frame.origin.y - offRect.origin.y, label.frame.size.width, label.frame.size.height); + } + + if (self.handlerBlock && callHandler) { + self.handlerBlock(selectedIndex); + } +} + +- (void)handleRecognizerTap:(UITapGestureRecognizer *)rec +{ + self.selectedIndex = rec.view.tag; + [self animateChangeToIndex:self.selectedIndex callHandler:YES]; +} + +- (void)sliderMoved:(UIPanGestureRecognizer *)rec +{ + if (rec.state == UIGestureRecognizerStateChanged) { + + CGRect oldFrame = self.sliderView.frame; + + CGFloat minPos = 0 + self.sliderOffset; + CGFloat maxPos = self.frame.size.width - self.sliderOffset - self.sliderView.frame.size.width; + + CGPoint center = rec.view.center; + CGPoint translation = [rec translationInView:rec.view]; + + center = CGPointMake(center.x + translation.x, center.y); + rec.view.center = center; + [rec setTranslation:CGPointZero inView:rec.view]; + + if (self.sliderView.frame.origin.x < minPos) { + + self.sliderView.frame = CGRectMake(minPos, self.sliderView.frame.origin.y, self.sliderView.frame.size.width, self.sliderView.frame.size.height); + + } else if (self.sliderView.frame.origin.x > maxPos) { + + self.sliderView.frame = CGRectMake(maxPos, self.sliderView.frame.origin.y, self.sliderView.frame.size.width, self.sliderView.frame.size.height); + } + + CGRect newFrame = self.sliderView.frame; + CGRect offRect = CGRectMake(newFrame.origin.x - oldFrame.origin.x, newFrame.origin.y - oldFrame.origin.y, 0, 0); + + for (UILabel *label in self.onTopLabels) { + + label.frame = CGRectMake(label.frame.origin.x - offRect.origin.x, label.frame.origin.y - offRect.origin.y, label.frame.size.width, label.frame.size.height); + } + + } else if (rec.state == UIGestureRecognizerStateEnded || rec.state == UIGestureRecognizerStateCancelled || rec.state == UIGestureRecognizerStateFailed) { + + NSMutableArray *distances = [[NSMutableArray alloc] init]; + + for (int i = 0; i < [self.strings count]; i++) { + + CGFloat possibleX = i * self.sliderView.frame.size.width; + CGFloat distance = possibleX - self.sliderView.frame.origin.x; + [distances addObject:@(fabs(distance))]; + } + + NSNumber *num = [distances valueForKeyPath:@"@min.doubleValue"]; + NSInteger index = [distances indexOfObject:num]; + + if (self.willBePressedHandlerBlock) { + self.willBePressedHandlerBlock(index); + } + + CGFloat sliderWidth = self.frame.size.width / [self.strings count]; + CGFloat desiredX = sliderWidth * index + self.sliderOffset; + + if (self.sliderView.frame.origin.x != desiredX) { + + CGRect evenOlderFrame = self.sliderView.frame; + + CGFloat distance = desiredX - self.sliderView.frame.origin.x; + CGFloat time = fabs(distance / 300); + + [UIView animateWithDuration:time animations:^{ + + self.sliderView.frame = CGRectMake(desiredX, self.sliderView.frame.origin.y, self.sliderView.frame.size.width, self.sliderView.frame.size.height); + + CGRect newFrame = self.sliderView.frame; + + CGRect offRect = CGRectMake(newFrame.origin.x - evenOlderFrame.origin.x, newFrame.origin.y - evenOlderFrame.origin.y, 0, 0); + + for (UILabel *label in self.onTopLabels) { + + label.frame = CGRectMake(label.frame.origin.x - offRect.origin.x, label.frame.origin.y - offRect.origin.y, label.frame.size.width, label.frame.size.height); + } + } completion:^(BOOL finished) { + + self.selectedIndex = index; + + if (self.handlerBlock) { + self.handlerBlock(index); + } + + }]; + + } else { + + self.selectedIndex = index; + + if (self.handlerBlock) { + self.handlerBlock(self.selectedIndex); + } + } + } +} + + +@end diff --git a/Paradise/App/Paradise/Settings/SettingsViewController.h b/Paradise/App/Paradise/Settings/SettingsViewController.h new file mode 100644 index 0000000..809e5da --- /dev/null +++ b/Paradise/App/Paradise/Settings/SettingsViewController.h @@ -0,0 +1,6 @@ +//#import +// +//@interface SettingsViewController : UIViewController +// +//@property (weak, nonatomic) IBOutlet UIButton *testBtn; +//@end diff --git a/Paradise/App/Paradise/Settings/SettingsViewController.m b/Paradise/App/Paradise/Settings/SettingsViewController.m new file mode 100644 index 0000000..2cee5c1 --- /dev/null +++ b/Paradise/App/Paradise/Settings/SettingsViewController.m @@ -0,0 +1,62 @@ +//#import "SettingsViewController.h" +// +//@implementation SettingsViewController +// +//-(void)viewWillAppear:(BOOL)animated { +// [super viewWillAppear:animated]; +// +// self.navigationItem.title = @"Settings"; +// self.navigationController.navigationBar.prefersLargeTitles = YES; +// +//} +// +//- (void)viewDidLoad { +// [super viewDidLoad]; +// self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; +// +// +// //UIButton *test = [[UIButton alloc] init]; +// //[test addTarget:self action:@selector(pageManagementMenu) forControlEvents:UIControlEventTouchUpInside]; +// +// self.testBtn.menu = [self pageManagementMenu]; +// self.testBtn.showsMenuAsPrimaryAction = true; +// //test.menu = [self pageManagementMenu]; +// //test.showsMenuAsPrimaryAction = true; +// +//} +// +//- (IBAction)menuAction:(id)sender { +// +// +// +// +//} +// +// +//-(UIMenu *)pageManagementMenu { +// UIAction *addPageAction = [UIAction actionWithTitle:@"Add Note" image:[UIImage systemImageNamed:@"rectangle.stack.fill.badge.plus"] identifier:nil handler:^(UIAction *action) { +// [self addPage]; +// }]; +// +// UIAction *removePageAction = [UIAction actionWithTitle:@"Remove Note" image:[UIImage systemImageNamed:@"rectangle.stack.fill.badge.minus"] identifier:nil handler:^(UIAction *action) { +// [self removePage]; +// }]; +// //removePageAction.attributes = (self.pages.count > 1) ? UIMenuElementAttributesDestructive : UIMenuElementAttributesDisabled; +// +// return [UIMenu menuWithTitle:@"Hi" children:@[removePageAction, addPageAction]]; +//} +// +// +//-(void)addPage { +// +// self.view.backgroundColor = UIColor.yellowColor; +// +//} +// +// +//-(void)removePage { +// +// self.view.backgroundColor = UIColor.greenColor; +//} +// +//@end diff --git a/Paradise/App/Paradise/TabViewController.h b/Paradise/App/Paradise/TabViewController.h new file mode 100644 index 0000000..53d01be --- /dev/null +++ b/Paradise/App/Paradise/TabViewController.h @@ -0,0 +1,11 @@ +#import +#import "EditorViewController.h" +//#import "AccessoriesViewController.h" +#import "ThemesViewController.h" +//#import "LibraryViewController.h" +//#import "SettingsViewController.h" + +@interface TabViewController : UITabBarController + +@end + diff --git a/Paradise/App/Paradise/TabViewController.m b/Paradise/App/Paradise/TabViewController.m new file mode 100644 index 0000000..0bddbd0 --- /dev/null +++ b/Paradise/App/Paradise/TabViewController.m @@ -0,0 +1,35 @@ +#import "TabViewController.h" + + +@implementation TabViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + EditorViewController *editorVC = [self.storyboard instantiateViewControllerWithIdentifier:@"EditorViewController"]; + + //AccessoriesViewController *accessoriesVC = [self.storyboard instantiateViewControllerWithIdentifier:@"AccessoriesViewController"]; + //UINavigationController *accessoriesNavigationController = [[UINavigationController alloc] initWithRootViewController:accessoriesVC]; + + ThemesViewController *themesVC = [self.storyboard instantiateViewControllerWithIdentifier:@"ThemesViewController"]; + UINavigationController *themesNavigationController = [[UINavigationController alloc] initWithRootViewController:themesVC]; + + //LibraryViewController *libraryVC = [self.storyboard instantiateViewControllerWithIdentifier:@"LibraryViewController"]; + //UINavigationController *libraryNavigationController = [[UINavigationController alloc] initWithRootViewController:libraryVC]; + // + //SettingsViewController *settingsVC = [self.storyboard instantiateViewControllerWithIdentifier:@"SettingsViewController"]; + //UINavigationController *settingsNavigationController = [[UINavigationController alloc] initWithRootViewController:settingsVC]; + + //NSArray *tabbarArray = @[editorVC, accessoriesNavigationController, themesNavigationController, libraryNavigationController, settingsNavigationController]; + NSArray *tabbarArray = @[editorVC, themesNavigationController]; + [self setViewControllers:tabbarArray]; + + editorVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Editor" image:[UIImage systemImageNamed:@"scribble.variable"] tag:0]; + //accessoriesVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Accessories" image:[UIImage systemImageNamed:@"apps.iphone"] tag:1]; + themesVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Themes" image:[UIImage systemImageNamed:@"folder.fill"] tag:2]; + //libraryVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Templates" image:[UIImage systemImageNamed:@"square.fill"] tag:3]; + //settingsVC.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Settings" image:[UIImage systemImageNamed:@"gear"] tag:4]; +} + + +@end diff --git a/Paradise/App/Paradise/Themes/AddFolderCell.h b/Paradise/App/Paradise/Themes/AddFolderCell.h new file mode 100644 index 0000000..89a24c3 --- /dev/null +++ b/Paradise/App/Paradise/Themes/AddFolderCell.h @@ -0,0 +1,10 @@ +#import +#import "ConstraintExtension.h" + +@interface AddFolderCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *gradientImage; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@end + diff --git a/Paradise/App/Paradise/Themes/AddFolderCell.m b/Paradise/App/Paradise/Themes/AddFolderCell.m new file mode 100644 index 0000000..67d82c0 --- /dev/null +++ b/Paradise/App/Paradise/Themes/AddFolderCell.m @@ -0,0 +1,59 @@ +#import "AddFolderCell.h" + +@implementation AddFolderCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 20; + + self.clipsToBounds = true; + self.layer.cornerRadius = 20; + + self.baseView = [[UIView alloc] init]; + self.baseView.layer.cornerRadius = 20; + self.baseView.backgroundColor = [UIColor colorNamed:@"Cell Background"]; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.gradientImage = [[UIImageView alloc] init]; + self.gradientImage.contentMode = UIViewContentModeScaleAspectFill; + [self.baseView addSubview:self.gradientImage]; + + [self.gradientImage fill]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage systemImageNamed:@"folder.fill.badge.plus"]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFill; + self.iconImage.tintColor = UIColor.whiteColor; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(55, 55)]; + [self.iconImage top:self.baseView.topAnchor padding:20]; + [self.iconImage x:self.baseView.centerXAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.font = [UIFont boldSystemFontOfSize:14]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.text = @"Create New Folder"; + self.titleLabel.textColor = UIColor.whiteColor; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel top:self.iconImage.bottomAnchor padding:10]; + [self.titleLabel x:self.baseView.centerXAnchor]; + [self.titleLabel leading:self.baseView.leadingAnchor padding:5]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-5]; + + } + return self; +} + +@end diff --git a/Paradise/App/Paradise/Themes/CreateThemeFolderVC.h b/Paradise/App/Paradise/Themes/CreateThemeFolderVC.h new file mode 100644 index 0000000..29152a7 --- /dev/null +++ b/Paradise/App/Paradise/Themes/CreateThemeFolderVC.h @@ -0,0 +1,7 @@ +#import + +@interface CreateThemeFolderVC : UIViewController +@property (weak, nonatomic) IBOutlet UITextField *textField; +@property (weak, nonatomic) IBOutlet UIButton *cancelButton; +@property (weak, nonatomic) IBOutlet UIButton *addButton; +@end diff --git a/Paradise/App/Paradise/Themes/CreateThemeFolderVC.m b/Paradise/App/Paradise/Themes/CreateThemeFolderVC.m new file mode 100644 index 0000000..51310bc --- /dev/null +++ b/Paradise/App/Paradise/Themes/CreateThemeFolderVC.m @@ -0,0 +1,100 @@ +#import "CreateThemeFolderVC.h" + +@implementation CreateThemeFolderVC + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + self.addButton.hidden = YES; + [self.textField becomeFirstResponder]; +} + + +- (IBAction)beginEditing:(id)sender { + + if (self.textField.text && self.textField.text.length > 0) { + self.addButton.hidden = NO; + } else { + self.addButton.hidden = YES; + } + +} + + +- (IBAction)editingChanged:(id)sender { + + if (self.textField.text && self.textField.text.length > 0) { + self.addButton.hidden = NO; + } else { + self.addButton.hidden = YES; + } + +} + + +- (IBAction)finishedEdited:(id)sender { + + if (self.textField.text && self.textField.text.length > 0) { + self.addButton.hidden = NO; + } else { + self.addButton.hidden = YES; + } + +} + + +- (IBAction)addNewFolder:(id)sender { + + NSString *string = self.textField.text; + + NSString *specialCharacterString = @"!~`@#$%^&*-+();:={}[],.<>?\\/\"\'."; + NSCharacterSet *specialCharacterSet = [NSCharacterSet characterSetWithCharactersInString:specialCharacterString]; + + if ([string.lowercaseString rangeOfCharacterFromSet:specialCharacterSet].length) { + + [self.textField resignFirstResponder]; + [self showWarningAlert]; + + } else { + + NSString *dataPath = [NSString stringWithFormat:@"/Library/Themes/%@.theme/", self.textField.text]; + NSString *dataPath2 = [NSString stringWithFormat:@"/Library/Themes/%@.theme/IconBundles/", self.textField.text]; + + if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath]) { + [[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:nil]; + [[NSFileManager defaultManager] createDirectoryAtPath:dataPath2 withIntermediateDirectories:NO attributes:nil error:nil]; + + } + + [self.textField resignFirstResponder]; + [self dismissViewControllerAnimated:YES completion:nil]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"AddedNewThemeNotification" object:self]; + + } + +} + + +-(void)showWarningAlert { + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Warning!" message:@"You can't use special character or adding .theme extension as it will be added automatically." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [self.textField becomeFirstResponder]; + }]; + + [alertController addAction:dismissAction]; + [self presentViewController:alertController animated:YES completion:nil]; + +} + + +- (IBAction)dismissVC:(id)sender { + + [self.textField resignFirstResponder]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/Paradise/App/Paradise/Themes/ThemesCell.h b/Paradise/App/Paradise/Themes/ThemesCell.h new file mode 100644 index 0000000..0d450fc --- /dev/null +++ b/Paradise/App/Paradise/Themes/ThemesCell.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" + +@interface ThemesCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *gradientImage; +@property (nonatomic, retain) UIImageView *folderImage; +@property (nonatomic, retain) UIImageView *checkedImage; +@property (nonatomic, retain) UILabel *themeLabel; +@property (nonatomic, retain) UILabel *countLabel; +@end diff --git a/Paradise/App/Paradise/Themes/ThemesCell.m b/Paradise/App/Paradise/Themes/ThemesCell.m new file mode 100644 index 0000000..272dc5e --- /dev/null +++ b/Paradise/App/Paradise/Themes/ThemesCell.m @@ -0,0 +1,78 @@ +#import "ThemesCell.h" + +@implementation ThemesCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.clipsToBounds = true; + self.layer.cornerRadius = 20; + + self.baseView = [[UIView alloc] init]; + self.baseView.layer.cornerRadius = 20; + self.baseView.backgroundColor = [UIColor colorNamed:@"Cell Background"]; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.gradientImage = [[UIImageView alloc] init]; + self.gradientImage.contentMode = UIViewContentModeScaleAspectFill; + [self.baseView addSubview:self.gradientImage]; + + [self.gradientImage fill]; + + + self.folderImage = [[UIImageView alloc] init]; + self.folderImage.image = [UIImage systemImageNamed:@"folder.fill"]; + self.folderImage.contentMode = UIViewContentModeScaleAspectFill; + self.folderImage.tintColor = UIColor.whiteColor; + [self.baseView addSubview:self.folderImage]; + + [self.folderImage size:CGSizeMake(30, 30)]; + [self.folderImage top:self.baseView.topAnchor padding:10]; + [self.folderImage leading:self.baseView.leadingAnchor padding:10]; + + + self.checkedImage = [[UIImageView alloc] init]; + self.checkedImage.contentMode = UIViewContentModeScaleAspectFill; + self.checkedImage.tintColor = UIColor.whiteColor; + [self.baseView addSubview:self.checkedImage]; + + [self.checkedImage size:CGSizeMake(25, 25)]; + [self.checkedImage top:self.baseView.topAnchor padding:7]; + [self.checkedImage trailing:self.baseView.trailingAnchor padding:-7]; + + + self.themeLabel = [[UILabel alloc] init]; + self.themeLabel.font = [UIFont boldSystemFontOfSize:16]; + self.themeLabel.textAlignment = NSTextAlignmentCenter; + self.themeLabel.textColor = UIColor.whiteColor; + [self.baseView addSubview:self.themeLabel]; + + [self.themeLabel x:self.baseView.centerXAnchor]; + [self.themeLabel y:self.baseView.centerYAnchor]; + [self.themeLabel leading:self.baseView.leadingAnchor padding:5]; + [self.themeLabel trailing:self.baseView.trailingAnchor padding:-5]; + + + self.countLabel = [[UILabel alloc] init]; + self.countLabel.font = [UIFont systemFontOfSize:12]; + self.countLabel.textAlignment = NSTextAlignmentCenter; + self.countLabel.textColor = UIColor.whiteColor; + [self.baseView addSubview:self.countLabel]; + + [self.countLabel top:self.themeLabel.bottomAnchor padding:5]; + [self.countLabel x:self.baseView.centerXAnchor]; + [self.countLabel leading:self.baseView.leadingAnchor padding:5]; + [self.countLabel trailing:self.baseView.trailingAnchor padding:-5]; + + } + return self; +} + +@end diff --git a/Paradise/App/Paradise/Themes/ThemesViewController.h b/Paradise/App/Paradise/Themes/ThemesViewController.h new file mode 100644 index 0000000..e56e738 --- /dev/null +++ b/Paradise/App/Paradise/Themes/ThemesViewController.h @@ -0,0 +1,15 @@ +#import +#import "CreateThemeFolderVC.h" +#import "AddFolderCell.h" +#import "ThemesCell.h" +#import "AppManager.h" + +@interface ThemesViewController : UIViewController { + UIBarButtonItem *createButton; +} + +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, strong) NSString *selectedTheme; +@property (nonatomic, strong) NSIndexPath *checkedIndexPath; + +@end diff --git a/Paradise/App/Paradise/Themes/ThemesViewController.m b/Paradise/App/Paradise/Themes/ThemesViewController.m new file mode 100644 index 0000000..43d1ad7 --- /dev/null +++ b/Paradise/App/Paradise/Themes/ThemesViewController.m @@ -0,0 +1,220 @@ +#import "ThemesViewController.h" + +static NSString *themePath = @"/Library/Themes/"; +static NSMutableArray *themeArrays; +static NSString *selectedThemeName; + +@implementation ThemesViewController + +-(void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + self.navigationItem.title = @"Themes"; + self.navigationController.navigationBar.prefersLargeTitles = YES; + + createButton = [[UIBarButtonItem alloc] initWithImage:[UIImage systemImageNamed:@"folder.fill.badge.plus"] style:UIBarButtonItemStylePlain target:self action:@selector(createThemeFolder)]; + self.navigationItem.rightBarButtonItem = nil; + +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + NSArray* directory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:themePath error:NULL]; + themeArrays = [[NSMutableArray alloc] init]; + [directory enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSString *filename = (NSString *)obj; + NSString *extension = [[filename pathExtension] lowercaseString]; + if ([extension isEqualToString:@"theme"]) { + [themeArrays addObject:filename]; + } + }]; + + [themeArrays sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[AddFolderCell class] forCellWithReuseIdentifier:@"addCell"]; + [self.collectionView registerClass:[ThemesCell class] forCellWithReuseIdentifier:@"themeCell"]; + [self.view addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveThemeNotification:) name:@"AddedNewThemeNotification" object:nil]; + +} + + +- (void)receiveThemeNotification:(NSNotification *) notification { + + if ([[notification name] isEqualToString:@"AddedNewThemeNotification"]) { + + [self performSelector:@selector(refreshData) withObject:nil afterDelay:0.5]; + } +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return themeArrays.count + 1; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + if (indexPath.row == 0) { + + AddFolderCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"addCell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.gradientImage.image = [UIImage imageNamed:@"gradient"]; + + return cell; + + } else { + + ThemesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"themeCell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.gradientImage.image = [UIImage imageNamed:@"gradient"]; + cell.themeLabel.text = [themeArrays objectAtIndex:indexPath.row -1]; + + NSString *iconString = [NSString stringWithFormat:@"/Library/Themes/%@/IconBundles/", [themeArrays objectAtIndex:indexPath.row -1]]; + NSUInteger iconCount = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:iconString error:nil] count]; + cell.countLabel.text = [NSString stringWithFormat: @"%ld Icons", (long)iconCount]; + + + selectedThemeName = [[AppManager sharedInstance] objectForKey:@"selectedThemesName"]; + + if (!self.checkedIndexPath) { + + if ([[themeArrays objectAtIndex:indexPath.row -1] isEqualToString:selectedThemeName]) { + + self.checkedIndexPath = indexPath; + + } + + } + + + if ([indexPath isEqual:self.checkedIndexPath]) { + + cell.checkedImage.image = [UIImage systemImageNamed:@"checkmark.circle.fill"]; + + } else { + + cell.checkedImage.image = nil; + + } + + return cell; + } + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat width = self.view.frame.size.width /2 -15; + return CGSizeMake(width, 130); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,10,0,10); // top, left, bottom, right +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + if (indexPath.row == 0) { + [self createThemeFolder]; + } else { + self.checkedIndexPath = indexPath; + self.selectedTheme = themeArrays[indexPath.row -1]; + [[AppManager sharedInstance] setObject:self.selectedTheme forKey:@"selectedThemesName"]; + [self.collectionView reloadData]; + } +} + + +- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath { + + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; + +} + + +- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath { + + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; + +} + + +-(void)createThemeFolder { + + CreateThemeFolderVC *createVC = [self.storyboard instantiateViewControllerWithIdentifier:@"CreateThemeFolderVC"]; + createVC.modalInPresentation = YES; + [self presentViewController:createVC animated:YES completion:nil]; +} + + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + + if (scrollView.contentOffset.y < 0) { + self.navigationItem.rightBarButtonItem = nil; + } else if (scrollView.contentOffset.y > 0) { + self.navigationItem.rightBarButtonItem = createButton; + } + +} + + +-(void)refreshData { + + NSArray* directory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:themePath error:NULL]; + themeArrays = [[NSMutableArray alloc] init]; + [directory enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSString *filename = (NSString *)obj; + NSString *extension = [[filename pathExtension] lowercaseString]; + if ([extension isEqualToString:@"theme"]) { + [themeArrays addObject:filename]; + } + }]; + + [themeArrays sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + + selectedThemeName = [[AppManager sharedInstance] objectForKey:@"selectedThemesName"]; + + self.checkedIndexPath = nil; + + [self.collectionView reloadData]; + +} + +@end diff --git a/Paradise/App/Paradise/Tutorial/TutorialCell.h b/Paradise/App/Paradise/Tutorial/TutorialCell.h new file mode 100644 index 0000000..2f56839 --- /dev/null +++ b/Paradise/App/Paradise/Tutorial/TutorialCell.h @@ -0,0 +1,9 @@ +#import +#import "ConstraintExtension.h" + +@interface TutorialCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UITextView *messageLabel; +@end + diff --git a/Paradise/App/Paradise/Tutorial/TutorialCell.m b/Paradise/App/Paradise/Tutorial/TutorialCell.m new file mode 100644 index 0000000..6733df1 --- /dev/null +++ b/Paradise/App/Paradise/Tutorial/TutorialCell.m @@ -0,0 +1,56 @@ +#import "TutorialCell.h" + +@implementation TutorialCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.contentView.clipsToBounds = true; + + self.baseView = [[UIView alloc] initWithFrame:CGRectZero]; + self.baseView.backgroundColor = [UIColor clearColor]; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:10].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-10].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-5].active = YES; + + + self.iconImage = [[UIImageView alloc] initWithFrame:CGRectZero]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + self.iconImage.tintColor = [UIColor colorNamed:@"Accent"]; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(45, 45)]; + [self.iconImage y:self.baseView.centerYAnchor]; + [self.iconImage leading:self.baseView.leadingAnchor padding:5]; + + + self.messageLabel = [[UITextView alloc] init]; + self.messageLabel.font = [UIFont systemFontOfSize:18]; + self.messageLabel.textAlignment = NSTextAlignmentLeft; + self.messageLabel.delegate = self; + self.messageLabel.textColor = UIColor.labelColor; + self.messageLabel.scrollEnabled = NO; + self.messageLabel.editable = NO; + self.messageLabel.backgroundColor = UIColor.clearColor; + self.messageLabel.userInteractionEnabled = NO; + [self.baseView addSubview:self.messageLabel]; + + [self.messageLabel top:self.baseView.topAnchor padding:0];; + [self.messageLabel leading:self.iconImage.trailingAnchor padding:10]; + [self.messageLabel trailing:self.baseView.trailingAnchor padding:-10]; + [self.messageLabel bottom:self.baseView.bottomAnchor padding:0]; + + } + + return self; +} + +@end diff --git a/Paradise/App/Paradise/Tutorial/TutorialViewController.h b/Paradise/App/Paradise/Tutorial/TutorialViewController.h new file mode 100644 index 0000000..c3c517c --- /dev/null +++ b/Paradise/App/Paradise/Tutorial/TutorialViewController.h @@ -0,0 +1,15 @@ +#import +#import "ConstraintExtension.h" +#import "TutorialCell.h" +#import "AppManager.h" +#import "Preferences.h" + +@interface TutorialViewController : UIViewController +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) UIButton *closeButton; +@property (nonatomic, retain) NSArray *descriptionArray; +@property (nonatomic, retain) NSArray *imageArray; +@end + diff --git a/Paradise/App/Paradise/Tutorial/TutorialViewController.m b/Paradise/App/Paradise/Tutorial/TutorialViewController.m new file mode 100644 index 0000000..ebc9cd0 --- /dev/null +++ b/Paradise/App/Paradise/Tutorial/TutorialViewController.m @@ -0,0 +1,122 @@ +#import "TutorialViewController.h" + +@implementation TutorialViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.descriptionArray = [[NSArray alloc] initWithObjects: + @"On the icon area you can use finger gestures to drag around the position of the icon, pinch the icon with two fingers to resize the icon, use two fingers to rotate the icon. Once you edit the icon, you will see the red reset icon, click that if you want to reset the icons position and size.", + @"On the top left corner menu button where you can preview the icon on the dummy home screen, save the icon to the theme folder, export the icon, save the icon to your photo library, show the tutorial again and reset the icon so it will revert everything back to default.", + @"On top right corner plane button, once you design your icon, click the plane button so that it will save the icon to your preferred theme folder and make sure you have selected which theme folder you want it to be saved to.", + @"You can change the icons by using 2000+ SF Symbols, choose the icon from your photo library, colour the icon, add a background image, set a solid background colour or a gradient.", + @"Please be advised to create a new theme folder because if you already have the icon for a certain app in theme folder, when you save the new icon it will overwrite onto the existing icon. It’s okay if you don’t have any icons for a certain app in that theme folder, then it will save that to that certain folder, make sure you selected your preferred theme folder or create a new one then once you finish designing your icon then click on the plane button to save the icon and head to your theme engine settings to apply that theme.", + nil]; + + self.imageArray = [[NSArray alloc] initWithObjects: + @"hand.tap.fill", + @"rectangle.grid.1x2.fill", + @"paperplane.fill", + @"square.fill", + @"folder.fill", + nil]; + + + self.view.backgroundColor = [UIColor colorNamed:@"Main Background"]; + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage imageNamed:@"paradise-icon"]; + self.iconImage.userInteractionEnabled = YES; + [self.view addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.heightAnchor constraintEqualToConstant:70].active = YES; + [self.iconImage.widthAnchor constraintEqualToConstant:70].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:10].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.view.centerXAnchor].active = true; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.font = [UIFont boldSystemFontOfSize:18]; + self.titleLabel.text = @"Tutorial"; + [self.view addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.titleLabel.topAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant:10].active = YES; + [[self.titleLabel centerXAnchor] constraintEqualToAnchor:self.view.centerXAnchor].active = true; + + + self.closeButton = [[UIButton alloc] init]; + self.closeButton.backgroundColor = [UIColor colorNamed:@"Accent"]; + self.closeButton.layer.cornerRadius = 15; + self.closeButton.layer.cornerCurve = kCACornerCurveContinuous; + [self.closeButton setTitle:@"Close" forState:UIControlStateNormal]; + [self.closeButton addTarget:self action:@selector(dismissVC) forControlEvents:UIControlEventTouchUpInside]; + [self.closeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + self.closeButton.titleLabel.font = [UIFont systemFontOfSize:18]; + [self.view addSubview:self.closeButton]; + + [self.closeButton size:CGSizeMake(250, 50)]; + [self.closeButton x:self.view.centerXAnchor]; + [self.closeButton bottom:self.view.bottomAnchor padding:-15]; + + + self.tableView = [[UITableView alloc] init]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + self.tableView.estimatedRowHeight = 60; + self.tableView.rowHeight = UITableViewAutomaticDimension; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + [self.tableView top:self.titleLabel.bottomAnchor padding:10]; + [self.tableView leading:self.view.leadingAnchor padding:10]; + [self.tableView trailing:self.view.trailingAnchor padding:-10]; + [self.tableView bottom:self.closeButton.topAnchor padding:-10]; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 5; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + TutorialCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[TutorialCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + NSString *imageString = [self.imageArray objectAtIndex:indexPath.row]; + + cell.iconImage.image = [[UIImage systemImageNamed:imageString] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + cell.messageLabel.text = [self.descriptionArray objectAtIndex:indexPath.row]; + + return cell; + +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; + [[AppManager sharedInstance] setBool:NO forKey:@"showTutorial"]; +} + + +@end diff --git a/Paradise/App/Paradise/main.m b/Paradise/App/Paradise/main.m new file mode 100644 index 0000000..3bd5764 --- /dev/null +++ b/Paradise/App/Paradise/main.m @@ -0,0 +1,12 @@ + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + NSString * appDelegateClassName; + @autoreleasepool { + // Setup code that might create autoreleased objects goes here. + appDelegateClassName = NSStringFromClass([AppDelegate class]); + } + return UIApplicationMain(argc, argv, nil, appDelegateClassName); +} diff --git a/Paradise/App/layout/DEBIAN/postinst b/Paradise/App/layout/DEBIAN/postinst new file mode 100755 index 0000000..9aa1905 --- /dev/null +++ b/Paradise/App/layout/DEBIAN/postinst @@ -0,0 +1,3 @@ +#!/bin/bash +uicache -p /Applications/Paradise.app +chown mobile:wheel /Library/Themes diff --git a/Paradise/LibraryUsage.md b/Paradise/LibraryUsage.md new file mode 100644 index 0000000..e2f7f4d --- /dev/null +++ b/Paradise/LibraryUsage.md @@ -0,0 +1,197 @@ +# Import header + +This is all you need to import in each class header +```objc +#import +``` + +# Object for key, boolean, integer and float value and set default too (can use either TDTweakManager or TDPrefsManager as long as you have same bundle ID for prefs) +```objc +bool value = [[TDTweakManager sharedInstance] boolForKey:@"exampleBoolean" defaultValue:NO]; +long long value = [[TDTweakManager sharedInstance] floatForKey:@"exampleFloat" defaultValue:20]; +int value = [[TDTweakManager sharedInstance] intForKey:@"exampleInteger" defaultValue:1]; +NSString *value = [[TDTweakManager sharedInstance] objectForKey:@"exampleString" defaultValue:@"Hello"]; +``` + +# Object for key, boolean, integer and float value without default (can use either TDTweakManager or TDPrefsManager as long as you have same bundle ID for prefs) +```objc +bool value = [[TDTweakManager sharedInstance] boolForKey:@"exampleBoolean"]; +long long value = [[TDTweakManager sharedInstance] floatForKey:@"exampleFloat"]; +int value = [[TDTweakManager sharedInstance] intForKey:@"exampleInt"]; +NSString *value = [[TDTweakManager sharedInstance] objectForKey:@"exampleString"]; +``` + +# Set object, boolean, integer and float value (can use either TDTweakManager or TDPrefsManager as long as you have same bundle ID for prefs) +```objc +[[TDTweakManager sharedInstance] setBool:YES forKey:@"testKey"]; +[[TDTweakManager sharedInstance] setFloat:10101010 forKey:@"testKeyFloat"]; +[[TDTweakManager sharedInstance] setInt:10 forKey:@"testKeyInt"]; +[[TDTweakManager sharedInstance] setObject:10 forKey:@"testKeyInt"]; +``` + +# Set the background colour from HEX string +```objc +NSString *colourString = @"FA682C"; +UIColor *exampleColour = colorFromHexString(colourString); +exampleView.backgroundColor = exampleColour; +``` + +# Set the background colour from the colour picker in prefs +```objc +exampleView.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"exampleColour" defaultValue:@"FA682C"]; +``` + +# Set the font from font picker +```objc +NSData *data = [[TDTweakManager sharedInstance] objectForKey:@"exampleFont"]; +UIFontDescriptor *descriptor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:data error:nil]; +self.exampleLabel.font = [UIFont fontWithDescriptor:descriptor size:18]; +``` + +# Set the date from date picker +```objc +NSDate *existingDate = [[TDTweakManager sharedInstance] objectForKey:@"exampleDate"]; +NSDateFormatter *pickedDateFormat = [[NSDateFormatter alloc] init]; +[pickedDateFormat setDateFormat:@"dd/MM/YYYY"]; +NSString *pickedDateString = [pickedDateFormat stringFromDate:existingDate]; +self.exampleLabel.text = pickedDateString; +``` + +# Get the weather information +```objc +[[TDWeather sharedInstance] refreshWeatherData]; +NSDictionary *weatherData = [[TDWeather sharedInstance] weatherData]; + +NSString *temperature = [weatherData objectForKey:@"temperature"]; +NSString *condition = [weatherData objectForKey:@"conditions"]; +NSString *location = [weatherData objectForKey:@"location"]; +NSDate *sunrise = [weatherData objectForKey:@"sunrise"]; +NSDate *sunset = [weatherData objectForKey:@"sunset"]; + +NSLog(@"temp:%@, condition:%@, location:%@, sunrise%@, sunset%@", temperature, condition, location, sunrise, sunset); + +UIImage *conditionsImage = [weatherData objectForKey:@"conditionsImage"]; +self.exampleImage.image = conditionsImage; +``` + +# Add blur effect view with style +```objc +TDBlurView *exampleBlur = [[TDBlurView alloc] initWithFrame:self.view.bounds style:Light]; // Light, Dark & Dynamic +[self.view addSubview:exampleBlur]; +``` + +# Add UILabel with text, font colour, text alignment, set the font size and bold +```objc +TDLabel *exampleLabel = [[TDLabel alloc] initWithText:@"Hello" colour:nil alignment:center size:40 bold:NO]; +[self.view addSubview:exampleLabel]; +``` + +# Add UIView with backgroun colour, corner radius, curve and clip to bounds +```objc +TDView *exampleView = [[TDView alloc] initWithColour:UIColor.redColor corner:25 curve:YES clip:YES]; +[self.view addSubview:exampleView]; +``` + +# Add UIButton with title, background colour, title colour, font size and the background corner radius +```objc +TDButton *exampleButton = [[TDButton alloc] initWithTitle:@"Button" colour:nil fontColour:nil fontSize:12 corner:20]; +[exampleButton addTarget:self action:@selector(action) forControlEvents:UIControlEventTouchUpInside]; +[self.view addSubview:exampleButton]; +``` + +# Add UIButton with image, inset, background colour, tint colour and corner radius for the background +```objc +UIImage *exampleImage = [[UIImage imageNamed:@"icon"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; +TDButton *exampleButton = [[TDButton alloc] initWithImage:exampleImage inset:UIEdgeInsetsMake(10, 10, 10, 10) colour:nil tint:YES tintColour:UIColor.redColor corner:0]; +[exampleButton addTarget:self action:@selector(action) forControlEvents:UIControlEventTouchUpInside]; +[self.view addSubview:exampleButton]; +``` + +# Add UIImageView with tint colour and corner radius if you wanr it to be cirle or whatever +```objc +UIImage *exampleImage = [[UIImage imageNamed:@"icon"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; +TDImage *exampleImageView = [[TDImage alloc] initWithImage:exampleImage tint:NO tintColour:UIColor.yellowColor corner:0]; +[self.view addSubview:exampleImageView]; +``` + +# Get the device name, battery or time/date from string +```objc +self.exampleLabel.text = [[TDUtilities sharedInstance] systemVersion]; +self.exampleLabel.text = [[TDUtilities sharedInstance] deviceName]; +self.exampleLabel.text = [[TDUtilities sharedInstance] deviceModel]; +self.exampleLabel.text = [[TDUtilities sharedInstance] timeWithFormat:@"hh:mm"]; +self.exampleLabel.text = [[TDUtilities sharedInstance] dateWithFormat:@"E, MMM D"]; +self.exampleLabel.text = [[TDUtilities sharedInstance] greeting]; // good morning, good afternoon, good evening, good night +self.exampleLabel.text = [[TDUtilities sharedInstance] battery]; // battery usage +``` + +# Function to respring, launch apps/url and haptic feedback +```objc +-(void)exampleMethod { + + [[TDUtilities sharedInstance] respring]; + [[TDUtilities sharedInstance] safemode]; + [[TDUtilities sharedInstance] reboot]; + [[TDUtilities sharedInstance] uicache]; + [[TDUtilities sharedInstance] launchURL:@"https://titand3v.com/"]; // Launch URL string + [[TDUtilities sharedInstance] launchApp:@"com.apple.AppStore"]; // Launch app + [[TDUtilities sharedInstance] haptic:0]; // 0: light, 1: medium, 2: heavy + +} +``` + +# Constraints helper +```objc +// "Insets": (CGFloat top, CGFloat left, CGFloat bottom, CGFloat right); + +[exampleView top:self.view.topAnchor leading:self.view.leadingAnchor bottom:nil trailing:nil padding:UIEdgeInsetsMake(10, 20, 0, 0)]; // Set example view all 4 sides with padding +[exampleView top:self.view.topAnchor padding:50]; // Set exampleView top anchor to self view top with padding of 50pts +[exampleView leading:self.view.leadingAnchor padding:50]; // Set exampleView leading (left) anchor to self view leading with padding of 50pts +[exampleView trailing:self.view.trailingAnchor padding:-50]; // Set exampleView trailing (right) anchor to self view trailing with padding of 50pts +[exampleView bottom:self.view.bottomAnchor padding:-50]; // Set exampleView bottom anchor to self view bottom with padding of 50pts + +[exampleView size:CGSizeMake(100, 200)]; // Set exampleView width:100 and height:200 +[exampleView width:200]; // Set exampleView width: 200 +[exampleView height:60]; // Set exampleView height: 60 + +[exampleView x:self.view.centerXAnchor y:self.view.centerYAnchor]; // Set exampleView center X and Y of self view +[exampleView x:self.view.centerXAnchor]; // Set exampleView center X of self view +[exampleView y:self.view.centerYAnchor]; // Set exampleView center Y of self view + +[exampleView fill]; // Set exampleView to fill the frame of self view or wherever subviews you added it to +``` + +# AppList +```objc + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + NSArray *enabledApps = mutableDict[@"exampleApplistKey"]; + NSLog(@"%@", enabledApps); + //for(NSString *bid in enabledApps) { + + //} +``` + +# AppList group hooks to blacklist apps + +```objc +NSString *plistPath = @"/var/mobile/Library/Preferences/com.TitanD3v.TweakNamePrefs.plist"; +%ctor { + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + NSArray *enabledApps = mutableDict[@"exampleApplistKey"]; + for(NSString *bid in enabledApps){ + + NSBundle* mainBundle = [NSBundle mainBundle]; + NSString* bundleIdentifier = mainBundle.bundleIdentifier; + + if ([bundleIdentifier isEqualToString:bid]) { + %init(TableHooks); + } + } + + %init(_ungrouped); +} +``` \ No newline at end of file diff --git a/Paradise/Makefile b/Paradise/Makefile new file mode 100644 index 0000000..e5d9755 --- /dev/null +++ b/Paradise/Makefile @@ -0,0 +1,16 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0 + +export CFLAGS = -include $(realpath NCCenter.h) + +FINALPACKAGE = 1 +DEBUG = 0 + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += App Tweak Prefs + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Paradise/NCCenter.h b/Paradise/NCCenter.h new file mode 100644 index 0000000..0b2feb1 --- /dev/null +++ b/Paradise/NCCenter.h @@ -0,0 +1,9 @@ +#import + +@interface NSDistributedNotificationCenter : NSNotificationCenter ++ (instancetype)defaultCenter; +-(void)postNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3 deliverImmediately:(BOOL)arg4 ; +- (void)postNotificationName:(NSString *)name object:(NSString *)object userInfo:(NSDictionary *)userInfo; +-(id)addObserverForName:(id)arg1 object:(id)arg2 queue:(id)arg3 usingBlock:(/*^block*/id)arg4 ; +-(void)addObserver:(id)arg1 selector:(SEL)arg2 name:(id)arg3 object:(id)arg4 ; +@end \ No newline at end of file diff --git a/Paradise/Prefs/Makefile b/Paradise/Prefs/Makefile new file mode 100644 index 0000000..203f176 --- /dev/null +++ b/Paradise/Prefs/Makefile @@ -0,0 +1,17 @@ +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +BUNDLE_NAME = ParadisePrefs + +$(BUNDLE_NAME)_FILES = $(wildcard *.m Purchase/*.m) +$(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles +$(BUNDLE_NAME)_FRAMEWORKS = UIKit +$(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences OnBoardingKit +$(BUNDLE_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(BUNDLE_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/bundle.mk + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) + $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/ParadisePrefs.plist$(ECHO_END) diff --git a/Paradise/Prefs/PARAPrimraryListController.h b/Paradise/Prefs/PARAPrimraryListController.h new file mode 100644 index 0000000..cdbf3be --- /dev/null +++ b/Paradise/Prefs/PARAPrimraryListController.h @@ -0,0 +1,29 @@ +#import +#import + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1;; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + + +@interface PARAPrimraryListController : TDPrimraryController { + OBWelcomeController *onboardingController; + OBWelcomeController *updateController; +} + +@end diff --git a/Paradise/Prefs/PARAPrimraryListController.m b/Paradise/Prefs/PARAPrimraryListController.m new file mode 100644 index 0000000..e877265 --- /dev/null +++ b/Paradise/Prefs/PARAPrimraryListController.m @@ -0,0 +1,123 @@ +#include "PARAPrimraryListController.h" + +@implementation PARAPrimraryListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Primrary" target:self]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[TDPrefsManager sharedInstance] initWithBundleID:@"com.TitanD3v.ParadisePrefs" tweakName:@"Paradise" prefsBundle:@"ParadisePrefs.bundle"]; + + [[TDPrefsManager sharedInstance] bannerTitle:@"Paradise" subtitle:@"Coded with 🤍" devName:@"TitanD3v" coverImagePath:@"/Assets/Banner/cover-image.png" showCoverImage:YES iconPath:@"" iconTint:NO]; + + [[TDPrefsManager sharedInstance] changelogPlistPath:@"/Assets/Changelog/changelog.plist" currentVersion:@"Version 1.1"]; + + [[TDPrefsManager sharedInstance] useAssetsFromLibrary:YES]; + +} + + +-(void)presentTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + onboardingController = [[OBWelcomeController alloc] initWithTitle:@"User Guide" detailText:@"A walk through tutorial how to use Paradise" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ParadisePrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]]; + + [onboardingController addBulletedListItemWithTitle:@"Your time" description:@"Please take a few minutes of your time to read through to get started." image:[UIImage systemImageNamed:@"timer"]]; + + [onboardingController addBulletedListItemWithTitle:@"Main page" description:@"On the main page, there's menu icon on the navigation bar it will present the drawer when tapped. You will find the social media details, changelog, backup/restore, themes, tweak list, profile and crew list." image:[UIImage systemImageNamed:@"square.stack.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Report a bug" description:@"If you are experiencing a bug or any other issues, you can report a bug from this page below the close button, it will bring up the Bug Report page. You can select the categories, write description about a bug, attach a .txt file, photo, provide URL link for the pastebin or any pasteboard website also you can attach all of them if you want. Once you submit a bug report and our team will be in touch with you within 48 hours. If you haven't heard anything from us and please don't hesitate to get in touch with us through social media." image:[UIImage systemImageNamed:@"ant.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Appearance" description:@"You can choose either light, dark or dynamic mode. If you don’t want to use blur effect then disable that and it will use the solid system background colour. You can set a wallpaper background for paradise bottom card." image:[UIImage systemImageNamed:@"circle.lefthalf.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Colour" description:@"If you don’t want it to adopt your system appearance then you can use custom colours" image:[UIImage systemImageNamed:@"drop.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Miscellaneous" description:@"You can enable or disable haptic feedback or choose the strength. If you want to use custom fonts, you can choose any custom font from the picker and it will apply to all the text labels of Paradise UI. If you want to change the corner radius of Paradise’s bottom card then you can change the corner radius however you like. If you want to use the 3D Touch menu to open Paradise then make sure you enable the 3D Touch Menu." image:[UIImage systemImageNamed:@"gear"]]; + + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [onboardingController.buttonTray addButton:dismissButton]; + + onboardingController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:onboardingController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [onboardingController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + onboardingController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [onboardingController.buttonTray addCaptionText:@"Thank you for installing Paradise"]; + + onboardingController.modalPresentationStyle = UIModalPresentationPageSheet; + onboardingController.modalInPresentation = YES; + [self presentViewController:onboardingController animated:YES completion:nil]; + + UIView *reportView = [[UIView alloc] init]; + reportView.backgroundColor = UIColor.clearColor; + [onboardingController.buttonTray addSubview:reportView]; + + reportView.translatesAutoresizingMaskIntoConstraints = NO; + [reportView.topAnchor constraintEqualToAnchor:dismissButton.bottomAnchor constant:10].active = YES; + [[reportView centerXAnchor] constraintEqualToAnchor:onboardingController.buttonTray.centerXAnchor].active = true; + [reportView.widthAnchor constraintEqualToConstant:140].active = YES; + [reportView.heightAnchor constraintEqualToConstant:40].active = YES; + + + UIImageView *bugImage = [[UIImageView alloc] init]; + bugImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + bugImage.tintColor = [[TDAppearance sharedInstance] tintColour]; + [reportView addSubview:bugImage]; + + bugImage.translatesAutoresizingMaskIntoConstraints = NO; + [bugImage.leadingAnchor constraintEqualToAnchor:reportView.leadingAnchor constant:10].active = YES; + [[bugImage centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + [bugImage.widthAnchor constraintEqualToConstant:30].active = YES; + [bugImage.heightAnchor constraintEqualToConstant:30].active = YES; + + + UILabel *reportLabel = [[UILabel alloc] init]; + reportLabel.text = @"Report a bug"; + reportLabel.textColor = [[TDAppearance sharedInstance] tintColour]; + reportLabel.textAlignment = NSTextAlignmentLeft; + [reportView addSubview:reportLabel]; + + reportLabel.translatesAutoresizingMaskIntoConstraints = NO; + [reportLabel.leadingAnchor constraintEqualToAnchor:bugImage.trailingAnchor constant:5].active = YES; + [[reportLabel centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + + [reportView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentReportBugVC)]]; + +} + + +-(void)dismissTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentReportBugVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; + + TDReportBugViewController *bugVC = [[TDReportBugViewController alloc] init]; + bugVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [self presentViewController:bugVC animated:YES completion:nil]; +} + +@end diff --git a/Paradise/Prefs/PARASecondaryListController.h b/Paradise/Prefs/PARASecondaryListController.h new file mode 100644 index 0000000..c8b2737 --- /dev/null +++ b/Paradise/Prefs/PARASecondaryListController.h @@ -0,0 +1,12 @@ +#import +#import + +@interface PARAAppearanceController : TDSecondaryController +@end + +@interface PARAColourController : TDSecondaryController +@end + +@interface PARAMiscellaneousController : TDSecondaryController +@end + diff --git a/Paradise/Prefs/PARASecondaryListController.m b/Paradise/Prefs/PARASecondaryListController.m new file mode 100644 index 0000000..3fabf53 --- /dev/null +++ b/Paradise/Prefs/PARASecondaryListController.m @@ -0,0 +1,39 @@ +#include "PARASecondaryListController.h" + +@implementation PARAAppearanceController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Appearance" target:self]; + } + + return _specifiers; +} + +@end + + +@implementation PARAColourController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Colour" target:self]; + } + + return _specifiers; +} + +@end + + +@implementation PARAMiscellaneousController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Miscellaneous" target:self]; + } + + return _specifiers; +} + +@end diff --git a/Paradise/Prefs/Resources/Appearance.plist b/Paradise/Prefs/Resources/Appearance.plist new file mode 100644 index 0000000..76a9de7 --- /dev/null +++ b/Paradise/Prefs/Resources/Appearance.plist @@ -0,0 +1,159 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Appearance + + + + cellClass + TDAppearanceCell + key + appdataAppearance + default + appdataLight + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + options + + light + + appearanceOption + appdataLight + title + Light + imageName + appearance-light + arrangement + 1 + + dark + + appearanceOption + appdataDark + title + Dark + imageName + appearance-dark + arrangement + 2 + + dynamic + + appearanceOption + appdataDynamic + title + Dynamic + imageName + appearance-dynamic + arrangement + 2 + + + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Blur + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleBlurEffect + title + Enable + subtitle + Blur Effect + iconName + switch + showTips + + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Wallpaper + + + + cellClass + TDEnableCell + default + + key + toggleAppdataBackgroundImage + disabledTitle + Disable Wallpaper + enabledTitle + Enable Wallpaper + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDImagePickerCell + title + Choose + subtitle + Wallpaper Image + action + chooseImage + key + appdataBackgroundImage + usesJPEG + + compressionQuality + 1.0 + iconName + photo + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + title + + + diff --git a/Paradise/Prefs/Resources/Assets/Banner/banner-icon.png b/Paradise/Prefs/Resources/Assets/Banner/banner-icon.png new file mode 100644 index 0000000..151e889 Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Banner/banner-icon.png differ diff --git a/Paradise/Prefs/Resources/Assets/Banner/cover-image.png b/Paradise/Prefs/Resources/Assets/Banner/cover-image.png new file mode 100644 index 0000000..dd02da4 Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Banner/cover-image.png differ diff --git a/Paradise/Prefs/Resources/Assets/Cell/prefs-icon@2x.png b/Paradise/Prefs/Resources/Assets/Cell/prefs-icon@2x.png new file mode 100644 index 0000000..62613d3 Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Cell/prefs-icon@2x.png differ diff --git a/Paradise/Prefs/Resources/Assets/Cell/prefs-icon@3x.png b/Paradise/Prefs/Resources/Assets/Cell/prefs-icon@3x.png new file mode 100644 index 0000000..d2a768f Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Cell/prefs-icon@3x.png differ diff --git a/Paradise/Prefs/Resources/Assets/Changelog/changelog.plist b/Paradise/Prefs/Resources/Assets/Changelog/changelog.plist new file mode 100644 index 0000000..8d4240d --- /dev/null +++ b/Paradise/Prefs/Resources/Assets/Changelog/changelog.plist @@ -0,0 +1,37 @@ + + + + + + + Date + 12th June 2021 + Version + v1.1 + ChangelogDescription + + Fixed activate licence after purchasing + + updateCategories + + 1 + + + + + Date + 11th June 2021 + Version + v1.0 + ChangelogDescription + + Initial Release... + + updateCategories + + 0 + + + + + diff --git a/Paradise/Prefs/Resources/Assets/ExtSettings/ExtPrimrary.plist b/Paradise/Prefs/Resources/Assets/ExtSettings/ExtPrimrary.plist new file mode 100644 index 0000000..5f96794 --- /dev/null +++ b/Paradise/Prefs/Resources/Assets/ExtSettings/ExtPrimrary.plist @@ -0,0 +1,46 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Categories + + + + cellClass + TDGridCell + leftTitle + Appearance + leftIconName + appearance + leftClass + ParadiseAppearanceController + middleTitle + Colour + middleIconName + colour + middleClass + ParadiseColourController + rightTitle + Miscellaneous + rightIconName + misc + rightClass + ParadiseMiscellaneousController + classID + external + + + + title + + + diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss1.png b/Paradise/Prefs/Resources/Assets/Payment/ss1.png new file mode 100644 index 0000000..666176b Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss1.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss10.png b/Paradise/Prefs/Resources/Assets/Payment/ss10.png new file mode 100644 index 0000000..2a8aa19 Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss10.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss11.png b/Paradise/Prefs/Resources/Assets/Payment/ss11.png new file mode 100644 index 0000000..cd2a266 Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss11.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss12.png b/Paradise/Prefs/Resources/Assets/Payment/ss12.png new file mode 100644 index 0000000..b71383f Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss12.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss13.png b/Paradise/Prefs/Resources/Assets/Payment/ss13.png new file mode 100644 index 0000000..f99a62a Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss13.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss14.png b/Paradise/Prefs/Resources/Assets/Payment/ss14.png new file mode 100644 index 0000000..1b8c63f Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss14.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss15.png b/Paradise/Prefs/Resources/Assets/Payment/ss15.png new file mode 100644 index 0000000..0e5abb1 Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss15.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss2.png b/Paradise/Prefs/Resources/Assets/Payment/ss2.png new file mode 100644 index 0000000..e416d20 Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss2.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss3.png b/Paradise/Prefs/Resources/Assets/Payment/ss3.png new file mode 100644 index 0000000..d81c175 Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss3.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss4.png b/Paradise/Prefs/Resources/Assets/Payment/ss4.png new file mode 100644 index 0000000..363e8cd Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss4.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss5.png b/Paradise/Prefs/Resources/Assets/Payment/ss5.png new file mode 100644 index 0000000..7842ef9 Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss5.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss6.png b/Paradise/Prefs/Resources/Assets/Payment/ss6.png new file mode 100644 index 0000000..3d3739f Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss6.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss7.png b/Paradise/Prefs/Resources/Assets/Payment/ss7.png new file mode 100644 index 0000000..b292a69 Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss7.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss8.png b/Paradise/Prefs/Resources/Assets/Payment/ss8.png new file mode 100644 index 0000000..71957e8 Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss8.png differ diff --git a/Paradise/Prefs/Resources/Assets/Payment/ss9.png b/Paradise/Prefs/Resources/Assets/Payment/ss9.png new file mode 100644 index 0000000..ea0164c Binary files /dev/null and b/Paradise/Prefs/Resources/Assets/Payment/ss9.png differ diff --git a/Paradise/Prefs/Resources/Colour.plist b/Paradise/Prefs/Resources/Colour.plist new file mode 100644 index 0000000..f20403e --- /dev/null +++ b/Paradise/Prefs/Resources/Colour.plist @@ -0,0 +1,200 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable Colour + + + + cellClass + TDEnableCell + default + + key + toggleAppdataColour + disabledTitle + Disable Colour + enabledTitle + Enable Colour + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Custom Colour + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Accent + subtitle + Colour + default + FFFFFF + key + appdataAccentColour + iconName + colour + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Background + subtitle + Colour + default + FFFFFF + key + appdataBackgroundColour + iconName + colour + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Font + subtitle + Colour + default + FFFFFF + key + appdataFontColour + iconName + colour + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Icon + subtitle + Colour + default + FFFFFF + key + appdataIconColour + iconName + colour + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Badge + subtitle + Colour + default + FFFFFF + key + appdataBadgeColour + iconName + colour + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Cell + subtitle + Colour + default + FFFFFF + key + appdataCellColour + iconName + colour + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Separator + subtitle + Colour + default + FFFFFF + key + appdataSeparatorColour + iconName + colour + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + title + + + diff --git a/Paradise/Prefs/Resources/Info.plist b/Paradise/Prefs/Resources/Info.plist new file mode 100644 index 0000000..8487d73 --- /dev/null +++ b/Paradise/Prefs/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ParadisePrefs + CFBundleIdentifier + com.TitanD3v.paradiseprefs + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + PARAPrimraryListController + + diff --git a/Paradise/Prefs/Resources/Miscellaneous.plist b/Paradise/Prefs/Resources/Miscellaneous.plist new file mode 100644 index 0000000..1d3e9f7 --- /dev/null +++ b/Paradise/Prefs/Resources/Miscellaneous.plist @@ -0,0 +1,198 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Haptic + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleAppdataHaptic + title + Enable + subtitle + Haptic Feedback + iconName + switch + showTips + + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + appdataHapticStrength + default + 0 + validTitles + + Light + Medium + Heavy + + validValues + + 0 + 1 + 2 + + title + Type + showTips + + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Custom Font + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleAppdataCustomFont + title + Enable + subtitle + Custom font + customIcon + + iconTint + + iconName + switch + showTips + + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDFontPickerCell + title + Select + subtitle + Font + key + appdataCustomFont + iconName + font + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Corner Radius + + + + cell + PSSliderCell + cellClass + TDSliderCell + title + Paradise Corner Radius + default + 30 + key + bottomSheetCornerRadius + min + 1 + max + 50 + showValue + + isSegmented + + showTips + + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + 3D Menu + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggle3DMenu + title + Enable + subtitle + Paradise 3D Menu + iconName + switch + showTips + + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + title + + + diff --git a/Paradise/Prefs/Resources/Primrary.plist b/Paradise/Prefs/Resources/Primrary.plist new file mode 100644 index 0000000..e231e64 --- /dev/null +++ b/Paradise/Prefs/Resources/Primrary.plist @@ -0,0 +1,82 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable + + + + cellClass + TDEnableCell + default + + key + toggleParadise + disabledTitle + Disable Paradise + enabledTitle + Enable Paradise + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + disabledIconPath + Assets/example-icon.png + enabledIconPath + Assets/example-icon.png + defaults + com.TitanD3v.ParadisePrefs + PostNotification + com.TitanD3v.ParadisePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Categories + + + + cellClass + TDGridCell + leftTitle + Appearance + leftIconName + appearance + leftClass + PARAAppearanceController + middleTitle + Colour + middleIconName + colour + middleClass + PARAColourController + rightTitle + Miscellaneous + rightIconName + misc + rightClass + PARAMiscellaneousController + classID + primrary + + + + title + + + diff --git a/Paradise/Prefs/entry.plist b/Paradise/Prefs/entry.plist new file mode 100644 index 0000000..0552f6b --- /dev/null +++ b/Paradise/Prefs/entry.plist @@ -0,0 +1,21 @@ + + + + + entry + + bundle + ParadisePrefs + cell + PSLinkCell + detail + PARAPrimraryListController + icon + Assets/Cell/prefs-icon.png + isController + + label + Paradise + + + diff --git a/Paradise/Tweak/.DS_Store b/Paradise/Tweak/.DS_Store new file mode 100644 index 0000000..a76a83e Binary files /dev/null and b/Paradise/Tweak/.DS_Store differ diff --git a/Paradise/Tweak/Headers.h b/Paradise/Tweak/Headers.h new file mode 100644 index 0000000..82a55d1 --- /dev/null +++ b/Paradise/Tweak/Headers.h @@ -0,0 +1,242 @@ +#import +#import +#import + +//#import "./DATA/DataController/DataViewController.h" + +// struct SBIconImageInfo iconspecs; + +// typedef struct SBIconImageInfo { +// CGSize size; +// double scale; +// double continuousCornerRadius; +// } SBIconImageInfo; + +static NSString *plistPath = @"/var/mobile/Library/Preferences/com.TitanD3v.ParadisePrefs.plist"; + +@interface FBProcessState : NSObject +@property (getter=isForeground,nonatomic,readonly) BOOL foreground; +@property (getter=isRunning,nonatomic,readonly) BOOL running; +@property (assign,nonatomic) long long taskState; +@end + +@interface FBProcess : NSObject +@property (nonatomic,copy,readonly) NSString * name; +@property (nonatomic,copy,readonly) NSString * bundleIdentifier; +@property (getter=isCurrentProcess,nonatomic,readonly) BOOL currentProcess; +-(void)_killForReason:(long long)arg1 andReport:(BOOL)arg2 withDescription:(id)arg3 completion:(/*^block*/id)arg4; +@end + +@interface SBClockApplicationIconImageView +-(void)presentAppDataVC:(UITapGestureRecognizer*)sender; +@end + +// @interface MTMaterialView : UIView +// @end + +@interface UIApplication (Paradise) +- (BOOL)launchApplicationWithIdentifier:(NSString *)identifier suspended:(BOOL)suspend; +@end + +@interface SBApplication : NSObject +@property (nonatomic,readonly) NSString * displayName; +@property (assign,nonatomic) id badgeNumberOrString; +@property (nonatomic,copy) id badgeValue; +-(NSString *)bundleIdentifier; +-(void)purgeCaches; +@end + +@interface SBIcon : NSObject +- (NSString *)applicationBundleID; +- (SBApplication *)application; +- (NSInteger)badgeValue; +struct SBIconImageInfo { + CGFloat width; + CGFloat height; + CGFloat field1; + CGFloat field2; +}; +-(BOOL)isWidgetIcon; +-(UIImage *)getIconImage:(int)arg1 ; +-(UIImage *)iconImageWithInfo:(struct SBIconImageInfo)info; +@end + +@interface SBLeafIcon : SBIcon +-(id)leafIdentifier; +@end + +@interface SBWidgetIcon : SBLeafIcon +@end + +@interface SBBookmarkIcon : SBLeafIcon +@end + +@interface SBHLibraryPodCategoryIcon : SBLeafIcon +@end + +@interface SBSApplicationShortcutIcon: NSObject +@end + +@interface SBFolderIcon : SBIcon +-(id)nodeIdentifier; +@end + +@interface SBSApplicationShortcutItem : NSObject +@property (nonatomic, retain) NSString *type; +@property (nonatomic, copy) NSString * localizedTitle; +@property (nonatomic, copy) SBSApplicationShortcutIcon * icon; +@property (nonatomic, copy) NSString * bundleIdentifierToLaunch; +- (void)setIcon:(SBSApplicationShortcutIcon *)arg1; +@end + +@interface SBSApplicationShortcutCustomImageIcon : SBSApplicationShortcutIcon +@property (nonatomic, readwrite) BOOL isTemplate; +- (id)initWithImagePNGData:(id)arg1; +- (BOOL)isTemplate; +@end + +@interface SBIconLabelImageParameters : NSObject +@property (nonatomic,copy,readonly) NSString * iconLocation; +@property (nonatomic,copy) NSString * text; +-(unsigned long long)hash; +-(id)description; +@end + +@interface SBIconView : UIView +@property (nonatomic, retain) SBIcon *icon; +@property (nonatomic, retain) SBFolderIcon * folderIcon; +@property (nonatomic,readonly) UIImage * iconImageSnapshot; +@property (nonatomic,readonly) UIView * iconImageSnapshotView; +@property (nonatomic,copy,readonly) NSString * applicationBundleIdentifierForShortcuts; +- (id)_iconImageView; +- (void)_updateLabel; +- (BOOL)ad_isFolderIcon; +- (SBIconLabelImageParameters*)_labelImageParameters; +@end + +@interface SBIconLegibilityLabelView +-(SBIconView *)iconView; +-(SBIconLabelImageParameters *)imageParameters; +@end + +@interface SBMutableIconLabelImageParameters : SBIconLabelImageParameters +@property (nonatomic,copy) NSString * text; +@property (nonatomic,retain) UIColor * textColor; +@property (nonatomic,retain) UIColor * focusHighlightColor; + +-(void)setFocusHighlightColor:(UIColor *)arg1; +-(void)setTextColor:(UIColor *)arg1; +-(void)setText:(NSString *)arg1; +@end + +@interface SBApplicationIcon : SBLeafIcon + +// iOS 12 and below +- (UIImage *)generateIconImage:(int)arg1; +// iOS 13 +// - (id)generateIconImageWithInfo:(SBIconImageInfo)arg1; +@end + +@interface SBIconModel : NSObject +- (SBApplicationIcon *)expectedIconForDisplayIdentifier:(id)arg1; +-(SBIcon *)applicationIconForBundleIdentifier:(id)arg1 ; +-(void)layout; +-(void)purgeAllIconCaches; +-(void)loadAllIcons; +@end + +@interface SBIconViewMap : NSObject +@property (nonatomic,readonly) SBIconModel * iconModel; +@end + +@interface SBHIconModel : NSObject +-(void)removeAllIcons; +-(void)layout; +-(id)iconState; +@end + +@interface SBIconController : UIViewController +// @property (nonatomic, retain) SBIconModel *model; ++(id)sharedInstance; +-(SBIconViewMap *)homescreenIconViewMap; +-(id)model; +@end + +@interface SBIconImageView : UIView +@property (assign,nonatomic) SBIconView * iconView; +-(void)setIconView:(SBIconView *)arg1 ; +-(SBIconView *)iconView; +@end + +@interface SBApplicationController : NSObject ++ (instancetype)sharedInstance; +- (SBApplication *)applicationWithBundleIdentifier:(NSString *)identifier; +@end + +@interface UIImage () ++ (id)imageNamed:(id)arg1 inBundle:(id)arg2; +@end + +@interface UIView (Private) +- (UIViewController *)_viewControllerForAncestor; +@end + + +// Core Services + +@interface _LSBoundIconInfo +@property (nonatomic, copy) NSString *applicationIdentifier; +@end + +@interface LSResourceProxy : NSObject +@end + +@interface LSBundleProxy : LSResourceProxy +@property (nonatomic,readonly) NSString * localizedShortName; +@property (nonatomic,copy) NSArray * machOUUIDs; +@property (nonatomic,copy) NSString * sdkVersion; +@property (nonatomic,readonly) NSString * bundleIdentifier; +@property (nonatomic,readonly) NSString * bundleType; +@property (nonatomic,readonly) NSURL * bundleURL; +@property (nonatomic,readonly) NSString * bundleExecutable; +@property (nonatomic,readonly) NSString * canonicalExecutablePath; +@property (nonatomic,readonly) NSURL * containerURL; +@property (nonatomic,readonly) NSURL * dataContainerURL; +@property (nonatomic,readonly) NSURL * bundleContainerURL; +@property (nonatomic,readonly) NSURL * appStoreReceiptURL; +@property (nonatomic,readonly) NSString * bundleVersion; +@property (nonatomic,readonly) NSString * signerIdentity; +@property (nonatomic,readonly) NSDictionary * entitlements; +@property (nonatomic,readonly) NSDictionary * environmentVariables; +@property (nonatomic,readonly) NSDictionary * groupContainerURLs; +- (id)localizedName; +@end + +@interface LSApplicationProxy : LSBundleProxy +@property (nonatomic,readonly) NSString * applicationIdentifier; ++ (LSApplicationProxy *)applicationProxyForIdentifier:(NSString *)identifier; +@property (nonatomic,readonly) NSString *shortVersionString; +@property (nonatomic, strong) NSString *itemName; +@property (nonatomic, strong) NSNumber *itemID; +@property (nonatomic,readonly) NSNumber * staticDiskUsage; +@property (nonatomic,readonly) NSNumber * dynamicDiskUsage; +@property (nonatomic,readonly) NSNumber * ODRDiskUsage; +@property (getter=isAppStoreVendable,nonatomic,readonly) BOOL appStoreVendable; +@property (getter=isDeletable,nonatomic,readonly) BOOL deletable; + +// iOS 13 +@property (nonatomic,readonly) NSSet *claimedDocumentContentTypes; +@property (nonatomic,readonly) NSSet *claimedURLSchemes; +@end + +@interface IXAppInstallCoordinator : NSObject ++(BOOL)demoteAppToPlaceholderWithBundleID:(id)arg1 forReason:(unsigned long long)arg2 waitForDeletion:(BOOL)arg3 error:(id*)arg4 ; ++(BOOL)demoteAppToPlaceholderWithBundleID:(id)arg1 forReason:(unsigned long long)arg2 error:(id*)arg3 ; ++(void)demoteAppToPlaceholderWithBundleID:(id)arg1 forReason:(unsigned long long)arg2 waitForDeletion:(BOOL)arg3 completion:(/*^block*/id)arg4 ; ++(void)uninstallAppWithBundleID:(id)arg1 requestUserConfirmation:(BOOL)arg2 waitForDeletion:(BOOL)arg3 completion:(/*^block*/id)arg4 ; +@end + +@interface SpringBoard : UIApplication +- (id)_accessibilityFrontMostApplication; +-(void)frontDisplayDidChange: (id)arg1; +@end \ No newline at end of file diff --git a/Paradise/Tweak/Makefile b/Paradise/Tweak/Makefile new file mode 100644 index 0000000..ecd1d7f --- /dev/null +++ b/Paradise/Tweak/Makefile @@ -0,0 +1,26 @@ +export ARCHS = arm64 arm64e +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +TWEAK_NAME = Paradise + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +dtoim = $(foreach d,$(1),-I$(d)) +_IMPORTS = $(shell /bin/ls -d ./*/) +_IMPORTS = $(shell /bin/ls -d ./PARADISE/) +_IMPORTS = $(shell /bin/ls -d ./PARADISE/*/) +_IMPORTS += $(shell /bin/ls -d ./PARADISE/*/*/) +_IMPORTS += $(shell /bin/ls -d ./PARADISE/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./PARADISE/*/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./) +IMPORTS = -I$./PARADISE $(call dtoim, $(_IMPORTS)) + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations -Wno-unused-variable -Wno-error -Wno-unused-function -Wall $(IMPORTS) +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = SpringBoardServices Preferences OnBoardingKit + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Paradise/Tweak/PARADISE/AppData/DataViewController.h b/Paradise/Tweak/PARADISE/AppData/DataViewController.h new file mode 100644 index 0000000..7a7800a --- /dev/null +++ b/Paradise/Tweak/PARADISE/AppData/DataViewController.h @@ -0,0 +1,44 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPreferences.h" +#import "BlurBaseView.h" +#import "IconCell.h" +#import "AccessoriesCell.h" +#import "../../Headers.h" +#import "ParadiseManager.h" +#import "ParadiseSettingViewController.h" +#import "UninstallAppsViewController.h" +#import "AccessoriesColourCell.h" + +@interface DataViewController : UIViewController { + SBIconView *iconVieww; +} +-(instancetype)initWithIconView:(id)iconView imgTitle:(NSString*)title iconID:(NSString*)iconID; +@property (nonatomic, retain) BlurBaseView *baseView; +@property (nonatomic, retain) UIView *headerView; +@property (nonatomic, retain) UIImageView *appImage; +@property (nonatomic, retain) UILabel *appLabel; +@property (nonatomic, retain) UILabel *versionLabel; +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *listArray; +@property (nonatomic, retain) NSArray *iconArray; +@property (nonatomic, strong) ParadiseManager *paradiseManager; +@property (nonatomic, strong) NSString *version; +@property (nonatomic, strong) NSString *bundleIdentifier; +@property (nonatomic, strong) NSString *appName; +@property (nonatomic, strong) NSURL *bundleURL; +@property (nonatomic, strong) NSURL *dataContainerURL; +@property (nonatomic, assign) NSInteger diskUsage; +@property (nonatomic, strong) NSString *diskUsageString; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *toolsArray; +@property (nonatomic, retain) UIButton *menuButton; +@property (nonatomic, retain) UIButton *settingButton; +@property (nonatomic, retain) UILabel *accessoriesLabel; +@property (nonatomic, retain) UILabel *infoLabel; + +@property (nonatomic, retain) NSString *lockButton; + + +@property (nonatomic, strong) NSString *iconID; +@end diff --git a/Paradise/Tweak/PARADISE/AppData/DataViewController.m b/Paradise/Tweak/PARADISE/AppData/DataViewController.m new file mode 100644 index 0000000..4f6535a --- /dev/null +++ b/Paradise/Tweak/PARADISE/AppData/DataViewController.m @@ -0,0 +1,785 @@ +#import "DataViewController.h" + +#define MAIN_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width +#define MAIN_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height + +static UIFontDescriptor *descriptor; +static NSInteger colourPickerIndex = 0; + +static NSString *getAppName(NSString *BID){ + SBApplication *app = [[NSClassFromString(@"SBApplicationController") sharedInstance] applicationWithBundleIdentifier:BID]; + return app.displayName; +} + + +@implementation DataViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + descriptor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:appdataCustomFont error:nil]; + + self.view.backgroundColor = UIColor.clearColor; + [self layoutBaseView]; + [self layoutHeaderView]; + [self layoutTableView]; + [self layoutCollectionView]; +} + + +-(instancetype)initWithIconView:(SBIconView*)iconView imgTitle:(NSString*)imgTitle iconID:(NSString*)iconID{ + iconVieww = iconView; + SBIcon *icon = iconVieww.icon; + + self.bundleIdentifier = icon.applicationBundleID; + self.appName = imgTitle; + self.paradiseManager = [NSClassFromString(@"ParadiseManager") initForBundleIdentifier:self.bundleIdentifier]; + + self.iconID = iconID; + + NSLog(@"ParadiseDebuggg iconID:-%@", self.iconID); + + return self; +} + + +-(void)layoutBaseView { + loadPrefs(); + self.baseView = [[BlurBaseView alloc] init]; + self.baseView.layer.cornerRadius = bottomSheetCornerRadius; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self.view addSubview:self.baseView]; + + [self.baseView x:self.view.centerXAnchor]; + [self.baseView height:MAIN_SCREEN_HEIGHT *0.55]; + [self.baseView bottom:self.view.bottomAnchor padding:-10]; + [self.baseView leading:self.view.leadingAnchor padding:10]; + [self.baseView trailing:self.view.trailingAnchor padding:-10]; + +} + + +-(void)layoutHeaderView { + + self.headerView = [[UIView alloc] init]; + self.headerView.backgroundColor = UIColor.clearColor; + [self.baseView addSubview:self.headerView]; + + [self.headerView height:130]; + [self.headerView top:self.baseView.topAnchor padding:0]; + [self.headerView leading:self.baseView.leadingAnchor padding:0]; + [self.headerView trailing:self.baseView.trailingAnchor padding:0]; + + + self.menuButton = [[UIButton alloc] init]; + UIImage *menuImage = [UIImage systemImageNamed:@"ellipsis"]; + [self.menuButton setImage:menuImage forState:UIControlStateNormal]; + self.menuButton.transform = CGAffineTransformMakeRotation(M_PI / 2); + self.menuButton.tintColor = [UIColor appdataIconColor]; + self.menuButton.menu = [self appMenu]; + self.menuButton.showsMenuAsPrimaryAction = true; + [self.headerView addSubview:self.menuButton]; + + [self.menuButton size:CGSizeMake(40, 40)]; + [self.menuButton top:self.headerView.topAnchor padding:10]; + [self.menuButton trailing:self.headerView.trailingAnchor padding:-10]; + + + self.settingButton = [[UIButton alloc] init]; + UIImage *settingImage = [UIImage systemImageNamed:@"gear"]; + [self.settingButton setImage:settingImage forState:UIControlStateNormal]; + self.settingButton.tintColor = [UIColor appdataIconColor]; + [self.settingButton addTarget:self action:@selector(presentSettingVC) forControlEvents:UIControlEventTouchUpInside]; + [self.headerView addSubview:self.settingButton]; + + [self.settingButton size:CGSizeMake(40, 40)]; + [self.settingButton top:self.headerView.topAnchor padding:10]; + [self.settingButton leading:self.headerView.leadingAnchor padding:10]; + + + self.appImage = [[UIImageView alloc] init]; + self.appImage.image = iconVieww.iconImageSnapshot; + self.appImage.layer.cornerRadius = 10; + self.appImage.clipsToBounds = true; + [self.headerView addSubview:self.appImage]; + + [self.appImage size:CGSizeMake(65, 65)]; + [self.appImage top:self.headerView.topAnchor padding:30]; + [self.appImage x:self.headerView.centerXAnchor]; + + + self.appLabel = [[UILabel alloc] init]; + if (toggleAppdataCustomFont) { + self.appLabel.font = [UIFont fontWithDescriptor:descriptor size:18]; + } else { + self.appLabel.font = [UIFont boldSystemFontOfSize:18]; + } + self.appLabel.textAlignment = NSTextAlignmentCenter; + self.appLabel.text = self.appName; + self.appLabel.textColor = [UIColor appdataFontColor]; + [self.headerView addSubview:self.appLabel]; + + [self.appLabel top:self.appImage.bottomAnchor padding:5]; + [self.appLabel x:self.headerView.centerXAnchor]; + +} + + +-(void)layoutTableView { + + self.listArray = [[NSArray alloc] initWithObjects:@"BundleID", @"Bundle", @"Container", nil]; + + self.tableView = [[UITableView alloc] init]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + self.tableView.showsVerticalScrollIndicator = NO; + if (toggleAppdataColour) { + [self.tableView setSeparatorColor:[[TDTweakManager sharedInstance] colourForKey:@"appdataSeparatorColour" defaultValue:@"FFFFFF" ID:BID]]; + } + [self.baseView addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + + self.tableView.translatesAutoresizingMaskIntoConstraints = NO; + [self.tableView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor].active = YES; + [self.tableView.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10].active = YES; + [self.tableView.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + [self.tableView.bottomAnchor constraintEqualToAnchor:self.baseView.bottomAnchor constant:-5].active = YES; + + self.tableView.tableFooterView = [UIView new]; + +} + + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.listArray.count; +} + + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + + IconCell *cell = [tableView dequeueReusableCellWithIdentifier:@"iconCell"]; + + if (cell == nil) { + cell = [[IconCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"iconCell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = [self.listArray objectAtIndex:indexPath.row]; + + + if (indexPath.row == 0) { // Bundle ID + + cell.subtitleLabel.text = self.bundleIdentifier; + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/copy.png"]; + + } else if (indexPath.row == 1) { // Bundle path + + cell.subtitleLabel.text = self.paradiseManager.bundlePATH; + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/folder.png"]; + + } else if (indexPath.row == 2) { // Container path + + cell.subtitleLabel.text = self.paradiseManager.containerPATH; + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/folder.png"]; + cell.separatorInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, CGFLOAT_MAX); + + if ([cell.subtitleLabel.text isEqualToString:@"(null)"]) { + cell.subtitleLabel.text = @"No container available"; + } + } + + return cell; + +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + [self invokeHapticFeedback]; + + switch (indexPath.row) { + + case 0: { // Copy bundle ID + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = self.bundleIdentifier; + + NSString *messageString = [NSString stringWithFormat:@"The bundle ID for %@ was saved to your clipboard.", self.bundleIdentifier]; + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Paradise" message:messageString preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + + break; + } + + case 1: { // Open bundle in filza + + UIApplication *filza = [UIApplication sharedApplication]; + NSString *appPath = [NSString stringWithFormat:@"filza:/%@", self.paradiseManager.bundlePATH]; + NSURL *URL = [NSURL URLWithString:appPath]; + [filza openURL:URL options:@{} completionHandler:nil]; + + break; + } + + case 2: { // Open container in filza + + UIApplication *filza = [UIApplication sharedApplication]; + NSString *appPath = [NSString stringWithFormat:@"filza:/%@", self.paradiseManager.containerPATH]; + NSURL *URL = [NSURL URLWithString:appPath]; + [filza openURL:URL options:@{} completionHandler:nil]; + + break; + } + default: break; + } + +} + + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 70; +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + + +-(void)invokeHapticFeedback { + if (toggleAppdataHaptic) { + + if (appdataHapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (appdataHapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (appdataHapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesEnded:touches withEvent:event]; + if (touches.anyObject.view == self.view) { + [self dismissViewControllerAnimated:YES completion:nil]; + [self invokeHapticFeedback]; + } else if (touches.anyObject.view != self.baseView) { + [self.baseView resignFirstResponder]; + } +} + + +-(UIMenu *)appMenu { + + UIAction *copyAction = [UIAction actionWithTitle:@"Copy App Info" image:[UIImage systemImageNamed:@"doc.plaintext.fill"] identifier:nil handler:^(UIAction *action) { + + NSString *appInfo = [NSString stringWithFormat:@"App Name: %@ \n\nVersion: %@ \n\nSize: %@ \n\nBundleID: %@ \n\nBundle Path: %@ \n\nContainer Path: %@", self.appLabel.text, self.paradiseManager.version, self.paradiseManager.diskUsageString, self.bundleIdentifier, self.paradiseManager.bundlePATH, self.paradiseManager.containerPATH]; + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = appInfo; + [self showAlertWithTitle:@"App Info" message:@"The app information have been added to your clipboard."]; + }]; + + + UIAction *exportAction = [UIAction actionWithTitle:@"Export App Info" image:[UIImage systemImageNamed:@"square.and.arrow.up.fill"] identifier:nil handler:^(UIAction *action) { + + NSString *appInfo = [NSString stringWithFormat:@"App Name: %@ \n\nVersion: %@ \n\nSize: %@ \n\nBundleID: %@ \n\nBundle Path: %@ \n\nContainer Path: %@", self.appLabel.text, self.paradiseManager.version, self.paradiseManager.diskUsageString, self.bundleIdentifier, self.paradiseManager.bundlePATH, self.paradiseManager.containerPATH]; + [self exportListWithString:appInfo]; + }]; + + + UIAction *tutorialAction = [UIAction actionWithTitle:@"Show Tutorial" image:[UIImage systemImageNamed:@"questionmark.circle.fill"] identifier:nil handler:^(UIAction *action) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"ShowTutorialNotification" object:self]; + [self dismissViewControllerAnimated:YES completion:nil]; + }]; + + return [UIMenu menuWithTitle:@"App Settings" children:@[copyAction, exportAction, tutorialAction]]; +} + + +-(void)layoutCollectionView { + + UIView *header = [[TDView alloc] init]; + header.frame = CGRectMake(0, 0, self.tableView.bounds.size.width, 155); + header.backgroundColor = UIColor.clearColor; + self.tableView.tableHeaderView = header; + + + self.accessoriesLabel = [[UILabel alloc] init]; + if (toggleAppdataCustomFont) { + self.accessoriesLabel.font = [UIFont fontWithDescriptor:descriptor size:16]; + } else { + self.accessoriesLabel.font = [UIFont boldSystemFontOfSize:16]; + } + self.accessoriesLabel.textAlignment = NSTextAlignmentLeft; + self.accessoriesLabel.text = @"Accessories"; + self.accessoriesLabel.textColor = [UIColor appdataFontColor]; + [header addSubview:self.accessoriesLabel]; + + [self.accessoriesLabel top:header.topAnchor padding:5]; + [self.accessoriesLabel leading:header.leadingAnchor padding:10]; + + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[AccessoriesCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.collectionView registerClass:[AccessoriesColourCell class] forCellWithReuseIdentifier:@"ColourCell"]; + [header addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + [self.collectionView top:self.accessoriesLabel.bottomAnchor padding:5]; + [self.collectionView leading:header.leadingAnchor padding:10]; + [self.collectionView trailing:header.trailingAnchor padding:-10]; + [self.collectionView height:80]; + + + self.infoLabel = [[UILabel alloc] init]; + if (toggleAppdataCustomFont) { + self.infoLabel.font = [UIFont fontWithDescriptor:descriptor size:16]; + } else { + self.infoLabel.font = [UIFont boldSystemFontOfSize:16]; + } + self.infoLabel.textAlignment = NSTextAlignmentLeft; + self.infoLabel.text = [NSString stringWithFormat:@"%@ Info", self.appName]; + self.infoLabel.textColor = [UIColor appdataFontColor]; + [header addSubview:self.infoLabel]; + + [self.infoLabel top:self.collectionView.bottomAnchor padding:25]; + [self.infoLabel leading:header.leadingAnchor padding:10]; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return 10; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + + if (indexPath.row == 2) { + + AccessoriesColourCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ColourCell" forIndexPath:indexPath]; + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = @"Label Colour"; + + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.iconID]; + NSData *decodedData = [[TDTweakManager sharedInstance] objectForKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + UIColor *savedColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + + if (decodedData != nil) { + cell.colourView.backgroundColor = savedColour; + } else { + cell.colourView.backgroundColor = UIColor.whiteColor; + } + + return cell; + + } else if (indexPath.row == 3) { + + AccessoriesColourCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ColourCell" forIndexPath:indexPath]; + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = @"Label BG \nColour"; + + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.iconID]; + NSData *decodedData = [[TDTweakManager sharedInstance] objectForKey:keyBG defaultValue:nil ID:@"com.TitanD3v.ParadisePrefs"]; + UIColor *savedColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + + if (decodedData) { + cell.colourView.backgroundColor = savedColour; + } else { + cell.colourView.backgroundColor = UIColor.whiteColor; + } + + return cell; + + } else { + + AccessoriesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + if (indexPath.row == 0) { + + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/icon-editor.png"]; + cell.titleLabel.text = @"Icon Editor"; + + } else if (indexPath.row == 1) { + + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/rename.png"]; + cell.titleLabel.text = @"Rename"; + + } else if (indexPath.row == 4) { + + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/offload.png"]; + cell.titleLabel.text = @"Offload App"; + + } else if (indexPath.row == 5) { + + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/uninstall.png"]; + cell.titleLabel.text = @"Uninstall App"; + + } else if (indexPath.row == 6) { + + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/uninstall.png"]; + cell.titleLabel.text = @"Uninstall \nMulti Apps"; + + } else if (indexPath.row == 7) { + + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png"]; + cell.titleLabel.text = @"Reset Name"; + + } else if (indexPath.row == 8) { + + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png"]; + cell.titleLabel.text = @"Reset Label \nColour"; + + } else if (indexPath.row == 9) { + + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png"]; + cell.titleLabel.text = @"Reset Label \nBG Colour"; + + } + + return cell; + + } + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + return CGSizeMake(130, 80); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + [self invokeHapticFeedback]; + [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES]; + + if (indexPath.row == 0) { + + [[TDTweakManager sharedInstance] setObject:self.appName forKey:@"paradiseAppName" ID:@"com.TitanD3v.ParadiseEditor"]; + [[TDTweakManager sharedInstance] setObject:self.bundleIdentifier forKey:@"paradiseBundleID" ID:@"com.TitanD3v.ParadiseEditor"]; + [[TDUtilities sharedInstance] launchApp:@"com.TitanD3v.Paradise"]; + + } else if (indexPath.row == 1) { + + NSString *messageString = [NSString stringWithFormat:@"The name for %@ will be changed to entered name.", self.appName]; + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Paradise" message:messageString preferredStyle:UIAlertControllerStyleAlert]; + + [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.placeholder = @"Enter New Name"; + }]; + + UIAlertAction* changeAction = [UIAlertAction actionWithTitle:@"Change" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + NSString *newAppName = alert.textFields.firstObject.text; + NSString *keyT = [NSString stringWithFormat:@"%@-Title", self.iconID]; + [[TDTweakManager sharedInstance] setObject:newAppName forKey:keyT ID:@"com.TitanD3v.ParadisePrefs"]; + self.infoLabel.text = [NSString stringWithFormat:@"%@ Info", alert.textFields.firstObject.text]; + self.appLabel.text = alert.textFields.firstObject.text; + [iconVieww _updateLabel]; + }]; + + UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + }]; + + + [alert addAction:changeAction]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; + + } else if (indexPath.row == 2) { + + colourPickerIndex = 0; + [self presentColourPickerVC]; + + } else if (indexPath.row == 3) { + + colourPickerIndex = 1; + [self presentColourPickerVC]; + + } else if (indexPath.row == 4) { + + NSString *messageString = [NSString stringWithFormat:@"Are you sure you want to offload %@?", self.appName]; + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Paradise" message:messageString preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *offloadAction = [UIAlertAction actionWithTitle:@"Offload" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + [NSClassFromString(@"IXAppInstallCoordinator") demoteAppToPlaceholderWithBundleID:self.bundleIdentifier forReason:1 waitForDeletion:YES completion:^{ + + dispatch_async(dispatch_get_main_queue(), ^{ + [self dismissViewControllerAnimated:YES completion:nil]; + }); + }]; + + }]; + + UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + }]; + + + [alert addAction:offloadAction]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; + + } else if (indexPath.row == 5) { + + [NSClassFromString(@"IXAppInstallCoordinator") uninstallAppWithBundleID:self.bundleIdentifier requestUserConfirmation:YES waitForDeletion:YES completion:^{ + + dispatch_async(dispatch_get_main_queue(), ^{ + [self dismissViewControllerAnimated:YES completion:nil]; + }); + }]; + + + } else if (indexPath.row == 6) { + + [self presentUninstallAppsVC]; + + } else if (indexPath.row == 7) { // (SGWC) need to fix label isn't showing default app name when reset + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Paradise" message:@"Are you sure you want to reset Application name to default name?" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* resetAction = [UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + NSString *keyT = [NSString stringWithFormat:@"%@-Title", self.iconID]; + [[TDTweakManager sharedInstance] setObject:@"" forKey:keyT ID:@"com.TitanD3v.ParadisePrefs"]; + self.appName = getAppName(self.iconID); + self.infoLabel.text = [NSString stringWithFormat:@"%@ Info", self.appName]; + self.appLabel.text = self.appName; + [iconVieww _updateLabel]; + [self.tableView reloadData]; + + }]; + + UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + }]; + + [alert addAction:resetAction]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; + +} else if (indexPath.row == 8) { // (SGWC) here you need to reset label colour + + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.iconID]; + //[[TDTweakManager sharedInstance] setObject:@"" forKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + [[TDTweakManager sharedInstance] removeObjectForKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + [iconVieww _updateLabel]; + + [self showAlertWithTitle:@"Paradise" message:@"Label colour has been Reset successfully"]; + + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + AccessoriesColourCell *cell = (AccessoriesColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath2]; + cell.colourView.backgroundColor = UIColor.whiteColor; + +} else if (indexPath.row == 9) { // (SGWC) here you need to reset label background colour + + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.iconID]; + //[[TDTweakManager sharedInstance] setObject:@"" forKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + [[TDTweakManager sharedInstance] removeObjectForKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + [iconVieww _updateLabel]; + + [self showAlertWithTitle:@"Paradise" message:@"Label background colour has been Reset successfully"]; + + NSIndexPath *_indexPath3 = [NSIndexPath indexPathForItem:3 inSection:0]; + AccessoriesColourCell *cell = (AccessoriesColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath3]; + cell.colourView.backgroundColor = UIColor.whiteColor; + +} + +} + +-(void)presentColourPickerVC { + + UIColor *previewColour; + + if (colourPickerIndex == 0) { + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + AccessoriesColourCell *cell = (AccessoriesColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath2]; + previewColour = cell.colourView.backgroundColor; + } else if (colourPickerIndex == 1) { + NSIndexPath *_indexPath3 = [NSIndexPath indexPathForItem:3 inSection:0]; + AccessoriesColourCell *cell = (AccessoriesColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath3]; + previewColour = cell.colourView.backgroundColor; + } + + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + colourPickerVC.selectedColor = previewColour; + [self presentViewController:colourPickerVC animated:YES completion:nil]; + +} + +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + + UIColor *cpSelectedColour = viewController.selectedColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:cpSelectedColour]; + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.iconID]; + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.iconID]; + + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + NSIndexPath *_indexPath3 = [NSIndexPath indexPathForItem:3 inSection:0]; + + if (colourPickerIndex == 0) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + AccessoriesColourCell *cell = (AccessoriesColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath2]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 0 :-%@", encodedData); + } else if (colourPickerIndex == 1) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + AccessoriesColourCell *cell = (AccessoriesColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath3]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 1 :-%@", encodedData); + } + + [iconVieww _updateLabel]; + +} + +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + + UIColor *cpSelectedColour = viewController.selectedColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:cpSelectedColour]; + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.iconID]; + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.iconID]; + + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + NSIndexPath *_indexPath3 = [NSIndexPath indexPathForItem:3 inSection:0]; + + if (colourPickerIndex == 0) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + AccessoriesColourCell *cell = (AccessoriesColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath2]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 0 :-%@", encodedData); + } else if (colourPickerIndex == 1) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + AccessoriesColourCell *cell = (AccessoriesColourCell *)[self.collectionView cellForItemAtIndexPath:_indexPath3]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 1 :-%@", encodedData); + } + + [iconVieww _updateLabel]; + +} + +-(void)presentUninstallAppsVC { + + UninstallAppsViewController *uvc = [[UninstallAppsViewController alloc] init]; + uvc.modalInPresentation = YES; + [self presentViewController:uvc animated:YES completion:nil]; +} + + +-(void)presentSettingVC { + + [self invokeHapticFeedback]; + + ParadiseSettingViewController *svc = [[ParadiseSettingViewController alloc] init]; + svc.modalInPresentation = YES; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:svc]; + [self presentViewController:navController animated:YES completion:nil]; + +} + + +-(void)showAlertWithTitle:(NSString *)title message:(NSString *)message { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [iconVieww _updateLabel]; + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + +} + + +-(void)exportListWithString:(NSString *)info { + + NSArray *dataToShare = @[info]; + + UIActivityViewController *controller = [[UIActivityViewController alloc]initWithActivityItems:dataToShare applicationActivities:nil]; + controller.excludedActivityTypes = @[UIActivityTypeAirDrop]; + [self presentViewController:controller animated:YES completion:nil]; + + [controller setCompletionWithItemsHandler:^(UIActivityType _Nullable activityType, BOOL completed, NSArray * _Nullable returnedItems, NSError * _Nullable activityError) { + + }]; + +} + + +- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath { + + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; + +} + + +- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath { + + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; + +} + +@end diff --git a/Paradise/Tweak/PARADISE/AppLibrary/AppLibraryViewController.h b/Paradise/Tweak/PARADISE/AppLibrary/AppLibraryViewController.h new file mode 100644 index 0000000..c21cc0e --- /dev/null +++ b/Paradise/Tweak/PARADISE/AppLibrary/AppLibraryViewController.h @@ -0,0 +1,25 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPreferences.h" +#import "BlurBaseView.h" +#import "LibraryCell.h" +#import "../../Headers.h" +#import "ColourCell.h" + +@interface AppLibraryViewController : UIViewController + +@property (nonatomic, retain) BlurBaseView *baseView; +@property (nonatomic, retain) UIView *headerView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *listArray; +@property (nonatomic, retain) NSArray *iconArray; + +@property (nonatomic, retain) SBIconView *iconView; +@property (nonatomic, retain) NSString *imgHash; +@property (nonatomic, retain) NSString *imgTitle; + +-(instancetype)initWithHash:(NSString*)imgHash imgTitle:(NSString*)title iconView:(SBIconView*)iconView; + +@end diff --git a/Paradise/Tweak/PARADISE/AppLibrary/AppLibraryViewController.m b/Paradise/Tweak/PARADISE/AppLibrary/AppLibraryViewController.m new file mode 100644 index 0000000..d28998f --- /dev/null +++ b/Paradise/Tweak/PARADISE/AppLibrary/AppLibraryViewController.m @@ -0,0 +1,454 @@ +#import "AppLibraryViewController.h" + +static UIFontDescriptor *descriptor; +static NSInteger colourPickerIndex = 0; + +@implementation AppLibraryViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + descriptor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:appdataCustomFont error:nil]; + + self.view.backgroundColor = UIColor.clearColor; + [self layoutBaseView]; + [self layoutHeaderView]; + [self layoutTableView]; +} + +-(instancetype)initWithHash:(NSString*)imgHash imgTitle:(NSString*)imgTitle iconView:(SBIconView*)iconView{ + + self.imgHash = imgHash; + self.iconView = iconView; + self.imgTitle = imgTitle; + NSLog(@"ParadiseDebug initWithHash self.imgHash:-%@, iconView:-%@" ,self.imgHash, self.iconView); + return self; + +} + +-(void)layoutBaseView { + + self.baseView = [[BlurBaseView alloc] init]; + self.baseView.layer.cornerRadius = bottomSheetCornerRadius; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self.view addSubview:self.baseView]; + + [self.baseView x:self.view.centerXAnchor]; + [self.baseView height:MAIN_SCREEN_HEIGHT *0.40]; + [self.baseView bottom:self.view.bottomAnchor padding:-10]; + [self.baseView leading:self.view.leadingAnchor padding:10]; + [self.baseView trailing:self.view.trailingAnchor padding:-10]; + +} + + +-(void)layoutHeaderView { + + self.headerView = [[UIView alloc] init]; + self.headerView.backgroundColor = UIColor.clearColor; + [self.baseView addSubview:self.headerView]; + + [self.headerView height:130]; + [self.headerView top:self.baseView.topAnchor padding:0]; + [self.headerView leading:self.baseView.leadingAnchor padding:0]; + [self.headerView trailing:self.baseView.trailingAnchor padding:0]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = self.iconView.iconImageSnapshot; + if(!self.iconImage.image) { + self.iconImage.image = [[UIImage systemImageNamed:@"square.grid.2x2.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + self.iconImage.layer.cornerRadius = 10; + self.iconImage.clipsToBounds = true; + self.iconImage.tintColor = [UIColor appdataIconColor]; + [self.headerView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(65, 65)]; + [self.iconImage top:self.headerView.topAnchor padding:10]; + [self.iconImage x:self.headerView.centerXAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + if (toggleAppdataCustomFont) { + self.titleLabel.font = [UIFont fontWithDescriptor:descriptor size:14]; + } else { + self.titleLabel.font = [UIFont boldSystemFontOfSize:14]; + } + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.text = self.imgTitle; + self.titleLabel.textColor = [UIColor appdataFontColor]; + [self.headerView addSubview:self.titleLabel]; + + [self.titleLabel top:self.iconImage.bottomAnchor padding:5]; + [self.titleLabel x:self.headerView.centerXAnchor]; + +} + + +-(void)layoutTableView { + + self.listArray = [[NSArray alloc] initWithObjects:@"Rename", @"Label Colour", @"Label Background Colour", @"Reset Name", @"Reset Label Colour", @"Reset Label Background Colour", nil]; + + self.tableView = [[UITableView alloc] init]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + self.tableView.showsVerticalScrollIndicator = NO; + if (toggleAppdataColour) { + [self.tableView setSeparatorColor:[[TDTweakManager sharedInstance] colourForKey:@"appdataSeparatorColour" defaultValue:@"FFFFFF" ID:BID]]; + } + [self.baseView addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + + self.tableView.translatesAutoresizingMaskIntoConstraints = NO; + [self.tableView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor].active = YES; + [self.tableView.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10].active = YES; + [self.tableView.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + [self.tableView.bottomAnchor constraintEqualToAnchor:self.baseView.bottomAnchor constant:-5].active = YES; + + self.tableView.tableFooterView = [UIView new]; + +} + + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.listArray.count; +} + + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + + if (indexPath.row == 1) { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"colourCell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"colourCell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = [self.listArray objectAtIndex:indexPath.row]; + + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.imgHash]; + NSData *decodedData = [[TDTweakManager sharedInstance] objectForKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + UIColor *savedColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + + if (decodedData != nil) { + cell.colourView.backgroundColor = savedColour; + } else { + cell.colourView.backgroundColor = UIColor.whiteColor; + } + + return cell; + + } else if (indexPath.row == 2) { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"colourCell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"colourCell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = [self.listArray objectAtIndex:indexPath.row]; + + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.imgHash]; + NSData *decodedData = [[TDTweakManager sharedInstance] objectForKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + UIColor *savedColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + + if (decodedData != nil) { + cell.colourView.backgroundColor = savedColour; + } else { + cell.colourView.backgroundColor = UIColor.whiteColor; + } + + return cell; + + } else { + + + LibraryCell *cell = [tableView dequeueReusableCellWithIdentifier:@"iconCell"]; + + if (cell == nil) { + cell = [[LibraryCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"iconCell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = [self.listArray objectAtIndex:indexPath.row]; + + if (indexPath.row == 0) { // Rename + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/rename.png"]; + } else if (indexPath.row == 3) { // Reset label + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png"]; + } else if (indexPath.row == 4) { // Reset label colour + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png"]; + } else if (indexPath.row == 5) { // Reset label background colour + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png"]; + cell.separatorInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, CGFLOAT_MAX); + + } + + return cell; + + } + +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + [self invokeHapticFeedback]; + + if (indexPath.row == 0) { // Rename + + [self renameLabel]; + + } else if (indexPath.row == 1) { // Label colour + + colourPickerIndex = 0; + [self presentColourPickerVC]; + + } else if (indexPath.row == 2) { // Label Background colour + + colourPickerIndex = 1; + [self presentColourPickerVC]; + + } else if (indexPath.row == 3) { // Reset label + + NSString *keyT = [NSString stringWithFormat:@"%@-Title", self.imgHash]; + [[TDTweakManager sharedInstance] setObject:@"" forKey:keyT ID:@"com.TitanD3v.ParadisePrefs"]; + [self showAlertWithTitle:@"Paradise" message:@"Label has been Reset successfully"]; + + } else if (indexPath.row == 4) { // Reset label colour + + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.imgHash]; + [[TDTweakManager sharedInstance] removeObjectForKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + [self.iconView _updateLabel]; + [self showAlertWithTitle:@"Paradise" message:@"Label colour has been Reset successfully"]; + + NSIndexPath *_indexPath1 = [NSIndexPath indexPathForItem:1 inSection:0]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath1]; + cell.colourView.backgroundColor = UIColor.whiteColor; + + } else if (indexPath.row == 5) { // Reset label background colour + + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.imgHash]; + [[TDTweakManager sharedInstance] removeObjectForKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + [self.iconView _updateLabel]; + [self showAlertWithTitle:@"Paradise" message:@"Label background colour has been Reset successfully"]; + + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath2]; + cell.colourView.backgroundColor = UIColor.whiteColor; + + } + + [self.iconView _updateLabel]; + +} + + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 50; +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + + +-(void)invokeHapticFeedback { + if (toggleAppdataHaptic) { + + if (appdataHapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (appdataHapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (appdataHapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesEnded:touches withEvent:event]; + if (touches.anyObject.view == self.view) { + [self dismissViewControllerAnimated:YES completion:nil]; + [self invokeHapticFeedback]; + } else if (touches.anyObject.view != self.baseView) { + [self.baseView resignFirstResponder]; + } +} + + +-(void)showAlertWithTitle:(NSString *)title message:(NSString *)message { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Okay!" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self.iconView _updateLabel]; + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + +} + +-(void)renameLabel{ + + UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Change Label Title" + message:@"\nEnter New Title" + preferredStyle:UIAlertControllerStyleAlert]; + + [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.placeholder = @"Enter New Title"; + }]; + + UIAlertAction* chngButton = [UIAlertAction actionWithTitle:@"Change" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + + NSString *newTitle = alert.textFields.firstObject.text; + NSString *keyT = [NSString stringWithFormat:@"%@-Title", self.imgHash]; + + self.titleLabel.text = newTitle; + [self.tableView reloadData]; + + [[TDTweakManager sharedInstance] setObject:newTitle forKey:keyT ID:@"com.TitanD3v.ParadisePrefs"]; + [self.iconView _updateLabel]; + + }]; + + UIAlertAction* clButton = [UIAlertAction actionWithTitle:@"Cancel" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + + [alert dismissViewControllerAnimated:YES completion:nil]; + + }]; + + [alert addAction:chngButton]; + [alert addAction:clButton]; + [self presentViewController:alert animated:YES completion:nil]; +} + + +-(void)presentColourPickerVC { // (SGWC) index == 0 for label colour, 1 for label background colour on lib only + + UIColor *previewColour; + + if (colourPickerIndex == 0) { + NSIndexPath *_indexPath1 = [NSIndexPath indexPathForItem:1 inSection:0]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath1]; + previewColour = cell.colourView.backgroundColor; + } else if (colourPickerIndex == 1) { + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath2]; + previewColour = cell.colourView.backgroundColor; + } + + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + colourPickerVC.selectedColor = previewColour; + [self presentViewController:colourPickerVC animated:YES completion:nil]; + +} + +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + + UIColor *cpSelectedColour = viewController.selectedColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:cpSelectedColour]; + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.imgHash]; + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.imgHash]; + + NSIndexPath *_indexPath1 = [NSIndexPath indexPathForItem:1 inSection:0]; + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + + if (colourPickerIndex == 0) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath1]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 0 :-%@", encodedData); + } else if (colourPickerIndex == 1) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath2]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 1 :-%@", encodedData); + } + + [self.iconView _updateLabel]; + +} + +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + + UIColor *cpSelectedColour = viewController.selectedColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:cpSelectedColour]; + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.imgHash]; + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.imgHash]; + + NSIndexPath *_indexPath1 = [NSIndexPath indexPathForItem:1 inSection:0]; + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + + if (colourPickerIndex == 0) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath1]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 0 :-%@", encodedData); + } else if (colourPickerIndex == 1) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath2]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 1 :-%@", encodedData); + } + + [self.iconView _updateLabel]; + +} +@end diff --git a/Paradise/Tweak/PARADISE/BlurEffects/BlurBaseView.h b/Paradise/Tweak/PARADISE/BlurEffects/BlurBaseView.h new file mode 100644 index 0000000..08a649f --- /dev/null +++ b/Paradise/Tweak/PARADISE/BlurEffects/BlurBaseView.h @@ -0,0 +1,7 @@ +#import +#import "GlobalPreferences.h" + +@interface BlurBaseView : UIView +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (nonatomic, retain) UIImageView *wallpaperImage; +@end diff --git a/Paradise/Tweak/PARADISE/BlurEffects/BlurBaseView.m b/Paradise/Tweak/PARADISE/BlurEffects/BlurBaseView.m new file mode 100644 index 0000000..cbd7623 --- /dev/null +++ b/Paradise/Tweak/PARADISE/BlurEffects/BlurBaseView.m @@ -0,0 +1,125 @@ +#import "BlurBaseView.h" + +@implementation BlurBaseView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + loadPrefs(); + + self.blurEffectView = [[UIVisualEffectView alloc] initWithFrame:CGRectZero]; + [self insertSubview:self.blurEffectView atIndex:0]; + + + self.blurEffectView.translatesAutoresizingMaskIntoConstraints = false; + [self.blurEffectView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0].active = YES; + [self.blurEffectView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0].active = YES; + [self.blurEffectView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:0].active = YES; + [self.blurEffectView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0].active = YES; + + if (!toggleAppdataColour) { + + if([appdataAppearance isEqualToString:@"appdataLight"]) { + + if (toggleBlurEffect) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + self.backgroundColor = UIColor.clearColor; + } else { + self.blurEffectView.alpha = 0; + self.backgroundColor = UIColor.whiteColor; + } + } else if([appdataAppearance isEqualToString:@"appdataDark"]) { + + if (toggleBlurEffect) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + self.backgroundColor = UIColor.clearColor; + } else { + self.blurEffectView.alpha = 0; + self.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.12 alpha: 1.00]; + } + } else if([appdataAppearance isEqualToString:@"appdataDynamic"]) { + + if (toggleBlurEffect) { + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + self.backgroundColor = UIColor.clearColor; + } else { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + self.backgroundColor = UIColor.clearColor; + } + + } else { + + self.blurEffectView.alpha = 0; + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.12 alpha: 1.00]; + } else { + self.backgroundColor = UIColor.whiteColor; + } + + } + + } + + } else { + + self.blurEffectView.alpha = 0; + self.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"appdataBackgroundColour" defaultValue:@"FFFFFF" ID:BID]; + + } + + + if (toggleAppdataBackgroundImage) { + + self.wallpaperImage = [[UIImageView alloc] init]; + self.wallpaperImage.image = [UIImage imageWithData:appdataBackgroundImage]; + self.wallpaperImage.contentMode = UIViewContentModeScaleAspectFill; + [self addSubview:self.wallpaperImage]; + [self.wallpaperImage fill]; + + self.blurEffectView.alpha = 0; + self.backgroundColor = UIColor.clearColor; + } + + } + + return self; + +} + + +- (void)traitCollectionDidChange:(UITraitCollection *) previousTraitCollection { + + if (!toggleAppdataColour) { + if([appdataAppearance isEqualToString:@"appdataDynamic"]) { + + if (toggleBlurEffect) { + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + self.backgroundColor = UIColor.clearColor; + } else { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + self.backgroundColor = UIColor.clearColor; + } + + } else { + + self.blurEffectView.alpha = 0; + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.12 alpha: 1.00]; + } else { + self.backgroundColor = UIColor.whiteColor; + } + + } + + } + } + +} + +@end diff --git a/Paradise/Tweak/PARADISE/Cells/AccessoriesCell.h b/Paradise/Tweak/PARADISE/Cells/AccessoriesCell.h new file mode 100644 index 0000000..417892d --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/AccessoriesCell.h @@ -0,0 +1,10 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPreferences.h" + +@interface AccessoriesCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (nonatomic, retain) UIImageView *accessoriesImage; +@property (nonatomic, retain) UILabel *titleLabel; +@end \ No newline at end of file diff --git a/Paradise/Tweak/PARADISE/Cells/AccessoriesCell.m b/Paradise/Tweak/PARADISE/Cells/AccessoriesCell.m new file mode 100644 index 0000000..0b5fbb0 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/AccessoriesCell.m @@ -0,0 +1,109 @@ +#import "AccessoriesCell.h" + +static UIFontDescriptor *descriptor; + +@implementation AccessoriesCell + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + loadPrefs(); + descriptor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:appdataCustomFont error:nil]; + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = UIColor.clearColor; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.blurEffectView = [[UIVisualEffectView alloc] initWithFrame:CGRectZero]; + self.blurEffectView.alpha = 0.5; + [self.baseView insertSubview:self.blurEffectView atIndex:0]; + + [self.blurEffectView fill]; + + + self.accessoriesImage = [[UIImageView alloc] init]; + self.accessoriesImage.tintColor = [UIColor appdataIconColor]; + self.accessoriesImage.layer.cornerRadius = 15; + self.accessoriesImage.clipsToBounds = true; + [self.baseView addSubview:self.accessoriesImage]; + + [self.accessoriesImage size:CGSizeMake(30, 30)]; + [self.accessoriesImage top:self.baseView.topAnchor padding:10]; + [self.accessoriesImage x:self.baseView.centerXAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + if (toggleAppdataCustomFont) { + self.titleLabel.font = [UIFont fontWithDescriptor:descriptor size:12]; + } else { + self.titleLabel.font = [UIFont boldSystemFontOfSize:12]; + } + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = [UIColor appdataFontColor]; + self.titleLabel.numberOfLines = 2; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel top:self.accessoriesImage.bottomAnchor padding:5]; + [self.titleLabel leading:self.baseView.leadingAnchor padding:5]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-5]; + [self.titleLabel x:self.baseView.centerXAnchor]; + + + if (!toggleAppdataColour) { + if([appdataAppearance isEqualToString:@"appdataLight"]) { + + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + + } else if([appdataAppearance isEqualToString:@"appdataDark"]) { + + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + + } else if([appdataAppearance isEqualToString:@"appdataDynamic"]) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + } else { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + } + + } + + } else { + + self.blurEffectView.alpha = 0; + self.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"appdataCellColour" defaultValue:@"FFFFFF" ID:BID]; + + } + + + } + return self; +} + + +- (void)traitCollectionDidChange:(UITraitCollection *) previousTraitCollection { + + if (!toggleAppdataColour) { + if([appdataAppearance isEqualToString:@"appdataDynamic"]) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + } else { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + } + + } + } + +} + + +@end diff --git a/Paradise/Tweak/PARADISE/Cells/AccessoriesColourCell.h b/Paradise/Tweak/PARADISE/Cells/AccessoriesColourCell.h new file mode 100644 index 0000000..10b5792 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/AccessoriesColourCell.h @@ -0,0 +1,11 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPreferences.h" + +@interface AccessoriesColourCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (nonatomic, retain) UIImageView *accessoriesImage; +@property (nonatomic, retain) UIView *colourView; +@property (nonatomic, retain) UILabel *titleLabel; +@end \ No newline at end of file diff --git a/Paradise/Tweak/PARADISE/Cells/AccessoriesColourCell.m b/Paradise/Tweak/PARADISE/Cells/AccessoriesColourCell.m new file mode 100644 index 0000000..fe46d7d --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/AccessoriesColourCell.m @@ -0,0 +1,119 @@ +#import "AccessoriesColourCell.h" + +static UIFontDescriptor *descriptor; + +@implementation AccessoriesColourCell + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + loadPrefs(); + descriptor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:appdataCustomFont error:nil]; + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = UIColor.clearColor; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.blurEffectView = [[UIVisualEffectView alloc] initWithFrame:CGRectZero]; + self.blurEffectView.alpha = 0.5; + [self.baseView insertSubview:self.blurEffectView atIndex:0]; + + [self.blurEffectView fill]; + + + self.accessoriesImage = [[UIImageView alloc] init]; + self.accessoriesImage.image = [[UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/colour-picker.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.accessoriesImage.layer.cornerRadius = 15; + self.accessoriesImage.clipsToBounds = true; + [self.baseView addSubview:self.accessoriesImage]; + + [self.accessoriesImage size:CGSizeMake(30, 30)]; + [self.accessoriesImage top:self.baseView.topAnchor padding:10]; + [self.accessoriesImage x:self.baseView.centerXAnchor]; + + + self.colourView = [[UIView alloc] init]; + self.colourView.layer.cornerRadius = 10; + self.colourView.clipsToBounds = true; + [self.baseView addSubview:self.colourView]; + + [self.colourView size:CGSizeMake(20, 20)]; + [self.colourView x:self.accessoriesImage.centerXAnchor]; + [self.colourView y:self.accessoriesImage.centerYAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + if (toggleAppdataCustomFont) { + self.titleLabel.font = [UIFont fontWithDescriptor:descriptor size:12]; + } else { + self.titleLabel.font = [UIFont boldSystemFontOfSize:12]; + } + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = [UIColor appdataFontColor]; + self.titleLabel.numberOfLines = 2; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel top:self.accessoriesImage.bottomAnchor padding:5]; + [self.titleLabel leading:self.baseView.leadingAnchor padding:5]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-5]; + [self.titleLabel x:self.baseView.centerXAnchor]; + + + if (!toggleAppdataColour) { + if([appdataAppearance isEqualToString:@"appdataLight"]) { + + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + + } else if([appdataAppearance isEqualToString:@"appdataDark"]) { + + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + + } else if([appdataAppearance isEqualToString:@"appdataDynamic"]) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + } else { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + } + + } + + } else { + + self.blurEffectView.alpha = 0; + self.backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"appdataCellColour" defaultValue:@"FFFFFF" ID:BID]; + + } + + + } + return self; +} + + +- (void)traitCollectionDidChange:(UITraitCollection *) previousTraitCollection { + + if (!toggleAppdataColour) { + if([appdataAppearance isEqualToString:@"appdataDynamic"]) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + } else { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + } + + } + } + +} + + +@end diff --git a/Paradise/Tweak/PARADISE/Cells/ColourCell.h b/Paradise/Tweak/PARADISE/Cells/ColourCell.h new file mode 100644 index 0000000..091be68 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/ColourCell.h @@ -0,0 +1,11 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPreferences.h" + +@interface ColourCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIImageView *accessoriesImage; +@property (nonatomic, retain) UIView *colourView; +@end diff --git a/Paradise/Tweak/PARADISE/Cells/ColourCell.m b/Paradise/Tweak/PARADISE/Cells/ColourCell.m new file mode 100644 index 0000000..b61154c --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/ColourCell.m @@ -0,0 +1,71 @@ +#import "ColourCell.h" + +static UIFontDescriptor *descriptor; + +@implementation ColourCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + loadPrefs(); + descriptor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:appdataCustomFont error:nil]; + + self.baseView = [[UIView alloc] init]; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:5].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-5].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-5].active = YES; + + + self.accessoriesImage = [[UIImageView alloc] init]; + self.accessoriesImage.tintColor = [UIColor appdataIconColor]; + self.accessoriesImage.image = [[UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/colour-picker.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.accessoriesImage.layer.cornerRadius = 15; + self.accessoriesImage.clipsToBounds = true; + [self.baseView addSubview:self.accessoriesImage]; + + self.accessoriesImage.translatesAutoresizingMaskIntoConstraints = NO; + [[self.accessoriesImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.accessoriesImage.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + [self.accessoriesImage.heightAnchor constraintEqualToConstant:30].active = YES; + [self.accessoriesImage.widthAnchor constraintEqualToConstant:30].active = YES; + + + self.colourView = [[UIView alloc] init]; + self.colourView.layer.cornerRadius = 10; + self.colourView.clipsToBounds = true; + [self.baseView addSubview:self.colourView]; + + [self.colourView size:CGSizeMake(20, 20)]; + [self.colourView x:self.accessoriesImage.centerXAnchor]; + [self.colourView y:self.accessoriesImage.centerYAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + if (toggleAppdataCustomFont) { + self.titleLabel.font = [UIFont fontWithDescriptor:descriptor size:14]; + } else { + self.titleLabel.font = [UIFont boldSystemFontOfSize:14]; + } + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.textColor = [UIColor appdataFontColor]; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.baseView.leadingAnchor padding:10]; + [self.titleLabel trailing:self.accessoriesImage.leadingAnchor padding:-10]; + [self.titleLabel y:self.baseView.centerYAnchor]; + + } + + return self; +} + + +@end diff --git a/Paradise/Tweak/PARADISE/Cells/IconCell.h b/Paradise/Tweak/PARADISE/Cells/IconCell.h new file mode 100644 index 0000000..3555879 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/IconCell.h @@ -0,0 +1,11 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPreferences.h" + +@interface IconCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) TDMarqueeLabel *subtitleLabel; +@property (nonatomic, retain) UIImageView *accessoriesImage; +@end diff --git a/Paradise/Tweak/PARADISE/Cells/IconCell.m b/Paradise/Tweak/PARADISE/Cells/IconCell.m new file mode 100644 index 0000000..428a353 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/IconCell.m @@ -0,0 +1,85 @@ +#import "IconCell.h" + +static UIFontDescriptor *descriptor; + +@implementation IconCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + loadPrefs(); + descriptor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:appdataCustomFont error:nil]; + + self.baseView = [[UIView alloc] init]; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:5].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-5].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-5].active = YES; + + + self.accessoriesImage = [[UIImageView alloc] init]; + self.accessoriesImage.layer.cornerRadius = 15; + self.accessoriesImage.clipsToBounds = true; + [self.baseView addSubview:self.accessoriesImage]; + + self.accessoriesImage.translatesAutoresizingMaskIntoConstraints = NO; + [[self.accessoriesImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.accessoriesImage.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + [self.accessoriesImage.heightAnchor constraintEqualToConstant:30].active = YES; + [self.accessoriesImage.widthAnchor constraintEqualToConstant:30].active = YES; + + + self.titleLabel = [[UILabel alloc] init]; + if (toggleAppdataCustomFont) { + self.titleLabel.font = [UIFont fontWithDescriptor:descriptor size:18]; + } else { + self.titleLabel.font = [UIFont boldSystemFontOfSize:18]; + } + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.textColor = [UIColor appdataFontColor]; + [self.baseView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.titleLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor constant:-10].active = true; + [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10].active = YES; + [self.titleLabel.trailingAnchor constraintEqualToAnchor:self.accessoriesImage.leadingAnchor constant:-15].active = YES; + [self.titleLabel.heightAnchor constraintEqualToConstant:18.0].active = YES; + + + self.subtitleLabel = [[TDMarqueeLabel alloc] initWithFrame:CGRectZero]; + self.subtitleLabel.textColor = [UIColor appdataFontColor]; + if (toggleAppdataCustomFont) { + self.subtitleLabel.font = [UIFont fontWithDescriptor:descriptor size:14]; + } else { + self.subtitleLabel.font = [UIFont systemFontOfSize:14]; + } + self.subtitleLabel.backgroundColor = [UIColor clearColor]; + self.subtitleLabel.labelSpacing = 60; + self.subtitleLabel.pauseInterval = 0.8; + self.subtitleLabel.scrollSpeed = 50; + self.subtitleLabel.textAlignment = NSTextAlignmentLeft; + self.subtitleLabel.fadeLength = 12.f; + self.subtitleLabel.scrollDirection = TDMarqueeLabelDirectionLeft; + [self.baseView addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.subtitleLabel.topAnchor constraintEqualToAnchor:self.titleLabel.bottomAnchor constant:10].active = YES; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10].active = YES; + [self.subtitleLabel.trailingAnchor constraintEqualToAnchor:self.accessoriesImage.leadingAnchor constant:-15].active = YES; + [self.subtitleLabel.heightAnchor constraintEqualToConstant:14].active = YES; + + + } + + return self; +} + + +@end diff --git a/Paradise/Tweak/PARADISE/Cells/LibraryCell.h b/Paradise/Tweak/PARADISE/Cells/LibraryCell.h new file mode 100644 index 0000000..d208566 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/LibraryCell.h @@ -0,0 +1,10 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPreferences.h" + +@interface LibraryCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIImageView *accessoriesImage; +@end diff --git a/Paradise/Tweak/PARADISE/Cells/LibraryCell.m b/Paradise/Tweak/PARADISE/Cells/LibraryCell.m new file mode 100644 index 0000000..493968c --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/LibraryCell.m @@ -0,0 +1,58 @@ +#import "LibraryCell.h" + +static UIFontDescriptor *descriptor; + +@implementation LibraryCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + loadPrefs(); + descriptor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:appdataCustomFont error:nil]; + + self.baseView = [[UIView alloc] init]; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:5].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-5].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-5].active = YES; + + + self.accessoriesImage = [[UIImageView alloc] init]; + self.accessoriesImage.tintColor = [UIColor appdataIconColor]; + [self.baseView addSubview:self.accessoriesImage]; + + self.accessoriesImage.translatesAutoresizingMaskIntoConstraints = NO; + [[self.accessoriesImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.accessoriesImage.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + [self.accessoriesImage.heightAnchor constraintEqualToConstant:30].active = YES; + [self.accessoriesImage.widthAnchor constraintEqualToConstant:30].active = YES; + + + self.titleLabel = [[UILabel alloc] init]; + if (toggleAppdataCustomFont) { + self.titleLabel.font = [UIFont fontWithDescriptor:descriptor size:14]; + } else { + self.titleLabel.font = [UIFont boldSystemFontOfSize:14]; + } + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.textColor = [UIColor appdataFontColor]; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.baseView.leadingAnchor padding:10]; + [self.titleLabel trailing:self.accessoriesImage.leadingAnchor padding:-10]; + [self.titleLabel y:self.baseView.centerYAnchor]; + + } + + return self; +} + + +@end diff --git a/Paradise/Tweak/PARADISE/Cells/WidgetCell.h b/Paradise/Tweak/PARADISE/Cells/WidgetCell.h new file mode 100644 index 0000000..7f453cc --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/WidgetCell.h @@ -0,0 +1,10 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPreferences.h" + +@interface WidgetCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIImageView *accessoriesImage; +@end diff --git a/Paradise/Tweak/PARADISE/Cells/WidgetCell.m b/Paradise/Tweak/PARADISE/Cells/WidgetCell.m new file mode 100644 index 0000000..41dc490 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Cells/WidgetCell.m @@ -0,0 +1,58 @@ +#import "WidgetCell.h" + +static UIFontDescriptor *descriptor; + +@implementation WidgetCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + loadPrefs(); + descriptor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:appdataCustomFont error:nil]; + + self.baseView = [[UIView alloc] init]; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:5].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-5].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-5].active = YES; + + + self.accessoriesImage = [[UIImageView alloc] init]; + self.accessoriesImage.tintColor = [UIColor appdataIconColor]; + [self.baseView addSubview:self.accessoriesImage]; + + self.accessoriesImage.translatesAutoresizingMaskIntoConstraints = NO; + [[self.accessoriesImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.accessoriesImage.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + [self.accessoriesImage.heightAnchor constraintEqualToConstant:30].active = YES; + [self.accessoriesImage.widthAnchor constraintEqualToConstant:30].active = YES; + + + self.titleLabel = [[UILabel alloc] init]; + if (toggleAppdataCustomFont) { + self.titleLabel.font = [UIFont fontWithDescriptor:descriptor size:14]; + } else { + self.titleLabel.font = [UIFont boldSystemFontOfSize:14]; + } + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.textColor = [UIColor appdataFontColor]; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.baseView.leadingAnchor padding:10]; + [self.titleLabel trailing:self.accessoriesImage.leadingAnchor padding:-10]; + [self.titleLabel y:self.baseView.centerYAnchor]; + + } + + return self; +} + + +@end diff --git a/Paradise/Tweak/PARADISE/ColourScheme/Colour-Scheme.h b/Paradise/Tweak/PARADISE/ColourScheme/Colour-Scheme.h new file mode 100644 index 0000000..b11209c --- /dev/null +++ b/Paradise/Tweak/PARADISE/ColourScheme/Colour-Scheme.h @@ -0,0 +1,13 @@ +#import "GlobalPreferences.h" + +@interface UIColor (AppdataFontColor) ++ (UIColor *)appdataFontColor; +@end + +@interface UIColor (AppdataIconColor) ++ (UIColor *)appdataIconColor; +@end + +@interface UIColor (AppdataAccentColor) ++ (UIColor *)appdataAccentColor; +@end diff --git a/Paradise/Tweak/PARADISE/ColourScheme/Colour-Scheme.m b/Paradise/Tweak/PARADISE/ColourScheme/Colour-Scheme.m new file mode 100644 index 0000000..0ef261c --- /dev/null +++ b/Paradise/Tweak/PARADISE/ColourScheme/Colour-Scheme.m @@ -0,0 +1,61 @@ +#import "Colour-Scheme.h" + +@implementation UIColor (AppdataFontColor) ++ (UIColor *)appdataFontColor { + static UIColor *customColour; + + loadPrefs(); + + if([appdataAppearance isEqualToString:@"appdataLight"]) { + customColour = UIColor.blackColor; + } else if([appdataAppearance isEqualToString:@"appdataDark"]) { + customColour = UIColor.whiteColor; + } else if([appdataAppearance isEqualToString:@"appdataDynamic"]) { + customColour = UIColor.labelColor; + } + + if (toggleAppdataColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"appdataFontColour" defaultValue:@"FFFFFF" ID:BID]; + } + + return customColour; +} +@end + +@implementation UIColor (AppdataIconColor) ++ (UIColor *)appdataIconColor { + static UIColor *customColour; + + loadPrefs(); + + if([appdataAppearance isEqualToString:@"appdataLight"]) { + customColour = UIColor.blackColor; + } else if([appdataAppearance isEqualToString:@"appdataDark"]) { + customColour = UIColor.whiteColor; + } else if([appdataAppearance isEqualToString:@"appdataDynamic"]) { + customColour = UIColor.labelColor; + } + + if (toggleAppdataColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"appdataIconColour" defaultValue:@"FFFFFF" ID:BID]; + } + + return customColour; +} +@end + +@implementation UIColor (AppdataAccentColor) ++ (UIColor *)appdataAccentColor { + static UIColor *customColour; + + loadPrefs(); + + if (toggleAppdataColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"appdataAccentColor" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemBlueColor; + } + + return customColour; +} +@end diff --git a/Paradise/Tweak/PARADISE/GlobalPrefs/GlobalPreferences.h b/Paradise/Tweak/PARADISE/GlobalPrefs/GlobalPreferences.h new file mode 100644 index 0000000..7aa9cf3 --- /dev/null +++ b/Paradise/Tweak/PARADISE/GlobalPrefs/GlobalPreferences.h @@ -0,0 +1,34 @@ +#import + +static NSString *BID = @"com.TitanD3v.ParadisePrefs"; + +static BOOL toggleParadise; +static NSString *appdataAppearance; +static BOOL toggleAppdataColour; +static BOOL toggleAppdataBackgroundImage; +static NSData *appdataBackgroundImage = nil; +static BOOL toggleAppdataHaptic; +static NSInteger appdataHapticStrength; +static BOOL toggleAppdataCustomFont; +static NSData *appdataCustomFont; +static BOOL toggleBlurEffect; +static float bottomSheetCornerRadius; +static BOOL toggle3DMenu; +static BOOL showSBTutorial; + +static void loadPrefs() { + + toggleParadise = [[TDTweakManager sharedInstance] boolForKey:@"toggleParadise" defaultValue:NO ID:BID]; + appdataAppearance = [[TDTweakManager sharedInstance] objectForKey:@"appdataAppearance" defaultValue:@"appdataLight" ID:BID]; + toggleAppdataColour = [[TDTweakManager sharedInstance] boolForKey:@"toggleAppdataColour" defaultValue:NO ID:BID]; + toggleAppdataBackgroundImage = [[TDTweakManager sharedInstance] boolForKey:@"toggleAppdataBackgroundImage" defaultValue:NO ID:BID]; + appdataBackgroundImage = [[TDTweakManager sharedInstance] objectForKey:@"appdataBackgroundImage" ID:BID]; + toggleAppdataHaptic = [[TDTweakManager sharedInstance] boolForKey:@"toggleAppdataHaptic" defaultValue:YES ID:BID]; + appdataHapticStrength = [[TDTweakManager sharedInstance] intForKey:@"appdataHapticStrength" defaultValue:0 ID:BID]; + toggleAppdataCustomFont = [[TDTweakManager sharedInstance] boolForKey:@"toggleAppdataCustomFont" defaultValue:NO ID:BID]; + appdataCustomFont = [[TDTweakManager sharedInstance] objectForKey:@"appdataCustomFont" ID:BID]; + toggleBlurEffect = [[TDTweakManager sharedInstance] boolForKey:@"toggleBlurEffect" defaultValue:YES ID:BID]; + bottomSheetCornerRadius = [[TDTweakManager sharedInstance] floatForKey:@"bottomSheetCornerRadius" defaultValue:30 ID:BID]; + toggle3DMenu = [[TDTweakManager sharedInstance] boolForKey:@"toggle3DMenu" defaultValue:NO ID:BID]; + showSBTutorial = [[TDTweakManager sharedInstance] boolForKey:@"showSBTutorial" defaultValue:YES ID:BID]; +} diff --git a/Paradise/Tweak/PARADISE/Manager/ParadiseFileManager.h b/Paradise/Tweak/PARADISE/Manager/ParadiseFileManager.h new file mode 100644 index 0000000..6f24734 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Manager/ParadiseFileManager.h @@ -0,0 +1,5 @@ +#import + +@interface NSFileManager (ParadiseFileManager) +- (BOOL)nr_getAllocatedSize:(unsigned long long *)size ofDirectoryAtURL:(NSURL *)url error:(NSError * __autoreleasing *)error; +@end \ No newline at end of file diff --git a/Paradise/Tweak/PARADISE/Manager/ParadiseFileManager.m b/Paradise/Tweak/PARADISE/Manager/ParadiseFileManager.m new file mode 100644 index 0000000..d7f1f73 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Manager/ParadiseFileManager.m @@ -0,0 +1,62 @@ +#import "ParadiseFileManager.h" + +@implementation NSFileManager (ParadiseFileManager) +- (BOOL)nr_getAllocatedSize:(unsigned long long *)size ofDirectoryAtURL:(NSURL *)directoryURL error:(NSError * __autoreleasing *)error +{ + NSParameterAssert(size != NULL); + NSParameterAssert(directoryURL != nil); + + unsigned long long accumulatedSize = 0; + + NSArray *prefetchedProperties = @[ + NSURLIsRegularFileKey, + NSURLFileAllocatedSizeKey, + NSURLTotalFileAllocatedSizeKey, + ]; + + __block BOOL errorDidOccur = NO; + BOOL (^errorHandler)(NSURL *, NSError *) = ^(NSURL *url, NSError *localError) { + if (error != NULL) + *error = localError; + errorDidOccur = YES; + return NO; + }; + + NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:directoryURL + includingPropertiesForKeys:prefetchedProperties + options:(NSDirectoryEnumerationOptions)0 + errorHandler:errorHandler]; + + for (NSURL *contentItemURL in enumerator) { + + if (errorDidOccur) + return NO; + + NSNumber *isRegularFile; + if (! [contentItemURL getResourceValue:&isRegularFile forKey:NSURLIsRegularFileKey error:error]) + return NO; + if (! [isRegularFile boolValue]) + continue; + + NSNumber *fileSize; + if (! [contentItemURL getResourceValue:&fileSize forKey:NSURLTotalFileAllocatedSizeKey error:error]) + return NO; + + if (fileSize == nil) { + if (! [contentItemURL getResourceValue:&fileSize forKey:NSURLFileAllocatedSizeKey error:error]) + return NO; + + NSAssert(fileSize != nil, @"huh? NSURLFileAllocatedSizeKey should always return a value"); + } + + accumulatedSize += [fileSize unsignedLongLongValue]; + } + + if (errorDidOccur) + return NO; + + *size = accumulatedSize; + return YES; +} + +@end diff --git a/Paradise/Tweak/PARADISE/Manager/ParadiseManager.h b/Paradise/Tweak/PARADISE/Manager/ParadiseManager.h new file mode 100644 index 0000000..c97e69d --- /dev/null +++ b/Paradise/Tweak/PARADISE/Manager/ParadiseManager.h @@ -0,0 +1,45 @@ +#import +#import "Headers.h" + +@interface ParadiseManager : NSObject +// @property (nonatomic, strong) LSApplicationProxy *appProxy; +// @property (nonatomic, strong) SBIconView *iconView; +@property (nonatomic, strong) UIImage *iconImage; + +@property (nonatomic, strong) NSString *version; +@property (nonatomic, strong) NSString *bundleIdentifier; +@property (nonatomic, strong) NSString *bundlePATH; +@property (nonatomic, strong) NSString *containerPATH; + +@property (nonatomic, strong) NSURL *bundleURL; +@property (nonatomic, strong) NSURL *dataContainerURL; + +@property (nonatomic, assign) NSInteger diskUsage; +@property (nonatomic, strong) NSString *diskUsageString; + ++(instancetype)sharedInstance; +-(id)init; +- (instancetype)initWithBundleIdentifier:(NSString *)bundleIdentifier; ++ (ParadiseManager *)initForBundleIdentifier:(NSString *)bundleIdentifier; +-(UIImage *)imageForBID; + +-(void)renameForBID:(NSString *)bid newName:(NSString*)newName; +-(NSString *)getAppNameForBID:(NSString *)BID; +- (NSString *)name; +- (BOOL)isApplication; +- (NSString *)customIconName; + +- (void)resetIconNameForBID:(NSString*)BID; +- (void)resetIconForBID:(NSString*)BID; + +- (bool)isCustomIconForBID:(NSString*)BID; +- (void)setCustomIconForBID:(NSString *)BID iconImage:(UIImage*)iconImage; + +- (void)getCachesDirectorySizeWithCompletion:(void(^)(NSString *formattedSize))completion; +- (void)clearAppCachesWithCompletion:(void(^)())completion; + +- (void)setAppBadgeCount:(NSInteger)badgeCount; +- (NSInteger)appBadgeCount; + +-(void)deleteKey:(NSString*)key; +@end \ No newline at end of file diff --git a/Paradise/Tweak/PARADISE/Manager/ParadiseManager.m b/Paradise/Tweak/PARADISE/Manager/ParadiseManager.m new file mode 100644 index 0000000..e787563 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Manager/ParadiseManager.m @@ -0,0 +1,239 @@ +#import "ParadiseManager.h" +#import "ParadiseFileManager.h" + +static NSString *prefPath = @"/var/mobile/Library/Preferences/com.Titand3v.ParadiseData.plist"; +NSMutableDictionary *settings; + + +@interface ParadiseManager () +@property (nonatomic, strong) SBApplication *sbApplication; +@property (nonatomic, strong) LSApplicationProxy *appProxy; +@property (nonatomic, strong) SBIconView *iconView; +@end + +@implementation ParadiseManager + ++(instancetype)sharedInstance { + static ParadiseManager *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[ParadiseManager alloc] init]; + }); + return sharedInstance; +} + ++ (ParadiseManager *)initForBundleIdentifier:(NSString *)bundleIdentifier{ + ParadiseManager *data = [[ParadiseManager alloc] initWithBundleIdentifier:bundleIdentifier]; + return data; +} + +-(UIImage *)imageForBID{ + UIImage *image; + SBIconModel *model; + + SBIconController *iconController = [NSClassFromString(@"SBIconController") sharedInstance]; + + if([iconController respondsToSelector:@selector(homescreenIconViewMap)]) model = [[iconController homescreenIconViewMap] iconModel]; + else if([iconController respondsToSelector:@selector(model)]) model = [iconController model]; + SBIcon *icon = [model applicationIconForBundleIdentifier:self.bundleIdentifier]; + if([icon respondsToSelector:@selector(getIconImage:)]) image = [icon getIconImage:2]; + else if([icon respondsToSelector:@selector(iconImageWithInfo:)]) image = [icon iconImageWithInfo:(struct SBIconImageInfo){60,60,2,0}]; + + return image; +} + +- (instancetype)initWithBundleIdentifier:(NSString *)bundleIdentifier { + if (self = [super init]) { + self.sbApplication = [self.class sbApplicationForBundleIdentifier:bundleIdentifier]; + self.appProxy = [NSClassFromString(@"LSApplicationProxy") applicationProxyForIdentifier:bundleIdentifier]; + self.bundleIdentifier = bundleIdentifier; + settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + [self loadData]; + } + return self; +} + +- (void)loadData { + // App Info + self.version = self.appProxy.shortVersionString ? : self.appProxy.bundleVersion; + self.iconImage = [self imageForBID]; + // Data URLs + self.bundleURL = self.appProxy.bundleURL ? : self.appProxy.bundleContainerURL; + if ([self.appProxy respondsToSelector:@selector(dataContainerURL)]) { + self.dataContainerURL = self.appProxy.dataContainerURL; + } + // Disk Usage + self.diskUsage = [self.appProxy.staticDiskUsage integerValue]; + self.diskUsageString = [NSByteCountFormatter stringFromByteCount:[self.appProxy.staticDiskUsage longLongValue] countStyle:NSByteCountFormatterCountStyleFile]; + + self.bundlePATH = [[NSString stringWithFormat:@"%@", self.bundleURL] stringByReplacingOccurrencesOfString:@"file://" withString:@""]; + self.containerPATH = [[NSString stringWithFormat:@"%@", self.dataContainerURL] stringByReplacingOccurrencesOfString:@"file://" withString:@""]; +} + +-(id)init { + settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return self; +} + +- (NSString *)name { + return [self.sbApplication respondsToSelector:@selector(displayName)] ? self.sbApplication.displayName : nil; +} + +- (BOOL)isApplication { + return self.sbApplication != nil; +} + +- (NSString *)customIconName { + return [settings objectForKey:self.bundleIdentifier]; +} + +-(void)refreshIcons{ + SBIconController *model = [NSClassFromString(@"SBIconController") sharedInstance]; + [[model model] layout]; +} + +- (void)resetIconNameForBID:(NSString*)BID { + [settings removeObjectForKey:BID]; + [self writeToPlist]; +} + +- (void)resetIconForBID:(NSString*)BID { + NSString *pathWithIcon = [NSString stringWithFormat:@"/Library/Paradise/%@-Large.png", BID]; + NSLog(@"yyyyyyyyyyyyyyyyyyyyy pathWithIcon:-%@", pathWithIcon); + [[NSFileManager defaultManager] removeItemAtPath:pathWithIcon error:nil]; + [self refreshIcons]; +} + +- (bool)isCustomIconForBID:(NSString*)BID{ + NSString *pathWithIcon = [NSString stringWithFormat:@"/Library/Paradise/%@-Large.png", BID]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if (![fileManager fileExistsAtPath:pathWithIcon]) { + return 0; + } + return 1; +} + +- (void)setCustomIconForBID:(NSString *)BID iconImage:(UIImage*)iconImage{ + NSString *pathWithIcon = [NSString stringWithFormat:@"/Library/Paradise/%@-Large.png", BID]; + NSLog(@"yyyyyyyyyyyyyyyyyyyyy pathWithIcon:-%@, BID:-%@, iconImage:-%@", pathWithIcon, BID, iconImage); + [UIImagePNGRepresentation(iconImage) writeToFile:pathWithIcon atomically:YES]; + [self refreshIcons]; +} + +-(void)renameForBID:(NSString *)bid newName:(NSString*)newName{ + SBApplication *app = [[NSClassFromString(@"SBApplicationController") sharedInstance] applicationWithBundleIdentifier:bid]; + NSString *bidForReal = [NSString stringWithFormat:@"%@.real", bid]; + [settings setObject:app.displayName forKey:bidForReal]; + [settings setObject:newName forKey:bid]; + NSLog(@"xxxxxxxxxxxxxx bidForReal:-%@, newName:-%@, renameForBID:-%@", bidForReal, newName, bid); + [self writeToPlist]; +} + ++ (SBApplication *)sbApplicationForBundleIdentifier:(NSString *)bundleIdentifier { + if ([[NSClassFromString(@"SBApplicationController") sharedInstance] respondsToSelector:@selector(applicationWithBundleIdentifier:)]) { + return [[NSClassFromString(@"SBApplicationController") sharedInstance] applicationWithBundleIdentifier:bundleIdentifier]; + } + return nil; +} + +- (NSInteger)appBadgeCount { + if ([self.sbApplication respondsToSelector:@selector(badgeValue)]) { + return [[self.sbApplication badgeValue] integerValue]; + } else if ([self.sbApplication respondsToSelector:@selector(badgeNumberOrString)]) { + return [[self.sbApplication badgeNumberOrString] integerValue]; + } + return 0; +} + +- (void)setAppBadgeCount:(NSInteger)badgeCount { + if ([self.sbApplication respondsToSelector:@selector(setBadgeValue:)]) { + [self.sbApplication setBadgeValue:[NSNumber numberWithInteger:badgeCount]]; + } else { + [self.sbApplication setBadgeNumberOrString:[NSNumber numberWithInteger:badgeCount]]; + } +} + +-(void)writeToPlist{ + [settings writeToFile:prefPath atomically:YES]; +} + +-(NSString *)getAppNameForBID:(NSString *)BID{ + NSString *appName = [settings objectForKey:BID]; + NSLog(@"xxxxxxxxxxxxxx getAppNameForBID:-%@", appName); + return appName; +} + +- (NSURL *)cacheDirectoryURL { + return [self.dataContainerURL URLByAppendingPathComponent:@"/Library/Caches/"]; +} + +- (NSURL *)tmpDirectoryURL { + return [self.dataContainerURL URLByAppendingPathComponent:@"/tmp/"]; +} + +- (NSArray *)cacheDirectoriesURLs { + NSMutableArray *caches = [NSMutableArray new]; + + NSURL *cacheDirectoryURL = [self cacheDirectoryURL]; + if (cacheDirectoryURL) [caches addObject:cacheDirectoryURL]; + + NSURL *tmpDirectoryURL = [self tmpDirectoryURL]; + if (tmpDirectoryURL) [caches addObject:tmpDirectoryURL]; + + return caches; +} + +- (void)getCachesDirectorySizeWithCompletion:(void(^)(NSString *formattedSize))completion { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + unsigned long long int totalSize = 0; + NSArray *cacheDirectoriesURLs = [self cacheDirectoriesURLs]; + for (NSURL *url in cacheDirectoriesURLs) { + if (url && [[NSFileManager defaultManager] fileExistsAtPath:url.path]) { + unsigned long long int folderSize = 0; + [[NSFileManager defaultManager] nr_getAllocatedSize:&folderSize ofDirectoryAtURL:url error:nil]; + totalSize += folderSize; + } + } + NSString *formattedSize = [NSByteCountFormatter stringFromByteCount:totalSize countStyle:NSByteCountFormatterCountStyleFile]; + dispatch_async(dispatch_get_main_queue(), ^{ + completion(formattedSize); + }); + }); +} + +- (void)clearAppCachesWithCompletion:(void(^)())completion { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + NSArray *cacheDirectoriesURLs = [self cacheDirectoriesURLs]; + for (NSURL *url in cacheDirectoriesURLs) { + [self.class deleteContentsOfDirectoryAtURL:url]; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + completion(); + }); + }); +} + ++ (void)deleteContentsOfDirectoryAtURL:(NSURL *)url { + NSFileManager *fm = [NSFileManager defaultManager]; + NSDirectoryEnumerator *enumerator = [fm enumeratorAtURL:url includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil]; + NSURL *child; + while ((child = [enumerator nextObject])) { + [fm removeItemAtURL:child error:NULL]; + } +} + + +//this to delete appDataSaved data +-(void)deleteKey:(NSString*)key{ + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:prefPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [mutableDict removeObjectForKey:key]; + [mutableDict writeToFile:prefPath atomically:YES]; + NSLog(@"ParadiseDebug deleteKey:-%@", key); +} + +@end diff --git a/Paradise/Tweak/PARADISE/Settings/ParadiseSettingViewController.h b/Paradise/Tweak/PARADISE/Settings/ParadiseSettingViewController.h new file mode 100644 index 0000000..9085f5d --- /dev/null +++ b/Paradise/Tweak/PARADISE/Settings/ParadiseSettingViewController.h @@ -0,0 +1,15 @@ +#import + +@interface ParadiseSettingViewController : TDExternalController +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@end + +@interface ParadiseAppearanceController : TDExternalController +@end + +@interface ParadiseColourController : TDExternalController +@end + +@interface ParadiseMiscellaneousController : TDExternalController +@end diff --git a/Paradise/Tweak/PARADISE/Settings/ParadiseSettingViewController.m b/Paradise/Tweak/PARADISE/Settings/ParadiseSettingViewController.m new file mode 100644 index 0000000..b8375d6 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Settings/ParadiseSettingViewController.m @@ -0,0 +1,161 @@ +#import "ParadiseSettingViewController.h" +#import + +@interface NSBundle(priv) +- (instancetype)initWithURL:(NSURL *)url; +@end + +@implementation ParadiseSettingViewController + +- (NSArray *)specifiers { + if (!_specifiers) { + NSBundle *bundle = [NSBundle bundleWithPath:@"/Library/PreferenceBundles/ParadisePrefs.bundle/Assets/ExtSettings/"]; + _specifiers = [self loadSpecifiersFromPlistName:@"ExtPrimrary" target:self bundle:bundle]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"Settings"; + + UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStylePlain target:self action:@selector(dismissVC)]; + self.navigationItem.leftBarButtonItem = closeButton; + + UIBarButtonItem *applyButton = [[UIBarButtonItem alloc] initWithTitle:@"Apply" style:UIBarButtonItemStylePlain target:self action:@selector(respringSpringBoard)]; + self.navigationItem.rightBarButtonItem = applyButton; + + [[TDPrefsManager sharedInstance] enableExternalCellInset:YES]; + + UITableView *tableView = self.view.subviews[0]; + + UIView *header = [[UIView alloc] init]; + header.frame = CGRectMake(0, 0, tableView.bounds.size.width, 175); + header.backgroundColor = UIColor.clearColor; + tableView.tableHeaderView = header; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Settings/banner-icon.png"]; + self.iconImage.layer.cornerRadius = 15; + self.iconImage.clipsToBounds = true; + [header addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.heightAnchor constraintEqualToConstant:70].active = YES; + [self.iconImage.widthAnchor constraintEqualToConstant:70].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:header.topAnchor constant:20].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:header.centerXAnchor].active = true; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = UIColor.whiteColor; + self.titleLabel.font = [UIFont boldSystemFontOfSize:30]; + self.titleLabel.text = @"PARADISE"; + [header addSubview:self.titleLabel]; + + [self.titleLabel x:header.centerXAnchor]; + [self.titleLabel top:self.iconImage.bottomAnchor padding:15]; + + [tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; + +} + + +-(void)respringSpringBoard { + [self dismissViewControllerAnimated:YES completion:nil]; + [[TDUtilities sharedInstance] respring]; +} + + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end + + +@implementation ParadiseAppearanceController + +- (NSArray *)specifiers { + if (!_specifiers) { + NSBundle *bundle = [NSBundle bundleWithPath:@"/Library/PreferenceBundles/ParadisePrefs.bundle/"]; + _specifiers = [self loadSpecifiersFromPlistName:@"Appearance" target:self bundle:bundle]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"Appearance"; + + [[TDPrefsManager sharedInstance] enableExternalCellInset:YES]; + + UITableView *tableView = self.view.subviews[0]; + [tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; + +} + +@end + + +@implementation ParadiseColourController + +- (NSArray *)specifiers { + if (!_specifiers) { + NSBundle *bundle = [NSBundle bundleWithPath:@"/Library/PreferenceBundles/ParadisePrefs.bundle/"]; + _specifiers = [self loadSpecifiersFromPlistName:@"Colour" target:self bundle:bundle]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"Colour"; + + [[TDPrefsManager sharedInstance] enableExternalCellInset:YES]; + + UITableView *tableView = self.view.subviews[0]; + [tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; + +} + +@end + + +@implementation ParadiseMiscellaneousController + +- (NSArray *)specifiers { + if (!_specifiers) { + NSBundle *bundle = [NSBundle bundleWithPath:@"/Library/PreferenceBundles/ParadisePrefs.bundle/"]; + _specifiers = [self loadSpecifiersFromPlistName:@"Miscellaneous" target:self bundle:bundle]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"Miscellaneous"; + + [[TDPrefsManager sharedInstance] enableExternalCellInset:YES]; + + UITableView *tableView = self.view.subviews[0]; + [tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; + +} + +@end diff --git a/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppList.h b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppList.h new file mode 100644 index 0000000..3a0cb7f --- /dev/null +++ b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppList.h @@ -0,0 +1,9 @@ +#import + +@interface UninstallAppList : NSObject ++ (NSMutableArray *)allApps; ++ (NSMutableArray *)userApps; ++ (NSMutableArray *)systemApps; ++ (NSMutableArray *)audioApps; ++(NSMutableArray*)sortArray:(NSMutableArray*)arrayToSort; +@end \ No newline at end of file diff --git a/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppList.m b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppList.m new file mode 100644 index 0000000..746fe1b --- /dev/null +++ b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppList.m @@ -0,0 +1,213 @@ +#import "UninstallAppList.h" + +@interface _LSLazyPropertyList : NSObject +@property(readonly) NSDictionary *propertyList; +@end + +@interface LSApplicationProxy : NSObject +@property(setter=_setLocalizedName:, nonatomic, copy) NSString *localizedName; +@property(nonatomic, readonly) NSString *bundleIdentifier; +@property(nonatomic, readonly) NSString *primaryIconName; +@property(nonatomic, readonly) NSDictionary *iconsDictionary; +@property(nonatomic, readonly) NSArray *appTags; +@property(setter=_setInfoDictionary:, nonatomic, copy) +_LSLazyPropertyList *_infoDictionary; +- (NSArray *)_boundIconFileNames; +- (NSArray *)boundIconFileNames; +@end + +@interface LSApplicationWorkspace ++ (id)defaultWorkspace; +- (id)allInstalledApplications; +- (id)allApplications; +- (id)applicationsOfType:(unsigned long long)arg1; +- (id)applicationsWithUIBackgroundModes; +@end + +@interface UninstallAppList () ++ (NSString *)nameForApp:(LSApplicationProxy *)app; +@end + +@interface UIImage (Private) ++(id)_applicationIconImageForBundleIdentifier:(NSString*)displayIdentifier format:(int)form scale:(CGFloat)scale; +@end + +@implementation UninstallAppList + +int iOSVersion; ++ (NSMutableArray *)userApps { + + NSMutableArray *userApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + applicationsOfType:0]; + + for (LSApplicationProxy *app in defaultWorkspaceApps) { + [userApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + return [self sortArray:userApps]; +} + ++ (NSMutableArray *)audioApps { + + NSMutableArray *audioApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + applicationsWithUIBackgroundModes]; + + for (LSApplicationProxy *app in defaultWorkspaceApps) { + NSDictionary *info = app._infoDictionary.propertyList; + NSArray *background = info[@"UIBackgroundModes"]; + if (background && [background containsObject:@"audio"]) { + if ([self hasIconAndVisible:app.bundleIdentifier]) { + [audioApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + } + } + return [self sortArray:audioApps]; +} + ++ (NSMutableArray *)systemApps { + + NSMutableArray *systemApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + applicationsOfType:1]; + + for (LSApplicationProxy *app in defaultWorkspaceApps) { + if ([self hasIconAndVisible:app.bundleIdentifier]) { + [systemApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + } + + return [self sortArray:systemApps]; +} + ++ (NSMutableArray *)allApps { + + NSMutableArray *allApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + allApplications]; + for (LSApplicationProxy *app in defaultWorkspaceApps) { + if ([self hasIconAndVisible:app.bundleIdentifier]) { + [allApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + } + return [self sortArray:allApps]; +} + ++ (BOOL)hasIconAndVisible:(NSString *)bundleIdentifier { + NSArray *blacklist = [NSArray arrayWithObjects:@"com.apple.Magnifier", + @"com.apple.InCallService", + @"com.apple.RemoteiCloudQuotaUI", + @"com.apple.PublicHealthRemoteUI", + @"com.apple.CarPlaySplashScreen", + @"com.apple.iMessageAppsViewService", + @"com.apple.BarcodeScanner", + @"com.apple.HealthENLauncher", + @"com.apple.AXUIViewService", + @"com.apple.AppSSOUIService", + @"com.apple.CarPlaySettings", + @"com.apple.mobilesms.compose", + @"com.apple.BusinessChatViewService", + @"com.apple.DiagnosticsService", + @"com.apple.CTNotifyUIService", + @"com.apple.HealthPrivacyService", + @"com.apple.WebContentFilter.remoteUI.WebContentAnalysisUI", + @"com.apple.ScreenshotServicesService", + @"com.apple.FTMInternal", + @"com.apple.carkit.DNDBuddy", + @"com.apple.PreBoard", + @"com.apple.datadetectors.DDActionsService", + @"com.apple.DemoApp", + @"com.apple.CoreAuthUI", + @"com.apple.SubcredentialUIService", + @"com.apple.MailCompositionService", + @"com.apple.Diagnostics", + @"com.apple.AuthKitUIService", + @"com.apple.TVRemote", + @"com.apple.gamecenter.GameCenterUIService", + @"com.apple.PrintKit.Print-Center", + @"com.apple.sidecar", + @"com.apple.AccountAuthenticationDialog", + @"com.apple.PassbookUIService", + @"com.apple.siri", + @"com.apple.CloudKit.ShareBear", + @"com.apple.HealthENBuddy", + @"com.apple.SafariViewService", + @"com.apple.SIMSetupUIService", + @"com.apple.CompassCalibrationViewService", + @"com.apple.PhotosViewService", + @"com.apple.MusicUIService", + @"com.apple.TrustMe", + @"com.apple.Home.HomeUIService", + @"com.apple.CTCarrierSpaceAuth", + @"com.apple.StoreDemoViewService", + @"com.apple.susuiservice", + @"com.apple.social.SLYahooAuth", + @"com.apple.Spotlight", + @"com.apple.fieldtest", + @"com.apple.WebSheet", + @"com.apple.iad.iAdOptOut", + @"com.apple.dt.XcodePreviews", + @"com.apple.appleseed.FeedbackAssistant", + @"com.apple.FontInstallViewService", + @"com.apple.ScreenSharingViewService", + @"com.apple.SharedWebCredentialViewService", + @"com.apple.CheckerBoard", + @"com.apple.DataActivation", + @"com.apple.TVAccessViewService", + @"com.apple.VSViewService", + @"com.apple.TVRemoteUIService", + @"com.apple.SharingViewService", + @"com.apple.ios.StoreKitUIService", + @"com.apple.purplebuddy", + @"com.apple.ScreenTimeUnlock", + @"com.apple.webapp", + @"com.apple.ActivityMessagesApp", + @"com.apple.icloud.apps.messages.business", + @"com.apple.ClipViewService", + @"com.apple.CredentialSharingService", + @"com.apple.ctkui", + @"com.apple.FunCamera.EmojiStickers", + @"com.apple.siri.parsec.HashtagImagesApp", + @"com.apple.icq", + @"com.apple.Jellyfish", + @"com.apple.Animoji.StickersApp", + @"com.apple.PassbookSecureUIService", + @"com.apple.Photos.PhotosUIService", + @"com.apple.shortcuts.runtime", + @"com.apple.SleepLockScreen", + @"com.apple.FunCamera.TextPicker", + @"com.apple.FunCamera.ShapesPicker", + @"com.apple.smsFilter", + @"com.apple.AskPermissionUI", nil]; + UIImage *image = [UIImage _applicationIconImageForBundleIdentifier:bundleIdentifier format:2 scale:[UIScreen mainScreen].scale]; + NSData *imageData = UIImagePNGRepresentation(image); + if(imageData.length == 9762 || [blacklist containsObject:bundleIdentifier]) + return NO; + return YES; +} + ++ (NSString *)nameForApp:(LSApplicationProxy *)app { + return (app.localizedName ? app.localizedName : app.bundleIdentifier); +} + ++(NSMutableArray*)sortArray:(NSMutableArray*)arrayToSort{ + NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)]; + return [[arrayToSort sortedArrayUsingDescriptors:@[sort]] mutableCopy]; +} +@end diff --git a/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsCell.h b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsCell.h new file mode 100644 index 0000000..eeef5db --- /dev/null +++ b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsCell.h @@ -0,0 +1,12 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPreferences.h" + +@interface UninstallAppsCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *appImage; +@property (nonatomic, retain) UILabel *appnameLabel; +@property (nonatomic, retain) UILabel *appBIDLabel; + +@end diff --git a/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsCell.m b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsCell.m new file mode 100644 index 0000000..fda47d6 --- /dev/null +++ b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsCell.m @@ -0,0 +1,70 @@ +#import "UninstallAppsCell.h" + +@implementation UninstallAppsCell + + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + loadPrefs(); + + + self.baseView = [[UIView alloc] initWithFrame:CGRectZero]; + self.baseView.layer.cornerRadius = 15; + self.baseView.clipsToBounds = true; + self.baseView.backgroundColor = [UIColor clearColor]; + [self addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:5].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5].active = YES; + + + self.appImage = [[UIImageView alloc] initWithFrame:CGRectZero]; + self.appImage.layer.cornerRadius = 10; + self.appImage.clipsToBounds = true; + [self.baseView addSubview:self.appImage]; + + self.appImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.appImage.widthAnchor constraintEqualToConstant:50.0].active = YES; + [self.appImage.heightAnchor constraintEqualToConstant:50.0].active = YES; + [[self.appImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.appImage.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10].active = YES; + + + self.appnameLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.appnameLabel.textColor = [UIColor appdataFontColor]; + self.appnameLabel.font = [UIFont boldSystemFontOfSize:16]; + self.appnameLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.appnameLabel]; + + self.appnameLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.appnameLabel.heightAnchor constraintEqualToConstant:18.0].active = YES; + [self.appnameLabel.widthAnchor constraintEqualToConstant:220.0].active = YES; + [[self.appnameLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor constant:-10].active = true; + [self.appnameLabel.leadingAnchor constraintEqualToAnchor:self.appImage.trailingAnchor constant:10.0].active = YES; + + + self.appBIDLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.appBIDLabel.textColor = [UIColor appdataFontColor]; + self.appBIDLabel.font = [UIFont systemFontOfSize:12]; + self.appBIDLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.appBIDLabel]; + + self.appBIDLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.appBIDLabel.heightAnchor constraintEqualToConstant:14.0].active = YES; + [self.appBIDLabel.widthAnchor constraintEqualToConstant:220.0].active = YES; + [self.appBIDLabel.topAnchor constraintEqualToAnchor:self.appnameLabel.bottomAnchor constant:5.0].active = YES; + [self.appBIDLabel.leadingAnchor constraintEqualToAnchor:self.appImage.trailingAnchor constant:10.0].active = YES; + + } + + return self; +} + +@end diff --git a/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsViewController.h b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsViewController.h new file mode 100644 index 0000000..e73296e --- /dev/null +++ b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsViewController.h @@ -0,0 +1,20 @@ +#import +#import "BlurBaseView.h" +#include "UninstallAppsCell.h" +#include "UninstallAppList.h" +#import "../../Headers.h" +#import "Colour-Scheme.h" +#import "GlobalPreferences.h" + +@interface UninstallAppsViewController : UIViewController +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIButton *uninstallButton; +@property (nonatomic, retain) UIButton *cancelButton; +@property(nonatomic, strong) NSMutableDictionary *appsToUninstall; +@property(nonatomic, strong) NSMutableDictionary *selectedApps; +@property(nonatomic, strong) NSMutableArray *fullAppList; +@property (nonatomic, retain) BlurBaseView *baseView; +@property (nonatomic, retain) UITableView *tableView; +-(void)refreshTable; +-(void)deleteKey:(NSString*)key; +@end \ No newline at end of file diff --git a/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsViewController.m b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsViewController.m new file mode 100644 index 0000000..bcbb322 --- /dev/null +++ b/Paradise/Tweak/PARADISE/UninstallApps/UninstallAppsViewController.m @@ -0,0 +1,262 @@ +#import "UninstallAppsViewController.h" + +@implementation UninstallAppsViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.clipsToBounds = true; + self.view.backgroundColor = UIColor.clearColor; + + self.baseView = [[BlurBaseView alloc] init]; + [self.view addSubview:self.baseView]; + [self.baseView fill]; + + [self layoutAccessoriesView]; + [self layoutTableView]; + +} + + +-(void)layoutAccessoriesView { + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = [UIColor appdataFontColor]; + self.titleLabel.font = [UIFont boldSystemFontOfSize:18]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.text = @"All Applications"; + [self.view addSubview:self.titleLabel]; + + [self.titleLabel x:self.view.centerXAnchor]; + [self.titleLabel top:self.view.topAnchor padding:20]; + + + self.cancelButton = [[UIButton alloc] init]; + [self.cancelButton addTarget:self action:@selector(dismissVC) forControlEvents:UIControlEventTouchUpInside]; + [self.cancelButton setTitle:@"Cancel" forState:UIControlStateNormal]; + [self.cancelButton setTitleColor:UIColor.systemRedColor forState:UIControlStateNormal]; + self.cancelButton.titleLabel.font = [UIFont systemFontOfSize:16]; + [self.view addSubview:self.cancelButton]; + + [self.cancelButton size:CGSizeMake(70, 30)]; + [self.cancelButton x:self.view.centerXAnchor]; + [self.cancelButton bottom:self.view.bottomAnchor padding:-15]; + + + self.uninstallButton = [[UIButton alloc] init]; + [self.uninstallButton addTarget:self action:@selector(presentUninstallConfirmation) forControlEvents:UIControlEventTouchUpInside]; + [self.uninstallButton setTitle:@"Uninstall" forState:UIControlStateNormal]; + [self.uninstallButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; + self.uninstallButton.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + self.uninstallButton.backgroundColor = [UIColor appdataAccentColor]; + self.uninstallButton.enabled = NO; + self.uninstallButton.alpha = 0.7; + self.uninstallButton.layer.cornerRadius = 10; + self.uninstallButton.layer.cornerCurve = kCACornerCurveContinuous; + [self.view addSubview:self.uninstallButton]; + + [self.uninstallButton size:CGSizeMake(200, 50)]; + [self.uninstallButton x:self.view.centerXAnchor]; + [self.uninstallButton bottom:self.cancelButton.topAnchor padding:-10]; + +} + + +-(void)layoutTableView { + + self.fullAppList = [[UninstallAppList userApps] mutableCopy]; + _appsToUninstall = [NSMutableDictionary new]; + _selectedApps = [NSMutableDictionary new]; + + + self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + if (toggleAppdataColour) { + [self.tableView setSeparatorColor:[[TDTweakManager sharedInstance] colourForKey:@"appdataSeparatorColour" defaultValue:@"FFFFFF" ID:BID]]; + } + self.tableView.backgroundColor = UIColor.clearColor; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + [self.tableView setAllowsMultipleSelection:YES]; + [self.tableView setAllowsMultipleSelectionDuringEditing:YES]; + + [self.tableView top:self.titleLabel.bottomAnchor padding:10]; + [self.tableView leading:self.view.leadingAnchor padding:0]; + [self.tableView trailing:self.view.trailingAnchor padding:0]; + [self.tableView bottom:self.uninstallButton.topAnchor padding:-10]; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [self.fullAppList count]; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + UninstallAppsCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[UninstallAppsCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + + NSString *BID = [NSString stringWithFormat:@"%@", [[self.fullAppList objectAtIndex:indexPath.row] objectForKey:@"bundleID"]]; + + cell.backgroundColor = UIColor.clearColor; + + cell.appImage.image = [UIImage _applicationIconImageForBundleIdentifier:BID format:2 scale:[UIScreen mainScreen].scale]; + cell.appnameLabel.text = [[self.fullAppList objectAtIndex:indexPath.row] objectForKey:@"name"]; + cell.appBIDLabel.text = [[self.fullAppList objectAtIndex:indexPath.row] objectForKey:@"bundleID"]; + + + if ([[_selectedApps valueForKey:[NSString stringWithFormat:@"%ld", indexPath.row]] boolValue]) { + + [cell setAccessoryType:UITableViewCellAccessoryCheckmark]; + } else { + [cell setAccessoryType:UITableViewCellAccessoryNone]; + } + + return cell; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath]; + + if (thisCell.accessoryType == UITableViewCellAccessoryNone) { + + thisCell.accessoryType = UITableViewCellAccessoryCheckmark; + NSString *BID = [self.fullAppList objectAtIndex:indexPath.row][@"bundleID"]; + [_appsToUninstall setValue:BID forKey:BID]; + [_selectedApps setValue:[NSNumber numberWithBool:YES] forKey:[NSString stringWithFormat:@"%ld", indexPath.row]]; + } + else if(_appsToUninstall.count !=0){ + NSString *BID = [self.fullAppList objectAtIndex:indexPath.row][@"bundleID"]; + thisCell.accessoryType = UITableViewCellAccessoryNone; + [_appsToUninstall removeObjectForKey:BID]; + [_selectedApps setValue:[NSNumber numberWithBool:NO] forKey:[NSString stringWithFormat:@"%ld", indexPath.row]]; + } + + + [self checkStatus]; + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 70; +} + + +-(void)presentUninstallConfirmation { + + UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"Paradise" message:@"Are you sure you want to uninstall those Applications?" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *uninstallAction = [UIAlertAction actionWithTitle:@"Uninstall" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self uninstallApps]; + }]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) {}]; + + [alertController addAction:uninstallAction]; + [alertController addAction:cancelAction]; + [self presentViewController:alertController animated:YES completion:nil]; + +} + + +-(void)checkStatus { + + if (_appsToUninstall.count != 0) { + [UIView animateWithDuration:0.2 animations:^ { + self.uninstallButton.enabled = YES; + self.uninstallButton.alpha = 1.0; + }]; + } else { + [UIView animateWithDuration:0.2 animations:^ { + self.uninstallButton.enabled = NO; + self.uninstallButton.alpha = 0.7; + }]; + } + +} + + +-(void)uninstallApps { + + __block NSString *message = [NSString stringWithFormat:@"Uninstalling apps 0/%ld", _appsToUninstall.count]; + UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"Paradise" + message:message + preferredStyle:UIAlertControllerStyleAlert]; + + [self presentViewController:alertController animated:YES completion:nil]; + + long counts = 0; + + for (NSString *bundleIdentifier in _appsToUninstall.allKeys){ + counts++; + + [NSClassFromString(@"IXAppInstallCoordinator") uninstallAppWithBundleID:bundleIdentifier requestUserConfirmation:NO waitForDeletion:NO completion:^{ + dispatch_async(dispatch_get_main_queue(), ^{ + + message = [NSString stringWithFormat:@"Uninstalling apps %ld/%ld", counts, _appsToUninstall.count]; + NSLog(@"spotiLove bundleIdentifier:-%@, message:-%@", bundleIdentifier, message); + alertController.message = message; + [self deleteKey:bundleIdentifier]; + }); + }]; + } + + + [self refreshTable]; + [alertController dismissViewControllerAnimated:YES completion:nil]; + + [UIView animateWithDuration:0.2 animations:^ { + self.uninstallButton.enabled = NO; + self.uninstallButton.alpha = 0.7; + }]; + +} + + +-(void)refreshTable { + [self.tableView reloadData]; +} + + +-(void)deleteKey:(NSString*)key{ + for(NSMutableDictionary *appData in self.fullAppList) { + if([appData[@"bundleID"] isEqual:key]) { + [self.fullAppList removeObject:appData]; + [_appsToUninstall removeObjectForKey:key]; + break; + } + } + + if(_appsToUninstall.count == 0){ + self.navigationItem.rightBarButtonItem = nil; + } + [_selectedApps removeAllObjects]; + [self refreshTable]; +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/Paradise/Tweak/PARADISE/Widget/WidgetViewController.h b/Paradise/Tweak/PARADISE/Widget/WidgetViewController.h new file mode 100644 index 0000000..9765d06 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Widget/WidgetViewController.h @@ -0,0 +1,27 @@ +#import +#import "Colour-Scheme.h" +#import "GlobalPreferences.h" +#import "BlurBaseView.h" +#import "WidgetCell.h" +#import "../../Headers.h" +#import "ParadiseManager.h" +#import "ColourCell.h" + +@interface WidgetViewController : UIViewController + +@property (nonatomic, retain) BlurBaseView *baseView; +@property (nonatomic, retain) UIView *headerView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *listArray; +@property (nonatomic, retain) NSArray *iconArray; + +@property (nonatomic, retain) SBIconView *iconView; +@property (nonatomic, retain) NSString *imgHash; +@property (nonatomic, retain) NSString *imgTitle; + +-(instancetype)initWithHash:(NSString*)imgHash imgTitle:(NSString*)title iconView:(SBIconView*)iconView; + +@end + diff --git a/Paradise/Tweak/PARADISE/Widget/WidgetViewController.m b/Paradise/Tweak/PARADISE/Widget/WidgetViewController.m new file mode 100644 index 0000000..1d08586 --- /dev/null +++ b/Paradise/Tweak/PARADISE/Widget/WidgetViewController.m @@ -0,0 +1,455 @@ +#import "WidgetViewController.h" + +static UIFontDescriptor *descriptor; +static NSInteger colourPickerIndex = 0; + +@implementation WidgetViewController + +-(instancetype)initWithHash:(NSString*)imgHash imgTitle:(NSString*)imgTitle iconView:(SBIconView*)iconView{ + + self.imgHash = imgHash; + self.iconView = iconView; + self.imgTitle = imgTitle; + NSLog(@"ParadiseDebug initWithHash self.imgHash:-%@, iconView:-%@" ,self.imgHash, iconView.iconImageSnapshot); + return self; + +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + descriptor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:appdataCustomFont error:nil]; + + self.view.backgroundColor = UIColor.clearColor; + [self layoutBaseView]; + [self layoutHeaderView]; + [self layoutTableView]; +} + + +-(void)layoutBaseView { + + self.baseView = [[BlurBaseView alloc] init]; + self.baseView.layer.cornerRadius = bottomSheetCornerRadius; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self.view addSubview:self.baseView]; + + [self.baseView x:self.view.centerXAnchor]; + [self.baseView height:MAIN_SCREEN_HEIGHT *0.40]; + [self.baseView bottom:self.view.bottomAnchor padding:-10]; + [self.baseView leading:self.view.leadingAnchor padding:10]; + [self.baseView trailing:self.view.trailingAnchor padding:-10]; + +} + + +-(void)layoutHeaderView { + + self.headerView = [[UIView alloc] init]; + self.headerView.backgroundColor = UIColor.clearColor; + [self.baseView addSubview:self.headerView]; + + [self.headerView height:130]; + [self.headerView top:self.baseView.topAnchor padding:0]; + [self.headerView leading:self.baseView.leadingAnchor padding:0]; + [self.headerView trailing:self.baseView.trailingAnchor padding:0]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [[UIImage systemImageNamed:@"square.grid.2x2.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + self.iconImage.layer.cornerRadius = 10; + self.iconImage.clipsToBounds = true; + self.iconImage.tintColor = [UIColor appdataIconColor]; + [self.headerView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(65, 65)]; + [self.iconImage top:self.headerView.topAnchor padding:10]; + [self.iconImage x:self.headerView.centerXAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + + if (toggleAppdataCustomFont) { + self.titleLabel.font = [UIFont fontWithDescriptor:descriptor size:14]; + } else { + self.titleLabel.font = [UIFont boldSystemFontOfSize:14]; + } + + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.text = self.imgTitle; + self.titleLabel.textColor = [UIColor appdataFontColor]; + [self.headerView addSubview:self.titleLabel]; + + [self.titleLabel top:self.iconImage.bottomAnchor padding:5]; + [self.titleLabel x:self.headerView.centerXAnchor]; + +} + + +-(void)layoutTableView { + + self.listArray = [[NSArray alloc] initWithObjects:@"Rename", @"Label Colour", @"Label Background Colour", @"Reset Name", @"Reset Label Colour", @"Reset Label Background Colour", nil]; + + self.tableView = [[UITableView alloc] init]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + self.tableView.showsVerticalScrollIndicator = NO; + if (toggleAppdataColour) { + [self.tableView setSeparatorColor:[[TDTweakManager sharedInstance] colourForKey:@"appdataSeparatorColour" defaultValue:@"FFFFFF" ID:BID]]; + } + [self.baseView addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + + self.tableView.translatesAutoresizingMaskIntoConstraints = NO; + [self.tableView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor].active = YES; + [self.tableView.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10].active = YES; + [self.tableView.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + [self.tableView.bottomAnchor constraintEqualToAnchor:self.baseView.bottomAnchor constant:-5].active = YES; + + self.tableView.tableFooterView = [UIView new]; + +} + + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.listArray.count; +} + + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + if (indexPath.row == 1) { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"colourCell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"colourCell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = [self.listArray objectAtIndex:indexPath.row]; + + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.imgHash]; + NSData *decodedData = [[TDTweakManager sharedInstance] objectForKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + UIColor *savedColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + + if (decodedData != nil) { + cell.colourView.backgroundColor = savedColour; + } else { + cell.colourView.backgroundColor = UIColor.whiteColor; + } + + return cell; + + } else if (indexPath.row == 2) { + + ColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"colourCell"]; + + if (cell == nil) { + cell = [[ColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"colourCell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = [self.listArray objectAtIndex:indexPath.row]; + + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.imgHash]; + NSData *decodedData = [[TDTweakManager sharedInstance] objectForKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + UIColor *savedColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + + if (decodedData != nil) { + cell.colourView.backgroundColor = savedColour; + } else { + cell.colourView.backgroundColor = UIColor.whiteColor; + } + + return cell; + + } else { + + + WidgetCell *cell = [tableView dequeueReusableCellWithIdentifier:@"iconCell"]; + + if (cell == nil) { + cell = [[WidgetCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"iconCell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = [self.listArray objectAtIndex:indexPath.row]; + + if (indexPath.row == 0) { // Rename + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/rename.png"]; + } else if (indexPath.row == 3) { // Reset label + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png"]; + } else if (indexPath.row == 4) { // Reset label colour + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png"]; + } else if (indexPath.row == 5) { // Reset label background colour + cell.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png"]; + cell.separatorInset = UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, CGFLOAT_MAX); + + } + + return cell; + + } + +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + [self invokeHapticFeedback]; + + if (indexPath.row == 0) { // Rename + + [self renameLabel]; + + } else if (indexPath.row == 1) { // Label colour + + colourPickerIndex = 0; + [self presentColourPickerVC]; + + } else if (indexPath.row == 2) { // Label Background colour + + colourPickerIndex = 1; + [self presentColourPickerVC]; + + } else if (indexPath.row == 3) { // Reset label + + NSString *keyT = [NSString stringWithFormat:@"%@-Title", self.imgHash]; + [[TDTweakManager sharedInstance] setObject:@"" forKey:keyT ID:@"com.TitanD3v.ParadisePrefs"]; + [self showAlertWithTitle:@"Paradise" message:@"Label has been Reset successfully"]; + + } else if (indexPath.row == 4) { // Reset label colour + + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.imgHash]; + [[TDTweakManager sharedInstance] removeObjectForKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + [self.iconView _updateLabel]; + [self showAlertWithTitle:@"Paradise" message:@"Label colour has been Reset successfully"]; + + NSIndexPath *_indexPath1 = [NSIndexPath indexPathForItem:1 inSection:0]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath1]; + cell.colourView.backgroundColor = UIColor.whiteColor; + + } else if (indexPath.row == 5) { // Reset label background colour + + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.imgHash]; + [[TDTweakManager sharedInstance] removeObjectForKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + [self.iconView _updateLabel]; + [self showAlertWithTitle:@"Paradise" message:@"Label background colour has been Reset successfully"]; + + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath2]; + cell.colourView.backgroundColor = UIColor.whiteColor; + + } + + [self.iconView _updateLabel]; + +} + + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 50; +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + + +-(void)invokeHapticFeedback { + if (toggleAppdataHaptic) { + + if (appdataHapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (appdataHapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (appdataHapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesEnded:touches withEvent:event]; + if (touches.anyObject.view == self.view) { + [self dismissViewControllerAnimated:YES completion:nil]; + [self invokeHapticFeedback]; + } else if (touches.anyObject.view != self.baseView) { + [self.baseView resignFirstResponder]; + } +} + +-(void)showAlertWithTitle:(NSString *)title message:(NSString *)message { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Okay!" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self.iconView _updateLabel]; + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + +} + + +-(void)renameLabel{ + + UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Change Label Title" + message:@"\nEnter New Title" + preferredStyle:UIAlertControllerStyleAlert]; + + [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.placeholder = @"Enter New Title"; + }]; + + UIAlertAction* chngButton = [UIAlertAction actionWithTitle:@"Change" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + + NSString *newTitle = alert.textFields.firstObject.text; + NSString *keyT = [NSString stringWithFormat:@"%@-Title", self.imgHash]; + + self.titleLabel.text = newTitle; + [self.tableView reloadData]; + + [[TDTweakManager sharedInstance] setObject:newTitle forKey:keyT ID:@"com.TitanD3v.ParadisePrefs"]; + [self.iconView _updateLabel]; + + }]; + + UIAlertAction* clButton = [UIAlertAction actionWithTitle:@"Cancel" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + + [alert dismissViewControllerAnimated:YES completion:nil]; + + }]; + + [alert addAction:chngButton]; + [alert addAction:clButton]; + [self presentViewController:alert animated:YES completion:nil]; +} + + +-(void)presentColourPickerVC { // (SGWC) index == 0 for label colour, 1 for label background colour on lib only + + UIColor *previewColour; + + if (colourPickerIndex == 0) { + NSIndexPath *_indexPath1 = [NSIndexPath indexPathForItem:1 inSection:0]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath1]; + previewColour = cell.colourView.backgroundColor; + } else if (colourPickerIndex == 1) { + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath2]; + previewColour = cell.colourView.backgroundColor; + } + + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + colourPickerVC.selectedColor = previewColour; + [self presentViewController:colourPickerVC animated:YES completion:nil]; + +} + +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + + UIColor *cpSelectedColour = viewController.selectedColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:cpSelectedColour]; + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.imgHash]; + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.imgHash]; + + NSIndexPath *_indexPath1 = [NSIndexPath indexPathForItem:1 inSection:0]; + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + + if (colourPickerIndex == 0) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath1]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 0 :-%@", encodedData); + } else if (colourPickerIndex == 1) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath2]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 1 :-%@", encodedData); + } + + [self.iconView _updateLabel]; + +} + +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + + UIColor *cpSelectedColour = viewController.selectedColor; + NSData *encodedData =[NSKeyedArchiver archivedDataWithRootObject:cpSelectedColour]; + NSString *keyC = [NSString stringWithFormat:@"%@-Color", self.imgHash]; + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", self.imgHash]; + + NSIndexPath *_indexPath1 = [NSIndexPath indexPathForItem:1 inSection:0]; + NSIndexPath *_indexPath2 = [NSIndexPath indexPathForItem:2 inSection:0]; + + if (colourPickerIndex == 0) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyC ID:@"com.TitanD3v.ParadisePrefs"]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath1]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 0 :-%@", encodedData); + } else if (colourPickerIndex == 1) { + [[TDTweakManager sharedInstance] setObject:encodedData forKey:keyBG ID:@"com.TitanD3v.ParadisePrefs"]; + ColourCell *cell = (ColourCell *)[self.tableView cellForRowAtIndexPath:_indexPath2]; + cell.colourView.backgroundColor = cpSelectedColour; + NSLog(@"ParadiseDebug colorPickerViewControllerDidFinish 1 :-%@", encodedData); + } + + [self.iconView _updateLabel]; + +} + +@end diff --git a/Paradise/Tweak/Paradise.plist b/Paradise/Tweak/Paradise.plist new file mode 100644 index 0000000..10dc654 --- /dev/null +++ b/Paradise/Tweak/Paradise.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard" ); }; } diff --git a/Paradise/Tweak/Paradise.xm b/Paradise/Tweak/Paradise.xm new file mode 100644 index 0000000..3505ddf --- /dev/null +++ b/Paradise/Tweak/Paradise.xm @@ -0,0 +1,316 @@ +#import +#import "AppLibraryViewController.h" +#import "WidgetViewController.h" +#import "DataViewController.h" +#import "GlobalPreferences.h" +#import "ParadiseManager.h" +#import "Headers.h" + + +%group Paradise + +%hook SBClockApplicationIconImageView + +%new +-(void)presentAppDataVC:(UITapGestureRecognizer*)sender{ + + SBIconImageView *iconImageView = (SBIconImageView*)sender.view; + + DataViewController *dvc = [[DataViewController alloc] initWithIconView:iconImageView.iconView imgTitle:@"Clock" iconID:@"com.apple.mobiletimer"]; + dvc.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [[%c(SBIconController) sharedInstance] presentViewController:dvc animated:YES completion:nil]; +} +%end + +%hook SBIconImageView + +- (SBIconImageView *)initWithFrame:(CGRect)arg1 { + + SBIconImageView *r = %orig; + + UISwipeGestureRecognizer *sortGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(presentAppDataVC:)]; + sortGesture.direction = UISwipeGestureRecognizerDirectionUp; + [self addGestureRecognizer:sortGesture]; + + r.userInteractionEnabled = YES; + + return r; +} + +%new +-(void)presentAppDataVC:(UITapGestureRecognizer*)sender { + + if (toggleAppdataHaptic) { + + if (appdataHapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (appdataHapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (appdataHapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + + } + + SBIconImageView *iconImageView = (SBIconImageView*)sender.view; + SBIcon *icon = iconImageView.iconView.icon; + + NSString *title = self.iconView._labelImageParameters.text; + NSString *bid; + + bool isApp = NO; + bool isClock = NO; + bool isWidget = NO; + + if([iconImageView.iconView isKindOfClass:[%c(SBWidgetIcon) class]]){ + SBWidgetIcon *widgetIcon = (SBWidgetIcon*)icon; + bid = widgetIcon.leafIdentifier; + isWidget = YES; + } + else if([icon isKindOfClass:[%c(SBFolderIcon) class]]){ + SBFolderIcon *folderIcon = (SBFolderIcon*)icon; + bid = folderIcon.nodeIdentifier; + } + else if([icon isKindOfClass:[%c(SBApplicationIcon) class]]){ + bid = icon.applicationBundleID; + isApp = YES; + } + else if([icon isKindOfClass:[%c(SBHLibraryPodCategoryIcon) class]]){ + SBHLibraryPodCategoryIcon *libraryPodCategoryIcon = (SBHLibraryPodCategoryIcon*)icon; + bid = libraryPodCategoryIcon.leafIdentifier; + } + else if([icon isKindOfClass:[%c(SBBookmarkIcon) class]]){ + SBBookmarkIcon *bookmarkIcon = (SBBookmarkIcon*)icon; + bid = bookmarkIcon.leafIdentifier; + } + else if([icon isKindOfClass:[%c(SBClockApplicationIconImageView) class]]){ + isClock = YES; + } + + if(isApp){ + + DataViewController *dvc = [[DataViewController alloc] initWithIconView:iconImageView.iconView imgTitle:title iconID:bid]; + dvc.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [[%c(SBIconController) sharedInstance] presentViewController:dvc animated:YES completion:nil]; + + } + else if(isWidget){ + + WidgetViewController *widVC = [[WidgetViewController alloc] initWithHash:bid imgTitle:title iconView:self.iconView]; + widVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [[%c(SBIconController) sharedInstance] presentViewController:widVC animated:YES completion:nil]; + + } + else if(!isClock){ + + AppLibraryViewController *libVC = [[AppLibraryViewController alloc] initWithHash:bid imgTitle:title iconView:self.iconView]; + libVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [[%c(SBIconController) sharedInstance] presentViewController:libVC animated:YES completion:nil]; + + } + +} + +%end + + +static NSString *getAppName(NSString *BID){ + SBApplication *app = [[NSClassFromString(@"SBApplicationController") sharedInstance] applicationWithBundleIdentifier:BID]; + return app.displayName; +} + + +%hook SBIconView +- (void)setApplicationShortcutItems:(NSArray *)arg1 { + + loadPrefs(); + + NSMutableArray *newItems = [[NSMutableArray alloc] init]; + + for (SBSApplicationShortcutItem *item in arg1) { + [newItems addObject:item]; + } + + NSData *lightIcon = UIImagePNGRepresentation([[UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/paradise-menu-light.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]); + NSData *darkIcon = UIImagePNGRepresentation([[UIImage imageWithContentsOfFile:@"/Library/Application Support/Paradise.bundle/Assets/Action Icons/paradise-menu-dark.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]); + + SBSApplicationShortcutItem *appItem; + + if (toggle3DMenu) { + appItem = [%c(SBSApplicationShortcutItem) alloc]; + appItem.localizedTitle = @"Edit With Paradise"; + appItem.type = @"com.TitanD3v.Paradise.AppData"; + } + + SBSApplicationShortcutItem *widgetItem = [%c(SBSApplicationShortcutItem) alloc]; + widgetItem.localizedTitle = @"Edit With Paradise"; + widgetItem.type = @"com.TitanD3v.Paradise.PushWidgetsView"; + + SBSApplicationShortcutCustomImageIcon *paradiseLightIcon = [[SBSApplicationShortcutCustomImageIcon alloc] initWithImagePNGData:lightIcon]; + SBSApplicationShortcutCustomImageIcon *paradiseDarkIcon = [[SBSApplicationShortcutCustomImageIcon alloc] initWithImagePNGData:darkIcon]; + + if (self.icon.isWidgetIcon) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + [widgetItem setIcon:paradiseDarkIcon]; + } else if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleLight) { + [widgetItem setIcon:paradiseLightIcon]; + } + + [newItems addObject:widgetItem]; + + } else if(!self.folderIcon) { + + if (toggle3DMenu) { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + [appItem setIcon:paradiseDarkIcon]; + } else if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleLight) { + [appItem setIcon:paradiseLightIcon]; + } + + [newItems addObject:appItem]; + } + + } + + %orig(newItems); +} + ++ (void)activateShortcut:(SBSApplicationShortcutItem *)item withBundleIdentifier:(NSString *)bundleID forIconView:(SBIconView *)iconView { + + NSLog(@"AJSGAJS activateShortcut iconView:-%@", iconView); + + + if ([[item type] isEqualToString:@"com.TitanD3v.Paradise.AppData"]) { + + SBIcon *icon = iconView.icon; + + NSLog(@"AJSGAJS iconImageView:-%@, icon:-%@", iconView.icon, icon); + + NSString *title = iconView._labelImageParameters.text; + NSString *bid = icon.applicationBundleID; + + DataViewController *dvc = [[DataViewController alloc] initWithIconView:iconView imgTitle:title iconID:bid]; + dvc.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [[%c(SBIconController) sharedInstance] presentViewController:dvc animated:YES completion:nil]; + + } else if ([[item type] isEqualToString:@"com.TitanD3v.Paradise.PushWidgetsView"]) { + + NSString *title = iconView._labelImageParameters.text; + SBWidgetIcon *widgetIcon = (SBWidgetIcon*)iconView.icon; + NSString *bid = widgetIcon.leafIdentifier; + + WidgetViewController *widVC = [[WidgetViewController alloc] initWithHash:bid imgTitle:title iconView:iconView]; + widVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [[%c(SBIconController) sharedInstance] presentViewController:widVC animated:YES completion:nil]; + + } else { + + %orig; + + } +} + + +-(id)_labelImageParameters{ + + SBMutableIconLabelImageParameters *param = %orig; + NSString *bid; + + if([self.icon isKindOfClass:[%c(SBWidgetIcon) class]]){ + SBWidgetIcon *widgetIcon = (SBWidgetIcon*)self.icon; + bid = widgetIcon.leafIdentifier; + } + else if([self.icon isKindOfClass:[%c(SBFolderIcon) class]]){ + SBFolderIcon *folderIcon = (SBFolderIcon*)self.icon; + bid = folderIcon.nodeIdentifier; + } + else if([self.icon isKindOfClass:[%c(SBApplicationIcon) class]]){ + bid = self.icon.applicationBundleID; + } + else if([self.icon isKindOfClass:[%c(SBHLibraryPodCategoryIcon) class]]){ + SBHLibraryPodCategoryIcon *libraryPodCategoryIcon = (SBHLibraryPodCategoryIcon*)self.icon; + bid = libraryPodCategoryIcon.leafIdentifier; + } + else if([self.icon isKindOfClass:[%c(SBBookmarkIcon) class]]){ + SBBookmarkIcon *bookmarkIcon = (SBBookmarkIcon*)self.icon; + bid = bookmarkIcon.leafIdentifier; + } + + NSString *keyT = [NSString stringWithFormat:@"%@-Title", bid]; + NSString *keyC = [NSString stringWithFormat:@"%@-Color", bid]; + NSString *keyBG = [NSString stringWithFormat:@"%@-BGColor", bid]; + + NSString *newTitle = [[TDTweakManager sharedInstance] objectForKey:keyT defaultValue:@"" ID:@"com.TitanD3v.ParadisePrefs"]; + NSData *newColor = [[TDTweakManager sharedInstance] objectForKey:keyC defaultValue:@"" ID:@"com.TitanD3v.ParadisePrefs"]; + NSData *newBGColor = [[TDTweakManager sharedInstance] objectForKey:keyBG defaultValue:@"" ID:@"com.TitanD3v.ParadisePrefs"]; + + if(newTitle.length !=0 ) + param.text = newTitle; + + if(newColor.length !=0 ){ + param.textColor = [NSKeyedUnarchiver unarchiveObjectWithData:newColor]; + } + else{ + param.textColor = [UIColor whiteColor]; + } + + if(newBGColor.length !=0 ){ + param.focusHighlightColor = [NSKeyedUnarchiver unarchiveObjectWithData:newBGColor]; + } + + return param; +} +%end + + +%hook SBIconLegibilityLabelView + +-(void)setIconView:(SBIconView *)arg1{ + + %orig; + + if([self.iconView.icon isKindOfClass:[%c(SBHLibraryPodCategoryIcon) class]]){ + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; + tapGesture.numberOfTapsRequired = 2; + [arg1 addGestureRecognizer:tapGesture]; + } + +} + +%new + +- (void)handleTapGesture:(UITapGestureRecognizer *)sender { + + NSString *title = self.imageParameters.text; + SBHLibraryPodCategoryIcon *libraryPodCategoryIcon = (SBHLibraryPodCategoryIcon*)self.iconView.icon; + NSString *bid = libraryPodCategoryIcon.leafIdentifier; + + if (sender.state == UIGestureRecognizerStateRecognized) { + + AppLibraryViewController *libVC = [[AppLibraryViewController alloc] initWithHash:bid imgTitle:title iconView:self.iconView]; + libVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [[%c(SBIconController) sharedInstance] presentViewController:libVC animated:YES completion:nil]; + + } + +} + +%end +%end + +void SettingsChanged() { + toggleParadise = [[TDTweakManager sharedInstance] boolForKey:@"toggleParadise" defaultValue:NO ID:BID]; +} + + +%ctor { + + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)SettingsChanged, CFSTR("com.TitanD3v.ParadisePrefs.settingschanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + SettingsChanged(); + + if (toggleParadise) { + %init(Paradise); + } +} diff --git a/Paradise/Tweak/Tutorial/Tutorial.xm b/Paradise/Tweak/Tutorial/Tutorial.xm new file mode 100644 index 0000000..a67e344 --- /dev/null +++ b/Paradise/Tweak/Tutorial/Tutorial.xm @@ -0,0 +1,119 @@ +#import +#import "GlobalPreferences.h" + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + +@interface SpringBoard : UIView +-(void)presentTutorialVC; +@end + + +OBWelcomeController *tutorialController; + + +%group Tutorial +%hook SpringBoard + +- (void)applicationDidFinishLaunching:(id)application { + %orig; + + loadPrefs(); + +if ((toggleParadise) && (showSBTutorial)) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self presentTutorialVC]; + }); +} + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveTutorialNotification:) name:@"ShowTutorialNotification" object:nil]; +} + + +%new +- (void)receiveTutorialNotification:(NSNotification *) notification { + + if ([[notification name] isEqualToString:@"ShowTutorialNotification"]) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self presentTutorialVC]; + }); + } +} + + +%new +-(void)presentTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + tutorialController = [[OBWelcomeController alloc] initWithTitle:@"Paradise" detailText:@"Tutorial" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/ParadisePrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]]; + tutorialController.view.tintColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + + [tutorialController addBulletedListItemWithTitle:@"App Icons" description:@"Just swipe up on any app icons and it will open paradise, if you have 3D Touch menu enabled from Paradise’s settings then long press on an app icon and click “Edit With Paradise” then you can rename the app label, change the label colour or the background. Copy an app’s information, open the app container or bundle in Filza, offload the app to optimise your storage space and keep app data. You can uninstall multiple apps, just select which apps you want to uninstall then press the “Uninstall” button to uninstall all of them in one go. If you want to edit the icons then click “Icon Editor” it will open the Paradise App and you can start designing some icons, make sure you selected your preferred theme folder for it to save your icon to that folder and apply it with any theme engine. " image:[UIImage systemImageNamed:@"square.fill"]]; + + [tutorialController addBulletedListItemWithTitle:@"Widgets" description:@"Long press on any widgets and the 3D Touch menu will appear, click “Edit With Paradise” and you can rename the widget name, change the label colour or the labels background colour and reset 3 of them." image:[UIImage systemImageNamed:@"rectangle.3.offgrid.fill"]]; + + [tutorialController addBulletedListItemWithTitle:@"Folders" description:@"Just swipe up any folders and it will open paradise and you can rename the folders name, change the label colour or the labels background colour and reset 3 of them." image:[UIImage systemImageNamed:@"folder.fill"]]; + + [tutorialController addBulletedListItemWithTitle:@"Bookmark" description:@"Just swipe up on any bookmark icons and it will open paradise and you can rename the bookmark’s name, change the labels colour or the label background colour and reset 3 of them." image:[UIImage systemImageNamed:@"bookmark.circle"]]; + + [tutorialController addBulletedListItemWithTitle:@"App Library" description:@"Just double tap on any folders from the App Library, make sure you double tap the folders near the edges and it will open Paradise. You can rename the App Library name, change the labels colour or the labels background colour and reset 3 of them." image:[UIImage systemImageNamed:@"square.grid.2x2.fill"]]; + + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissUpdateVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [tutorialController.buttonTray addButton:dismissButton]; + + tutorialController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:tutorialController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [tutorialController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + tutorialController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [tutorialController.buttonTray addCaptionText:@"Thank you for installing Paradise"]; + + tutorialController.modalPresentationStyle = UIModalPresentationPageSheet; + tutorialController.modalInPresentation = YES; + [[%c(SBIconController) sharedInstance] presentViewController:tutorialController animated:YES completion:nil]; + +} + +%new +-(void)dismissUpdateVC { + [[TDUtilities sharedInstance] haptic:0]; + [tutorialController dismissViewControllerAnimated:YES completion:nil]; + [[TDTweakManager sharedInstance] setBool:NO forKey:@"showSBTutorial" ID:BID]; +} +%end +%end + + +%ctor { + loadPrefs(); + NSString * path = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0]; + if ([path containsString:@"/Application"] || [path containsString:@"SpringBoard.app"]) { + %init(Tutorial); + } +} diff --git a/Paradise/control b/Paradise/control new file mode 100644 index 0000000..3d905d0 --- /dev/null +++ b/Paradise/control @@ -0,0 +1,11 @@ +Package: com.titand3v.paradise +Name: Paradise +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal, firmware (>= 14.0) +Version: 1.1 +Section: Tweaks +Description: Customise springboard apps +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/paradise/index.html +Icon: https://titand3v.github.io/depictions/paradise/assets/icon.png diff --git a/Paradise/layout/.DS_Store b/Paradise/layout/.DS_Store new file mode 100644 index 0000000..dbadf7e Binary files /dev/null and b/Paradise/layout/.DS_Store differ diff --git a/Paradise/layout/DEBIAN/postinst b/Paradise/layout/DEBIAN/postinst new file mode 100755 index 0000000..06b589f --- /dev/null +++ b/Paradise/layout/DEBIAN/postinst @@ -0,0 +1,13 @@ +#!/bin/bash + +chown mobile:wheel /Library/Themes +su mobile -c uicache &>/dev/null + +echo "" +echo "" +echo "Thank you for installing Paradise 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" \ No newline at end of file diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/colour-picker.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/colour-picker.png new file mode 100644 index 0000000..5d564ec Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/colour-picker.png differ diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/copy.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/copy.png new file mode 100644 index 0000000..8b41bf5 Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/copy.png differ diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/folder.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/folder.png new file mode 100644 index 0000000..5a00895 Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/folder.png differ diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/icon-editor.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/icon-editor.png new file mode 100644 index 0000000..02eae4f Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/icon-editor.png differ diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/limit.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/limit.png new file mode 100644 index 0000000..9766f02 Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/limit.png differ diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/offload.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/offload.png new file mode 100644 index 0000000..9641a82 Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/offload.png differ diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/paradise-menu-dark.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/paradise-menu-dark.png new file mode 100644 index 0000000..48563c4 Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/paradise-menu-dark.png differ diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/paradise-menu-light.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/paradise-menu-light.png new file mode 100644 index 0000000..4c85c60 Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/paradise-menu-light.png differ diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/rename.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/rename.png new file mode 100644 index 0000000..484ae44 Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/rename.png differ diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png new file mode 100644 index 0000000..a8b56c6 Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/reset.png differ diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/uninstall.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/uninstall.png new file mode 100644 index 0000000..a5a6ba3 Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Assets/Action Icons/uninstall.png differ diff --git a/Paradise/layout/Library/Application Support/Paradise.bundle/Settings/banner-icon.png b/Paradise/layout/Library/Application Support/Paradise.bundle/Settings/banner-icon.png new file mode 100644 index 0000000..151e889 Binary files /dev/null and b/Paradise/layout/Library/Application Support/Paradise.bundle/Settings/banner-icon.png differ diff --git a/Phoenix/.DS_Store b/Phoenix/.DS_Store new file mode 100644 index 0000000..6e60d9d Binary files /dev/null and b/Phoenix/.DS_Store differ diff --git a/Phoenix/Makefile b/Phoenix/Makefile new file mode 100644 index 0000000..4c652b7 --- /dev/null +++ b/Phoenix/Makefile @@ -0,0 +1,16 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.4 + +FINALPACKAGE = 1 +DEBUG = 0 + +export CFLAGS = -include $(realpath NCCenter.h) + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak Prefs + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Phoenix/NCCenter.h b/Phoenix/NCCenter.h new file mode 100644 index 0000000..0b2feb1 --- /dev/null +++ b/Phoenix/NCCenter.h @@ -0,0 +1,9 @@ +#import + +@interface NSDistributedNotificationCenter : NSNotificationCenter ++ (instancetype)defaultCenter; +-(void)postNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3 deliverImmediately:(BOOL)arg4 ; +- (void)postNotificationName:(NSString *)name object:(NSString *)object userInfo:(NSDictionary *)userInfo; +-(id)addObserverForName:(id)arg1 object:(id)arg2 queue:(id)arg3 usingBlock:(/*^block*/id)arg4 ; +-(void)addObserver:(id)arg1 selector:(SEL)arg2 name:(id)arg3 object:(id)arg4 ; +@end \ No newline at end of file diff --git a/Phoenix/Prefs/.DS_Store b/Phoenix/Prefs/.DS_Store new file mode 100644 index 0000000..b344dc2 Binary files /dev/null and b/Phoenix/Prefs/.DS_Store differ diff --git a/Phoenix/Prefs/Makefile b/Phoenix/Prefs/Makefile new file mode 100644 index 0000000..c7fd254 --- /dev/null +++ b/Phoenix/Prefs/Makefile @@ -0,0 +1,15 @@ +BUNDLE_NAME = PhoenixPrefs + +$(BUNDLE_NAME)_FILES = $(wildcard *.m Purchase/*.m) +$(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles +$(BUNDLE_NAME)_FRAMEWORKS = UIKit +$(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences OnBoardingKit +$(BUNDLE_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(BUNDLE_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/bundle.mk + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) + $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/PhoenixPrefs.plist$(ECHO_END) diff --git a/Phoenix/Prefs/PHXPrimraryListController.h b/Phoenix/Prefs/PHXPrimraryListController.h new file mode 100644 index 0000000..5fd9a04 --- /dev/null +++ b/Phoenix/Prefs/PHXPrimraryListController.h @@ -0,0 +1,29 @@ +#import +#import + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1;; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + + +@interface PHXPrimraryListController : TDPrimraryController { + OBWelcomeController *onboardingController; + OBWelcomeController *updateController; +} + +@end diff --git a/Phoenix/Prefs/PHXPrimraryListController.m b/Phoenix/Prefs/PHXPrimraryListController.m new file mode 100644 index 0000000..edde685 --- /dev/null +++ b/Phoenix/Prefs/PHXPrimraryListController.m @@ -0,0 +1,116 @@ +#include "PHXPrimraryListController.h" + +@implementation PHXPrimraryListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Primrary" target:self]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[TDPrefsManager sharedInstance] initWithBundleID:@"com.TitanD3v.PhoenixPrefs" tweakName:@"Phoenix" prefsBundle:@"PhoenixPrefs.bundle"]; + + [[TDPrefsManager sharedInstance] bannerTitle:@"Phoenix" subtitle:@"Coded with 🤍" devName:@"TitanD3v" coverImagePath:@"/Assets/Banner/cover-image.png" showCoverImage:YES iconPath:@"/Assets/Banner/banner-icon.png" iconTint:NO]; + + [[TDPrefsManager sharedInstance] changelogPlistPath:@"/Assets/Changelog/changelog.plist" currentVersion:@"Version 1.0"]; + + [[TDPrefsManager sharedInstance] useAssetsFromLibrary:YES]; + +} + + +-(void)presentTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + onboardingController = [[OBWelcomeController alloc] initWithTitle:@"User Guide" detailText:@"A walk through tutorial how to use Phoenix" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]]; + + [onboardingController addBulletedListItemWithTitle:@"Your time" description:@"Please take a few minutes of your time to read through to get started." image:[UIImage systemImageNamed:@"timer"]]; + + [onboardingController addBulletedListItemWithTitle:@"Main page" description:@"On the main page, there's menu icon on the navigation bar it will present the drawer when tapped. You will find the social media details, changelog, backup/restore, tweak list, profile and crew list." image:[UIImage systemImageNamed:@"square.stack.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Report a bug" description:@"If you are experiencing a bug or any other issues, you can report a bug from this page below the close button, it will bring up the Bug Report page. You can select the categories, write description about a bug, attach a .txt file, photo, provide URL link for the pastebin or any pasteboard website also you can attach all of them if you want. Once you submit a bug report and our team will be in touch with you within 48 hours. If you haven't heard anything from us and please don't hesitate to get in touch with us through social media." image:[UIImage systemImageNamed:@"ant.circle.fill"]]; + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [onboardingController.buttonTray addButton:dismissButton]; + + onboardingController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:onboardingController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [onboardingController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + onboardingController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [onboardingController.buttonTray addCaptionText:@"Thank you for installing Phoenix"]; + + onboardingController.modalPresentationStyle = UIModalPresentationPageSheet; + onboardingController.modalInPresentation = YES; + [self presentViewController:onboardingController animated:YES completion:nil]; + + UIView *reportView = [[UIView alloc] init]; + reportView.backgroundColor = UIColor.clearColor; + [onboardingController.buttonTray addSubview:reportView]; + + reportView.translatesAutoresizingMaskIntoConstraints = NO; + [reportView.topAnchor constraintEqualToAnchor:dismissButton.bottomAnchor constant:10].active = YES; + [[reportView centerXAnchor] constraintEqualToAnchor:onboardingController.buttonTray.centerXAnchor].active = true; + [reportView.widthAnchor constraintEqualToConstant:140].active = YES; + [reportView.heightAnchor constraintEqualToConstant:40].active = YES; + + + UIImageView *bugImage = [[UIImageView alloc] init]; + bugImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + bugImage.tintColor = [[TDAppearance sharedInstance] tintColour]; + [reportView addSubview:bugImage]; + + bugImage.translatesAutoresizingMaskIntoConstraints = NO; + [bugImage.leadingAnchor constraintEqualToAnchor:reportView.leadingAnchor constant:10].active = YES; + [[bugImage centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + [bugImage.widthAnchor constraintEqualToConstant:30].active = YES; + [bugImage.heightAnchor constraintEqualToConstant:30].active = YES; + + + UILabel *reportLabel = [[UILabel alloc] init]; + reportLabel.text = @"Report a bug"; + reportLabel.textColor = [[TDAppearance sharedInstance] tintColour]; + reportLabel.textAlignment = NSTextAlignmentLeft; + [reportView addSubview:reportLabel]; + + reportLabel.translatesAutoresizingMaskIntoConstraints = NO; + [reportLabel.leadingAnchor constraintEqualToAnchor:bugImage.trailingAnchor constant:5].active = YES; + [[reportLabel centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + + [reportView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentReportBugVC)]]; + +} + + +-(void)dismissTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentReportBugVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; + + TDReportBugViewController *bugVC = [[TDReportBugViewController alloc] init]; + bugVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [self presentViewController:bugVC animated:YES completion:nil]; +} + +@end diff --git a/Phoenix/Prefs/Purchase/PHXEnableCell.h b/Phoenix/Prefs/Purchase/PHXEnableCell.h new file mode 100644 index 0000000..1cd284b --- /dev/null +++ b/Phoenix/Prefs/Purchase/PHXEnableCell.h @@ -0,0 +1,26 @@ +#import +#import +#import +#import "PHXHelper.m" + +@interface PHXEnableCell : PSTableCell { + + BOOL isEnabled; + BOOL customIcon; + UIColor *disabledColour; + UIColor *enabledColour; + float inset; +} + +@property (nonatomic, retain) UIStackView *stackView; +@property (nonatomic, retain) UIView *disabledView; +@property (nonatomic, retain) UIImageView *disabledImage; +@property (nonatomic, retain) UILabel *disabledLabel; +@property (nonatomic, retain) UIView *disabledStateView; +@property (nonatomic, retain) UIView *enabledView; +@property (nonatomic, retain) UIImageView *enabledImage; +@property (nonatomic, retain) UILabel *enabledLabel; +@property (nonatomic, retain) UIView *enabledStateView; +@property (nonatomic, retain) UIColor *backgroundColour; + +@end diff --git a/Phoenix/Prefs/Purchase/PHXEnableCell.m b/Phoenix/Prefs/Purchase/PHXEnableCell.m new file mode 100644 index 0000000..bc5d685 --- /dev/null +++ b/Phoenix/Prefs/Purchase/PHXEnableCell.m @@ -0,0 +1,282 @@ +#import "PHXEnableCell.h" + +static NSString *URL = @"https://payments.titand3v.com/api/deviceCheck.php?udid="; +static NSString *TweakName = @"Phoenix"; +static NSString *UDID = nil; + + +@implementation PHXEnableCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + specifier.properties[@"height"] = [NSNumber numberWithInt:100]; + + if (self) { + + self.backgroundColour = [[TDAppearance sharedInstance] backgroundColour]; + + UDID = (__bridge_transfer NSString *)MGCopyAnswer(kMGUniqueDeviceID); + + NSString *disabledColourString = specifier.properties[@"disabledColour"]; + disabledColour = colorFromHexString(disabledColourString); + + NSString *enabledColourString = specifier.properties[@"enabledColour"]; + enabledColour = colorFromHexString(enabledColourString); + + + customIcon = specifier.properties[@"customIcon"] && [specifier.properties[@"customIcon"] boolValue]; + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *disabledIconPath = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, specifier.properties[@"disabledIconPath"]]; + NSString *enabledIconPath = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, specifier.properties[@"enabledIconPath"]]; + + + self.stackView = [[UIStackView alloc] init]; + self.stackView.axis = UILayoutConstraintAxisHorizontal; + self.stackView.alignment = UIStackViewAlignmentCenter; + self.stackView.distribution = UIStackViewDistributionFillEqually; + self.stackView.spacing = 10; + [self addSubview:self.stackView]; + + + self.disabledView = [[UIView alloc] init]; + self.disabledView.layer.cornerRadius = 10; + if (@available(iOS 13.0, *)) { + self.disabledView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.disabledView.clipsToBounds = true; + self.disabledView.backgroundColor = self.backgroundColour; + self.disabledView.layer.shadowOpacity = 0.5; + self.disabledView.layer.shadowOffset = CGSizeMake(0.0,0.0); + self.disabledView.layer.shadowRadius = 3.0; + self.disabledView.layer.masksToBounds = false; + + [self.disabledView.heightAnchor constraintEqualToConstant:80].active = true; + + + self.disabledImage = [[UIImageView alloc] init]; + if (customIcon) { + self.disabledImage.image = [[UIImage imageWithContentsOfFile:disabledIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } else { + self.disabledImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/disabled.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } + self.disabledImage.tintColor = disabledColour; + [self.disabledView addSubview:self.disabledImage]; + + self.disabledImage.translatesAutoresizingMaskIntoConstraints = false; + [self.disabledImage.heightAnchor constraintEqualToConstant:30].active = true; + [self.disabledImage.widthAnchor constraintEqualToConstant:30].active = true; + [self.disabledImage.topAnchor constraintEqualToAnchor:self.disabledView.topAnchor constant:10].active = true; + [self.disabledImage.centerXAnchor constraintEqualToAnchor:self.disabledView.centerXAnchor].active = true; + + + self.disabledLabel = [[UILabel alloc] init]; + self.disabledLabel.textAlignment = NSTextAlignmentCenter; + self.disabledLabel.font = [UIFont boldSystemFontOfSize:12]; + self.disabledLabel.text = specifier.properties[@"disabledTitle"]; + self.disabledLabel.textColor = disabledColour; + [self.disabledView addSubview:self.disabledLabel]; + + self.disabledLabel.translatesAutoresizingMaskIntoConstraints = false; + [self.disabledLabel.topAnchor constraintEqualToAnchor:self.disabledImage.bottomAnchor constant:5].active = true; + [self.disabledLabel.centerXAnchor constraintEqualToAnchor:self.disabledView.centerXAnchor].active = true; + + + self.disabledStateView = [[UIView alloc] init]; + self.disabledStateView.backgroundColor = disabledColour; + self.disabledStateView.layer.cornerRadius = 3; + [self.disabledView addSubview:self.disabledStateView]; + + self.disabledStateView.translatesAutoresizingMaskIntoConstraints = false; + [self.disabledStateView.heightAnchor constraintEqualToConstant:6].active = true; + [self.disabledStateView.widthAnchor constraintEqualToConstant:50].active = true; + [self.disabledStateView.bottomAnchor constraintEqualToAnchor:self.disabledView.bottomAnchor constant:-5].active = true; + [self.disabledStateView.centerXAnchor constraintEqualToAnchor:self.disabledView.centerXAnchor].active = true; + + + self.enabledView = [[UIView alloc] init]; + self.enabledView.layer.cornerRadius = 10; + if (@available(iOS 13.0, *)) { + self.enabledView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.enabledView.clipsToBounds = true; + self.enabledView.backgroundColor = self.backgroundColour; + self.enabledView.layer.shadowOpacity = 0.5; + self.enabledView.layer.shadowOffset = CGSizeMake(0.0,0.0); + self.enabledView.layer.shadowRadius = 3.0; + self.enabledView.layer.masksToBounds = false; + + [self.enabledView.heightAnchor constraintEqualToConstant:80].active = true; + + + self.enabledImage = [[UIImageView alloc] init]; + if (customIcon) { + self.enabledImage.image = [[UIImage imageWithContentsOfFile:enabledIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } else { + self.enabledImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/enabled.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } + self.enabledImage.tintColor = enabledColour; + [self.enabledView addSubview:self.enabledImage]; + + self.enabledImage.translatesAutoresizingMaskIntoConstraints = false; + [self.enabledImage.heightAnchor constraintEqualToConstant:30].active = true; + [self.enabledImage.widthAnchor constraintEqualToConstant:30].active = true; + [self.enabledImage.topAnchor constraintEqualToAnchor:self.enabledView.topAnchor constant:10].active = true; + [self.enabledImage.centerXAnchor constraintEqualToAnchor:self.enabledView.centerXAnchor].active = true; + + + self.enabledLabel = [[UILabel alloc] init]; + self.enabledLabel.textAlignment = NSTextAlignmentCenter; + self.enabledLabel.font = [UIFont boldSystemFontOfSize:12]; + self.enabledLabel.text = specifier.properties[@"enabledTitle"]; + self.enabledLabel.textColor = enabledColour; + [self.enabledView addSubview:self.enabledLabel]; + + self.enabledLabel.translatesAutoresizingMaskIntoConstraints = false; + [self.enabledLabel.topAnchor constraintEqualToAnchor:self.enabledImage.bottomAnchor constant:5].active = true; + [self.enabledLabel.centerXAnchor constraintEqualToAnchor:self.enabledView.centerXAnchor].active = true; + + + self.enabledStateView = [[UIView alloc] init]; + self.enabledStateView.backgroundColor = enabledColour; + self.enabledStateView.layer.cornerRadius = 3; + [self.enabledView addSubview:self.enabledStateView]; + + self.enabledStateView.translatesAutoresizingMaskIntoConstraints = false; + [self.enabledStateView.heightAnchor constraintEqualToConstant:6].active = true; + [self.enabledStateView.widthAnchor constraintEqualToConstant:50].active = true; + [self.enabledStateView.bottomAnchor constraintEqualToAnchor:self.enabledView.bottomAnchor constant:-5].active = true; + [self.enabledStateView.centerXAnchor constraintEqualToAnchor:self.enabledView.centerXAnchor].active = true; + + + [self.stackView addArrangedSubview:self.disabledView]; + [self.stackView addArrangedSubview:self.enabledView]; + + self.stackView.translatesAutoresizingMaskIntoConstraints = false; + [self.stackView.topAnchor constraintEqualToAnchor:self.topAnchor constant:10].active = true; + [self.stackView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10].active = true; + [self.stackView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = true; + [self.stackView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-10].active = true; + [self.stackView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor].active = true; + [self.stackView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor].active = true; + + + [self.disabledView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(disableAction)]]; + [self.enabledView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(enableAction)]]; + + } + + return self; +} + + +-(void)updatingValue { + + NSString *prefsPlistPath = @"/var/mobile/Library/Preferences/com.TitanD3v.PhoenixPrefs.plist"; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPlistPath]]; + + isEnabled = [[settings objectForKey:@"togglePhoenix"] boolValue]; + + if (isEnabled) { + + self.disabledView.layer.shadowColor = UIColor.clearColor.CGColor; + self.enabledView.layer.shadowColor = enabledColour.CGColor; + + self.disabledImage.alpha = 0.4; + self.disabledLabel.alpha = 0.4; + self.disabledStateView.alpha = 0.4; + self.enabledImage.alpha = 1.0; + self.enabledLabel.alpha = 1.0; + self.enabledStateView.alpha = 1.0; + + } else { + + self.disabledView.layer.shadowColor = disabledColour.CGColor; + self.enabledView.layer.shadowColor = UIColor.clearColor.CGColor; + + self.disabledImage.alpha = 1.0; + self.disabledLabel.alpha = 1.0; + self.disabledStateView.alpha = 1.0; + self.enabledImage.alpha = 0.4; + self.enabledLabel.alpha = 0.4; + self.enabledStateView.alpha = 0.4; + + } + +} + + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + [self updatingValue]; +} + + +-(void)disableAction { + + invokeHapticFeedback(); + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:[NSNumber numberWithBool:NO] forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + + [self updatingValue]; + +} + + +-(void)enableAction { + + invokeHapticFeedback(); + + NSString *isT = readPlist(@"isT"); + NSString *isU = readPlist(@"isU"); + NSString *mT = readPlist(@"mT"); + NSString *uT = readPlist(@"uT"); + NSString *udd = readPlist(@"udd"); + + NSString *UDID = (__bridge_transfer NSString *)MGCopyAnswer(kMGUniqueDeviceID); + if (([isT isEqual:@"YES"] || [isU isEqual:@"YES"]) && (![mT isEqual:@"Trial not found"] || ![uT isEqual:@"License not found"]) && [udd isEqual:UDID]) { + writeToPrefsPlist(@"togglePhoenix", @"YES"); + NSLog(@"AJSGAJSASAS enableAction enabeing tweak"); + } + else{ + NSLog(@"AJSGAJSASAS enableAction enabeing tweak"); + writeToPrefsPlist(@"togglePhoenix", @"NO"); + [self showAlert]; + } + + [self updatingValue]; + +} + + +-(void)showAlert { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:@"Sorry you can’t enable Phoenix because you haven’t purchased it.\n\nIf you already bought Phoenix then please connect to internet to use it" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + + }]; + [alertController addAction:okAction]; + alertController.view.tintColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController presentViewController:alertController animated:YES completion:nil]; + +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/Phoenix/Prefs/Purchase/PHXHelper.m b/Phoenix/Prefs/Purchase/PHXHelper.m new file mode 100644 index 0000000..5592231 --- /dev/null +++ b/Phoenix/Prefs/Purchase/PHXHelper.m @@ -0,0 +1,62 @@ +#import + +//Black : This is the purchase and trial prefs file which will save data for trail and purchase. +static NSString *plistPath = @"/var/mobile/Library/Preferences/com.applle.storeKit.Phoenix.plist"; + +//Black : this is the main Jarvis prefs file where enable/disable tweak will be saved changed with your own +static NSString *prefsPlistPath = @"/var/mobile/Library/Preferences/com.TitanD3v.PhoenixPrefs.plist"; + +static NSString* encryptString(NSString* plaintext) { + NSError *error = nil; + NSString *UDID = (__bridge_transfer NSString *)MGCopyAnswer(kMGUniqueDeviceID); + NSString *key = [NSString stringWithFormat:@"UDID%@meblackhat", UDID]; + NSData *data = [plaintext dataUsingEncoding:NSUTF8StringEncoding]; + NSData *encryptedData = [RNEncryptor encryptData:data withSettings:kRNCryptorAES256Settings password:key error:&error]; + return [encryptedData base64EncodedStringWithOptions:0]; +} + +static NSString* decryptString(NSString* encryptedString) { + if(!encryptedString) + return nil; + NSError *error = nil; + NSString *UDID = (__bridge_transfer NSString *)MGCopyAnswer(kMGUniqueDeviceID); + NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:encryptedString options:0]; + NSString *key = [NSString stringWithFormat:@"UDID%@meblackhat", UDID]; + + NSData *decryptedData = [RNDecryptor decryptData:decodedData withPassword:key error:&error]; + return [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];; +} + +// Black this will write values to purchase file +static void writeToPlist(NSString *key, NSString *value){ + NSString *valueE = encryptString(value); + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [mutableDict setValue:valueE forKey:key]; + [mutableDict writeToFile:plistPath atomically:YES]; +} + +// Black this will write values to tweaksMain prefs file +static void writeToPrefsPlist(NSString *key, NSString *value){ + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:prefsPlistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [mutableDict setValue:value forKey:key]; + [mutableDict writeToFile:prefsPlistPath atomically:YES]; +} + +// Black this will read values from purchase plist +static NSString *readPlist(NSString *key){ + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath]; + return decryptString([dict objectForKey:key]); +} + +// Black this will read values from main tweak prefs plist +static BOOL readPrefsPlist(NSString *key){ + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:prefsPlistPath]; + return [[dict objectForKey:key] boolValue]; +} + +static NSString *timeStamp(){ + long long mn = (long long)([[NSDate date] timeIntervalSince1970] * 1000.0); + return [NSString stringWithFormat:@"%lld", mn]; +} diff --git a/Phoenix/Prefs/Purchase/PHXPurchaseCell.h b/Phoenix/Prefs/Purchase/PHXPurchaseCell.h new file mode 100644 index 0000000..70bc919 --- /dev/null +++ b/Phoenix/Prefs/Purchase/PHXPurchaseCell.h @@ -0,0 +1,7 @@ +#import +#import + +@interface PHXPurchaseCell : UICollectionViewCell +@property (nonatomic, retain) BlurBannerView *baseView; +@property (nonatomic, retain) UIImageView *screenshotImage; +@end \ No newline at end of file diff --git a/Phoenix/Prefs/Purchase/PHXPurchaseCell.m b/Phoenix/Prefs/Purchase/PHXPurchaseCell.m new file mode 100644 index 0000000..84e3016 --- /dev/null +++ b/Phoenix/Prefs/Purchase/PHXPurchaseCell.m @@ -0,0 +1,27 @@ +#import "PHXPurchaseCell.h" + +@implementation PHXPurchaseCell + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 15; + self.clipsToBounds = true; + + self.baseView = [[BlurBannerView alloc] init]; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + self.screenshotImage = [[UIImageView alloc] init]; + [self.baseView addSubview:self.screenshotImage]; + + [self.screenshotImage fill]; + + } + return self; +} + +@end diff --git a/Phoenix/Prefs/Purchase/PHXPurchaseViewController.h b/Phoenix/Prefs/Purchase/PHXPurchaseViewController.h new file mode 100644 index 0000000..1da3178 --- /dev/null +++ b/Phoenix/Prefs/Purchase/PHXPurchaseViewController.h @@ -0,0 +1,22 @@ +#import +#import +#import +#import "PHXHelper.m" +#import "PHXPurchaseCell.h" + +@interface PHXPurchaseViewController : UIViewController +@property (nonatomic, retain) UIView *bannerView; +@property (nonatomic, retain) UIActivityIndicatorView *activityIndicator; +@property (nonatomic, retain) UILabel *tweaknameLabel; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UIButton *purchaseButton; +@property (nonatomic, retain) UIButton *trialButton; +@property (nonatomic, retain) UIButton *cancelButton; +@property (nonatomic, retain) TDConfettiView *confettiView; +@property (nonatomic, retain) UIImageView *bannerImage; +@property (nonatomic, retain) UIImageView *helpImage; +@property (nonatomic, retain) UIImageView *paypalImage; +@property (nonatomic, retain) UIImageView *stripeImage; +@property (nonatomic, strong) TDCyclePagerView *collectionView; +@property (nonatomic, strong) NSArray *screenshotArray; +@end diff --git a/Phoenix/Prefs/Purchase/PHXPurchaseViewController.m b/Phoenix/Prefs/Purchase/PHXPurchaseViewController.m new file mode 100644 index 0000000..787e458 --- /dev/null +++ b/Phoenix/Prefs/Purchase/PHXPurchaseViewController.m @@ -0,0 +1,484 @@ +#import "PHXPurchaseViewController.h" + +static NSString *UDIDCheckURL = @"https://payments.titand3v.com/api/check_udid.php?udid="; +static NSString *TRIALCheckURL = @"https://payments.titand3v.com/api/check_trial.php?udid="; +static NSString *URL = @"https://payments.titand3v.com/api/deviceCheck.php?udid="; + +static NSString *UDID = nil; +static NSString *tweaknameString = @"Phoenix"; +static NSString *priceString = @"$2.00"; +static BOOL showConfetti; + +static NSInteger helpActionIndex = 0; + +@implementation PHXPurchaseViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[TDPrefsManager sharedInstance] initWithBundleID:@"com.TitanD3v.PhoenixPrefs"]; + showConfetti = [[TDPrefsManager sharedInstance] boolForKey:@"showConfetti" defaultValue:YES]; + + self.view.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + self.view.clipsToBounds = true; + UDID = (__bridge_transfer NSString *)MGCopyAnswer(kMGUniqueDeviceID); + [self checkNetworkStatus]; + [self layoutBannerView]; + [self layoutCollectionView]; + [self layoutViews]; + [self layoutConfetti]; + +} + + +-(void)checkNetworkStatus { + + Reachability *_reachability = [Reachability reachabilityForInternetConnection]; + [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNetworkChange:) name:kReachabilityChangedNotification object: nil]; + _reachability = [Reachability reachabilityForInternetConnection]; + [_reachability startNotifier]; + [self performSelector:@selector(handleNetworkChange:) withObject:nil afterDelay:0]; + + + self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; + self.activityIndicator.alpha = 1.0; + self.activityIndicator.color = [UIColor colorWithRed: 0.95 green: 0.27 blue: 0.17 alpha: 1.00]; + self.activityIndicator.center = self.view.center; + [self.view addSubview:self.activityIndicator]; + +} + + +-(void)layoutBannerView { + + self.bannerImage = [[UIImageView alloc] init]; + self.bannerImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Payment/purchase-banner.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.bannerImage.tintColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + [self.view addSubview:self.bannerImage]; + + [self.bannerImage height:555]; + [self.bannerImage width:748]; + [self.bannerImage x:self.view.centerXAnchor]; + [self.bannerImage bottom:self.view.topAnchor padding:170]; + + + self.bannerView = [[UIView alloc] init]; + self.bannerView.clipsToBounds = true; + self.bannerView.backgroundColor = UIColor.clearColor; + [self.view addSubview:self.bannerView]; + + [self.bannerView top:self.view.topAnchor padding:0]; + [self.bannerView leading:self.view.leadingAnchor padding:0]; + [self.bannerView trailing:self.view.trailingAnchor padding:0]; + [self.bannerView height:170]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.clipsToBounds = true; + [self.bannerView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(50, 50)]; + [self.iconImage x:self.bannerView.centerXAnchor]; + [self.iconImage top:self.bannerView.topAnchor padding:40]; + + + self.tweaknameLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.tweaknameLabel.font = [UIFont boldSystemFontOfSize:14]; + self.tweaknameLabel.textColor = UIColor.whiteColor; + self.tweaknameLabel.text = tweaknameString; + self.tweaknameLabel.textAlignment = NSTextAlignmentCenter; + [self.bannerView addSubview:self.tweaknameLabel]; + + [self.tweaknameLabel x:self.bannerView.centerXAnchor]; + [self.tweaknameLabel top:self.iconImage.bottomAnchor padding:5]; + +} + + +-(void)layoutCollectionView { + + self.screenshotArray = [[NSMutableArray alloc] initWithObjects: + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss1.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss2.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss3.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss4.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss5.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss6.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss7.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss8.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss9.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss10.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss11.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss12.png"], + [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/PhoenixPrefs.bundle/Assets/Payment/ss13.png"], + nil]; + + self.collectionView = [[TDCyclePagerView alloc]init]; + self.collectionView.isInfiniteLoop = YES; + self.collectionView.autoScrollInterval = 2.0; + self.collectionView.dataSource = self; + self.collectionView.delegate = self; + self.collectionView.backgroundColor = UIColor.clearColor; + [self.collectionView registerClass:[PHXPurchaseCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.view addSubview:self.collectionView]; + + [self.collectionView width:self.view.frame.size.width]; + [self.collectionView height:300]; + [self.collectionView x:self.view.centerXAnchor]; + [self.collectionView top:self.view.topAnchor padding:130]; +} + + +- (NSInteger)numberOfItemsInPagerView:(TDCyclePagerView *)pageView { + return self.screenshotArray.count; +} + + +- (UICollectionViewCell *)pagerView:(TDCyclePagerView *)pagerView cellForItemAtIndex:(NSInteger)index { + + PHXPurchaseCell *cell = [pagerView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndex:index]; + cell.screenshotImage.image = [self.screenshotArray objectAtIndex:index]; + return cell; + +} + + +- (TDCyclePagerViewLayout *)layoutForPagerView:(TDCyclePagerView *)pageView { + TDCyclePagerViewLayout *layout = [[TDCyclePagerViewLayout alloc]init]; + layout.itemSize = CGSizeMake(300, 300); + layout.itemSpacing = 15; + layout.minimumAlpha = 0.3; + layout.itemHorizontalCenter = YES; + layout.layoutType = 1; + return layout; +} + + +- (void)pagerView:(TDCyclePagerView *)pageView didScrollFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex { + NSLog(@"%ld -> %ld",fromIndex,toIndex); +} + + +-(void)pagerView:(TDCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndex:(NSInteger)index { +} + + +-(void)layoutViews { + + + self.cancelButton = [[UIButton alloc] init]; + [self.cancelButton addTarget:self action:@selector(dismissVC) forControlEvents:UIControlEventTouchUpInside]; + [self.cancelButton setTitle:@"Cancel" forState:UIControlStateNormal]; + [self.cancelButton setTitleColor:[UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00] forState:UIControlStateNormal]; + self.cancelButton.backgroundColor = UIColor.clearColor; + self.cancelButton.layer.cornerRadius = 15; + [self.view addSubview:self.cancelButton]; + + [self.cancelButton size:CGSizeMake(250, 50)]; + [self.cancelButton x:self.view.centerXAnchor]; + [self.cancelButton bottom:self.view.bottomAnchor padding:-20]; + + + NSString *purchaseString = [NSString stringWithFormat:@"Purchase %@", priceString]; + self.purchaseButton = [[UIButton alloc] initWithFrame:CGRectZero]; + [self.purchaseButton addTarget:self action:@selector(purchaseTweak) forControlEvents:UIControlEventTouchUpInside]; + [self.purchaseButton setTitle:purchaseString forState:UIControlStateNormal]; + self.purchaseButton.backgroundColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + self.purchaseButton.layer.cornerRadius = 15; + [self.view addSubview:self.purchaseButton]; + + [self.purchaseButton size:CGSizeMake(270, 50)]; + [self.purchaseButton x:self.view.centerXAnchor]; + [self.purchaseButton bottom:self.cancelButton.topAnchor padding:-10]; + + + self.paypalImage = [[UIImageView alloc] init]; + self.paypalImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Payment/PayPal.png"]; + [self.view addSubview:self.paypalImage]; + + [self.paypalImage size:CGSizeMake(30, 21)]; + [self.paypalImage x:self.view.centerXAnchor padding:-20]; + [self.paypalImage bottom:self.purchaseButton.topAnchor padding:-5]; + + + self.stripeImage = [[UIImageView alloc] init]; + self.stripeImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Payment/Stripe.png"]; + [self.view addSubview:self.stripeImage]; + + [self.stripeImage size:CGSizeMake(30, 21)]; + [self.stripeImage x:self.view.centerXAnchor padding:20]; + [self.stripeImage bottom:self.purchaseButton.topAnchor padding:-5]; + + + self.helpImage = [[UIImageView alloc] init]; + self.helpImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Payment/payment-help.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.helpImage.tintColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + self.helpImage.userInteractionEnabled = true; + [self.view addSubview:self.helpImage]; + + [self.helpImage size:CGSizeMake(35, 35)]; + [self.helpImage bottom:self.view.bottomAnchor padding:-20]; + [self.helpImage trailing:self.view.trailingAnchor padding:-20]; + + [self.helpImage addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(helpTapped)]]; +} + + +-(void)layoutConfetti { + + self.confettiView = [[TDConfettiView alloc] initWithFrame:self.view.bounds]; + self.confettiView.colors = @[ + [UIColor colorWithRed:0.95 green:0.40 blue:0.27 alpha:1.0], + [UIColor colorWithRed:1.00 green:0.78 blue:0.36 alpha:1.0], + [UIColor colorWithRed:0.48 green:0.78 blue:0.64 alpha:1.0], + [UIColor colorWithRed:0.30 green:0.76 blue:0.85 alpha:1.0], + [UIColor colorWithRed:0.58 green:0.39 blue:0.55 alpha:1.0]]; + + self.confettiView.type = TDConfettiTypeConfetti; + self.confettiView.alpha = 0; + [self.view addSubview:self.confettiView]; + +} + + +- (void)handleNetworkChange:(NSNotification *)notice{ + + Reachability *_reachability = [Reachability reachabilityForInternetConnection]; + NetworkStatus remoteHostStatus = [_reachability currentReachabilityStatus]; + if (remoteHostStatus == NotReachable) { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:tweaknameString message:@"The internet connection appears to be offline. Please connect to the internet." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + + [self.activityIndicator startAnimating]; + + } else if (remoteHostStatus == ReachableViaWiFi) { + + [self.activityIndicator stopAnimating]; + + } else if (remoteHostStatus == ReachableViaWWAN) { + + [self.activityIndicator stopAnimating]; + + } +} + + +-(void)purchaseTweak { + + [[TDUtilities sharedInstance] haptic:0]; + + NSString *purchaseURLString = [NSString stringWithFormat:@"https://payments.titand3v.com/?udid=%@&tn=%@", UDID, tweaknameString]; + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:purchaseURLString]]; + [self dismissVC]; +} + + +- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller { + + UDID = (__bridge_transfer NSString *)MGCopyAnswer(kMGUniqueDeviceID); + NSString *finalURL = [NSString stringWithFormat:@"%@%@&tweak=%@", URL, UDID, tweaknameString]; + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; + [request setURL:[NSURL URLWithString:finalURL]]; + [request setHTTPMethod:@"GET"]; + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; + [[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + if(!data){ + dispatch_async(dispatch_get_main_queue(), ^{ + writeToPlist(@"isT", @"NOTHING"); + writeToPlist(@"isU", @"NOTHING"); + writeToPlist(@"mT", @"NOTHING"); + writeToPlist(@"uT", @"NOTHING"); + writeToPlist(@"udd", @"NOTHING"); + writeToPlist(@"stp", @"NOTHING"); + }); + return; + } + NSString *resString = decryptString([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); + id J = [NSJSONSerialization JSONObjectWithData:[resString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; + id T = [NSJSONSerialization JSONObjectWithData:[J[@"trialStatus"] dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; + id U = [NSJSONSerialization JSONObjectWithData:[J[@"udidStatus"] dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; + + NSString *isT = T[@"status"]; + NSString *isU = U[@"status"]; + NSString *mT = U[@"msg"]; + NSString *uT = T[@"msg"]; + NSString *udd = T[@"udid"]; + + NSString *stp = T[@"stamp"]; + + if(([isT isEqual:@"YES"] || [isU isEqual:@"YES"]) && (![mT isEqual:@"Trial not found"] || ![uT isEqual:@"License not found"]) && [udd isEqual:UDID]){ + dispatch_async(dispatch_get_main_queue(), ^{ + if (showConfetti) { + self.confettiView.alpha = 1; + [self.confettiView startConfetti]; + [self performSelector:@selector(stopConfetti) withObject:nil afterDelay:5]; + [[TDPrefsManager sharedInstance] setBool:NO forKey:@"showConfetti"]; + } + }); + } + + writeToPlist(@"isT", T[@"status"]); + writeToPlist(@"isU", U[@"status"]); + writeToPlist(@"mT", mT); + writeToPlist(@"uT", uT); + writeToPlist(@"udd", udd); + writeToPlist(@"stp", stp); + }] resume]; + + [controller dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)helpTapped { + + [[TDUtilities sharedInstance] haptic:0]; + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Need some help?" message:@"😟" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* loadingAction = [UIAlertAction actionWithTitle:@"Not Loading" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + helpActionIndex = 0; + [self helpAlert]; + }]; + + UIAlertAction* trialAction = [UIAlertAction actionWithTitle:@"Can't Activate Trial" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + helpActionIndex = 1; + [self helpAlert]; + }]; + + UIAlertAction* purchaseAction = [UIAlertAction actionWithTitle:@"Can't Purchase" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + helpActionIndex = 2; + [self helpAlert]; + }]; + + UIAlertAction* licenceAction = [UIAlertAction actionWithTitle:@"Licence Transfer" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + helpActionIndex = 3; + [self helpAlert]; + }]; + + UIAlertAction* contactAction = [UIAlertAction actionWithTitle:@"Contact Us" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + helpActionIndex = 4; + [self helpAlert]; + }]; + + UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + }]; + + [alert addAction:loadingAction]; + [alert addAction:trialAction]; + [alert addAction:purchaseAction]; + [alert addAction:licenceAction]; + [alert addAction:contactAction]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + + +-(void)helpAlert { + + if (helpActionIndex == 0) { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Not Loading" message:@"Please make sure you are connected to the internet or try using a fast Wi-Fi connection." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + + } else if (helpActionIndex == 1) { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Can't Activate Trial" message:@"If you can't activate trial then it could be that you already used the free trial and it has expired." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + + } else if (helpActionIndex == 2) { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Can't Purchase" message:@"If you can't purchase the tweak, please try to connect to the internet or open the link in your Safari web browser. You can check if PayPal or Stripe is available in your country." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* paypalAction = [UIAlertAction actionWithTitle:@"PayPal available countries list" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self dismissVC]; + [[TDUtilities sharedInstance] launchURL:@"https://www.paypal.com/uk/webapps/mpp/country-worldwide"]; + }]; + + UIAlertAction* stripeAction = [UIAlertAction actionWithTitle:@"Stripe available countries list" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self dismissVC]; + [[TDUtilities sharedInstance] launchURL:@"https://stripe.com/global"]; + }]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + }]; + + [alert addAction:paypalAction]; + [alert addAction:stripeAction]; + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + + } else if (helpActionIndex == 3) { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Licence Transfer" message:@"If you have a new device or want to use the tweak on your other device then please contact us through our social media below, send us proof of your purchase and UDID of the device you want to transfer the licence to. You are entitled to a maxium of 2 licences." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* twitterAction = [UIAlertAction actionWithTitle:@"Contact us via Twitter" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self dismissVC]; + [[TDUtilities sharedInstance] launchURL:@"https://twitter.com/D3vTitan"]; + }]; + + UIAlertAction* discordAction = [UIAlertAction actionWithTitle:@"Contact us via Discord" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self dismissVC]; + [[TDUtilities sharedInstance] launchURL:@"https://discord.com/invite/Kk4KYpZ528"]; + }]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + }]; + + [alert addAction:twitterAction]; + [alert addAction:discordAction]; + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + + } else if (helpActionIndex == 4) { + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Contact Us" message:@"You can contact us through our social media below" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* twitterAction = [UIAlertAction actionWithTitle:@"Contact us via Twitter" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self dismissVC]; + [[TDUtilities sharedInstance] launchURL:@"https://twitter.com/D3vTitan"]; + }]; + + UIAlertAction* discordAction = [UIAlertAction actionWithTitle:@"Contact us via Discord" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self dismissVC]; + [[TDUtilities sharedInstance] launchURL:@"https://discord.com/invite/Kk4KYpZ528"]; + }]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + }]; + + [alert addAction:twitterAction]; + [alert addAction:discordAction]; + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + + } + +} + +-(void)stopConfetti { + [self.confettiView stopConfetti]; + self.confettiView.alpha = 0; +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/Phoenix/Prefs/Resources/Assets/Banner/banner-icon.png b/Phoenix/Prefs/Resources/Assets/Banner/banner-icon.png new file mode 100644 index 0000000..e05c2b0 Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Banner/banner-icon.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Banner/cover-image.png b/Phoenix/Prefs/Resources/Assets/Banner/cover-image.png new file mode 100644 index 0000000..4987a4d Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Banner/cover-image.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Cell/cell-banner.png b/Phoenix/Prefs/Resources/Assets/Cell/cell-banner.png new file mode 100644 index 0000000..67f24fc Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Cell/cell-banner.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Cell/prefs-icon@2x.png b/Phoenix/Prefs/Resources/Assets/Cell/prefs-icon@2x.png new file mode 100644 index 0000000..34ca3eb Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Cell/prefs-icon@2x.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Cell/prefs-icon@3x.png b/Phoenix/Prefs/Resources/Assets/Cell/prefs-icon@3x.png new file mode 100644 index 0000000..3e8eb3a Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Cell/prefs-icon@3x.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Changelog/changelog.plist b/Phoenix/Prefs/Resources/Assets/Changelog/changelog.plist new file mode 100644 index 0000000..b48871c --- /dev/null +++ b/Phoenix/Prefs/Resources/Assets/Changelog/changelog.plist @@ -0,0 +1,41 @@ + + + + + + + Date + 15th November 2021 + Version + v1.1 + ChangelogDescription + + Added toggle switch in the settings from the Phone app to hide phone number and email address for the contacts list + Added # for the index to show contacts that saved by number instead of names + Fixed index and search bugs + + updateCategories + + 3 + 3 + 1 + + + + + Date + 13th November 2021 + Version + v1.0 + ChangelogDescription + + Initial Release... + + updateCategories + + 0 + + + + + diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss1.png b/Phoenix/Prefs/Resources/Assets/Payment/ss1.png new file mode 100644 index 0000000..dafdc99 Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss1.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss10.png b/Phoenix/Prefs/Resources/Assets/Payment/ss10.png new file mode 100644 index 0000000..ce536a8 Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss10.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss11.png b/Phoenix/Prefs/Resources/Assets/Payment/ss11.png new file mode 100644 index 0000000..2bc593f Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss11.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss12.png b/Phoenix/Prefs/Resources/Assets/Payment/ss12.png new file mode 100644 index 0000000..1791ec8 Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss12.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss13.png b/Phoenix/Prefs/Resources/Assets/Payment/ss13.png new file mode 100644 index 0000000..bc75169 Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss13.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss2.png b/Phoenix/Prefs/Resources/Assets/Payment/ss2.png new file mode 100644 index 0000000..d433486 Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss2.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss3.png b/Phoenix/Prefs/Resources/Assets/Payment/ss3.png new file mode 100644 index 0000000..082d5ac Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss3.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss4.png b/Phoenix/Prefs/Resources/Assets/Payment/ss4.png new file mode 100644 index 0000000..94e3d0e Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss4.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss5.png b/Phoenix/Prefs/Resources/Assets/Payment/ss5.png new file mode 100644 index 0000000..bd0e622 Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss5.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss6.png b/Phoenix/Prefs/Resources/Assets/Payment/ss6.png new file mode 100644 index 0000000..3c99d67 Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss6.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss7.png b/Phoenix/Prefs/Resources/Assets/Payment/ss7.png new file mode 100644 index 0000000..00acdb4 Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss7.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss8.png b/Phoenix/Prefs/Resources/Assets/Payment/ss8.png new file mode 100644 index 0000000..c437cc3 Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss8.png differ diff --git a/Phoenix/Prefs/Resources/Assets/Payment/ss9.png b/Phoenix/Prefs/Resources/Assets/Payment/ss9.png new file mode 100644 index 0000000..d554515 Binary files /dev/null and b/Phoenix/Prefs/Resources/Assets/Payment/ss9.png differ diff --git a/Phoenix/Prefs/Resources/Info.plist b/Phoenix/Prefs/Resources/Info.plist new file mode 100644 index 0000000..b4b2fab --- /dev/null +++ b/Phoenix/Prefs/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + PhoenixPrefs + CFBundleIdentifier + com.titand3v.phoenixprefs + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + PHXPrimraryListController + + diff --git a/Phoenix/Prefs/Resources/Primrary.plist b/Phoenix/Prefs/Resources/Primrary.plist new file mode 100644 index 0000000..6b43814 --- /dev/null +++ b/Phoenix/Prefs/Resources/Primrary.plist @@ -0,0 +1,48 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable + + + + cellClass + TDEnableCell + default + + key + togglePhoenix + disabledTitle + Disable Phoenix + enabledTitle + Enable Phoenix + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + disabledIconPath + Assets/example-icon.png + enabledIconPath + Assets/example-icon.png + defaults + com.TitanD3v.PhoenixPrefs + PostNotification + com.TitanD3v.PhoenixPrefs.settingschanged + + + + title + + + diff --git a/Phoenix/Prefs/entry.plist b/Phoenix/Prefs/entry.plist new file mode 100644 index 0000000..6916d27 --- /dev/null +++ b/Phoenix/Prefs/entry.plist @@ -0,0 +1,21 @@ + + + + + entry + + bundle + PhoenixPrefs + cell + PSLinkCell + detail + PHXPrimraryListController + icon + Assets/Cell/prefs-icon.png + isController + + label + Phoenix + + + diff --git a/Phoenix/Tweak/Interfaces.h b/Phoenix/Tweak/Interfaces.h new file mode 100644 index 0000000..a8148f7 --- /dev/null +++ b/Phoenix/Tweak/Interfaces.h @@ -0,0 +1,122 @@ +#import +#import + +@interface PHVoicemailMessageTableViewCell : UITableViewCell +@end + +@interface PHVoicemailMailboxTableViewCell : UITableViewCell +@end + +@interface CNContactListTableView : UITableView +@end + +@interface MPVoicemailMailboxTableViewCell : UITableViewCell +@end + +@interface CNContactListTableViewCell : UITableViewCell +@end + +@interface CNContactListViewController : UITableViewController +@end + +@interface PHVoicemailInboxListViewController : UITableViewController +@end + +@interface PHVoicemailTrashListViewController : UITableViewController +@end + +@interface MPFavoritesTableViewCell : UITableViewCell +@end + +@interface MPFavoritesTableViewController : UITableViewController +@end + +@interface MPRecentsTableViewCell : UITableViewCell +@end + +@interface MPRecentsTableViewController : UITableViewController +@end + +// @interface PHHandsetDialerNumberPadButton : UIControl +// @property (retain) UIView *circleView; +// @end + +// @implementation PHHandsetDialerNumberPadButton +// @synthesize circleView=_circleView; +// @end + +// @interface TPDialerNumberPad : UIView +// @end + +// @interface PHBottomBarButton : UIButton +// @end + +@interface CNContactListHeaderFooterView : UIView +@end + +@interface _UITableViewHeaderFooterViewLabel : UILabel +@end + + +@interface RTTTelephonyUtilities ++(id)sharedUtilityProvider; +-(id)myPhoneNumber; +@end + +@interface CNContact(Priv) +@property (getter=isUnknown,nonatomic,readonly) BOOL unknown; +@end + +@interface CNUINavigationListItem : NSObject +-(void)setImage:(UIImage *)arg1 ; +-(NSString *)subtitle; +-(id)initWithTitle:(id)arg1 ; +-(void)setSubtitle:(NSString *)arg1 ; +-(void)setItems:(NSArray *)arg1 ; +-(void)setIdentifier:(NSString *)arg1 ; +-(void)setDefaultItem:(id)arg1 ; +@end + +@interface CNUINavigationListViewController : UIViewController +@property (nonatomic, copy) CNContact *contact; +-(NSArray *)items; +@end + +@interface CNContactActionsController +@property (nonatomic, strong, readwrite) CNContact *contact; +@end + +@interface CNAvatarCardViewController +@property (nonatomic, strong, readwrite) CNContactActionsController *actionsController; +- (id)actionListViewController; +-(void)dismissAnimated:(BOOL)arg1 ; +@end + +@interface CNContactHeaderView : UIView +@property (nonatomic,retain) NSArray * contacts; +@property (nonatomic,retain) UILabel *nameLabel; +@end + +//This is to add contacts headers image +@interface CNContactHeaderDisplayView : CNContactHeaderView +@property (nonatomic, copy) UIImage *headerImage; +@property (nonatomic, copy) NSString *contactId; +- (UIViewController *)_viewControllerForAncestor; + +-(UIImage *)coverImageForCID:(NSString *)CID; +-(void)setCoverImageForCID:(NSString *)CID image:(UIImage*)headerImage; +@end + +@interface CNActionItem : NSObject +- (id)initWithImage:(id)arg1 type:(id)arg2; +- (void)setTitle:(id)arg1; +- (NSString *)type; +@end + +@interface CNActionsView : UIView +- (void)addActionItem:(CNActionItem *)action; +@end + + +@interface CNContactInlineActionsViewController : UIViewController +@end \ No newline at end of file diff --git a/Phoenix/Tweak/Makefile b/Phoenix/Tweak/Makefile new file mode 100644 index 0000000..c94a0b0 --- /dev/null +++ b/Phoenix/Tweak/Makefile @@ -0,0 +1,23 @@ +TWEAK_NAME = Phoenix + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +dtoim = $(foreach d,$(1),-I$(d)) +_IMPORTS = $(shell /bin/ls -d ./*/) +_IMPORTS = $(shell /bin/ls -d ./PHOENIX/) +_IMPORTS = $(shell /bin/ls -d ./PHOENIX/*/) +_IMPORTS += $(shell /bin/ls -d ./PHOENIX/*/*/) +_IMPORTS += $(shell /bin/ls -d ./PHOENIX/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./PHOENIX/*/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./) +IMPORTS = -I$./PHOENIX $(call dtoim, $(_IMPORTS)) + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations -Wno-unused-variable -Wno-error -Wno-unused-function -Wall $(IMPORTS) +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Phoenix/Tweak/PHOENIX/Action/ActionMenuViewController.h b/Phoenix/Tweak/PHOENIX/Action/ActionMenuViewController.h new file mode 100644 index 0000000..29ff065 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Action/ActionMenuViewController.h @@ -0,0 +1,25 @@ +#import +#import "ContactsData.h" +#import "ActionMenuCell.h" +#import "TDAnimator.h" +#import +#import +#import "SettingManager.h" + +@protocol DeleteContactProtocol +@required +-(void)needRefreshDataSourceAfterDeleteContact; +@end + +@interface ActionMenuViewController : UIViewController +@property (strong) CNContactStore *store; +@property (strong) CNContact *contact; +-(instancetype)initWithData:(ContactsData *)data cncontact:(CNContact *)cncontact height:(CGFloat)height; +@property (nonatomic, retain) ContactsData *contactData; +@property (nonatomic, retain) TDAnimator *myAnimator; +@property (nonatomic, retain) UIImageView *avatar; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *actionArray; +@property(nonatomic,assign)id delegate; +@end diff --git a/Phoenix/Tweak/PHOENIX/Action/ActionMenuViewController.m b/Phoenix/Tweak/PHOENIX/Action/ActionMenuViewController.m new file mode 100644 index 0000000..003030c --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Action/ActionMenuViewController.m @@ -0,0 +1,287 @@ +#import "ActionMenuViewController.h" + +#define CELL_WIDTH 50 +#define CELL_SPACING 10 + +@implementation ActionMenuViewController + +-(instancetype)initWithData:(ContactsData *)data cncontact:(CNContact *)cncontact height:(CGFloat)height { + + self = [super init]; + if (self) { + self.contactData = data; + self.modalPresentationStyle = UIModalPresentationCustom; + self.myAnimator = [[TDAnimator alloc] initWithCHeight:height andDimALpha:1.0]; + self.transitioningDelegate = self.myAnimator; + + self.contact = cncontact; + self.store = [[CNContactStore alloc] init]; + self.actionArray = [[NSMutableArray alloc] init]; + + if (self.contactData.phone != nil) { + [self.actionArray addObject:@"Phone"]; + [self.actionArray addObject:@"Message"]; + } + + + if (self.contactData.email != nil) { + [self.actionArray addObject:@"Email"]; + } + + + // [MBH's task] + // Need to check if facetime is available for self.contactData.phone then [self.actionArray addObject:@"FaceTime"]; + + + [self.actionArray addObject:@"Delete"]; + + } + return self; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.systemBackgroundColor; + self.view.layer.cornerRadius = 25; + self.view.layer.cornerCurve = kCACornerCurveContinuous; + self.view.layer.maskedCorners = 3; + + [self layoutHeaderView]; + [self layoutCollectionView]; +} + + +-(void)layoutHeaderView { + + + self.avatar = [[UIImageView alloc] init]; + self.avatar.layer.cornerRadius = 35; + self.avatar.contentMode = UIViewContentModeScaleAspectFill; + self.avatar.clipsToBounds = YES; + if (self.contactData.avatar != nil) { + self.avatar.image = self.contactData.avatar; + } else { + self.avatar.image = [UIImage systemImageNamed:@"person.crop.circle.fill"]; + self.avatar.tintColor = [[SettingManager sharedInstance] accentColour]; + } + [self.view addSubview:self.avatar]; + + [self.avatar size:CGSizeMake(70, 70)]; + [self.avatar x:self.view.centerXAnchor]; + [self.avatar top:self.view.topAnchor padding:20]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.textAlignment = NSTextAlignmentCenter; + self.nameLabel.textColor = UIColor.labelColor; + self.nameLabel.font = [UIFont systemFontOfSize:22 weight:UIFontWeightSemibold]; + self.nameLabel.text = [NSString stringWithFormat:@"%@ %@", self.contactData.firstName, self.contactData.lastName]; + [self.view addSubview:self.nameLabel]; + + [self.nameLabel x:self.view.centerXAnchor]; + [self.nameLabel top:self.avatar.bottomAnchor padding:10]; + [self.nameLabel leading:self.view.leadingAnchor padding:15]; + [self.nameLabel trailing:self.view.trailingAnchor padding:-15]; + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[ActionMenuCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.view addSubview:self.collectionView]; + + [self.collectionView height:70]; + [self.collectionView x:self.view.centerXAnchor]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + [self.collectionView top:self.nameLabel.bottomAnchor padding:15]; + + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.actionArray.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ActionMenuCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + if ([[self.actionArray objectAtIndex:indexPath.row] isEqualToString:@"Phone"]) { + + cell.iconView.backgroundColor = [[[SettingManager sharedInstance] callButtonColour] colorWithAlphaComponent:0.3]; + cell.iconImage.image = [UIImage systemImageNamed:@"phone.fill"]; + cell.iconImage.tintColor = [[SettingManager sharedInstance] callButtonColour]; + cell.titleLabel.text = @"Call"; + + } else if ([[self.actionArray objectAtIndex:indexPath.row] isEqualToString:@"Message"]) { + cell.iconView.backgroundColor = [[[SettingManager sharedInstance] messageButtonColour] colorWithAlphaComponent:0.3]; + cell.iconImage.image = [UIImage systemImageNamed:@"message.fill"]; + cell.iconImage.tintColor = [[SettingManager sharedInstance] messageButtonColour]; + cell.titleLabel.text = @"Message"; + + } else if ([[self.actionArray objectAtIndex:indexPath.row] isEqualToString:@"Email"]) { + cell.iconView.backgroundColor = [[[SettingManager sharedInstance] emailButtonColour] colorWithAlphaComponent:0.3]; + cell.iconImage.image = [UIImage systemImageNamed:@"envelope.fill"]; + cell.iconImage.tintColor = [[SettingManager sharedInstance] emailButtonColour]; + cell.titleLabel.text = @"Email"; + + } else if ([[self.actionArray objectAtIndex:indexPath.row] isEqualToString:@"FaceTime"]) { + cell.iconView.backgroundColor = [UIColor.systemBlueColor colorWithAlphaComponent:0.3]; + cell.iconImage.image = [UIImage systemImageNamed:@"video.fill"]; + cell.iconImage.tintColor = UIColor.systemBlueColor; + cell.titleLabel.text = @"FaceTime"; + + } else if ([[self.actionArray objectAtIndex:indexPath.row] isEqualToString:@"Delete"]) { + cell.iconView.backgroundColor = [[[SettingManager sharedInstance] deleteButtonColour] colorWithAlphaComponent:0.3]; + cell.iconImage.image = [UIImage systemImageNamed:@"trash.fill"]; + cell.iconImage.tintColor = [[SettingManager sharedInstance] deleteButtonColour]; + cell.titleLabel.text = @"Delete"; + } + + return cell; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + return CGSizeMake(50, 70); +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + NSInteger viewWidth = self.view.frame.size.width; + NSInteger totalCellWidth = CELL_WIDTH * self.actionArray.count; + NSInteger totalSpacingWidth = CELL_SPACING * (self.actionArray.count -1); + + NSInteger leftInset = (viewWidth - (totalCellWidth + totalSpacingWidth)) / 2; + NSInteger rightInset = leftInset; + + return UIEdgeInsetsMake(0, leftInset, 0, rightInset); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + UIApplication *application = [UIApplication sharedApplication]; + + if ([[self.actionArray objectAtIndex:indexPath.row] isEqualToString:@"Phone"]) { + + [self dismissVC]; + NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"tel:%@", self.contactData.phone]]; + [application openURL:URL options:@{} completionHandler:nil]; + + } else if ([[self.actionArray objectAtIndex:indexPath.row] isEqualToString:@"Message"]) { + + [self dismissVC]; + NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"sms:%@", self.contactData.phone]]; + [application openURL:URL options:@{} completionHandler:nil]; + + } else if ([[self.actionArray objectAtIndex:indexPath.row] isEqualToString:@"Email"]) { + + [self presentEmailAlert]; + + } else if ([[self.actionArray objectAtIndex:indexPath.row] isEqualToString:@"FaceTime"]) { + + [self dismissVC]; + NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"facetime://%@", self.contactData.phone]]; + [application openURL:URL options:@{} completionHandler:nil]; + + } else if ([[self.actionArray objectAtIndex:indexPath.row] isEqualToString:@"Delete"]) { + + [self presentDeleteAlert]; + } + +} + + + +-(void)presentDeleteAlert { + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning!" message:[NSString stringWithFormat:@"Are you sure you want to delete %@ %@? You can't undo once deleted.", self.contactData.firstName, self.contactData.lastName] preferredStyle:UIAlertControllerStyleAlert]; + + + UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:@"Delete" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) { + + CNMutableContact *mutableContact = self.contact.mutableCopy; + + CNContactStore *store = [[CNContactStore alloc] init]; + CNSaveRequest *deleteRequest = [[CNSaveRequest alloc] init]; + [deleteRequest deleteContact:mutableContact]; + + NSError *error; + if([store executeSaveRequest:deleteRequest error:&error]) { + NSLog(@"delete complete"); + [self.delegate needRefreshDataSourceAfterDeleteContact]; + [self dismissVC]; + }else { + NSLog(@"delete error: %@", [error description]); + } + + }]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self dismissVC]; + }]; + + [alert addAction:deleteAction]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; + +} + + +-(void)presentEmailAlert { + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Email" message:[NSString stringWithFormat:@"Which email app would you like to send the email to %@ %@", self.contactData.firstName, self.contactData.lastName] preferredStyle:UIAlertControllerStyleAlert]; + + UIApplication *application = [UIApplication sharedApplication]; + + UIAlertAction *mailAction = [UIAlertAction actionWithTitle:@"Mail" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + [self dismissVC]; + NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@", self.contactData.email]]; + [application openURL:URL options:@{} completionHandler:nil]; + + }]; + + UIAlertAction *gmailAction = [UIAlertAction actionWithTitle:@"Gmail" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + [self dismissVC]; + NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"googlegmail:///co?to=%@", self.contactData.email]]; + [application openURL:URL options:@{} completionHandler:nil]; + }]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self dismissVC]; + }]; + + [alert addAction:mailAction]; + [alert addAction:gmailAction]; + [alert addAction:cancelAction]; + [self presentViewController:alert animated:YES completion:nil]; + +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Categories/CategoriesColourSection.h b/Phoenix/Tweak/PHOENIX/Categories/CategoriesColourSection.h new file mode 100644 index 0000000..0f3d225 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Categories/CategoriesColourSection.h @@ -0,0 +1,12 @@ +#import + +@interface CategoriesColourSection : UIView +-(instancetype)initWithFrame:(CGRect)frame icon:(UIImage *)icon; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *icon; +@property (nonatomic, retain) UILabel *title; +@property (nonatomic, retain) UIImageView *wheelImage; +@property (nonatomic, retain) UIImage *iconImage; +@property (nonatomic, retain) UIView *colourView; +@end + diff --git a/Phoenix/Tweak/PHOENIX/Categories/CategoriesColourSection.m b/Phoenix/Tweak/PHOENIX/Categories/CategoriesColourSection.m new file mode 100644 index 0000000..666f7e3 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Categories/CategoriesColourSection.m @@ -0,0 +1,77 @@ +#import "CategoriesColourSection.h" + +@implementation CategoriesColourSection + +-(instancetype)initWithFrame:(CGRect)frame icon:(UIImage *)icon { + + self = [super initWithFrame:frame]; + if (self) { + + self.clipsToBounds = YES; + self.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.layer.cornerRadius = 20; + self.layer.cornerCurve = kCACornerCurveContinuous; + + self.iconImage = icon; + + [self layoutViews]; + + } + return self; +} + + +-(void)layoutViews { + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 12; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + [self addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(45, 45)]; + [self.iconView y:self.centerYAnchor]; + [self.iconView leading:self.leadingAnchor padding:15]; + + + self.icon = [[UIImageView alloc] init]; + self.icon.contentMode = UIViewContentModeScaleAspectFit; + self.icon.image = self.iconImage; + [self addSubview:self.icon]; + + [self.icon size:CGSizeMake(30, 30)]; + [self.icon x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.title = [[UILabel alloc] init]; + self.title.textAlignment = NSTextAlignmentLeft; + self.title.textColor = UIColor.labelColor; + self.title.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold]; + [self addSubview:self.title]; + + [self.title y:self.centerYAnchor]; + [self.title leading:self.icon.trailingAnchor padding:15]; + + + self.wheelImage = [[UIImageView alloc] init]; + self.wheelImage.contentMode = UIViewContentModeScaleAspectFill; + self.wheelImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Phoenix.bundle/Assets/colour-wheel.png"]; + self.wheelImage.layer.cornerRadius = 20; + self.wheelImage.clipsToBounds = YES; + [self addSubview:self.wheelImage]; + + [self.wheelImage size:CGSizeMake(40, 40)]; + [self.wheelImage y:self.centerYAnchor]; + [self.wheelImage trailing:self.trailingAnchor padding:-10]; + + + self.colourView = [[UIView alloc] init]; + self.colourView.layer.cornerRadius = 17.5; + self.colourView.clipsToBounds = YES; + [self addSubview:self.colourView]; + + [self.colourView size:CGSizeMake(35, 35)]; + [self.colourView x:self.wheelImage.centerXAnchor y:self.wheelImage.centerYAnchor]; + +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Categories/CategoriesNextButton.h b/Phoenix/Tweak/PHOENIX/Categories/CategoriesNextButton.h new file mode 100644 index 0000000..8e196b2 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Categories/CategoriesNextButton.h @@ -0,0 +1,8 @@ +#import + +@interface CategoriesNextButton : UIControl +-(instancetype)initWithIcon:(NSString *)iconString title:(NSString *)titleString accent:(UIColor *)accent action:(SEL)customAction; +@property (nonatomic, retain) UILabel *title; +@property (nonatomic, retain) UIImageView *icon; +@end + diff --git a/Phoenix/Tweak/PHOENIX/Categories/CategoriesNextButton.m b/Phoenix/Tweak/PHOENIX/Categories/CategoriesNextButton.m new file mode 100644 index 0000000..7fa7ef2 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Categories/CategoriesNextButton.m @@ -0,0 +1,74 @@ +#import "CategoriesNextButton.h" + +@implementation CategoriesNextButton + +-(instancetype)initWithIcon:(NSString *)iconString title:(NSString *)titleString accent:(UIColor *)accent action:(SEL)customAction { + + self = [super init]; + if (self) { + + + self.backgroundColor = accent; + self.clipsToBounds = YES; + + + self.icon = [[UIImageView alloc] init]; + self.icon.contentMode = UIViewContentModeScaleAspectFit; + self.icon.tintColor = UIColor.whiteColor; + self.icon.image = [UIImage systemImageNamed:iconString]; + [self addSubview:self.icon]; + + [self.icon size:CGSizeMake(30, 30)]; + [self.icon y:self.centerYAnchor]; + [self.icon trailing:self.trailingAnchor padding:-10]; + + + self.title = [[UILabel alloc] init]; + self.title.textAlignment = NSTextAlignmentLeft; + self.title.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold]; + self.title.textColor = UIColor.whiteColor; + self.title.text = titleString; + [self addSubview:self.title]; + + [self.title y:self.centerYAnchor]; + [self.title leading:self.leadingAnchor padding:15]; + [self.title trailing:self.icon.leadingAnchor padding:-10]; + + [self addTarget:self.superview action:customAction forControlEvents:UIControlEventTouchUpInside]; + + } + + return self; +} + + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesBegan:touches withEvent:event]; + [self touchAnimateWithHighlighted:YES]; +} + + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesEnded:touches withEvent:event]; + [self touchAnimateWithHighlighted:NO]; +} + + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesCancelled:touches withEvent:event]; + [self touchAnimateWithHighlighted:NO]; +} + + +-(void)touchAnimateWithHighlighted:(BOOL)isHighlighted { + + [UIView animateWithDuration:0.3 animations:^{ + self.alpha = isHighlighted ? 0.8 : 1.0; + CGAffineTransform transform = self.transform; + transform = isHighlighted ? CGAffineTransformScale(transform, 0.96, 0.96) : CGAffineTransformIdentity; + self.transform = transform; + }]; + +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Categories/CreateCategoriesViewController.h b/Phoenix/Tweak/PHOENIX/Categories/CreateCategoriesViewController.h new file mode 100644 index 0000000..4d9f050 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Categories/CreateCategoriesViewController.h @@ -0,0 +1,38 @@ +#import +#import "CategoriesNextButton.h" +#import "CategoriesIconCell.h" +#import "CategoriesColourCell.h" +#import "CreateCategoryDataSource.h" +#import "CategoriesColourSection.h" +#import "SettingManager.h" + +@protocol CreateNewCategoryProtocol +@required +-(void)didCreatedNewCategory; +@end + +@interface CreateCategoriesViewController : UIViewController +@property (nonatomic, retain) UIColor *accentColour; +@property (nonatomic, retain) TDHeaderView *headerView; +@property (nonatomic, retain) UIScrollView *scrollView; +@property (nonatomic, retain) NSMutableArray *pageArray; +@property (nonatomic, retain) UITextField *textField; +@property (nonatomic, retain) UIView *toolView; +@property (nonatomic, retain) CategoriesNextButton *nameButton; +@property (nonatomic, retain) UICollectionView *iconCollectionView; +@property (nonatomic, retain) CategoriesNextButton *iconButton; +@property (nonatomic, retain) UICollectionView *colourCollectionView; +@property (nonatomic, retain) CategoriesNextButton *colourButton; +@property (nonatomic, retain) NSMutableArray *iconArray; +@property (nonatomic, retain) NSMutableArray *colourArray; +@property (nonatomic, retain) NSString *categoryName; +@property (nonatomic, retain) NSString *iconName; +@property (nonatomic, retain) NSString *categoryColour; +@property (nonatomic) BOOL didSelectIcon; +@property (nonatomic) NSInteger iconSelectedIndex; +@property (nonatomic) BOOL didSelectColour; +@property (nonatomic) NSInteger colourSelectedIndex; +@property (nonatomic, retain) CategoriesColourSection *customColour; +@property(nonatomic,assign)id delegate; +@property (nonatomic, retain) NSMutableDictionary *mutableDict; +@end diff --git a/Phoenix/Tweak/PHOENIX/Categories/CreateCategoriesViewController.m b/Phoenix/Tweak/PHOENIX/Categories/CreateCategoriesViewController.m new file mode 100644 index 0000000..0c4341b --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Categories/CreateCategoriesViewController.m @@ -0,0 +1,558 @@ +#import "CreateCategoriesViewController.h" + + +@implementation CreateCategoriesViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.systemBackgroundColor; + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [[SettingManager sharedInstance] accentColour]; + self.view.tintColor = [[SettingManager sharedInstance] accentColour]; + self.accentColour = [[SettingManager sharedInstance] accentColour]; + + self.iconArray = [[CreateCategoryDataSource sharedInstance] iconData]; + self.colourArray = [[CreateCategoryDataSource sharedInstance] colourData]; + + [self layoutScrollView]; + [self setupScrollViewData]; + [self.textField becomeFirstResponder]; + [self layoutHeaderView]; +} + + +-(void)layoutScrollView { + + self.pageArray = [[NSMutableArray alloc] init]; + [self.pageArray addObject:@"Categories Name"]; + [self.pageArray addObject:@"Icons"]; + [self.pageArray addObject:@"Colour"]; + + + self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds]; + self.scrollView.backgroundColor = [UIColor clearColor]; + self.scrollView.pagingEnabled = YES; + self.scrollView.clipsToBounds = NO; + [self.scrollView setShowsHorizontalScrollIndicator:NO]; + [self.scrollView setShowsVerticalScrollIndicator:NO]; + self.scrollView.scrollEnabled = NO; + [self.view addSubview:self.scrollView]; + +} + + +-(void)setupScrollViewData { + + [self.scrollView setContentSize:CGSizeMake(self.view.frame.size.width * self.pageArray.count, self.view.frame.size.height)]; + + [self.scrollView.subviews makeObjectsPerformSelector: @selector(removeFromSuperview)]; + + int i = 0; + + for (NSString *string in self.pageArray) { + + if ([string isEqualToString:@"Categories Name"]) { + [self namePage:i]; + } else if ([string isEqualToString:@"Icons"]) { + [self iconsPage:i]; + } else if ([string isEqualToString:@"Colour"]) { + [self colourPage:i]; + } + + i = i + 1; + } + +} + + +-(void)layoutHeaderView { + + self.headerView = [[TDHeaderView alloc] initWithTitle:@"" accent:self.accentColour leftIcon:@"xmark" leftAction:@selector(dismissVC)]; + self.headerView.leftButton.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.headerView.rightButton.alpha = 0; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.safeAreaLayoutGuide.topAnchor padding:0]; + +} + + +-(void)namePage:(int)page { + + UIView *baseView = [[UIView alloc] initWithFrame:CGRectMake(self.scrollView.frame.size.width * page, 0, self.view.frame.size.width, self.view.frame.size.height)]; + [self.scrollView addSubview:baseView]; + + + UIImageView *icon = [[UIImageView alloc] init]; + icon.image = [UIImage systemImageNamed:@"folder.fill"]; + icon.contentMode = UIViewContentModeScaleAspectFit; + icon.tintColor = UIColor.tertiaryLabelColor; + [baseView addSubview:icon]; + + [icon size:CGSizeMake(70, 70)]; + [icon x:baseView.centerXAnchor]; + [icon top:baseView.topAnchor padding:80]; + + + UILabel *header = [[UILabel alloc] init]; + header.textAlignment = NSTextAlignmentCenter; + header.textColor = UIColor.labelColor; + header.font = [UIFont systemFontOfSize:22 weight:UIFontWeightBlack]; + header.text = @"Category Name"; + [baseView addSubview:header]; + + [header x:baseView.centerXAnchor]; + [header top:icon.bottomAnchor padding:15]; + + + self.textField = [[UITextField alloc] init]; + self.textField.layer.cornerRadius = 12; + self.textField.layer.cornerCurve = kCACornerCurveContinuous; + self.textField.font = [UIFont systemFontOfSize:18]; + self.textField.placeholder = @"Categories name..."; + self.textField.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.textField.tintColor = self.accentColour; + self.textField.autocorrectionType = UITextAutocorrectionTypeNo; + self.textField.keyboardType = UIKeyboardTypeASCIICapable; + self.textField.clearButtonMode = UITextFieldViewModeWhileEditing; + self.textField.delegate = self; + [self.textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged]; + [baseView addSubview:self.textField]; + + [self.textField size:CGSizeMake(self.view.frame.size.width-40, 45)]; + [self.textField x:baseView.centerXAnchor]; + [self.textField top:header.bottomAnchor padding:30]; + + UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(15,0,10,45)]; + leftView.backgroundColor = [UIColor clearColor]; + self.textField.leftView = leftView; + self.textField.leftViewMode = UITextFieldViewModeAlways; + + + self.toolView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 65)]; + self.textField.inputAccessoryView = self.toolView; + + + self.nameButton = [[CategoriesNextButton alloc] initWithIcon:@"arrow.right" title:@"Icon" accent:self.accentColour action:@selector(pushToIconPage)]; + self.nameButton.layer.cornerRadius = 25; + self.nameButton.alpha = 0.7; + self.nameButton.enabled = NO; + [self.toolView addSubview:self.nameButton]; + + [self.nameButton size:CGSizeMake(180, 50)]; + [self.nameButton x:self.toolView.centerXAnchor]; + [self.nameButton y:self.toolView.centerYAnchor]; + +} + + +-(void)iconsPage:(int)page { + + UIView *baseView = [[UIView alloc] initWithFrame:CGRectMake(self.scrollView.frame.size.width * page, 0, self.view.frame.size.width, self.view.frame.size.height)]; + [self.scrollView addSubview:baseView]; + + + UIImageView *icon = [[UIImageView alloc] init]; + icon.image = [UIImage systemImageNamed:@"sparkles"]; + icon.contentMode = UIViewContentModeScaleAspectFit; + icon.tintColor = UIColor.tertiaryLabelColor; + [baseView addSubview:icon]; + + [icon size:CGSizeMake(70, 70)]; + [icon x:baseView.centerXAnchor]; + [icon top:baseView.topAnchor padding:80]; + + + UILabel *header = [[UILabel alloc] init]; + header.textAlignment = NSTextAlignmentCenter; + header.textColor = UIColor.labelColor; + header.font = [UIFont systemFontOfSize:22 weight:UIFontWeightBlack]; + header.text = @"Icon"; + [baseView addSubview:header]; + + [header x:baseView.centerXAnchor]; + [header top:icon.bottomAnchor padding:15]; + + + self.iconButton = [[CategoriesNextButton alloc] initWithIcon:@"arrow.right" title:@"Colour" accent:self.accentColour action:@selector(pushToColourPage)]; + self.iconButton.layer.cornerRadius = 25; + self.iconButton.alpha = 0.7; + self.iconButton.enabled = NO; + [baseView addSubview:self.iconButton]; + + [self.iconButton size:CGSizeMake(180, 50)]; + [self.iconButton x:baseView.centerXAnchor]; + [self.iconButton bottom:self.view.bottomAnchor padding:-40]; + + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.iconCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.iconCollectionView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.iconCollectionView.layer.cornerRadius = 15; + self.iconCollectionView.layer.cornerCurve = kCACornerCurveContinuous; + self.iconCollectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.iconCollectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.iconCollectionView setShowsHorizontalScrollIndicator:NO]; + [self.iconCollectionView setShowsVerticalScrollIndicator:NO]; + [self.iconCollectionView registerClass:[CategoriesIconCell class] forCellWithReuseIdentifier:@"IconCell"]; + [baseView addSubview:self.iconCollectionView]; + + [self.iconCollectionView width:self.view.frame.size.width-40]; + [self.iconCollectionView x:baseView.centerXAnchor]; + [self.iconCollectionView top:header.bottomAnchor padding:30]; + [self.iconCollectionView bottom:self.iconButton.topAnchor padding:-30]; + + self.iconCollectionView.delegate = self; + self.iconCollectionView.dataSource = self; +} + + +-(void)colourPage:(int)page { + + UIView *baseView = [[UIView alloc] initWithFrame:CGRectMake(self.scrollView.frame.size.width * page, 0, self.view.frame.size.width, self.view.frame.size.height)]; + [self.scrollView addSubview:baseView]; + + + UIImageView *icon = [[UIImageView alloc] init]; + icon.image = [UIImage systemImageNamed:@"paintpalette.fill"]; + icon.contentMode = UIViewContentModeScaleAspectFit; + icon.tintColor = UIColor.tertiaryLabelColor; + [baseView addSubview:icon]; + + [icon size:CGSizeMake(70, 70)]; + [icon x:baseView.centerXAnchor]; + [icon top:baseView.topAnchor padding:80]; + + + UILabel *header = [[UILabel alloc] init]; + header.textAlignment = NSTextAlignmentCenter; + header.textColor = UIColor.labelColor; + header.font = [UIFont systemFontOfSize:22 weight:UIFontWeightBlack]; + header.text = @"Colour"; + [baseView addSubview:header]; + + [header x:baseView.centerXAnchor]; + [header top:icon.bottomAnchor padding:15]; + + + self.colourButton = [[CategoriesNextButton alloc] initWithIcon:@"arrow.right" title:@"Create" accent:self.accentColour action:@selector(saveNewCategory)]; + self.colourButton.layer.cornerRadius = 25; + self.colourButton.alpha = 0.7; + self.colourButton.enabled = NO; + [baseView addSubview:self.colourButton]; + + [self.colourButton size:CGSizeMake(180, 50)]; + [self.colourButton x:baseView.centerXAnchor]; + [self.colourButton bottom:self.view.bottomAnchor padding:-40]; + + + self.customColour = [[CategoriesColourSection alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"eyedropper.halffull"]]; + self.customColour.iconView.backgroundColor = [self.accentColour colorWithAlphaComponent:0.4]; + self.customColour.icon.tintColor = self.accentColour; + self.customColour.title.text = @"Custom colour"; + self.customColour.colourView.backgroundColor = UIColor.systemIndigoColor; + [baseView addSubview:self.customColour]; + + [self.customColour size:CGSizeMake(self.view.frame.size.width-40, 70)]; + [self.customColour x:baseView.centerXAnchor]; + [self.customColour bottom:self.colourButton.topAnchor padding:-25]; + + [self.customColour addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentColourPickerVC)]]; + + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.colourCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.colourCollectionView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.colourCollectionView.layer.cornerRadius = 15; + self.colourCollectionView.layer.cornerCurve = kCACornerCurveContinuous; + self.colourCollectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.colourCollectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.colourCollectionView setShowsHorizontalScrollIndicator:NO]; + [self.colourCollectionView setShowsVerticalScrollIndicator:NO]; + [self.colourCollectionView registerClass:[CategoriesColourCell class] forCellWithReuseIdentifier:@"ColourCell"]; + [baseView addSubview: self.colourCollectionView]; + + [self.colourCollectionView width:self.view.frame.size.width-40]; + [self.colourCollectionView x:baseView.centerXAnchor]; + [self.colourCollectionView top:header.bottomAnchor padding:30]; + [self.colourCollectionView bottom:self.customColour.topAnchor padding:-20]; + + self.colourCollectionView.delegate = self; + self.colourCollectionView.dataSource = self; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + if (collectionView == self.iconCollectionView) { + return self.iconArray.count; + } else { + return self.colourArray.count; + } +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + if (collectionView == self.iconCollectionView) { + + CategoriesIconCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"IconCell" forIndexPath:indexPath]; + + CategoriesIconModel *model = [self.iconArray objectAtIndex:indexPath.row]; + + cell.backgroundColor = UIColor.clearColor; + cell.baseView.backgroundColor = [self.accentColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = self.accentColour; + cell.iconImage.image = [UIImage systemImageNamed:model.imageName]; + + if (self.didSelectIcon) { + if (indexPath.row == self.iconSelectedIndex) { + cell.iconImage.image = [UIImage systemImageNamed:@"checkmark"]; + cell.iconImage.tintColor = UIColor.whiteColor; + } + } + + return cell; + + } else { + + CategoriesColourCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ColourCell" forIndexPath:indexPath]; + + CategoriesColourModel *model = [self.colourArray objectAtIndex:indexPath.row]; + + cell.backgroundColor = UIColor.clearColor; + cell.baseView.backgroundColor = [self colorWithHexString:model.colourHEX]; + cell.iconImage.tintColor = UIColor.whiteColor; + + if (self.didSelectColour) { + if (indexPath.row == self.colourSelectedIndex) { + cell.iconImage.image = [UIImage systemImageNamed:@"checkmark"]; + } + } + + return cell; + + } + +} + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat width = (self.view.frame.size.width-110)/3; + return CGSizeMake(width, width-30); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(20,20,20,20); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + if (collectionView == self.iconCollectionView) { + + self.iconButton.alpha = 1; + self.iconButton.enabled = YES; + + self.didSelectIcon = YES; + self.iconSelectedIndex = indexPath.row; + + CategoriesIconModel *model = [self.iconArray objectAtIndex:indexPath.row]; + self.iconName = model.imageName; + + [self.iconCollectionView reloadData]; + + } else { + + CategoriesColourModel *model = [self.colourArray objectAtIndex:indexPath.row]; + + self.didSelectColour = YES; + self.colourSelectedIndex = indexPath.row; + self.colourButton.alpha = 1; + self.colourButton.enabled = YES; + self.categoryColour = model.colourHEX; + [self.colourCollectionView reloadData]; + } + +} + + +- (void)textFieldDidChange:(UITextField *)textField { + [self updateCategoryNameWithString:textField.text]; +} + + +- (void)textFieldDidEndEditing:(UITextField *)textField { + [self updateCategoryNameWithString:textField.text]; +} + + +- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + [self updateCategoryNameWithString:textField.text]; + return YES; +} + + +-(void)updateCategoryNameWithString:(NSString *)category { + if (self.textField && self.textField.text.length > 0) { + self.nameButton.alpha = 1.0; + self.nameButton.enabled = YES; + } else { + self.nameButton.alpha = 0.7; + self.nameButton.enabled = NO; + } +} + + +-(void)pushToIconPage { + [self.textField resignFirstResponder]; + [self scrollToPage:1]; +} + + +-(void)pushToColourPage { + [self scrollToPage:2]; +} + + +-(void)presentColourPickerVC { + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + colourPickerVC.selectedColor = self.customColour.colourView.backgroundColor; + colourPickerVC.supportsAlpha = NO; + [self presentViewController:colourPickerVC animated:YES completion:nil]; +} + + +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + self.colourButton.alpha = 1; + self.colourButton.enabled = YES; + self.didSelectColour = NO; + [self.colourCollectionView reloadData]; + UIColor *cpSelectedColour = viewController.selectedColor; + self.customColour.colourView.backgroundColor = cpSelectedColour; + self.categoryColour = [self hexStringFromColor:cpSelectedColour]; +} + + +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + self.colourButton.alpha = 1; + self.colourButton.enabled = YES; + self.didSelectColour = NO; + [self.colourCollectionView reloadData]; + UIColor *cpSelectedColour = viewController.selectedColor; + self.customColour.colourView.backgroundColor = cpSelectedColour; + self.categoryColour = [self hexStringFromColor:cpSelectedColour]; +} + + +-(void)saveNewCategory { + + self.categoryName = self.textField.text; + + //NSString *plistName = [self.categoryName stringByReplacingOccurrencesOfString:@" " withString:@""]; + //NSLog(@"categories name: %@ plistname: %@ icon: %@ colour: %@", self.categoryName, plistName, self.iconName, self.categoryColour); + //NSString *prefPath = @"/var/mobile/Library/Preferences/PaletteCollections.plist"; + + // [IMPORTANT] need to post notification to write new categories to plist + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/Categories.plist", aDocumentsDirectory]; + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + self.mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + NSString *withID = [NSString stringWithFormat:@"%lld", (long long)([[NSDate date] timeIntervalSince1970] * 1000.0)]; + NSDictionary *data = @{@"id" : withID, @"categoriesName" : self.categoryName, @"categoriesColour" : self.categoryColour, @"categoriesIcon" : self.iconName}; + [self.mutableDict setValue:data forKey:withID]; + [self.mutableDict writeToFile:plistPath atomically:YES]; + + [self.delegate didCreatedNewCategory]; + + [self dismissVC]; +} + + +-(void)scrollToPage:(NSInteger)page { + CGPoint offset = CGPointMake(page * self.scrollView.frame.size.width, 0); + [self.scrollView setContentOffset:offset animated:YES]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + }]; + + [alert addAction:defaultAction]; + + [self presentViewController:alert animated:YES completion:nil]; +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +- (NSString *)hexStringFromColor:(UIColor *)color { + const CGFloat *components = CGColorGetComponents(color.CGColor); + + CGFloat r = components[0]; + CGFloat g = components[1]; + CGFloat b = components[2]; + + return [NSString stringWithFormat:@"%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255)]; +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Categories/CreateCategoryDataSource.h b/Phoenix/Tweak/PHOENIX/Categories/CreateCategoryDataSource.h new file mode 100644 index 0000000..5dfc0ae --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Categories/CreateCategoryDataSource.h @@ -0,0 +1,19 @@ +#import +#import + +@interface CategoriesIconModel : NSObject +-(id)initWithImageName:(NSString *)name; +@property (nonatomic, retain) NSString *imageName; +@end + +@interface CategoriesColourModel : NSObject +-(id)initWithColourHex:(NSString *)hex; +@property (nonatomic, retain) NSString *colourHEX; +@end + +@interface CreateCategoryDataSource : NSObject ++(instancetype)sharedInstance; +-(id)init; +-(NSMutableArray*)iconData; +-(NSMutableArray *)colourData; +@end diff --git a/Phoenix/Tweak/PHOENIX/Categories/CreateCategoryDataSource.m b/Phoenix/Tweak/PHOENIX/Categories/CreateCategoryDataSource.m new file mode 100644 index 0000000..7b62fe9 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Categories/CreateCategoryDataSource.m @@ -0,0 +1,174 @@ +#import "CreateCategoryDataSource.h" + +@implementation CategoriesIconModel +-(id)initWithImageName:(NSString *)name { + self = [super init]; + if(self) { + self.imageName = name; + } + return self; +} +@end + + +@implementation CategoriesColourModel +-(id)initWithColourHex:(NSString *)hex { + self = [super init]; + if(self) { + self.colourHEX = hex; + } + return self; +} +@end + + +@implementation CreateCategoryDataSource + ++(instancetype)sharedInstance { + static CreateCategoryDataSource *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[CreateCategoryDataSource alloc] init]; + }); + return sharedInstance; +} + + +-(id)init { + return self; +} + + +-(NSMutableArray *)iconData { + + NSMutableArray *array = [[NSMutableArray alloc] init]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"airplane"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"airpods"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"alarm.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"ant.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"arrow.3.trianglepath"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"arrowtriangle.forward"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"bag"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"barcode"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"book"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"books.vertical"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"building.columns"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"bus"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"camera"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"cart"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"comb.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"cross"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"desktopcomputer"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"ellipsis"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"envelope"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"face.dashed"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"graduationcap"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"gamecontroller.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"greetingcard"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"guitars"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"hare"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"lightbulb"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"mouth"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"radio"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"sportscourt"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"appletv.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"hifispeaker"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"keyboard"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"tv.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"bicycle"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"figure.walk"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"car"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"tram"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"eye"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"mustache"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"person"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"number"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"percent.ar"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"creditcard"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"giftcard"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"infinity"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"pause"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"play"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"playpause"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"stop"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"heart.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"pills.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"cross.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"staroflife.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"clock.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"hourglass.tophalf.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"bag.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"cart.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"creditcard.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"giftcard.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"textformat.alt"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"scribble"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"paintbrush.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"paintbrush.pointed.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"hare.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"bolt.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"flame.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"drop.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"person.crop.circle.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"eye.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"nose.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"mustache.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"mouth.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"face.smiling.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"hand.raised.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"ear.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"hand.thumbsup.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"hand.thumbsdown.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"hand.wave.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"car.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"bicycle"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"icloud.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"dpad.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"macpro.gen1"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"laptopcomputer.and.iphone"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"headphones"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"binoculars.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"paintpalette.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"moon.circle.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"moon.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"cloud.moon.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"message.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"phone.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"video.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"sparkles"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"sparkle"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"crown.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"comb.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"briefcase.fill"]]; + [array addObject:[[CategoriesIconModel alloc] initWithImageName:@"hands.sparkles.fill"]]; + + return array; +} + + +-(NSMutableArray *)colourData { + + NSMutableArray *array = [[NSMutableArray alloc] init]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"007AFF"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"31ADE6"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"30B1C7"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"04C7BE"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"35C759"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"FFCC01"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"FF9500"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"FF3C2F"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"FF2C55"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"AF52DE"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"5956D5"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"251E3E"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"03396C"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"EEC9D2"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"F27737"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"FCF498"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"7BC043"]]; + [array addObject:[[CategoriesColourModel alloc] initWithColourHex:@"FFBBEE"]]; + return array; + +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/ActionMenuCell.h b/Phoenix/Tweak/PHOENIX/Cells/ActionMenuCell.h new file mode 100644 index 0000000..abecf7f --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/ActionMenuCell.h @@ -0,0 +1,9 @@ +#import + +@interface ActionMenuCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@end + diff --git a/Phoenix/Tweak/PHOENIX/Cells/ActionMenuCell.m b/Phoenix/Tweak/PHOENIX/Cells/ActionMenuCell.m new file mode 100644 index 0000000..b5b97a6 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/ActionMenuCell.m @@ -0,0 +1,59 @@ +#import "ActionMenuCell.h" + +@implementation ActionMenuCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = UIColor.clearColor; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:0]; + [self.baseView leading:self.leadingAnchor padding:0]; + [self.baseView trailing:self.trailingAnchor padding:0]; + [self.baseView bottom:self.bottomAnchor padding:0]; + + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 10; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + [self.baseView addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(50, 50)]; + [self.iconView x:self.baseView.centerXAnchor]; + [self.iconView top:self.baseView.topAnchor padding:0]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.iconView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(30, 30)]; + [self.iconImage x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.font = [UIFont systemFontOfSize:9 weight:UIFontWeightRegular]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel top:self.iconView.bottomAnchor padding:3]; + [self.titleLabel x:self.baseView.centerXAnchor]; + + } + + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.iconImage.image = nil; + self.titleLabel.text = nil; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/CategoriesColourCell.h b/Phoenix/Tweak/PHOENIX/Cells/CategoriesColourCell.h new file mode 100644 index 0000000..16a7e25 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/CategoriesColourCell.h @@ -0,0 +1,6 @@ +#import + +@interface CategoriesColourCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/CategoriesColourCell.m b/Phoenix/Tweak/PHOENIX/Cells/CategoriesColourCell.m new file mode 100644 index 0000000..34760c3 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/CategoriesColourCell.m @@ -0,0 +1,47 @@ +#import "CategoriesColourCell.h" + +@implementation CategoriesColourCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 12; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = true; + + self.baseView = [[UIView alloc] init]; + self.baseView.layer.cornerRadius = 12; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(40, 40)]; + [self.iconImage x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + + self.iconImage.image = nil; +} + + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.backgroundColor = highlighted ? UIColor.secondarySystemBackgroundColor : UIColor.secondarySystemBackgroundColor; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/CategoriesIconCell.h b/Phoenix/Tweak/PHOENIX/Cells/CategoriesIconCell.h new file mode 100644 index 0000000..2be1382 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/CategoriesIconCell.h @@ -0,0 +1,6 @@ +#import + +@interface CategoriesIconCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/CategoriesIconCell.m b/Phoenix/Tweak/PHOENIX/Cells/CategoriesIconCell.m new file mode 100644 index 0000000..ad4f5b2 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/CategoriesIconCell.m @@ -0,0 +1,47 @@ +#import "CategoriesIconCell.h" + +@implementation CategoriesIconCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 12; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = true; + + self.baseView = [[UIView alloc] init]; + self.baseView.layer.cornerRadius = 12; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(40, 40)]; + [self.iconImage x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + + self.iconImage.image = nil; +} + + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.backgroundColor = highlighted ? UIColor.secondarySystemBackgroundColor : UIColor.secondarySystemBackgroundColor; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/ContactCell.h b/Phoenix/Tweak/PHOENIX/Cells/ContactCell.h new file mode 100644 index 0000000..c7d2b08 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/ContactCell.h @@ -0,0 +1,12 @@ +#import +#import "SettingManager.h" + +@interface ContactCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *avatar; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UILabel *numberLabel; +@property (nonatomic, retain) UILabel *emailLabel; +@property (nonatomic) BOOL hideContactsDetails; +@end + diff --git a/Phoenix/Tweak/PHOENIX/Cells/ContactCell.m b/Phoenix/Tweak/PHOENIX/Cells/ContactCell.m new file mode 100644 index 0000000..043f55c --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/ContactCell.m @@ -0,0 +1,94 @@ +#import "ContactCell.h" + +@implementation ContactCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.hideContactsDetails = [[SettingManager sharedInstance] boolForKey:@"hideContactsDetails" defaultValue:NO]; + + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerRadius = 10; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:3]; + [self.baseView leading:self.leadingAnchor padding:2]; + [self.baseView trailing:self.trailingAnchor padding:-2]; + [self.baseView bottom:self.bottomAnchor padding:-3]; + + + self.avatar = [[UIImageView alloc] init]; + self.avatar.contentMode = UIViewContentModeScaleAspectFill; + self.avatar.layer.cornerRadius = 25; + self.avatar.clipsToBounds = YES; + [self.baseView addSubview:self.avatar]; + + [self.avatar size:CGSizeMake(50, 50)]; + [self.avatar leading:self.baseView.leadingAnchor padding:10]; + [self.avatar y:self.baseView.centerYAnchor]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.textAlignment = NSTextAlignmentLeft; + self.nameLabel.textColor = UIColor.labelColor; + [self.baseView addSubview:self.nameLabel]; + + if (!self.hideContactsDetails) { + self.nameLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightBold]; + [self.nameLabel top:self.avatar.topAnchor padding:-5]; + [self.nameLabel leading:self.avatar.trailingAnchor padding:10]; + [self.nameLabel trailing:self.baseView.trailingAnchor padding:-10]; + } else { + self.nameLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightBold]; + [self.nameLabel y:self.baseView.centerYAnchor]; + [self.nameLabel leading:self.avatar.trailingAnchor padding:10]; + [self.nameLabel trailing:self.baseView.trailingAnchor padding:-10]; + } + + + if (!self.hideContactsDetails) { + self.numberLabel = [[UILabel alloc] init]; + self.numberLabel.textAlignment = NSTextAlignmentLeft; + self.numberLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightRegular]; + self.numberLabel.textColor = UIColor.tertiaryLabelColor; + [self.baseView addSubview:self.numberLabel]; + + [self.numberLabel y:self.baseView.centerYAnchor]; + [self.numberLabel leading:self.avatar.trailingAnchor padding:10]; + [self.numberLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.emailLabel = [[UILabel alloc] init]; + self.emailLabel.textAlignment = NSTextAlignmentLeft; + self.emailLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightRegular]; + self.emailLabel.textColor = UIColor.tertiaryLabelColor; + [self.baseView addSubview:self.emailLabel]; + + [self.emailLabel bottom:self.avatar.bottomAnchor padding:2]; + [self.emailLabel leading:self.avatar.trailingAnchor padding:10]; + [self.emailLabel trailing:self.baseView.trailingAnchor padding:-10]; + } + + } + + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + + self.avatar.image = nil; + self.nameLabel.text = nil; + self.numberLabel.text = nil; + self.emailLabel.text = nil; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/FavouriteCategoriesCell.h b/Phoenix/Tweak/PHOENIX/Cells/FavouriteCategoriesCell.h new file mode 100644 index 0000000..b27799d --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/FavouriteCategoriesCell.h @@ -0,0 +1,12 @@ +#import + +@interface FavouriteCategoriesCell : UICollectionViewCell { + CGFloat iconSize; + CGFloat iconTopPadding; + CGFloat fontSize; + CGFloat fontBottomPadding; +} +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/FavouriteCategoriesCell.m b/Phoenix/Tweak/PHOENIX/Cells/FavouriteCategoriesCell.m new file mode 100644 index 0000000..ac7adbb --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/FavouriteCategoriesCell.m @@ -0,0 +1,105 @@ +#import "FavouriteCategoriesCell.h" + +@implementation FavouriteCategoriesCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + + if (iPhone_6_8) { + iconSize = 30; + iconTopPadding = 5; + fontSize = 10; + fontBottomPadding = 7; + } else if (iPhone_6_8_Plus) { + iconSize = 40; + iconTopPadding = 5; + fontSize = 12; + fontBottomPadding = 7; + } else if (iPhone_X_XS_11Pro) { + iconSize = 35; + iconTopPadding = 3; + fontSize = 11; + fontBottomPadding = 5; + } else if (iPhone_XR_XS_11Pro) { + iconSize = 45; + iconTopPadding = 3; + fontSize = 13; + fontBottomPadding = 5; + } else if (iPhone_12_Pro) { + iconSize = 40; + iconTopPadding = 3; + fontSize = 11; + fontBottomPadding = 5; + } else if (iPhone_12_mini) { + iconSize = 30; + iconTopPadding = 5; + fontSize = 10; + fontBottomPadding = 7; + } else if (iPhone_12_Pro_Max) { + iconSize = 45; + iconTopPadding = 3; + fontSize = 13; + fontBottomPadding = 5; + } else { + iconSize = 30; + iconTopPadding = 5; + fontSize = 10; + fontBottomPadding = 7; + } + + + self.layer.cornerRadius = 12; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = true; + + self.baseView = [[UIView alloc] init]; + self.baseView.layer.cornerRadius = 12; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(iconSize, iconSize)]; + [self.iconImage x:self.baseView.centerXAnchor]; + [self.iconImage top:self.baseView.topAnchor padding:iconTopPadding]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = UIColor.whiteColor; + self.titleLabel.font = [UIFont systemFontOfSize:fontSize weight:UIFontWeightRegular]; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel x:self.baseView.centerXAnchor]; + [self.titleLabel bottom:self.baseView.bottomAnchor padding:-fontBottomPadding]; + [self.titleLabel leading:self.baseView.leadingAnchor padding:3]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-3]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + + self.iconImage.image = nil; + self.titleLabel.text = nil; +} + + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.backgroundColor = highlighted ? UIColor.secondarySystemBackgroundColor : UIColor.secondarySystemBackgroundColor; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/FavouriteCell.h b/Phoenix/Tweak/PHOENIX/Cells/FavouriteCell.h new file mode 100644 index 0000000..04bd68a --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/FavouriteCell.h @@ -0,0 +1,24 @@ +#import +#import "SettingManager.h" + +@protocol FavouriteActionButtonDelegate +@optional +- (void)callButtonTappedForCell:(UICollectionViewCell *)cell; +- (void)messageButtonTappedForCell:(UICollectionViewCell *)cell; +- (void)emailButtonTappedForCell:(UICollectionViewCell *)cell; +@end + +@interface FavouriteCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *avatarImage; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UIView *actionView; +@property (nonatomic, retain) UIStackView *favStackView; +@property (nonatomic, retain) UIButton *favCallButton; +@property (nonatomic, retain) UIButton *favMessageButton; +@property (nonatomic, retain) UIButton *favEmailButton; +@property (nonatomic, retain) UIColor *accentColour; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, weak) id favouriteDelegate; +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/FavouriteCell.m b/Phoenix/Tweak/PHOENIX/Cells/FavouriteCell.m new file mode 100644 index 0000000..f502ccb --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/FavouriteCell.m @@ -0,0 +1,168 @@ +#import "FavouriteCell.h" + +@implementation FavouriteCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 15; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = true; + + self.accentColour = [[SettingManager sharedInstance] accentColour]; + + + self.baseView = [[UIView alloc] init]; + self.baseView.layer.cornerRadius = 15; + self.baseView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.avatarImage = [[UIImageView alloc] init]; + self.avatarImage.layer.cornerRadius = 30; + self.avatarImage.clipsToBounds = true; + self.avatarImage.contentMode = UIViewContentModeScaleAspectFill; + [self.baseView addSubview:self.avatarImage]; + + [self.avatarImage size:CGSizeMake(60, 60)]; + [self.avatarImage top:self.baseView.topAnchor padding:10]; + [self.avatarImage x:self.baseView.centerXAnchor]; + + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 12.5; + self.iconView.clipsToBounds = YES; + [self.baseView addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(25, 25)]; + [self.iconView bottom:self.avatarImage.bottomAnchor padding:4]; + [self.iconView trailing:self.avatarImage.trailingAnchor padding:4]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + self.iconImage.tintColor = UIColor.whiteColor; + [self.iconView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(17.5, 17.5)]; + [self.iconImage x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold]; + self.nameLabel.textAlignment = NSTextAlignmentCenter; + self.nameLabel.textColor = [UIColor labelColor]; + [self.baseView addSubview:self.nameLabel]; + + [self.nameLabel top:self.avatarImage.bottomAnchor padding:7]; + [self.nameLabel x:self.baseView.centerXAnchor]; + [self.nameLabel leading:self.baseView.leadingAnchor padding:5]; + [self.nameLabel trailing:self.baseView.trailingAnchor padding:-5]; + + + self.actionView = [[UIView alloc] init]; + [self.baseView addSubview:self.actionView]; + + [self.actionView height:40]; + [self.actionView leading:self.baseView.leadingAnchor padding:15]; + [self.actionView trailing:self.baseView.trailingAnchor padding:-15]; + [self.actionView bottom:self.baseView.bottomAnchor padding:-7]; + + + self.favCallButton = [[UIButton alloc] init]; + UIImage *callImage = [UIImage systemImageNamed:@"phone.fill" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:20]]; + [self.favCallButton setImage:callImage forState:UIControlStateNormal]; + self.favCallButton.imageView.contentMode = UIViewContentModeScaleAspectFit; + self.favCallButton.tintColor = self.accentColour; + self.favCallButton.layer.cornerRadius = 10; + self.favCallButton.layer.cornerCurve = kCACornerCurveContinuous; + self.favCallButton.backgroundColor = [self.accentColour colorWithAlphaComponent:0.4]; + [self.favCallButton addTarget:self action:@selector(callButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + + [self.favCallButton size:CGSizeMake(40, 40)]; + + + self.favMessageButton = [[UIButton alloc] init]; + UIImage *messageImage = [UIImage systemImageNamed:@"message.fill" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:20]]; + [self.favMessageButton setImage:messageImage forState:UIControlStateNormal]; + self.favMessageButton.imageView.contentMode = UIViewContentModeScaleAspectFit; + self.favMessageButton.tintColor = self.accentColour; + self.favMessageButton.layer.cornerRadius = 10; + self.favMessageButton.layer.cornerCurve = kCACornerCurveContinuous; + self.favMessageButton.backgroundColor = [self.accentColour colorWithAlphaComponent:0.4]; + [self.favMessageButton addTarget:self action:@selector(messageButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + + [self.favMessageButton size:CGSizeMake(40, 40)]; + + + self.favEmailButton = [[UIButton alloc] init]; + UIImage *emailImage = [UIImage systemImageNamed:@"envelope.fill" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:20]]; + [self.favEmailButton setImage:emailImage forState:UIControlStateNormal]; + self.favEmailButton.imageView.contentMode = UIViewContentModeScaleAspectFit; + self.favEmailButton.tintColor = self.accentColour; + self.favEmailButton.layer.cornerRadius = 10; + self.favEmailButton.layer.cornerCurve = kCACornerCurveContinuous; + self.favEmailButton.backgroundColor = [self.accentColour colorWithAlphaComponent:0.4]; + [self.favEmailButton addTarget:self action:@selector(emailButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + + [self.favEmailButton size:CGSizeMake(40, 40)]; + + + self.favStackView = [[UIStackView alloc] init]; + self.favStackView.axis = UILayoutConstraintAxisHorizontal; + self.favStackView.distribution = UIStackViewDistributionEqualSpacing; + self.favStackView.alignment = UIStackViewAlignmentCenter; + self.favStackView.spacing = 10; + [self.actionView addSubview:self.favStackView]; + + [self.favStackView x:self.actionView.centerXAnchor y:self.actionView.centerYAnchor]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + + self.avatarImage.image = nil; + self.nameLabel.text = nil; + self.iconImage.image = nil; + [self.favStackView removeArrangedSubview:self.favCallButton]; + [self.favStackView removeArrangedSubview:self.favMessageButton]; + [self.favStackView removeArrangedSubview:self.favEmailButton]; + + [self.favCallButton removeFromSuperview]; + [self.favMessageButton removeFromSuperview]; + [self.favEmailButton removeFromSuperview]; + +} + + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.backgroundColor = highlighted ? UIColor.secondarySystemBackgroundColor : UIColor.secondarySystemBackgroundColor; +} + + +-(void)callButtonPressed:(id)sender { + [self.favouriteDelegate callButtonTappedForCell:self]; +} + + +-(void)messageButtonPressed:(id)sender { + [self.favouriteDelegate messageButtonTappedForCell:self]; +} + + +-(void)emailButtonPressed:(id)sender { + [self.favouriteDelegate emailButtonTappedForCell:self]; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/FavouriteFilterCell.h b/Phoenix/Tweak/PHOENIX/Cells/FavouriteFilterCell.h new file mode 100644 index 0000000..e158243 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/FavouriteFilterCell.h @@ -0,0 +1,7 @@ +#import + +@interface FavouriteFilterCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/FavouriteFilterCell.m b/Phoenix/Tweak/PHOENIX/Cells/FavouriteFilterCell.m new file mode 100644 index 0000000..1256f77 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/FavouriteFilterCell.m @@ -0,0 +1,61 @@ +#import "FavouriteFilterCell.h" + +@implementation FavouriteFilterCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 12; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = true; + + self.baseView = [[UIView alloc] init]; + self.baseView.layer.cornerRadius = 12; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(35, 35)]; + [self.iconImage x:self.baseView.centerXAnchor]; + [self.iconImage top:self.baseView.topAnchor padding:10]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = UIColor.whiteColor; + self.titleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightRegular]; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel x:self.baseView.centerXAnchor]; + [self.titleLabel bottom:self.baseView.bottomAnchor padding:-5]; + [self.titleLabel leading:self.baseView.leadingAnchor padding:3]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-3]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + + self.iconImage.image = nil; + self.titleLabel.text = nil; +} + + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.backgroundColor = highlighted ? UIColor.secondarySystemBackgroundColor : UIColor.secondarySystemBackgroundColor; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/SettingColourCell.h b/Phoenix/Tweak/PHOENIX/Cells/SettingColourCell.h new file mode 100644 index 0000000..abf47a7 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/SettingColourCell.h @@ -0,0 +1,12 @@ +#import + +@interface SettingColourCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UIImageView *accessoriesImage; +@property (nonatomic, retain) UIView *colourView; +@end + diff --git a/Phoenix/Tweak/PHOENIX/Cells/SettingColourCell.m b/Phoenix/Tweak/PHOENIX/Cells/SettingColourCell.m new file mode 100644 index 0000000..4607b23 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/SettingColourCell.m @@ -0,0 +1,100 @@ +#import "SettingColourCell.h" + +@implementation SettingColourCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:5]; + [self.baseView leading:self.leadingAnchor padding:5]; + [self.baseView trailing:self.trailingAnchor padding:-5]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 10; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + self.iconView.clipsToBounds = YES; + [self.baseView addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(40, 40)]; + [self.iconView y:self.baseView.centerYAnchor]; + [self.iconView leading:self.baseView.leadingAnchor padding:10]; + + + self.iconImage = [[UIImageView alloc] init]; + [self.iconView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(30, 30)]; + [self.iconImage x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.textColor = UIColor.labelColor; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.titleLabel top:self.iconView.topAnchor padding:2]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.subtitleLabel = [[UILabel alloc] init]; + self.subtitleLabel.textAlignment = NSTextAlignmentLeft; + self.subtitleLabel.font = [UIFont systemFontOfSize:13]; + self.subtitleLabel.textColor = UIColor.tertiaryLabelColor; + [self.baseView addSubview:self.subtitleLabel]; + + [self.subtitleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.subtitleLabel bottom:self.iconView.bottomAnchor padding:-2]; + [self.subtitleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.accessoriesImage = [[UIImageView alloc] init]; + self.accessoriesImage.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/Phoenix.bundle/Assets/colour-wheel.png"]; + self.accessoriesImage.layer.cornerRadius = 15; + self.accessoriesImage.clipsToBounds = true; + [self.baseView addSubview:self.accessoriesImage]; + + self.accessoriesImage.translatesAutoresizingMaskIntoConstraints = NO; + [[self.accessoriesImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.accessoriesImage.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + [self.accessoriesImage.heightAnchor constraintEqualToConstant:30].active = YES; + [self.accessoriesImage.widthAnchor constraintEqualToConstant:30].active = YES; + + + self.colourView = [[UIView alloc] init]; + self.colourView.layer.cornerRadius = 12.5; + self.colourView.clipsToBounds = true; + [self.baseView addSubview:self.colourView]; + + [self.colourView size:CGSizeMake(25, 25)]; + [self.colourView x:self.accessoriesImage.centerXAnchor]; + [self.colourView y:self.accessoriesImage.centerYAnchor]; + + } + + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + + self.iconImage.image = nil; + self.titleLabel.text = nil; + self.subtitleLabel.text = nil; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Cells/SettingSwitchCell.h b/Phoenix/Tweak/PHOENIX/Cells/SettingSwitchCell.h new file mode 100644 index 0000000..46c4679 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/SettingSwitchCell.h @@ -0,0 +1,11 @@ +#import + +@interface SettingSwitchCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UISwitch *toggleSwitch; +@end + diff --git a/Phoenix/Tweak/PHOENIX/Cells/SettingSwitchCell.m b/Phoenix/Tweak/PHOENIX/Cells/SettingSwitchCell.m new file mode 100644 index 0000000..01932cc --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Cells/SettingSwitchCell.m @@ -0,0 +1,86 @@ +#import "SettingSwitchCell.h" + +@implementation SettingSwitchCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.baseView.layer.cornerRadius = 15; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:5]; + [self.baseView leading:self.leadingAnchor padding:5]; + [self.baseView trailing:self.trailingAnchor padding:-5]; + [self.baseView bottom:self.bottomAnchor padding:-5]; + + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 10; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + self.iconView.clipsToBounds = YES; + [self.baseView addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(40, 40)]; + [self.iconView y:self.baseView.centerYAnchor]; + [self.iconView leading:self.baseView.leadingAnchor padding:10]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.iconView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(30, 30)]; + [self.iconImage x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.toggleSwitch = [[UISwitch alloc] init]; + self.toggleSwitch.thumbTintColor = UIColor.secondarySystemBackgroundColor; + [self.contentView addSubview:self.toggleSwitch]; + + [self.toggleSwitch y:self.baseView.centerYAnchor]; + [self.toggleSwitch trailing:self.baseView.trailingAnchor padding:-10]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.textColor = UIColor.labelColor; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.titleLabel top:self.iconView.topAnchor padding:2]; + [self.titleLabel trailing:self.toggleSwitch.leadingAnchor padding:-10]; + + + self.subtitleLabel = [[UILabel alloc] init]; + self.subtitleLabel.textAlignment = NSTextAlignmentLeft; + self.subtitleLabel.font = [UIFont systemFontOfSize:13]; + self.subtitleLabel.textColor = UIColor.tertiaryLabelColor; + [self.baseView addSubview:self.subtitleLabel]; + + [self.subtitleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.subtitleLabel bottom:self.iconView.bottomAnchor padding:-2]; + [self.subtitleLabel trailing:self.toggleSwitch.leadingAnchor padding:-10]; + + } + + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + + self.iconImage.image = nil; + self.titleLabel.text = nil; + self.subtitleLabel.text = nil; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Contacts/ContactViewController.h b/Phoenix/Tweak/PHOENIX/Contacts/ContactViewController.h new file mode 100644 index 0000000..b668267 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Contacts/ContactViewController.h @@ -0,0 +1,76 @@ +#import +#import "ContactsData.h" +#import "ContactCell.h" +#import +#import +#import "FavouriteCell.h" +#import "CreateFavouriteViewController.h" +#import "ActionMenuViewController.h" +#import "FavouriteFilterViewController.h" +#import "MessageView.h" +#import "SettingManager.h" +#import "SettingViewController.h" +#import "GlobalHaptic.h" + +@interface CNContactContentViewController +-(id)_faceTimeAction; +-(id)_faceTimeAudioAction; +@end + +@interface CNPhoneNumber (Priv) +-(id)initWithStringValue:(id)arg1 ; +@end + +@interface CNContact(Priv) ++(id)predicateForMeContact; +-(id)initWithIdentifier:(id)arg1; ++(id)contactWithIdentifier:(id)arg1; +@end + +@interface CNContactViewController (Priv) +@property (nonatomic,retain) CNContactContentViewController * contentViewController; +-(void)presentationControllerDidAttemptToDismiss:(id)arg1; +@end + +@interface ContactViewController : UIViewController { + UIImpactFeedbackGenerator *haptic; +} +@property (strong) CNContactStore *store; +@property (strong) CNContactViewController *controller; +@property (nonatomic, retain) UITableView *tableView; +@property (strong, nonatomic) NSArray * sectionIndexTitles; +@property (strong, nonatomic) NSMutableArray * contactPeople; +@property (strong, nonatomic) NSMutableArray * parsedContacts; +@property (nonatomic, retain) UIView *headerView; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIButton *addButton; +@property (nonatomic, retain) UIButton *settingButton; +@property (nonatomic, retain) UIView *searchBarView; +@property (nonatomic, retain) UIImageView *searchIcon; +@property (nonatomic, retain) UITextField *searchTextField; +@property (nonatomic, retain) UIView *bannerView; +@property (nonatomic, retain) UIView *myCardView; +@property (nonatomic, retain) TDIndexBar *indexBar; +@property (nonatomic, retain) UIColor *accentColour; +@property (nonatomic, retain) UIImageView *avatarImage; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UILabel *countLabel; +@property (nonatomic, retain) UIRefreshControl *refreshController; +@property (nonatomic, retain) UIView *favouriteView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) UIButton *contactCardButton; +@property (nonatomic, retain) CNContact *meContact; +@property (nonatomic, retain) NSMutableArray *favouritesArray; +@property (nonatomic, retain) UIView *favouriteSectionView; +@property (nonatomic, retain) UILabel *favouriteSectionLabel; +@property (nonatomic, retain) UIButton *favouriteSectionButton; +@property (nonatomic, retain) NSString *categoriesName; +@property (nonatomic, retain) MessageView *messageView; +@property (nonatomic) BOOL showFavourite; +@property (nonatomic) BOOL isMyCardAvailable; +@property (nonatomic) BOOL hideContactsDetails; + ++ (id)defaultPNGName; +-(bool)isFaceTimeContact:(NSString*)identifier; +-(bool)isIMessageContact:(NSString*)identifier; +@end diff --git a/Phoenix/Tweak/PHOENIX/Contacts/ContactViewController.m b/Phoenix/Tweak/PHOENIX/Contacts/ContactViewController.m new file mode 100644 index 0000000..8bd4b43 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Contacts/ContactViewController.m @@ -0,0 +1,1224 @@ +#import "ContactViewController.h" + +long totalContact = 0; + +NSMutableArray *arraySearchContactData; + +static void deleteDataForID(NSString *idToRemove){ + + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/AllFavourites.plist", aDocumentsDirectory]; + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [mutableDict removeObjectForKey:idToRemove]; + [mutableDict writeToFile:plistPath atomically:YES]; + +} + + +static void deleteCategoriesForID(NSString *idToRemove, NSString*categories) { + + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/%@.plist", aDocumentsDirectory, categories]; + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [mutableDict removeObjectForKey:idToRemove]; + [mutableDict writeToFile:plistPath atomically:YES]; + +} + +static void writePhoneNumberToPlist(NSString * phoneNumber){ + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/%@.plist", aDocumentsDirectory, @"PhoenixPhoneNumber"]; + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [mutableDict setObject:phoneNumber forKey:@"myPhoneNumber"]; + [mutableDict writeToFile:plistPath atomically:YES]; +} + +static CNContact *getMyContact(){ + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/%@.plist", aDocumentsDirectory, @"PhoenixPhoneNumber"]; + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + + if(!dict[@"myPhoneNumber"]) + return nil; + + id keysToFetch = @[[CNContactViewController descriptorForRequiredKeys]]; + CNContactStore *contactStore = [[CNContactStore alloc] init]; + NSError *error; + return [contactStore unifiedContactsMatchingPredicate:[CNContact predicateForContactsWithIdentifiers:@[dict[@"myPhoneNumber"]]] keysToFetch:keysToFetch error:&error][0]; +} + + +@implementation ContactViewController + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self.navigationController setNavigationBarHidden:YES animated:animated]; + [self refreshData]; +} + + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [self.navigationController setNavigationBarHidden:NO animated:animated]; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + arraySearchContactData = [NSMutableArray new]; + + self.view.backgroundColor = UIColor.systemBackgroundColor; + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [[SettingManager sharedInstance] accentColour]; + self.view.tintColor = [[SettingManager sharedInstance] accentColour]; + self.accentColour = [[SettingManager sharedInstance] accentColour]; + self.store = [[CNContactStore alloc] init]; + + self.categoriesName = [[SettingManager sharedInstance] objectForKey:@"savedCategoriesName" defaultValue:@"All Favourites"]; + self.showFavourite = [[SettingManager sharedInstance] boolForKey:@"showFavourites" defaultValue:YES]; + self.hideContactsDetails = [[SettingManager sharedInstance] boolForKey:@"hideContactsDetails" defaultValue:NO]; + + if(getMyContact() && !self.meContact){ + self.meContact = getMyContact(); + self.isMyCardAvailable = YES; + } + else + self.isMyCardAvailable = NO; + + [self copyDefaultCategoriesPlist]; + [self getFavouriteData]; + [self layoutHeaderView]; + [self getContacts]; + [self appendContacts]; + [self layoutTableView]; + [self layoutBannerAccessoriesView]; + [self checkIfFavouriteIsEmpty]; + + if (!self.isMyCardAvailable) { + [self showAlertWithTitle:@"Me Card" subtitle:@"To setup Me Card click on the Me Card view and choose your own contact from the list, if you dont have your own contact saved please add your phone number to the contact then it will load your details automatically."]; + } + +} + + +-(void)copyDefaultCategoriesPlist { + + NSFileManager *fileManager = [NSFileManager defaultManager]; + + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/Categories.plist", aDocumentsDirectory]; + + if(![fileManager fileExistsAtPath:plistPath]) { + NSString *defaultPlist = @"/Library/Application Support/Phoenix.bundle/DefaultCategories/Categories.plist"; + [fileManager copyItemAtPath:defaultPlist toPath:plistPath error:nil]; + } +} + + +-(void)getFavouriteData { + // [IMPORTANT] + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *categoriesString = [self.categoriesName stringByReplacingOccurrencesOfString:@" " withString:@""]; + NSString *plistPath = [NSString stringWithFormat:@"%@/%@.plist", aDocumentsDirectory, categoriesString]; + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + self.favouritesArray = [NSMutableArray new]; + for(NSString *key in mutableDict){ + [self.favouritesArray addObject:mutableDict[key]]; + + NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"fullName" ascending:YES]; + [self.favouritesArray sortUsingDescriptors:[NSArray arrayWithObject:sort]]; + } + +} + + +-(void)checkIfFavouriteIsEmpty { + + if (self.favouritesArray.count == 0) { + self.messageView.alpha = 1; + } else { + self.messageView.alpha = 0; + } +} + + +-(void)layoutHeaderView { + + self.headerView = [[UIView alloc] init]; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 150)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.topAnchor padding:0]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.font = [UIFont systemFontOfSize:30 weight:UIFontWeightBlack]; + self.titleLabel.text = @"Contacts"; + [self.headerView addSubview:self.titleLabel]; + + [self.titleLabel top:self.view.safeAreaLayoutGuide.topAnchor padding:0]; + [self.titleLabel leading:self.headerView.leadingAnchor padding:20]; + [self.titleLabel trailing:self.headerView.trailingAnchor padding:-20]; + + + self.settingButton = [[UIButton alloc] init]; + [self.settingButton addTarget:self action:@selector(settingVC) forControlEvents:UIControlEventTouchUpInside]; + UIImage *settingImage = [UIImage systemImageNamed:@"gear" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:20]]; + [self.settingButton setImage:settingImage forState:UIControlStateNormal]; + self.settingButton.imageView.contentMode = UIViewContentModeScaleAspectFit; + self.settingButton.tintColor = self.accentColour; + self.settingButton.layer.cornerRadius = 10; + self.settingButton.layer.cornerCurve = kCACornerCurveContinuous; + self.settingButton.backgroundColor = [self.accentColour colorWithAlphaComponent:0.4]; + [self.headerView addSubview:self.settingButton]; + + [self.settingButton size:CGSizeMake(45, 45)]; + [self.settingButton top:self.titleLabel.bottomAnchor padding:10]; + [self.settingButton trailing:self.headerView.trailingAnchor padding:-20]; + + + self.addButton = [[UIButton alloc] init]; + UIImage *addImage = [UIImage systemImageNamed:@"person.crop.circle.badge.plus" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:20]]; + [self.addButton setImage:addImage forState:UIControlStateNormal]; + self.addButton.imageView.contentMode = UIViewContentModeScaleAspectFit; + self.addButton.tintColor = self.accentColour; + self.addButton.layer.cornerRadius = 10; + self.addButton.layer.cornerCurve = kCACornerCurveContinuous; + self.addButton.backgroundColor = [self.accentColour colorWithAlphaComponent:0.4]; + self.addButton.menu = [self addContactManager]; + self.addButton.showsMenuAsPrimaryAction = true; + [self.headerView addSubview:self.addButton]; + + [self.addButton size:CGSizeMake(45, 45)]; + [self.addButton top:self.titleLabel.bottomAnchor padding:10]; + [self.addButton trailing:self.settingButton.leadingAnchor padding:-10]; + + + self.searchBarView = [[UIView alloc] init]; + self.searchBarView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.searchBarView.layer.cornerRadius = 10; + self.searchBarView.layer.cornerCurve = kCACornerCurveContinuous; + self.searchBarView.clipsToBounds = YES; + [self.headerView addSubview:self.searchBarView]; + + [self.searchBarView height:45]; + [self.searchBarView top:self.titleLabel.bottomAnchor padding:10]; + [self.searchBarView leading:self.view.leadingAnchor padding:20]; + [self.searchBarView trailing:self.addButton.leadingAnchor padding:-10]; + + + self.searchIcon = [[UIImageView alloc] init]; + self.searchIcon.contentMode = UIViewContentModeScaleAspectFit; + self.searchIcon.tintColor = UIColor.tertiaryLabelColor; + self.searchIcon.image = [UIImage systemImageNamed:@"magnifyingglass" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:20]]; + [self.searchBarView addSubview:self.searchIcon]; + + [self.searchIcon size:CGSizeMake(25, 25)]; + [self.searchIcon y:self.searchBarView.centerYAnchor]; + [self.searchIcon leading:self.searchBarView.leadingAnchor padding:5]; + + + self.searchTextField = [[UITextField alloc] init]; + self.searchTextField.font = [UIFont systemFontOfSize:18]; + self.searchTextField.placeholder = @"Search contacts..."; + self.searchTextField.backgroundColor = UIColor.clearColor; + self.searchTextField.tintColor = self.accentColour; + self.searchTextField.autocorrectionType = UITextAutocorrectionTypeNo; + self.searchTextField.keyboardType = UIKeyboardTypeDefault; + self.searchTextField.clearButtonMode = UITextFieldViewModeWhileEditing; + self.searchTextField.delegate = self; + [self.searchTextField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged]; + [self.searchBarView addSubview:self.searchTextField]; + + [self.searchTextField top:self.searchBarView.topAnchor padding:0]; + [self.searchTextField leading:self.searchIcon.trailingAnchor padding:5]; + [self.searchTextField trailing:self.searchBarView.trailingAnchor padding:-5]; + [self.searchTextField bottom:self.searchBarView.bottomAnchor padding:0]; +} + +// -(CNContact*)getMeContact:(NSString *)identifier{ +-(bool)isFaceTimeContact:(NSString*)identifier{ + // id keysToFetch = @[[CNContactViewController descriptorForRequiredKeys]]; + // CNContact *contact = [self.store unifiedContactWithIdentifier:identifier keysToFetch:keysToFetch error:nil]; + + // self.controller = [CNContactViewController viewControllerForContact:contact]; + // self.controller.delegate = self; + + // NSLog(@"AAAAAAAAAAA isFaceTimeContact_faceTimeAction:-%@", self.controller.contentViewController); + // NSLog(@"AAAAAAAAAAA isFaceTimeContact_faceTimeAudioAction:-%@", self.controller.contentViewController._faceTimeAudioAction); + + return 1; +} + +-(bool)isIMessageContact:(NSString*)identifier{ + // id keysToFetch = @[[CNContactViewController descriptorForRequiredKeys]]; + // CNContact *contact = [self.store unifiedContactWithIdentifier:identifier keysToFetch:keysToFetch error:nil]; + + // self.controller = [CNContactViewController viewControllerForContact:contact]; + // self.controller.delegate = self; + + // NSLog(@"AAAAAAAAAAA isIMessageContact_faceTimeAction:-%@", self.controller.contentViewController); + // NSLog(@"AAAAAAAAAAA isIMessageContact_faceTimeAudioAction:-%@", self.controller.contentViewController._faceTimeAudioAction); + + return 1; +} + + +-(void)getContacts { + + CNAuthorizationStatus authorizationStatus = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; + if (authorizationStatus != CNAuthorizationStatusAuthorized) { + NSLog(@"No authorization..."); + return; + } + + self.contactPeople = [[NSMutableArray alloc] init]; + + //[NEW CODE]; + [arraySearchContactData removeAllObjects]; + + NSArray *keysToFetch = @[CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey, CNContactEmailAddressesKey, CNContactImageDataKey, CNContactIdentifierKey]; + CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch]; + CNContactStore *contactStore = [[CNContactStore alloc] init]; + [contactStore enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) { + + NSString *givenName = contact.givenName; + NSString *familyName = contact.familyName; + + ContactsData *contactData = [[ContactsData alloc] init]; + contactData.firstName = givenName; + contactData.lastName = familyName; + + NSArray *phoneNumbers = contact.phoneNumbers; + for (CNLabeledValue *labelValue in phoneNumbers) { + CNPhoneNumber *phoneNumber = labelValue.value; + NSString * onePhone = phoneNumber.stringValue; + + contactData.phone = [onePhone stringByReplacingOccurrencesOfString:@" " withString:@""]; + } + + + NSArray *emailArray = contact.emailAddresses; + for (CNLabeledValue *labelValue2 in emailArray) { + NSString *email = labelValue2.value; + contactData.email = email; + } + + + if (contact.imageData != nil ) { + UIImage *contactImage = [UIImage imageWithData:(NSData *)contact.imageData]; + contactData.avatar = contactImage; + } + + + NSString *ids = contact.identifier; + contactData.identifier = ids; + + + [self.contactPeople addObject:contactData]; + + self.contactPeople = [[self.contactPeople sortedArrayUsingComparator:^(ContactsData *obj1, ContactsData *obj2) { + return [obj1.firstName compare:obj2.firstName options:(NSCaseInsensitiveSearch)]; + }] mutableCopy]; + + [arraySearchContactData addObject:contactData]; + + }]; + +} + + +-(void)appendContacts { + + NSCharacterSet *validChars = [NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"]; + validChars = [validChars invertedSet]; + NSMutableArray *notCharContacts = [NSMutableArray new]; + + NSMutableArray * columns = [[NSMutableArray alloc] initWithCapacity:26]; + for(int i = 0; i < 26; i ++){ + NSMutableArray * group = [[NSMutableArray alloc] init]; + for(int j = 0; j < self.contactPeople.count ; j++){ + ContactsData *contactData = self.contactPeople [j]; + NSString * letter; + if(contactData.firstName.length != 0) { + letter = [contactData.firstName substringToIndex:1]; + } + else if(contactData.lastName.length != 0) { + letter = [contactData.lastName substringToIndex:1]; + } + + NSRange range = [letter rangeOfCharacterFromSet:validChars]; + if (NSNotFound != range.location && letter.length !=0) { + [notCharContacts addObject:contactData]; + } + else if( letter == [NSString stringWithFormat: @"%c", i+'A'] ){ + [group addObject:contactData]; + } + + + } + if (group.count) { + [columns addObject:group]; + } + } + + self.parsedContacts = columns; + NSMutableArray* letters = [[NSMutableArray alloc] init]; + + if(notCharContacts.count !=0){ + NSArray *aSortedArray = [notCharContacts sortedArrayUsingComparator:^(ContactsData *obj1, ContactsData *obj2) { + return (NSComparisonResult) [obj1.firstName compare:obj2.firstName options:(NSCaseInsensitiveSearch)]; + }]; + + NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:aSortedArray]; + aSortedArray = [[orderedSet array] mutableCopy]; + + [self.parsedContacts addObject:aSortedArray]; + } + + for(int i = 0; i < self.parsedContacts.count; i ++){ + NSString * item = [NSString stringWithFormat:@"%c", i+'A']; + [letters addObject:item]; + } + + if(notCharContacts.count !=0) + [letters addObject:@"#"]; + self.sectionIndexTitles = [letters copy]; +} + + +-(void)layoutTableView { + + self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped]; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor;; + self.tableView.sectionIndexColor = self.accentColour; + self.tableView.showsVerticalScrollIndicator = NO; + self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; + [self.view addSubview:self.tableView]; + + self.tableView.delegate = self; + self.tableView.dataSource = self; + + [self.tableView top:self.headerView.bottomAnchor padding:0]; + [self.tableView leading:self.view.leadingAnchor padding:0]; + [self.tableView trailing:self.view.trailingAnchor padding:0]; + [self.tableView bottom:self.view.bottomAnchor padding:0]; + + + self.refreshController = [[UIRefreshControl alloc] init]; + [self.refreshController addTarget:self action:@selector(refreshData) forControlEvents:UIControlEventValueChanged]; + NSString *title = @"Refresh Contacts"; + NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject:self.accentColour forKey:NSForegroundColorAttributeName]; + NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:title attributes:attrsDictionary]; + self.refreshController.attributedTitle = attributedTitle; + self.refreshController.tintColor = self.accentColour; + [self.tableView addSubview:self.refreshController]; + + + self.indexBar = [[TDIndexBar alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 25, 0, 25, self.view.frame.size.height)]; + self.indexBar.delegate = self; + [self.view addSubview:self.indexBar]; + + self.indexBar.textColor = self.accentColour; + self.indexBar.selectedTextColor = self.accentColour; + self.indexBar.selectedBackgroundColor = UIColor.clearColor; + self.indexBar.detailViewDrawColor = self.accentColour; + self.indexBar.detailViewTextColor = UIColor.whiteColor; + + + NSCharacterSet *validChars = [NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"]; + validChars = [validChars invertedSet]; + + NSMutableArray *indices = [[NSMutableArray alloc] init]; + for (int i = 0; i < self.parsedContacts.count; ++i) { + ContactsData *contactsData = self.parsedContacts[i][0]; + NSString * title; + + + if (contactsData.firstName.length != 0) { + title = [contactsData.firstName substringToIndex:1]; + } else { + title = [contactsData.lastName substringToIndex:1]; + } + + NSRange range = [title rangeOfCharacterFromSet:validChars]; + if (NSNotFound != range.location) { + title = @"#"; + } + + [indices addObject:title]; + } + + [self.indexBar setIndexes:indices]; + + + self.bannerView = [[UIView alloc] init]; + if (self.showFavourite) { + self.bannerView.frame = CGRectMake(0, 0, self.tableView.frame.size.width, 285); + } else { + self.bannerView.frame = CGRectMake(0, 0, self.tableView.frame.size.width, 80); + } + self.tableView.tableHeaderView = self.bannerView; +} + + +-(void)layoutBannerAccessoriesView { + + if (self.showFavourite) { + self.favouriteSectionView = [[UIView alloc] init]; + [self.bannerView addSubview:self.favouriteSectionView]; + + [self.favouriteSectionView size:CGSizeMake(self.view.frame.size.width, 40)]; + [self.favouriteSectionView top:self.bannerView.topAnchor padding:5]; + [self.favouriteSectionView x:self.bannerView.centerXAnchor]; + + + self.favouriteSectionLabel = [[UILabel alloc] init]; + self.favouriteSectionLabel.textAlignment = NSTextAlignmentLeft; + self.favouriteSectionLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold]; + self.favouriteSectionLabel.textColor = UIColor.tertiaryLabelColor; + self.favouriteSectionLabel.text = self.categoriesName; + [self.favouriteSectionView addSubview:self.favouriteSectionLabel]; + + [self.favouriteSectionLabel y:self.favouriteSectionView.centerYAnchor]; + [self.favouriteSectionLabel leading:self.favouriteSectionView.leadingAnchor padding:20]; + + + self.favouriteSectionButton = [[UIButton alloc] init]; + self.favouriteSectionButton.tintColor = self.accentColour; + UIImage *favImage = [UIImage systemImageNamed:@"switch.2" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:20]]; + [self.favouriteSectionButton setImage:favImage forState:UIControlStateNormal]; + self.favouriteSectionButton.imageView.contentMode = UIViewContentModeScaleAspectFit; + [self.favouriteSectionButton addTarget:self action:@selector(presentFavouriteFilterVC) forControlEvents:UIControlEventTouchUpInside]; + [self.favouriteSectionView addSubview:self.favouriteSectionButton]; + + [self.favouriteSectionButton size:CGSizeMake(25, 25)]; + [self.favouriteSectionButton y:self.favouriteSectionView.centerYAnchor]; + [self.favouriteSectionButton trailing:self.favouriteSectionView.trailingAnchor padding:-20]; + + + self.favouriteView = [[UIView alloc] init]; + [self.bannerView addSubview:self.favouriteView]; + + [self.favouriteView size:CGSizeMake(self.view.frame.size.width, 140)]; + [self.favouriteView x:self.bannerView.centerXAnchor]; + [self.favouriteView top:self.favouriteSectionView.bottomAnchor padding:0]; + + + self.messageView = [[MessageView alloc] init]; + self.messageView.icon.image = [UIImage systemImageNamed:@"heart.fill"]; + self.messageView.icon.tintColor = self.accentColour; + self.messageView.title.text = @"You don't have any favourites!"; + self.messageView.alpha = 0; + self.messageView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.messageView.layer.cornerRadius = 15; + self.messageView.layer.cornerCurve = kCACornerCurveContinuous; + [self.favouriteView addSubview:self.messageView]; + + [self.messageView top:self.favouriteView.topAnchor padding:0]; + [self.messageView leading:self.favouriteView.leadingAnchor padding:20]; + [self.messageView trailing:self.favouriteView.trailingAnchor padding:-20]; + [self.messageView bottom:self.favouriteView.bottomAnchor padding:0]; + + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[FavouriteCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.favouriteView addSubview:self.collectionView]; + + [self.collectionView height:150]; + [self.collectionView x:self.favouriteView.centerXAnchor]; + [self.collectionView leading:self.favouriteView.leadingAnchor padding:20]; + [self.collectionView trailing:self.favouriteView.trailingAnchor padding:-20]; + [self.collectionView top:self.favouriteView.topAnchor padding:0]; + + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + } + + self.myCardView = [[UIView alloc] init]; + self.myCardView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.myCardView.layer.cornerRadius = 15; + self.myCardView.layer.cornerCurve = kCACornerCurveContinuous; + self.myCardView.clipsToBounds = YES; + [self.bannerView addSubview:self.myCardView]; + + if (self.showFavourite) { + [self.myCardView size:CGSizeMake(self.view.frame.size.width-40, 70)]; + [self.myCardView x:self.bannerView.centerXAnchor]; + [self.myCardView top:self.favouriteView.bottomAnchor padding:20]; + } else { + [self.myCardView size:CGSizeMake(self.view.frame.size.width-40, 70)]; + [self.myCardView x:self.bannerView.centerXAnchor]; + [self.myCardView top:self.bannerView.topAnchor padding:10]; + } + + + UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pushMyCardVC)]; + tapRecognizer.delegate = self; + [self.myCardView addGestureRecognizer:tapRecognizer]; + + self.avatarImage = [[UIImageView alloc] init]; + if(self.isMyCardAvailable) { + self.avatarImage.image = [UIImage imageWithData:(NSData *)self.meContact.imageData]; + } else { + self.avatarImage.image = [[SettingManager sharedInstance] icloudAvatar]; + } + self.avatarImage.contentMode = UIViewContentModeScaleAspectFill; + self.avatarImage.layer.cornerRadius = 25; + self.avatarImage.clipsToBounds = YES; + self.avatarImage.layer.borderWidth = 1.5; + self.avatarImage.layer.borderColor = self.accentColour.CGColor; + [self.myCardView addSubview:self.avatarImage]; + + [self.avatarImage size:CGSizeMake(50, 50)]; + [self.avatarImage y:self.myCardView.centerYAnchor]; + [self.avatarImage leading:self.myCardView.leadingAnchor padding:10]; + + + self.contactCardButton = [[UIButton alloc] init]; + self.contactCardButton.tintColor = self.accentColour; + [self.contactCardButton addTarget:self action:@selector(presentContactCardsVC) forControlEvents:UIControlEventTouchUpInside]; + UIImage *cardImage = [UIImage systemImageNamed:@"rectangle.stack.person.crop.fill" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:20]]; + [self.contactCardButton setImage:cardImage forState:UIControlStateNormal]; + self.contactCardButton.imageView.contentMode = UIViewContentModeScaleAspectFit; + [self.myCardView addSubview:self.contactCardButton]; + + [self.contactCardButton size:CGSizeMake(40, 40)]; + [self.contactCardButton y:self.myCardView.centerYAnchor]; + [self.contactCardButton trailing:self.myCardView.trailingAnchor padding:-10]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.textAlignment = NSTextAlignmentLeft; + self.nameLabel.textColor = UIColor.labelColor; + self.nameLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightBold]; + if(self.isMyCardAvailable) { + self.nameLabel.text = [NSString stringWithFormat:@"%@ %@", self.meContact.givenName, self.meContact.familyName]; + } else { + self.nameLabel.text = [[SettingManager sharedInstance] icloudFullName]; + } + [self.myCardView addSubview:self.nameLabel]; + + [self.nameLabel top:self.avatarImage.topAnchor padding:3]; + [self.nameLabel leading:self.avatarImage.trailingAnchor padding:10]; + [self.nameLabel trailing:self.contactCardButton.leadingAnchor padding:-10]; + + + self.countLabel = [[UILabel alloc] init]; + self.countLabel.textAlignment = NSTextAlignmentLeft; + self.countLabel.textColor = UIColor.labelColor; + self.countLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightRegular]; + [self.myCardView addSubview:self.countLabel]; + + [self.countLabel bottom:self.avatarImage.bottomAnchor padding:-3]; + [self.countLabel leading:self.avatarImage.trailingAnchor padding:10]; + [self.countLabel trailing:self.contactCardButton.leadingAnchor padding:-10]; + + [self updateContactCount]; + +} + + +-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { + ContactsData *contactsData = self.parsedContacts [section] [0]; + NSString * title; + if(contactsData.firstName.length != 0) { + title = [contactsData.firstName substringToIndex:1]; + } else { + title = [contactsData.lastName substringToIndex:1]; + } + return title; +} + + +-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [self.parsedContacts[section] count]; +} + + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return self.parsedContacts.count; +} + + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + ContactCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[ContactCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *bgColorView = [[UIView alloc] init]; + bgColorView.backgroundColor = UIColor.clearColor; + [cell setSelectedBackgroundView:bgColorView]; + + cell.backgroundColor = UIColor.clearColor; + + ContactsData *contactsData = self.parsedContacts [indexPath.section] [indexPath.row]; + cell.nameLabel.text = [NSString stringWithFormat:@"%@ %@", contactsData.firstName, contactsData.lastName]; + + //cell.emailLabel.text = contactsData.email; + + if (!self.hideContactsDetails) { + if (contactsData.phone != nil) { + cell.numberLabel.text = contactsData.phone; + } else { + cell.numberLabel.text = @"No phone number available"; + } + + + if (contactsData.email != nil) { + cell.emailLabel.text = contactsData.email; + } else { + cell.emailLabel.text = @"No email address available"; + } + } + + + if (contactsData.avatar !=nil) { + cell.avatar.image = contactsData.avatar; + } else { + cell.avatar.image = [UIImage systemImageNamed:@"person.crop.circle.fill"]; + cell.avatar.tintColor = self.accentColour; + } + + UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc] init]; + [gestureRecognizer addTarget:self action:@selector(contactsLongPressed:)]; + gestureRecognizer.delegate = self; + gestureRecognizer.minimumPressDuration = 0.3; + [cell addGestureRecognizer:gestureRecognizer]; + + + [self isFaceTimeContact:contactsData.identifier]; + [self isIMessageContact:contactsData.identifier]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 75; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + + invokeHaptic(); + + ContactsData *contactsData = self.parsedContacts[indexPath.section][indexPath.row]; + [self showContactDetailsWthID:contactsData.identifier]; + + self.indexBar.alpha = 1; + [self.searchTextField resignFirstResponder]; + self.searchTextField.text = nil; + [self refreshData]; +} + + +-(void)showContactDetailsWthID:(NSString *)identifier { + // Here we push contact id to show contact details + id keysToFetch = @[[CNContactViewController descriptorForRequiredKeys]]; + CNContact *contact = [self.store unifiedContactWithIdentifier:identifier keysToFetch:keysToFetch error:nil]; + + + self.controller = [CNContactViewController viewControllerForContact:contact]; + self.controller.delegate = self; + self.controller.allowsEditing = YES; + self.controller.allowsActions = YES; + [self.navigationController pushViewController:self.controller animated:YES]; + +} + + +- (void)textFieldDidChange:(UITextField *)textField { + [self updateSearchResultWithString:textField.text]; +} + + +- (void)textFieldDidEndEditing:(UITextField *)textField { + [self updateSearchResultWithString:textField.text]; +} + + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + [textField resignFirstResponder]; + return YES; +} + + +- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + + [self updateSearchResultWithString:textField.text]; + + UIToolbar *textToolbar = [[UIToolbar alloc] init]; + [textToolbar sizeToFit]; + textToolbar.barStyle = UIBarStyleDefault; + textToolbar.tintColor = self.accentColour; + textToolbar.items = [self textToolBarButtons]; + self.searchTextField.inputAccessoryView = textToolbar; + + return YES; + +} + + +-(NSArray *)textToolBarButtons { + + NSMutableArray *textButtons = [[NSMutableArray alloc] init]; + + [textButtons addObject:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil]]; + + [textButtons addObject:[[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(dismissKeyboard)]]; + + return [textButtons copy]; + +} + + +-(void)dismissKeyboard { + invokeHaptic(); + [self.searchTextField resignFirstResponder]; +} + + +- (void)indexDidChanged:(TDIndexBar *)indexBar index:(NSInteger)index title:(NSString *)title { + [_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:index] atScrollPosition:UITableViewScrollPositionTop animated:NO]; +} + + +-(void)updateSearchResultWithString:(NSString *)string { + + [self.contactPeople removeAllObjects]; + + NSString *name = @""; + NSString *phoneNumber = @""; + + if ([string length] > 0) + { + self.indexBar.alpha = 0; + for (int i = 0; i < [arraySearchContactData count] ; i++) + { + ContactsData *data = [arraySearchContactData objectAtIndex:i]; + name = [NSString stringWithFormat:@"%@ %@", data.firstName, data.lastName]; + phoneNumber = data.phone; + if (name.length >= string.length) + { + NSRange titleResultsRange = [name rangeOfString:string options:NSCaseInsensitiveSearch]; + NSRange titleResultsRangePhn = [phoneNumber rangeOfString:string options:NSCaseInsensitiveSearch]; + if (titleResultsRange.length > 0 || titleResultsRangePhn.length >0) + { + [self.contactPeople addObject:[arraySearchContactData objectAtIndex:i]]; + } + } + } + } + else{ + //[New Code] + self.indexBar.alpha = 1; + [self.contactPeople removeAllObjects]; + [self.contactPeople addObjectsFromArray:arraySearchContactData]; + } + + [self appendContacts]; + [self.tableView reloadData]; + [self updateContactCount]; +} + + +-(void)refreshData { + [self.refreshController endRefreshing]; + [self getContacts]; + [self appendContacts]; + [self.tableView reloadData]; + [self updateContactCount]; + + self.indexBar.alpha = 1; + [self.searchTextField resignFirstResponder]; + self.searchTextField.text = nil; + + + NSCharacterSet *validChars = [NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"]; + validChars = [validChars invertedSet]; + + NSMutableArray *indices = [[NSMutableArray alloc] init]; + for (int i = 0; i < self.parsedContacts.count; ++i) { + ContactsData *contactsData = self.parsedContacts[i][0]; + NSString * title; + + + if (contactsData.firstName.length != 0) { + title = [contactsData.firstName substringToIndex:1]; + } else { + title = [contactsData.lastName substringToIndex:1]; + } + + NSRange range = [title rangeOfCharacterFromSet:validChars]; + if (NSNotFound != range.location) { + title = @"#"; + } + + [indices addObject:title]; + } + + [self.indexBar setIndexes:indices]; +} + + +-(void)updateContactCount { + + NSString *countString = [NSString stringWithFormat:@"%ld", self.contactPeople.count]; + self.countLabel.text = [NSString stringWithFormat:@"%@ contacts", countString]; + + NSMutableAttributedString *attrsString = [[NSMutableAttributedString alloc] initWithAttributedString:self.countLabel.attributedText]; + NSRange range = [self.countLabel.text rangeOfString:countString]; + if (range.location != NSNotFound) { + [attrsString addAttribute:NSForegroundColorAttributeName value:self.accentColour range:range]; + } + self.countLabel.attributedText = attrsString; + +} + + +-(void)settingVC { + invokeHaptic(); + SettingViewController *vc = [[SettingViewController alloc] init]; + [self presentViewController:vc animated:YES completion:nil]; +} + + +-(void)addContactVC { + invokeHaptic(); + CNMutableContact *contact = [[CNMutableContact alloc] init]; + CNContactViewController *controller = [CNContactViewController viewControllerForNewContact:contact]; + controller.delegate = self; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller]; + [self presentViewController:navController animated:YES completion:nil]; +} + + +- (BOOL)contactViewController:(CNContactViewController *)viewController shouldPerformDefaultActionForContactProperty:(CNContactProperty *)property { + return YES; +} + + +-(void)contactViewController:(CNContactViewController*)arg1 didCompleteWithContact:(id)arg2{ + + if (arg2 == NULL) { + [arg1 dismissViewControllerAnimated:YES completion:nil]; + } + + [self refreshData]; + [self refreshController]; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.favouritesArray.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + FavouriteCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.favouriteDelegate = self; + + NSData *avatarImageData = self.favouritesArray[indexPath.row][@"avatarImage"]; + cell.avatarImage.image = [UIImage imageWithData:avatarImageData]; + + cell.nameLabel.text = self.favouritesArray[indexPath.row][@"fullName"]; + + cell.iconImage.image = [UIImage systemImageNamed:self.favouritesArray[indexPath.row][@"categoriesIcon"]]; + cell.iconView.backgroundColor = [self colorWithHexString:(NSString*)[[self.favouritesArray objectAtIndex:indexPath.row] objectForKey:@"categoriesColour"]]; + + BOOL isPhoneNumberAvailable = [self.favouritesArray[indexPath.row][@"isPhoneNumberAvailable"] boolValue]; + if (isPhoneNumberAvailable){ + [cell.favStackView addArrangedSubview:cell.favCallButton]; + [cell.favStackView addArrangedSubview:cell.favMessageButton]; + } + + BOOL isEmailAvailable = [self.favouritesArray[indexPath.row][@"isEmailAvailable"] boolValue]; + if (isEmailAvailable){ + [cell.favStackView addArrangedSubview:cell.favEmailButton]; + } + + return cell; + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + return CGSizeMake(180, 150); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + invokeHaptic(); + NSString *contactIdentifier = self.favouritesArray[indexPath.row][@"contactIdentifier"]; + [self showContactDetailsWthID:contactIdentifier]; +} + + +- (void)callButtonTappedForCell:(UICollectionViewCell *)cell { + NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell]; + UIApplication *application = [UIApplication sharedApplication]; + NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"tel:%@", self.favouritesArray[indexPath.row][@"phoneNumber"]]]; + [application openURL:URL options:@{} completionHandler:nil]; +} + + +- (void)messageButtonTappedForCell:(UICollectionViewCell *)cell { + NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell]; + UIApplication *application = [UIApplication sharedApplication]; + NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"sms:%@", self.favouritesArray[indexPath.row][@"phoneNumber"]]]; + [application openURL:URL options:@{} completionHandler:nil]; +} + + +- (void)emailButtonTappedForCell:(UICollectionViewCell *)cell { + NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell]; + UIApplication *application = [UIApplication sharedApplication]; + NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@", self.favouritesArray[indexPath.row][@"emailAddress"]]]; + [application openURL:URL options:@{} completionHandler:nil]; +} + + +- (UIContextMenuConfiguration *)collectionView:(UICollectionView *)collectionView contextMenuConfigurationForItemAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point { + + UIContextMenuConfiguration* config = [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil actionProvider:^UIMenu* _Nullable(NSArray* _Nonnull suggestedActions) { + + UIAction *deleteAction = [UIAction actionWithTitle:@"Delete" image:[UIImage systemImageNamed:@"trash.fill"] identifier:nil handler:^(UIAction *action) { + + NSString *getCategoriesName = self.favouritesArray[indexPath.row][@"categoriesName"]; + NSString *categoriesString = [getCategoriesName stringByReplacingOccurrencesOfString:@" " withString:@""]; + + deleteDataForID(self.favouritesArray[indexPath.row][@"id"]); + deleteCategoriesForID(self.favouritesArray[indexPath.row][@"id"], categoriesString); + [self getFavouriteData]; + [self.collectionView reloadData]; + [self checkIfFavouriteIsEmpty]; + + }]; + deleteAction.attributes = UIMenuElementAttributesDestructive; + + return [UIMenu menuWithTitle:@"Favourites" children:@[deleteAction]]; + + }]; + + return config; +} + + +-(UIMenu *)addContactManager { + + UIAction *addContactAction = [UIAction actionWithTitle:@"Create New Contact" image:[UIImage systemImageNamed:@"person.crop.circle.fill"] identifier:nil handler:^(UIAction *action) { + [self addContactVC]; + }]; + + UIAction *addFavouriteAction = [UIAction actionWithTitle:@"Create New Favourite" image:[UIImage systemImageNamed:@"rectangle.stack.fill.badge.person.crop"] identifier:nil handler:^(UIAction *action) { + if (self.showFavourite) { + [self addFavouriteVC]; + } else { + [self showAlertWithTitle:@"Sorry!" subtitle:@"You have disabled favourites, please enable them if you want to add new favourites."]; + } + }]; + + return [UIMenu menuWithTitle:@"" children:@[addContactAction, addFavouriteAction]]; +} + + +-(void)addFavouriteVC { + invokeHaptic(); + CreateFavouriteViewController *vc = [[CreateFavouriteViewController alloc] init]; + vc.delegate = self; + [self presentViewController:vc animated:YES completion:nil]; +} + + +-(void)pushMyCardVC { + + if (!self.isMyCardAvailable) { + CNContactPickerViewController *contactPicker = [[CNContactPickerViewController alloc] init]; + + contactPicker.delegate = self; + contactPicker.displayedPropertyKeys = (NSArray *)CNContactGivenNameKey; + + [self presentViewController:contactPicker animated:YES completion:nil]; + + } else { + invokeHaptic(); + self.controller = [CNContactViewController viewControllerForContact:self.meContact]; + self.controller.delegate = self; + self.controller.allowsEditing = YES; + self.controller.allowsActions = YES; + [self.navigationController pushViewController:self.controller animated:YES]; + } +} + +-(void) contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact{ + writePhoneNumberToPlist(contact.identifier); + self.isMyCardAvailable = YES; + self.meContact = getMyContact(); + [self refreshData]; +} + +-(void)presentContactCardsVC { +} + ++ (id)defaultPNGName{ + return @"Default"; +} + + +- (void)contactsLongPressed:(UILongPressGestureRecognizer*)sender { + + ContactCell *cell = (ContactCell *)[sender view]; + + if (sender.state == UIGestureRecognizerStateBegan) { + + CGPoint touchPoint = [sender locationInView:self.tableView]; + NSIndexPath *contactsIndex = [self.tableView indexPathForRowAtPoint:touchPoint]; + + ContactsData *contactsData = self.parsedContacts[contactsIndex.section][contactsIndex.row]; + + id keysToFetch = @[[CNContactViewController descriptorForRequiredKeys]]; + CNContact *contact = [self.store unifiedContactWithIdentifier:contactsData.identifier keysToFetch:keysToFetch error:nil]; + + NSInteger contactSection = contactsIndex.section; + NSInteger contactRow = contactsIndex.row; + + if (sender.state == UIGestureRecognizerStateBegan) { + [UIView animateWithDuration:0.1 animations:^{ + cell.baseView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.97, 0.97); + }]; + + [self presentActionMenuWithData:contactsData cncontact:contact section:contactSection row:contactRow]; + + } + + } + +} + + +-(void)presentActionMenuWithData:(ContactsData *)data cncontact:(CNContact*)cncontact section:(NSInteger)section row:(NSInteger)row { + + haptic = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; + [haptic impactOccurred]; + + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:row inSection:section]; + ContactCell *cell = (ContactCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + + [UIView animateWithDuration:0.2 animations:^{ + cell.baseView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.0, 1.0); + }]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + ActionMenuViewController *vc = [[ActionMenuViewController alloc] initWithData:data cncontact:cncontact height:230]; + vc.delegate = self; + [self presentViewController:vc animated:YES completion:nil]; + }); + +} + + +-(void)needRefreshDataSourceAfterDeleteContact { + [self refreshData]; +} + + +-(void)didCreatedNewFavourite { + [self getFavouriteData]; + [self.collectionView reloadData]; + [self checkIfFavouriteIsEmpty]; +} + + +-(void)presentFavouriteFilterVC { + invokeHaptic(); + FavouriteFilterViewController *vc = [[FavouriteFilterViewController alloc] initWithHeight:240]; + vc.delegate = self; + [self presentViewController:vc animated:YES completion:nil]; +} + + +-(void)filterFavouritesWithCategoriesName:(NSString *)categories { + self.categoriesName = categories; + self.favouriteSectionLabel.text = categories; + [self getFavouriteData]; + [self.collectionView reloadData]; + [self checkIfFavouriteIsEmpty]; +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Contacts/ContactsData.h b/Phoenix/Tweak/PHOENIX/Contacts/ContactsData.h new file mode 100644 index 0000000..2e41e05 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Contacts/ContactsData.h @@ -0,0 +1,12 @@ +#import +#import + +@interface ContactsData : NSObject +@property (strong, nonatomic) NSString *firstName; +@property (strong, nonatomic) NSString *lastName; +@property (strong, nonatomic) NSString *phone; +@property (strong, nonatomic) NSString *email; +@property (strong, nonatomic) NSString *identifier; +@property (strong, nonatomic) UIImage *avatar; +@end + diff --git a/Phoenix/Tweak/PHOENIX/Contacts/ContactsData.m b/Phoenix/Tweak/PHOENIX/Contacts/ContactsData.m new file mode 100644 index 0000000..ad3bc98 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Contacts/ContactsData.m @@ -0,0 +1,4 @@ +#import "ContactsData.h" + +@implementation ContactsData +@end diff --git a/Phoenix/Tweak/PHOENIX/CustomClasses/CustomNavigationController.h b/Phoenix/Tweak/PHOENIX/CustomClasses/CustomNavigationController.h new file mode 100644 index 0000000..065f15c --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/CustomClasses/CustomNavigationController.h @@ -0,0 +1,9 @@ +#import + +@interface CNContactNavigationController : UINavigationController +@end + +@interface CustomNavigationController : CNContactNavigationController ++ (id)defaultPNGName; +-(BOOL)shouldSnapshot; +@end diff --git a/Phoenix/Tweak/PHOENIX/CustomClasses/CustomNavigationController.xm b/Phoenix/Tweak/PHOENIX/CustomClasses/CustomNavigationController.xm new file mode 100644 index 0000000..ada1894 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/CustomClasses/CustomNavigationController.xm @@ -0,0 +1,21 @@ +#import "CustomNavigationController.h" + +// [NEW CODE] also rename this file ext to .xm from .m +%subclass CustomNavigationController : CNContactNavigationController + +- (void)viewDidLoad { + // [super viewDidLoad]; + %orig; +} + +%new ++ (id)defaultPNGName{ + return @"Default"; +} + +%new +-(BOOL)shouldSnapshot{ + return 0; +} + +%end diff --git a/Phoenix/Tweak/PHOENIX/CustomClasses/MessageView.h b/Phoenix/Tweak/PHOENIX/CustomClasses/MessageView.h new file mode 100644 index 0000000..c363d77 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/CustomClasses/MessageView.h @@ -0,0 +1,7 @@ +#import + +@interface MessageView : UIView +@property (nonatomic, retain) UIImageView *icon; +@property (nonatomic, retain) UILabel *title; +@end + diff --git a/Phoenix/Tweak/PHOENIX/CustomClasses/MessageView.m b/Phoenix/Tweak/PHOENIX/CustomClasses/MessageView.m new file mode 100644 index 0000000..deffe1b --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/CustomClasses/MessageView.m @@ -0,0 +1,37 @@ +#import "MessageView.h" + +@implementation MessageView + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + + + self.icon = [[UIImageView alloc] init]; + self.icon.contentMode = UIViewContentModeScaleAspectFit; + [self addSubview:self.icon]; + + [self.icon size:CGSizeMake(70, 70)]; + [self.icon x:self.centerXAnchor]; + [self.icon top:self.topAnchor padding:10]; + + + self.title = [[UILabel alloc] init]; + self.title.textAlignment = NSTextAlignmentCenter; + self.title.textColor = UIColor.tertiaryLabelColor; + self.title.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold]; + self.title.numberOfLines = 2; + [self addSubview:self.title]; + + [self.title x:self.centerXAnchor]; + [self.title top:self.icon.bottomAnchor padding:15]; + [self.title leading:self.leadingAnchor padding:15]; + [self.title trailing:self.trailingAnchor padding:-15]; + + } + + return self; + +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/CustomClasses/TDAnimator.h b/Phoenix/Tweak/PHOENIX/CustomClasses/TDAnimator.h new file mode 100644 index 0000000..1b85106 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/CustomClasses/TDAnimator.h @@ -0,0 +1,7 @@ +#import + +@interface TDAnimator : NSObject +- (instancetype)initWithCHeight:(CGFloat)cHeight andDimALpha:(CGFloat)dimAlpha; +@property (nonatomic, assign) CGFloat cHeight; +@property (nonatomic, assign) CGFloat dimAlpha; +@end diff --git a/Phoenix/Tweak/PHOENIX/CustomClasses/TDAnimator.m b/Phoenix/Tweak/PHOENIX/CustomClasses/TDAnimator.m new file mode 100644 index 0000000..2da7cb7 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/CustomClasses/TDAnimator.m @@ -0,0 +1,22 @@ +#import "TDAnimator.h" +#import "TDPresentationController.h" + + +@implementation TDAnimator + +- (instancetype)initWithCHeight:(CGFloat)cHeight andDimALpha:(CGFloat)dimAlpha { + self = [super init]; + if (self) { + _cHeight = cHeight; + _dimAlpha = dimAlpha; + } + return self; +} + +- (nullable UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(nullable UIViewController *)presenting sourceViewController:(UIViewController *)source { + + TDPresentationController * prensentVc = [[TDPresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting andControllerHeight:self.cHeight andDimAlpha:_dimAlpha]; + return prensentVc; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/CustomClasses/TDPresentationController.h b/Phoenix/Tweak/PHOENIX/CustomClasses/TDPresentationController.h new file mode 100644 index 0000000..fc1ab6d --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/CustomClasses/TDPresentationController.h @@ -0,0 +1,28 @@ +#import + +@interface _UIBackdropView : UIView +-(id)initWithFrame:(CGRect)arg1 autosizesToFitSuperview:(BOOL)arg2 settings:(id)arg3 ; +-(id)initWithSettings:(id)arg1 ; +-(id)initWithStyle:(long long)arg1 ; +- (void)setBlurFilterWithRadius:(float)arg1 blurQuality:(id)arg2 blurHardEdges:(int)arg3; +- (void)setBlurFilterWithRadius:(float)arg1 blurQuality:(id)arg2; +- (void)setBlurHardEdges:(int)arg1; +- (void)setBlurQuality:(id)arg1; +- (void)setBlurRadius:(float)arg1; +- (void)setBlurRadiusSetOnce:(BOOL)arg1; +- (void)setBlursBackground:(BOOL)arg1; +- (void)setBlursWithHardEdges:(BOOL)arg1; +@end + +@interface _UIBackdropViewSettings : NSObject +@property (assign,getter=isEnabled,nonatomic) BOOL enabled; +@property (assign,nonatomic) double blurRadius; +@property (nonatomic,copy) NSString * blurQuality; +@property (assign,nonatomic) BOOL usesBackdropEffectView; +-(id)initWithDefaultValues; ++(id)settingsForStyle:(long long)arg1 ; +@end + +@interface TDPresentationController : UIPresentationController +- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(UIViewController *)presentingViewController andControllerHeight:(CGFloat)cHeight andDimAlpha:(CGFloat)dimAlpha; +@end diff --git a/Phoenix/Tweak/PHOENIX/CustomClasses/TDPresentationController.m b/Phoenix/Tweak/PHOENIX/CustomClasses/TDPresentationController.m new file mode 100644 index 0000000..6f0f515 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/CustomClasses/TDPresentationController.m @@ -0,0 +1,99 @@ +#import "TDPresentationController.h" + +#define XYHALFMODALHEIGHT 500 + + +@interface TDPresentationController () +@property (nonatomic, strong) _UIBackdropViewSettings *dimViewSetting; +@property (nonatomic, strong) _UIBackdropView *dimView; +@property(nonatomic,strong)UITapGestureRecognizer * tap; +@property (nonatomic, assign) CGFloat controllerHeight; +@property (nonatomic, assign) CGFloat dimAlpha; +@end + + +@implementation TDPresentationController + +- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(UIViewController *)presentingViewController andControllerHeight:(CGFloat)cHeight andDimAlpha:(CGFloat)dimAlpha { + self = [super initWithPresentedViewController:presentedViewController presentingViewController:presentingViewController]; + if (self) { + _controllerHeight = cHeight; + _dimAlpha = dimAlpha; + } + return self; +} + +- (void)containerViewWillLayoutSubviews { + [super containerViewWillLayoutSubviews]; + + UIView *mainView = self.presentedView; + + [self.containerView addSubview:mainView]; + + if (!self.dimView) { + self.dimViewSetting = [_UIBackdropViewSettings settingsForStyle:2]; + self.dimView = [[_UIBackdropView alloc] initWithSettings:self.dimViewSetting]; + self.dimView.alpha = 0; + self.dimView.userInteractionEnabled = YES; + [self.containerView insertSubview:self.dimView atIndex:0]; + } + + [self.dimView addGestureRecognizer:self.tap]; + + if (self.dimAlpha >=1) { + self.dimAlpha = 1; + }else if (self.dimAlpha <0) { + self.dimAlpha = 1; + } + + [UIView animateWithDuration:0.20 animations:^{ + self.dimView.alpha = self.dimAlpha; + }]; + + [self frameSetup]; +} + +- (void)dismissalTransitionWillBegin { + [UIView animateWithDuration:0.25 animations:^{ + self.dimView.alpha = 0; + }]; +} + + +- (void)frameSetup { + + CGFloat x,y,w,h,cHeight; + + cHeight = self.controllerHeight <= 0 ? XYHALFMODALHEIGHT:self.controllerHeight; + + x = 0; + y = [UIScreen mainScreen].bounds.size.height - cHeight; + w = [UIScreen mainScreen].bounds.size.width; + h = cHeight; + + self.presentedView.frame = CGRectMake(x, y, w, h); + + y = 0; + + h = [UIScreen mainScreen].bounds.size.height; + + self.dimView.frame = CGRectMake(x, y, w, h); + +} + + +- (void)tapClick { + + [self.presentedViewController dismissViewControllerAnimated:YES completion:nil]; + +} + + +- (UITapGestureRecognizer *)tap { + if (!_tap) { + _tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapClick)]; + } + return _tap; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Favourites/CreateFavouriteViewController.h b/Phoenix/Tweak/PHOENIX/Favourites/CreateFavouriteViewController.h new file mode 100644 index 0000000..8ea77c8 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Favourites/CreateFavouriteViewController.h @@ -0,0 +1,35 @@ +#import +#import "FavouriteCategoriesCell.h" +#import "CreateCategoriesViewController.h" +#import "SettingManager.h" + +@protocol CreateNewFavouriteProtocol +@required +-(void)didCreatedNewFavourite; +@end + +@interface CreateFavouriteViewController : UIViewController +@property (nonatomic, retain) UIColor *accentColour; +@property (nonatomic, retain) TDHeaderView *headerView; +@property (nonatomic, retain) UIImageView *avatarImage; +@property (nonatomic, retain) UIButton *addButton; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UIButton *avatarButton; +@property (nonatomic, retain) UILabel *categoriesLabel; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *categoriesArray; +@property (nonatomic) NSInteger categoriesIndex; +@property (nonatomic) BOOL didChooseContact; +@property (nonatomic) BOOL didChooseCategories; +@property (nonatomic, retain) NSString *categoriesName; +@property (nonatomic, retain) NSString *categoriesColour; +@property (nonatomic, retain) NSString *categoriesIcon; +@property (nonatomic, retain) TDContact *tdcontact; +@property (nonatomic, retain) NSMutableDictionary *mutableDict; +@property (nonatomic, retain) NSMutableDictionary *categoriesDict; +@property (nonatomic, retain) NSString *phoneNumber; +@property (nonatomic, retain) NSString *emailAddress; +@property(nonatomic,assign)id delegate; +@property (nonatomic) BOOL isPhoneNumberAvailable; +@property (nonatomic) BOOL didChooseAvatar; +@end diff --git a/Phoenix/Tweak/PHOENIX/Favourites/CreateFavouriteViewController.m b/Phoenix/Tweak/PHOENIX/Favourites/CreateFavouriteViewController.m new file mode 100644 index 0000000..dceff03 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Favourites/CreateFavouriteViewController.m @@ -0,0 +1,473 @@ +#import "CreateFavouriteViewController.h" + +static void deleteDataForID(NSString *idToRemove){ + + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/Categories.plist", aDocumentsDirectory]; + //NSString *plistPath = @"/var/mobile/Library/Preferences/PaletteCollections.plist"; + //NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"Categories" ofType:@"plist"]; + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + [mutableDict removeObjectForKey:idToRemove]; + [mutableDict writeToFile:plistPath atomically:YES]; + +} + + +@implementation CreateFavouriteViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = UIColor.systemBackgroundColor; + + self.view.backgroundColor = UIColor.systemBackgroundColor; + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [[SettingManager sharedInstance] accentColour]; + self.view.tintColor = [[SettingManager sharedInstance] accentColour]; + self.accentColour = [[SettingManager sharedInstance] accentColour]; + + self.tdcontact = [[TDContact alloc] init]; + + [self layoutHeaderView]; + [self layoutHeaderSubViews]; + [self setupCategoriesData]; + [self layoutCollectionView]; +} + + +-(void)layoutHeaderView { + + self.headerView = [[TDHeaderView alloc] initWithTitle:@"New Favourite" accent:self.accentColour leftIcon:@"xmark" leftAction:@selector(dismissVC) rightIcon:@"person.crop.circle.fill.badge.checkmark" rightAction:@selector(applyChanges)]; + self.headerView.leftButton.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.headerView.rightButton.tintColor = UIColor.whiteColor; + self.headerView.rightButton.backgroundColor = self.accentColour; + self.headerView.rightButton.alpha = 0; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.safeAreaLayoutGuide.topAnchor padding:0]; +} + + +-(void)layoutHeaderSubViews { + + self.avatarImage = [[UIImageView alloc] init]; + self.avatarImage.layer.cornerRadius = 55; + self.avatarImage.clipsToBounds = YES; + self.avatarImage.image = [UIImage systemImageNamed:@"person.crop.circle.fill"]; + self.avatarImage.contentMode = UIViewContentModeScaleAspectFit; + self.avatarImage.tintColor = UIColor.tertiaryLabelColor; + self.avatarImage.userInteractionEnabled = YES; + [self.view addSubview:self.avatarImage]; + + [self.avatarImage size:CGSizeMake(110, 110)]; + [self.avatarImage x:self.view.centerXAnchor]; + [self.avatarImage top:self.headerView.bottomAnchor padding:20]; + + [self.avatarImage addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentContactPickerVC)]]; + + + self.addButton = [[UIButton alloc] init]; + self.addButton.backgroundColor = self.accentColour; + self.addButton.tintColor = UIColor.whiteColor; + self.addButton.layer.cornerRadius = 15; + [self.addButton addTarget:self action:@selector(presentContactPickerVC) forControlEvents:UIControlEventTouchUpInside]; + UIImage *addImage = [UIImage systemImageNamed:@"plus"]; + [self.addButton setImage:addImage forState:UIControlStateNormal]; + [self.view addSubview:self.addButton]; + + [self.addButton size:CGSizeMake(30, 30)]; + [self.addButton trailing:self.avatarImage.trailingAnchor padding:-3]; + [self.addButton bottom:self.avatarImage.bottomAnchor padding:-3]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.textAlignment = NSTextAlignmentCenter; + self.nameLabel.textColor = UIColor.labelColor; + self.nameLabel.font = [UIFont systemFontOfSize:26 weight:UIFontWeightSemibold]; + self.nameLabel.text = @"Choose Contact"; + [self.view addSubview:self.nameLabel]; + + [self.nameLabel x:self.view.centerXAnchor]; + [self.nameLabel top:self.avatarImage.bottomAnchor padding:15]; + [self.nameLabel leading:self.view.leadingAnchor padding:20]; + [self.nameLabel trailing:self.view.trailingAnchor padding:-20]; + + + self.avatarButton = [[UIButton alloc] init]; + [self.avatarButton addTarget:self action:@selector(presentAvatarPickerVC) forControlEvents:UIControlEventTouchUpInside]; + [self.avatarButton setTitle:@"Choose Avatar" forState:UIControlStateNormal]; + [self.avatarButton setTitleColor:self.accentColour forState:UIControlStateNormal]; + self.avatarButton.alpha = 0; + [self.view addSubview:self.avatarButton]; + + [self.avatarButton size:CGSizeMake(200, 30)]; + [self.avatarButton x:self.view.centerXAnchor]; + [self.avatarButton top:self.nameLabel.bottomAnchor padding:3]; + + + self.categoriesLabel = [[UILabel alloc] init]; + self.categoriesLabel.textAlignment = NSTextAlignmentLeft; + self.categoriesLabel.textColor = UIColor.tertiaryLabelColor; + self.categoriesLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightRegular]; + self.categoriesLabel.text = @"Categories"; + [self.view addSubview:self.categoriesLabel]; + + [self.categoriesLabel top:self.avatarButton.bottomAnchor padding:20]; + [self.categoriesLabel leading:self.view.leadingAnchor padding:20]; + [self.categoriesLabel trailing:self.view.trailingAnchor padding:-20]; + +} + + +-(void)setupCategoriesData { + // [IMPORTANT] + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/Categories.plist", aDocumentsDirectory]; + //NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"Categories" ofType:@"plist"]; + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + self.categoriesArray = [NSMutableArray new]; + for(NSString *key in mutableDict){ + [self.categoriesArray addObject:mutableDict[key]]; + + NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"categoriesName" ascending:YES]; + [self.categoriesArray sortUsingDescriptors:[NSArray arrayWithObject:sort]]; + } + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.collectionView.layer.cornerRadius = 15; + self.collectionView.layer.cornerCurve = kCACornerCurveContinuous; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[FavouriteCategoriesCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.view addSubview:self.collectionView]; + + [self.collectionView leading:self.view.leadingAnchor padding:20]; + [self.collectionView trailing:self.view.trailingAnchor padding:-20]; + [self.collectionView top:self.categoriesLabel.bottomAnchor padding:10]; + [self.collectionView bottom:self.view.safeAreaLayoutGuide.bottomAnchor padding:-15]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.categoriesArray.count+1; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + FavouriteCategoriesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + if (indexPath.row == 0) { + + cell.backgroundColor = UIColor.clearColor; + cell.baseView.backgroundColor = [self.accentColour colorWithAlphaComponent:0.4]; + cell.iconImage.image = [UIImage systemImageNamed:@"folder.fill.badge.plus"]; + cell.iconImage.tintColor = self.accentColour; + cell.titleLabel.text = @"Create New"; + + } else { + + cell.baseView.backgroundColor = [[self colorWithHexString:(NSString*)[[self.categoriesArray objectAtIndex:indexPath.row-1 ] objectForKey:@"categoriesColour"]] colorWithAlphaComponent:0.4]; + cell.titleLabel.text = self.categoriesArray[indexPath.row-1][@"categoriesName"]; + cell.iconImage.image = [UIImage systemImageNamed:self.categoriesArray[indexPath.row-1][@"categoriesIcon"]]; + cell.iconImage.tintColor = [self colorWithHexString:(NSString*)[[self.categoriesArray objectAtIndex:indexPath.row-1 ] objectForKey:@"categoriesColour"]]; + + if (indexPath.row == self.categoriesIndex) { + cell.iconImage.image = self.didChooseCategories ? [UIImage systemImageNamed:@"checkmark"] : [UIImage systemImageNamed:self.categoriesArray[indexPath.row-1][@"categoriesIcon"]]; + cell.iconImage.tintColor = UIColor.whiteColor; + } + } + + return cell; + +} + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat width = (self.view.frame.size.width-110)/3; + return CGSizeMake(width, width-30); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(20,20,20,20); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + if (indexPath.row == 0) { + + CreateCategoriesViewController *vc = [[CreateCategoriesViewController alloc] init]; + vc.delegate = self; + vc.modalInPresentation = YES; + [self presentViewController:vc animated:YES completion:nil]; + } else { + + self.modalInPresentation = YES; + self.didChooseCategories = YES; + + self.categoriesIndex = indexPath.row; + self.categoriesName = self.categoriesArray[indexPath.row-1][@"categoriesName"]; + self.categoriesColour = self.categoriesArray[indexPath.row-1][@"categoriesColour"]; + self.categoriesIcon = self.categoriesArray[indexPath.row-1][@"categoriesIcon"]; + + [self.collectionView reloadData]; + self.avatarButton.alpha = 1; + [self didCompletedRequirements]; + } + +} + + +- (UIContextMenuConfiguration *)collectionView:(UICollectionView *)collectionView contextMenuConfigurationForItemAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point { + + if (indexPath.row != 0) { + + UIContextMenuConfiguration* config = [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil actionProvider:^UIMenu* _Nullable(NSArray* _Nonnull suggestedActions) { + // [IMPORTANT] need to post notification to delete categories from plist and delete categories plist name + UIAction *deleteAction = [UIAction actionWithTitle:@"Delete" image:[UIImage systemImageNamed:@"trash.fill"] identifier:nil handler:^(UIAction *action) { + deleteDataForID(self.categoriesArray[indexPath.row-1][@"id"]); + [self setupCategoriesData]; + [self.collectionView reloadData]; + }]; + deleteAction.attributes = UIMenuElementAttributesDestructive; + + NSString *titleString = self.categoriesArray[indexPath.row-1][@"categoriesName"]; + return [UIMenu menuWithTitle:titleString children:@[deleteAction]]; + + }]; + + return config; + + } else { + return nil; + } + +} + + +-(void)presentContactPickerVC { + + TDContactPickerViewController *vc = [[TDContactPickerViewController alloc] initWithTitle:@"Pick a Contact" accentColour:self.accentColour]; + vc.delegate = self; + [self presentViewController:vc animated:YES completion:nil]; + +} + + +-(void)didPickAContact:(TDContact *)contact { + NSLog(@"Full name: %@", contact.fullName); + NSLog(@"Phone number: %@", contact.phoneNumber); + NSLog(@"Is phone number contain prefix: %d", contact.isPhoneNumberContainPrefix); + NSLog(@"Email address: %@", contact.emailAddress); + NSLog(@"Is email address available: %d", contact.isEmailAvailable); + NSLog(@"ID: %@", contact.identifier); + NSLog(@"Avatar: %@", contact.avatarImage); + NSLog(@"Is avatar available: %d", contact.isAvatarAvailable); + + self.tdcontact = contact; + + self.didChooseContact = YES; + self.modalInPresentation = YES; + self.avatarButton.alpha = 1; + [self didCompletedRequirements]; + + UIImage *editImage = [UIImage systemImageNamed:@"pencil"]; + [self.addButton setImage:editImage forState:UIControlStateNormal]; + + self.nameLabel.text = contact.fullName; + + if (contact.avatarImage != nil) { + self.avatarImage.image = contact.avatarImage; + self.avatarImage.contentMode = UIViewContentModeScaleAspectFill; + [self.avatarButton setTitle:@"Change Avatar" forState:UIControlStateNormal]; + self.didChooseAvatar = YES; + } else { + self.avatarImage.image = [UIImage systemImageNamed:@"person.crop.circle.fill"]; + self.avatarImage.contentMode = UIViewContentModeScaleAspectFit; + [self.avatarButton setTitle:@"Choose Avatar" forState:UIControlStateNormal]; + self.didChooseAvatar = NO; + } + +} + + +-(void)didCancelPickAContact { + NSLog(@"Cancelled pick a contact"); +} + + +-(void)presentAvatarPickerVC { + TDAvatarIdentityPickerViewController *vc = [[TDAvatarIdentityPickerViewController alloc] initWithTitle:@"Avatar" showDefaultAvatar:YES avatarImage:nil accent:self.accentColour]; + vc.delegate = self; + [self presentViewController:vc animated:YES completion:nil]; +} + + +-(void)didCreatedAvatar:(UIImage *)avatar { + self.avatarImage.contentMode = UIViewContentModeScaleAspectFill; + self.avatarImage.image = avatar; + self.didChooseAvatar = YES; +} + + +-(void)didDismissedAvatarPicker { + NSLog(@"Avatar picker dismissed"); +} + + +-(void)didCompletedRequirements { + if (self.didChooseContact && self.didChooseCategories) { + self.headerView.rightButton.alpha = 1; + } +} + + +-(void)applyChanges { + + if (!self.didChooseAvatar) { + [self showAlertWithTitle:@"Warning!" subtitle:@"Your contact doesn't have an avatar image, please choose an avatar image."]; + } else { + + if (self.tdcontact.phoneNumber != nil) { + self.phoneNumber = self.tdcontact.phoneNumber; + self.isPhoneNumberAvailable = YES; + } else { + self.phoneNumber = @""; + self.isPhoneNumberAvailable = NO; + } + + + if (self.tdcontact.emailAddress != nil) { + self.emailAddress = self.tdcontact.emailAddress; + } else { + self.emailAddress = @""; + } + + + // [IMPORTANT] need to post notification to write new categories to plist + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/AllFavourites.plist", aDocumentsDirectory]; + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + self.mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + UIImage *image = self.avatarImage.image; + NSData *avatarData = UIImagePNGRepresentation(image); + + NSString *withID = [NSString stringWithFormat:@"%lld", (long long)([[NSDate date] timeIntervalSince1970] * 1000.0)]; + NSDictionary *data = @{@"id" : withID, @"categoriesName" : self.categoriesName, @"categoriesColour" : self.categoriesColour, @"categoriesIcon" : self.categoriesIcon, @"fullName" : self.tdcontact.fullName, @"phoneNumber" : self.phoneNumber, @"isPhoneNumberAvailable" : [NSNumber numberWithBool:self.isPhoneNumberAvailable], @"emailAddress" : self.emailAddress, @"isEmailAvailable" : [NSNumber numberWithBool:self.tdcontact.isEmailAvailable], @"contactIdentifier" : self.tdcontact.identifier, @"avatarImage" : avatarData}; + + + [self.mutableDict setValue:data forKey:withID]; + [self.mutableDict writeToFile:plistPath atomically:YES]; + + + // Write to other plist with categories name + NSString *aDocumentsDirectory2 = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistName = [self.categoriesName stringByReplacingOccurrencesOfString:@" " withString:@""]; + NSString *plistPath2 = [NSString stringWithFormat:@"%@/%@.plist", aDocumentsDirectory2, plistName]; + + NSDictionary *dict2 = [NSDictionary dictionaryWithContentsOfFile:plistPath2]; + self.categoriesDict = dict2 ? [dict2 mutableCopy] : [NSMutableDictionary dictionary]; + + //NSDictionary *data2 = @{@"id" : withID, @"categoriesName" : self.categoriesName, @"categoriesColour" : self.categoriesColour, @"categoriesIcon" : self.categoriesIcon, @"fullName" : self.tdcontact.fullName, @"phoneNumber" : self.tdcontact.phoneNumber, @"emailAddress" : self.tdcontact.emailAddress, @"isEmailAvailable" : [NSNumber numberWithBool:self.tdcontact.isEmailAvailable], @"contactIdentifier" : self.tdcontact.identifier, @"avatarImage" : avatarData}; + + [self.categoriesDict setValue:data forKey:withID]; + [self.categoriesDict writeToFile:plistPath2 atomically:YES]; + + + [self.delegate didCreatedNewFavourite]; + [self dismissVC]; + } +} + + +-(void)didCreatedNewCategory { + [self setupCategoriesData]; + [self.collectionView reloadData]; +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + }]; + [alert addAction:ok]; + [self presentViewController:alert animated:YES completion:nil]; + +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Favourites/FavouriteFilterViewController.h b/Phoenix/Tweak/PHOENIX/Favourites/FavouriteFilterViewController.h new file mode 100644 index 0000000..c34b96b --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Favourites/FavouriteFilterViewController.h @@ -0,0 +1,22 @@ +#import +#import "TDAnimator.h" +#import "FavouriteFilterCell.h" +#import "SettingManager.h" + +@protocol FavouriteFilterProtocol +@required +-(void)filterFavouritesWithCategoriesName:(NSString *)categories; +@end + +@interface FavouriteFilterViewController : UIViewController +-(instancetype)initWithHeight:(CGFloat)height; +@property (nonatomic, retain) TDAnimator *myAnimator; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *categoriesArray; +@property (nonatomic) NSInteger categoriesIndex; +@property (nonatomic) BOOL didChooseCategories; +@property (nonatomic, retain) NSString *categoriesName; +@property(nonatomic,assign)id delegate; +@end diff --git a/Phoenix/Tweak/PHOENIX/Favourites/FavouriteFilterViewController.m b/Phoenix/Tweak/PHOENIX/Favourites/FavouriteFilterViewController.m new file mode 100644 index 0000000..b9b3fd2 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Favourites/FavouriteFilterViewController.m @@ -0,0 +1,220 @@ +#import "FavouriteFilterViewController.h" + +@implementation FavouriteFilterViewController + +-(instancetype)initWithHeight:(CGFloat)height { + + self = [super init]; + if (self) { + self.modalPresentationStyle = UIModalPresentationCustom; + self.myAnimator = [[TDAnimator alloc] initWithCHeight:height andDimALpha:1.0]; + self.transitioningDelegate = self.myAnimator; + + } + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.systemBackgroundColor; + self.view.layer.cornerRadius = 25; + self.view.layer.cornerCurve = kCACornerCurveContinuous; + self.view.layer.maskedCorners = 3; + + self.categoriesName = [[SettingManager sharedInstance] objectForKey:@"savedCategoriesName" defaultValue:@"All Favourites"]; + + [self layoutHeader]; + [self setupCategoriesData]; + [self layoutCollectionView]; +} + + +-(void)layoutHeader { + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + self.iconImage.tintColor = UIColor.tertiaryLabelColor; + self.iconImage.image = [UIImage systemImageNamed:@"switch.2"]; + [self.view addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(60, 60)]; + [self.iconImage x:self.view.centerXAnchor]; + [self.iconImage top:self.view.topAnchor padding:10]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold]; + self.titleLabel.text = @"Favourite Filters"; + [self.view addSubview:self.titleLabel]; + + [self.titleLabel x:self.view.centerXAnchor]; + [self.titleLabel top:self.iconImage.bottomAnchor padding:10]; +} + + +-(void)setupCategoriesData { + // [IMPORTANT] + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/Categories.plist", aDocumentsDirectory]; + //NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"Categories" ofType:@"plist"]; + + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + self.categoriesArray = [NSMutableArray new]; + for(NSString *key in mutableDict){ + [self.categoriesArray addObject:mutableDict[key]]; + + NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"categoriesName" ascending:YES]; + [self.categoriesArray sortUsingDescriptors:[NSArray arrayWithObject:sort]]; + } + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[FavouriteFilterCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.view addSubview:self.collectionView]; + + [self.collectionView top:self.titleLabel.bottomAnchor padding:20]; + [self.collectionView height:75]; + [self.collectionView width:self.view.frame.size.width]; + [self.collectionView x:self.view.centerXAnchor]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.categoriesArray.count+1; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + FavouriteFilterCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + if (indexPath.row == 0) { + + cell.baseView.backgroundColor = [[[SettingManager sharedInstance] accentColour] colorWithAlphaComponent:0.4]; + cell.titleLabel.text = @"All Favourites"; + + if ([cell.titleLabel.text isEqualToString:self.categoriesName]) { + cell.iconImage.image = [UIImage systemImageNamed:@"checkmark"]; + cell.iconImage.tintColor = UIColor.whiteColor; + } else { + cell.iconImage.image = [UIImage systemImageNamed:@"folder.fill.badge.person.crop"]; + cell.iconImage.tintColor = [[SettingManager sharedInstance] accentColour]; + } + + } else { + + cell.baseView.backgroundColor = [[self colorWithHexString:(NSString*)[[self.categoriesArray objectAtIndex:indexPath.row-1 ] objectForKey:@"categoriesColour"]] colorWithAlphaComponent:0.4]; + cell.titleLabel.text = self.categoriesArray[indexPath.row-1][@"categoriesName"]; + + if ([cell.titleLabel.text isEqualToString:self.categoriesName]) { + cell.iconImage.image = [UIImage systemImageNamed:@"checkmark"]; + cell.iconImage.tintColor = UIColor.whiteColor; + } else { + cell.iconImage.image = [UIImage systemImageNamed:self.categoriesArray[indexPath.row-1][@"categoriesIcon"]]; + cell.iconImage.tintColor = [self colorWithHexString:(NSString*)[[self.categoriesArray objectAtIndex:indexPath.row-1 ] objectForKey:@"categoriesColour"]]; + + } + + } + + return cell; + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + return CGSizeMake(105, 75); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,25,0,25); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + if (indexPath.row == 0) { + self.categoriesName = @"All Favourites"; + } else { + self.categoriesName = self.categoriesArray[indexPath.row-1][@"categoriesName"]; + } + + self.categoriesIndex = indexPath.row; + self.didChooseCategories = YES; + [self.collectionView reloadData]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self applyCategoriesFilter]; + }); +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)applyCategoriesFilter { + [[SettingManager sharedInstance] setObject:self.categoriesName forKey:@"savedCategoriesName"]; + [self.delegate filterFavouritesWithCategoriesName:self.categoriesName]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/Phoenix/Tweak/PHOENIX/Manager/GlobalHaptic.h b/Phoenix/Tweak/PHOENIX/Manager/GlobalHaptic.h new file mode 100644 index 0000000..382e7c8 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Manager/GlobalHaptic.h @@ -0,0 +1,12 @@ +#import +#import "SettingManager.h" + + +static void invokeHaptic() { + BOOL enableHaptic = [[SettingManager sharedInstance] boolForKey:@"enableHaptic" defaultValue:NO]; + + if (enableHaptic) { + UIImpactFeedbackGenerator *haptic = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; + [haptic impactOccurred]; + } +} diff --git a/Phoenix/Tweak/PHOENIX/Manager/SettingManager.h b/Phoenix/Tweak/PHOENIX/Manager/SettingManager.h new file mode 100644 index 0000000..8b3c616 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Manager/SettingManager.h @@ -0,0 +1,27 @@ +#import + +@interface SettingManager : NSObject ++(instancetype)sharedInstance; +-(id)init; + +- (void)setBool:(BOOL)anObject forKey:(id)aKey; +- (void)setObject:(id)anObject forKey:(id)aKey; +- (void)setFloat:(long long)anObject forKey:(id)aKey; +- (void)setInt:(int)anObject forKey:(id)aKey; +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue; +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue; +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue; +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue; +- (bool)boolForKey:(id)aKey; +- (id)objectForKey:(id)aKey; +- (long long)floatForKey:(id)aKey; +- (int)intForKey:(id)aKey; +-(UIColor *)systemColourForKey:(id)aKey defaultColour:(UIColor *)defaultColour; +-(UIColor *)accentColour; +-(UIColor *)callButtonColour; +-(UIColor *)messageButtonColour; +-(UIColor *)emailButtonColour; +-(UIColor *)deleteButtonColour; +-(UIImage *)icloudAvatar; +-(NSString *)icloudFullName; +@end diff --git a/Phoenix/Tweak/PHOENIX/Manager/SettingManager.m b/Phoenix/Tweak/PHOENIX/Manager/SettingManager.m new file mode 100644 index 0000000..62f7cf6 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Manager/SettingManager.m @@ -0,0 +1,215 @@ +#import "SettingManager.h" + +@implementation SettingManager + ++(instancetype)sharedInstance { + static SettingManager *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[SettingManager alloc] init]; + }); + return sharedInstance; +} + +-(id)init { + return self; +} + +- (void)setBool:(BOOL)anObject forKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + [settings setObject:[NSNumber numberWithBool:anObject] forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (void)setObject:(id)anObject forKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + [settings setObject:anObject forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; + NSLog(@"Write image data..."); +} + +- (void)setFloat:(long long)anObject forKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + [settings setObject:@(anObject) forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (void)setInt:(int)anObject forKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + [settings setObject:@(anObject) forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + if([settings objectForKey:aKey] == NULL){ + return defaultValue; + } + return [[settings objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [settings objectForKey:aKey]?:defaultValue; +} + +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [[settings objectForKey:aKey] longLongValue]?:defaultValue; +} + +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [[settings objectForKey:aKey] intValue]?:defaultValue; +} + +- (bool)boolForKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [[settings objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [settings objectForKey:aKey]; +} + +- (long long)floatForKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [[settings objectForKey:aKey] longLongValue]; +} + +- (int)intForKey:(id)aKey { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + return [[settings objectForKey:aKey] intValue]; +} + + +- (UIColor *)systemColourForKey:(id)aKey defaultColour:(UIColor *)defaultColour { + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *prefPath = [NSString stringWithFormat:@"%@/PhoenixSettings.plist", aDocumentsDirectory]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + NSData *decodedData = [settings objectForKey:aKey]; + UIColor *color = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]?:defaultColour; + return color; +} + + +-(UIColor *)accentColour { + UIColor *customColour = [self colorWithHexString:[self objectForKey:@"accentColour" defaultValue:@"007AFF"]]; + return customColour; +} + + +-(UIColor *)callButtonColour { + UIColor *customColour = [self colorWithHexString:[self objectForKey:@"callButtonColour" defaultValue:@"35C759"]]; + return customColour; +} + + +-(UIColor *)messageButtonColour { + UIColor *customColour = [self colorWithHexString:[self objectForKey:@"messageButtonColour" defaultValue:@"007AFF"]]; + return customColour; +} + + +-(UIColor *)emailButtonColour { + UIColor *customColour = [self colorWithHexString:[self objectForKey:@"emailButtonColour" defaultValue:@"31ADE6"]]; + return customColour; +} + + +-(UIColor *)deleteButtonColour { + UIColor *customColour = [self colorWithHexString:[self objectForKey:@"deleteButtonColour" defaultValue:@"FF3C2F"]]; + return customColour; +} + + +-(UIColor *)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(UIImage *)icloudAvatar { + UIImage *avatar; + NSString *prefPath = @"/var/mobile/Library/Preferences/com.TitanD3v.PhoenixPrefs.plist"; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + NSData *imageData = [settings objectForKey:@"meCardAvatar"]; + avatar = [UIImage imageWithData:imageData];; + return avatar; +} + + +-(NSString *)icloudFullName { + NSString *name; + NSString *prefPath = @"/var/mobile/Library/Preferences/com.TitanD3v.PhoenixPrefs.plist"; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + name = [settings objectForKey:@"meCardFullName"]; + return name; +} + + +@end diff --git a/Phoenix/Tweak/PHOENIX/Settings/SettingViewController.h b/Phoenix/Tweak/PHOENIX/Settings/SettingViewController.h new file mode 100644 index 0000000..f5582ee --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Settings/SettingViewController.h @@ -0,0 +1,11 @@ +#import +#import "SettingColourCell.h" +#import "SettingSwitchCell.h" +#import "GlobalHaptic.h" + +@interface SettingViewController : UIViewController +@property (nonatomic, retain) TDHeaderView *headerView; +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic) NSInteger colourPickerIndex; +@property (nonatomic, retain) UIColor *accentColour; +@end diff --git a/Phoenix/Tweak/PHOENIX/Settings/SettingViewController.m b/Phoenix/Tweak/PHOENIX/Settings/SettingViewController.m new file mode 100644 index 0000000..42eed00 --- /dev/null +++ b/Phoenix/Tweak/PHOENIX/Settings/SettingViewController.m @@ -0,0 +1,456 @@ +#import "SettingViewController.h" + + +@implementation SettingViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.systemBackgroundColor; + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [[SettingManager sharedInstance] accentColour]; + self.view.tintColor = [[SettingManager sharedInstance] accentColour]; + self.accentColour = [[SettingManager sharedInstance] accentColour]; + + [self layoutHeaderView]; + [self layoutTableView]; +} + + +-(void)layoutHeaderView { + + self.headerView = [[TDHeaderView alloc] initWithTitle:@"Settings" accent:UIColor.systemBlueColor leftIcon:@"xmark" leftAction:@selector(dismissVC) rightIcon:@"checkmark" rightAction:@selector(applyChanges)]; + self.headerView.leftButton.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.headerView.leftButton.tintColor = self.accentColour; + self.headerView.rightButton.backgroundColor = self.accentColour; + self.headerView.rightButton.tintColor = UIColor.whiteColor; + self.headerView.rightButton.alpha = 0; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 70)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.safeAreaLayoutGuide.topAnchor padding:0]; +} + + +-(void)layoutTableView { + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleInsetGrouped]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + [self.tableView top:self.headerView.bottomAnchor padding:20]; + [self.tableView leading:self.view.leadingAnchor padding:0]; + [self.tableView trailing:self.view.trailingAnchor padding:0]; + [self.tableView bottom:self.view.bottomAnchor padding:0]; +} + + +-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 3; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + if (section == 0) { + return 3; + } else if (section == 1) { + return 1; + } else { + return 4; + } +} + + +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + return 35.0f; +} + + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { + + UIView *sectionHeaderView = [[UIView alloc] initWithFrame:CGRectMake(15, 0, tableView.frame.size.width -15, 45)]; + sectionHeaderView.backgroundColor = UIColor.clearColor; + sectionHeaderView.layer.cornerRadius = 15; + sectionHeaderView.clipsToBounds = true; + + UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, sectionHeaderView.frame.size.height /2 -9, 200, 18)]; + headerLabel.backgroundColor = [UIColor clearColor]; + headerLabel.textColor = UIColor.tertiaryLabelColor; + headerLabel.textAlignment = NSTextAlignmentLeft; + headerLabel.font = [UIFont boldSystemFontOfSize:16]; + [sectionHeaderView addSubview:headerLabel]; + + if (section == 0) { + headerLabel.text = @"General"; + } else if (section == 1) { + headerLabel.text = @"Accent"; + } else { + headerLabel.text = @"Actions Colour"; + } + + return sectionHeaderView; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + if (indexPath.section == 0) { + + SettingSwitchCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[SettingSwitchCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + if (indexPath.row == 0) { + + cell.iconView.backgroundColor = [UIColor.systemPinkColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [UIImage systemImageNamed:@"heart.fill"]; + cell.iconImage.tintColor = UIColor.systemPinkColor; + cell.titleLabel.text = @"Favourites"; + cell.subtitleLabel.text = @"Show favourites"; + [cell.toggleSwitch addTarget:self action:@selector(toggleFavourites:) forControlEvents:UIControlEventValueChanged]; + [cell.toggleSwitch setOn:[[SettingManager sharedInstance] boolForKey:@"showFavourites" defaultValue:YES] animated:NO]; + cell.toggleSwitch.onTintColor = UIColor.systemPinkColor; + + } else if (indexPath.row == 1) { + + cell.iconView.backgroundColor = [UIColor.systemIndigoColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [UIImage systemImageNamed:@"waveform"]; + cell.iconImage.tintColor = UIColor.systemIndigoColor; + cell.titleLabel.text = @"Haptic"; + cell.subtitleLabel.text = @"Enable haptic feedback"; + [cell.toggleSwitch addTarget:self action:@selector(toggleHaptic:) forControlEvents:UIControlEventValueChanged]; + [cell.toggleSwitch setOn:[[SettingManager sharedInstance] boolForKey:@"enableHaptic" defaultValue:NO] animated:NO]; + cell.toggleSwitch.onTintColor = UIColor.systemIndigoColor; + + } else if (indexPath.row == 2) { + + cell.iconView.backgroundColor = [UIColor.systemOrangeColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [UIImage systemImageNamed:@"eye.fill"]; + cell.iconImage.tintColor = UIColor.systemOrangeColor; + cell.titleLabel.text = @"Contacts"; + cell.subtitleLabel.text = @"Hide phone number & email"; + [cell.toggleSwitch addTarget:self action:@selector(toggleHideContactsDetails:) forControlEvents:UIControlEventValueChanged]; + [cell.toggleSwitch setOn:[[SettingManager sharedInstance] boolForKey:@"hideContactsDetails" defaultValue:NO] animated:NO]; + cell.toggleSwitch.onTintColor = UIColor.systemIndigoColor; + } + + return cell; + + } else if (indexPath.section == 1) { + + SettingColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[SettingColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + cell.iconView.backgroundColor = [UIColor.systemYellowColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [UIImage systemImageNamed:@"paintpalette.fill"]; + cell.iconImage.tintColor = UIColor.systemYellowColor; + cell.titleLabel.text = @"Accent"; + cell.subtitleLabel.text = @"Global accent colour"; + cell.colourView.backgroundColor = [[SettingManager sharedInstance] accentColour]; + + return cell; + + } else { + + SettingColourCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[SettingColourCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + + + if (indexPath.row == 0) { + + cell.iconView.backgroundColor = [UIColor.systemGreenColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [UIImage systemImageNamed:@"phone.fill"]; + cell.iconImage.tintColor = UIColor.systemGreenColor; + cell.titleLabel.text = @"Call"; + cell.subtitleLabel.text = @"Action button colour"; + cell.colourView.backgroundColor = [[SettingManager sharedInstance] callButtonColour]; + + } else if (indexPath.row == 1) { + + cell.iconView.backgroundColor = [UIColor.systemBlueColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [UIImage systemImageNamed:@"message.fill"]; + cell.iconImage.tintColor = UIColor.systemBlueColor; + cell.titleLabel.text = @"Message"; + cell.subtitleLabel.text = @"Action button colour"; + cell.colourView.backgroundColor = [[SettingManager sharedInstance] messageButtonColour]; + + } else if (indexPath.row == 2) { + + cell.iconView.backgroundColor = [UIColor.systemTealColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [UIImage systemImageNamed:@"envelope.fill"]; + cell.iconImage.tintColor = UIColor.systemTealColor; + cell.titleLabel.text = @"Email"; + cell.subtitleLabel.text = @"Action button colour"; + cell.colourView.backgroundColor = [[SettingManager sharedInstance] emailButtonColour]; + + } else if (indexPath.row == 3) { + + cell.iconView.backgroundColor = [UIColor.systemRedColor colorWithAlphaComponent:0.4]; + cell.iconImage.image = [UIImage systemImageNamed:@"trash.fill"]; + cell.iconImage.tintColor = UIColor.systemRedColor; + cell.titleLabel.text = @"Delete"; + cell.subtitleLabel.text = @"Action button colour"; + cell.colourView.backgroundColor = [[SettingManager sharedInstance] deleteButtonColour]; + + } + + return cell; + } + +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 75; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + + if (indexPath.section == 1) { + self.colourPickerIndex = 0; + [self presentColourPickerVC]; + } + + if (indexPath.section == 2) { + + if (indexPath.row == 0) { + self.colourPickerIndex = 1; + } else if (indexPath.row == 1) { + self.colourPickerIndex = 2; + } else if (indexPath.row == 2) { + self.colourPickerIndex = 3; + } else if (indexPath.row == 3) { + self.colourPickerIndex = 4; + } + + [self presentColourPickerVC]; + } + +} + + +-(void)toggleFavourites:(UISwitch *)sender { + [self didMakeChanges]; + [[SettingManager sharedInstance] setBool:sender.on forKey:@"showFavourites"]; +} + + +-(void)toggleHaptic:(UISwitch *)sender { + [self didMakeChanges]; + [[SettingManager sharedInstance] setBool:sender.on forKey:@"enableHaptic"]; +} + + +-(void)toggleHideContactsDetails:(UISwitch *)sender { + [self didMakeChanges]; + [[SettingManager sharedInstance] setBool:sender.on forKey:@"hideContactsDetails"]; +} + + +-(void)presentColourPickerVC { + + UIColor *previewColour; + + if (self.colourPickerIndex == 0) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:1]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + previewColour = cell.colourView.backgroundColor; + } else if (self.colourPickerIndex == 1) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + previewColour = cell.colourView.backgroundColor; + } else if (self.colourPickerIndex == 2) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:1 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + previewColour = cell.colourView.backgroundColor; + } else if (self.colourPickerIndex == 3) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:2 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + previewColour = cell.colourView.backgroundColor; + } else if (self.colourPickerIndex == 4) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:3 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + previewColour = cell.colourView.backgroundColor; + } + + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + colourPickerVC.selectedColor = previewColour; + [self presentViewController:colourPickerVC animated:YES completion:nil]; + +} + + +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController{ + [self didMakeChanges]; + UIColor *cpSelectedColour = viewController.selectedColor; + + if (self.colourPickerIndex == 0) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:1]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + [[SettingManager sharedInstance] setObject:[self hexStringFromColor:cpSelectedColour] forKey:@"accentColour"]; + } else if (self.colourPickerIndex == 1) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + [[SettingManager sharedInstance] setObject:[self hexStringFromColor:cpSelectedColour] forKey:@"callButtonColour"]; + } else if (self.colourPickerIndex == 2) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:1 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + [[SettingManager sharedInstance] setObject:[self hexStringFromColor:cpSelectedColour] forKey:@"messageButtonColour"]; + } else if (self.colourPickerIndex == 3) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:2 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + [[SettingManager sharedInstance] setObject:[self hexStringFromColor:cpSelectedColour] forKey:@"emailButtonColour"]; + } else if (self.colourPickerIndex == 4) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:3 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + [[SettingManager sharedInstance] setObject:[self hexStringFromColor:cpSelectedColour] forKey:@"deleteButtonColour"]; + } + +} + + +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController{ + [self didMakeChanges]; + UIColor *cpSelectedColour = viewController.selectedColor; + + if (self.colourPickerIndex == 0) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:1]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + [[SettingManager sharedInstance] setObject:[self hexStringFromColor:cpSelectedColour] forKey:@"accentColour"]; + } else if (self.colourPickerIndex == 1) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + [[SettingManager sharedInstance] setObject:[self hexStringFromColor:cpSelectedColour] forKey:@"callButtonColour"]; + } else if (self.colourPickerIndex == 2) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:1 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + [[SettingManager sharedInstance] setObject:[self hexStringFromColor:cpSelectedColour] forKey:@"messageButtonColour"]; + } else if (self.colourPickerIndex == 3) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:2 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + [[SettingManager sharedInstance] setObject:[self hexStringFromColor:cpSelectedColour] forKey:@"emailButtonColour"]; + } else if (self.colourPickerIndex == 4) { + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:3 inSection:2]; + SettingColourCell *cell = (SettingColourCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + cell.colourView.backgroundColor = cpSelectedColour; + [[SettingManager sharedInstance] setObject:[self hexStringFromColor:cpSelectedColour] forKey:@"deleteButtonColour"]; + } + +} + + +- (NSString *)hexStringFromColor:(UIColor *)color { + const CGFloat *components = CGColorGetComponents(color.CGColor); + + CGFloat r = components[0]; + CGFloat g = components[1]; + CGFloat b = components[2]; + + return [NSString stringWithFormat:@"%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255)]; +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)didMakeChanges { + self.headerView.rightButton.alpha = 1; + self.modalInPresentation = YES; +} + + +-(void)applyChanges { + + // UIApplication *app = [UIApplication sharedApplication]; + // [app performSelector:@selector(suspend)]; + // [NSThread sleepForTimeInterval:1.0]; + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Phoenix/RelaunchPhoneApp" object:nil userInfo:nil deliverImmediately:YES]; + exit(0); + +} + +@end diff --git a/Phoenix/Tweak/Phoenix.plist b/Phoenix/Tweak/Phoenix.plist new file mode 100644 index 0000000..33f7e9b --- /dev/null +++ b/Phoenix/Tweak/Phoenix.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.mobilephone", "com.apple.springboard", "com.apple.Preferences" ); }; } diff --git a/Phoenix/Tweak/Phoenix.xm b/Phoenix/Tweak/Phoenix.xm new file mode 100644 index 0000000..28ce94f --- /dev/null +++ b/Phoenix/Tweak/Phoenix.xm @@ -0,0 +1,396 @@ +#import +#import "ContactViewController.h" +#import "CustomNavigationController.h" +#import "SettingManager.h" +#import "Interfaces.h" +#include + +static NSString *BID = @"com.TitanD3v.PhoenixPrefs"; +static BOOL togglePhoenix; +BOOL isAddNewCoverImage = NO; +UIImageView *contactCoverImageView; + +@interface PhoneTabBarController +- (void)setContactsViewController:(id)arg1; +- (void)setKeypadViewController:(id)arg1; +@end + + +%group PhoenixHook + +%hook PhoneTabBarController + +- (void)setContactsViewController:(UIViewController*)arg1 { + ContactViewController *contactVC = [[ContactViewController alloc] init]; + arg1 = [[%c(CustomNavigationController) alloc] initWithRootViewController:contactVC]; + arg1.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Contacts" image:[UIImage systemImageNamed:@"person.crop.circle" withConfiguration:[UIImageSymbolConfiguration configurationWithPointSize:22]] tag:0]; + %orig; +} + +- (id)init { + [self setContactsViewController:nil]; + return %orig; +} +%end + + +%hook UIColor ++(id)systemBlueColor { + return [[SettingManager sharedInstance] accentColour]; +} +%end + + +%hook PHBottomBarButton +-(void)setBackgroundColor:(UIColor *)color { + + %orig([[SettingManager sharedInstance] accentColour]); +} +%end + + +%hook MPFavoritesTableViewCell + +-(void)layoutSubviews { + %orig; + + self.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.layer.cornerRadius = 15; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = YES; + self.contentView.clipsToBounds = YES; + + CGRect updateFrame = self.frame; + updateFrame.size.height = 65; + self.frame = updateFrame; + +} + +%end + + +%hook MPFavoritesTableViewController + +-(void)viewDidLoad { + + %orig; + + self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + CGFloat updateHeight = %orig; + updateHeight = 75; + return updateHeight; +} + +%end + + +%hook MPRecentsTableViewCell + +-(void)layoutSubviews { + %orig; + + self.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.layer.cornerRadius = 15; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = YES; + self.contentView.clipsToBounds = YES; + + + CGRect updateFrame = self.frame; + updateFrame.size.height = 65; + self.frame = updateFrame; + +} + +%end + + +%hook MPRecentsTableViewController + +-(void)viewDidLoad { + + %orig; + + self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; + self.tableView.rowHeight = 75; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + CGFloat updateHeight = %orig; + updateHeight = 75; + return updateHeight; +} + +%end + + +%hook CNUINavigationListViewController +%property (nonatomic, copy) CNContact *contact; + +- (void)setItems:(NSArray*)arg1{ + NSMutableArray *itemArray = [arg1 mutableCopy]; + CNUINavigationListItem *newItem = [[CNUINavigationListItem alloc] initWithTitle:@"Delete Contact"]; + UIImage *trashIcon = [UIImage systemImageNamed:@"trash.fill"]; + trashIcon = [trashIcon imageWithTintColor:[UIColor systemRedColor]]; + [newItem setImage:trashIcon]; + [itemArray addObject:newItem]; + %orig(itemArray); +} + + +-(void)navigationListView:(id)arg1 didSelectRowAtIndexPath:(NSIndexPath*)indexPath{ + long deleteIndex = self.items.count - 1; + if(indexPath.row == deleteIndex){ + CNContactStore *contactStore = [[CNContactStore alloc] init]; + CNSaveRequest *saveRequest = [[CNSaveRequest alloc] init]; + [saveRequest deleteContact:[self.contact mutableCopy]]; + + UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Delete Contact" + message:@"Are you sure you want to delete this contact?" + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* yesButton = [UIAlertAction actionWithTitle:@"YES" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + [contactStore executeSaveRequest:saveRequest error:nil]; + [self dismissViewControllerAnimated:NO completion:nil]; + }]; + + UIAlertAction* noButton = [UIAlertAction actionWithTitle:@"NO" + style:UIAlertActionStyleDestructive + handler:^(UIAlertAction * action) { + }]; + + [alert addAction:yesButton]; + [alert addAction:noButton]; + [self presentViewController:alert animated:YES completion:nil]; + } + %orig; +} + +%end + + +%hook CNAvatarCardViewController +%property (nonatomic, copy) CNContact *contact; + +- (void)setCardController:(id)arg1 { + %orig; + CNContactActionsController *actionsController = arg1; + CNContact *contact = actionsController.contact; + + if(!contact || contact.unknown) + return; + + [[(NSObject *)self valueForKey:@"actionListViewController"] setValue:actionsController.contact forKey:@"contact"]; +} +%end + + +%hook UITableView + +-(UIEdgeInsets)_sectionContentInset { + UIEdgeInsets orig = %orig; + + bool isRecent = [self.dataSource isKindOfClass:[%c(MPRecentsTableViewController) class]]; + bool isFav = [self.prefetchDataSource isKindOfClass:[%c(MPFavoritesTableViewController) class]]; + + if(isRecent || isFav){ + return UIEdgeInsetsMake(orig.top, 20, orig.bottom, 20); + } + + return orig; +} +%end + + +%hook CNContactContentViewController + +-(BOOL)allowsActions{ + return 1; +} + +-(BOOL)allowsContactBlocking{ + return 1; +} + +-(void)setAllowsEditPhoto:(BOOL)arg1{ + %orig(1); +} + +-(BOOL)allowsDeletion{ + return 1; +} + +-(void)setAllowsDeletion:(BOOL)arg1{ + %orig(1); +} +%end + + +%hook CNActionsView +- (void)addActionItem:(CNActionItem *)action { + %orig; + if ([action.type isEqualToString:@"AudioCallActionType"]) { + CNActionItem *action = [[%c(CNActionItem) alloc] initWithImage:[UIImage systemImageNamed:@"photo.fill"] type:@"SET_COVER_IMAGE"]; + [action setTitle:@"Cover Image"]; + [self addActionItem:action]; + } +} +%end + + +%hook CNContactInlineActionsViewController +- (void)didSelectAction:(CNActionItem *)action withSourceView:(id)arg2 longPress:(BOOL)arg3 { + if ([action.type isEqualToString:@"SET_COVER_IMAGE"]) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Phoenix/PresentPhotoPickerVC" object:nil userInfo:nil]; + } else { + %orig; + } +} +%end + + +%hook CNContactContentViewController + +-(void)viewDidDisappear:(BOOL)arg1 { + %orig; + isAddNewCoverImage = NO; +} + +- (id)headerHeightConstraint{ + [[NSNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.Phoenix/updateCoverImageHeight" object:nil userInfo:nil]; + return %orig; +} + +%end + + + +%hook CNContactHeaderDisplayView +%property (nonatomic, copy) UIImage *headerImage; +%property (nonatomic, copy) NSString *contactId; + + +-(id)initWithContact:(id)arg1 frame:(CGRect)arg2 monogrammerStyle:(long long)arg3 shouldAllowImageDrops:(BOOL)arg4 showingNavBar:(BOOL)arg5 monogramOnly:(BOOL)arg6 delegate:(id)arg7 { + + [[NSNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.Phoenix/updateCoverImageHeight" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + contactCoverImageView.frame = self.frame; + }]; + return %orig; +} + + +-(void)layoutSubviews{ + %orig; + + if(isAddNewCoverImage || [self contacts].count == 0) + return; + + isAddNewCoverImage = YES; + + CNContact *contact = [self contacts][0]; + self.contactId = contact.identifier; + + self.headerImage = [self coverImageForCID:self.contactId]; + + if(!self.headerImage) { + + contactCoverImageView = [[UIImageView alloc] init]; + contactCoverImageView.contentMode = UIViewContentModeScaleAspectFill; + contactCoverImageView.clipsToBounds = YES; + contactCoverImageView.frame = self.frame; + contactCoverImageView.layer.cornerRadius = 20; + contactCoverImageView.layer.cornerCurve = kCACornerCurveContinuous; + contactCoverImageView.layer.maskedCorners = 12; + [self insertSubview:contactCoverImageView atIndex:0]; + + } else { + + contactCoverImageView = [[UIImageView alloc] initWithImage:self.headerImage]; + contactCoverImageView.contentMode = UIViewContentModeScaleAspectFill; + contactCoverImageView.clipsToBounds = YES; + contactCoverImageView.frame = self.frame; + contactCoverImageView.layer.cornerRadius = 20; + contactCoverImageView.layer.cornerCurve = kCACornerCurveContinuous; + contactCoverImageView.layer.maskedCorners = 12; + [self insertSubview:contactCoverImageView atIndex:0]; + } + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(presentImagePickerVC) name:@"com.TitanD3v.Phoenix/PresentPhotoPickerVC" object:nil]; +} + + + +%new +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { + + UIImage *chosenImage = info[UIImagePickerControllerEditedImage]; + self.headerImage = chosenImage; + contactCoverImageView.image = chosenImage; + CNContact *contact = [self contacts][0]; + self.contactId = contact.identifier; + [self setCoverImageForCID:self.contactId image:self.headerImage]; + + [picker dismissViewControllerAnimated:YES completion:nil]; + +} + + + +%new +-(void)presentImagePickerVC { + + UIImagePickerController *picker = [[UIImagePickerController alloc] init]; + picker.delegate = self; + picker.allowsEditing = YES; + + UIViewController *controller = [self _viewControllerForAncestor]; + [controller presentViewController:picker animated:YES completion:nil]; +} + + +%new +-(UIImage *)coverImageForCID:(NSString *)CID { + + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/PhoenixBannerImages.plist", aDocumentsDirectory]; + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + return [[UIImage alloc] initWithData:dict[CID]]; +} + + +%new +-(void)setCoverImageForCID:(NSString *)CID image:(UIImage*)coverImage { + + NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; + NSString *plistPath = [NSString stringWithFormat:@"%@/PhoenixBannerImages.plist", aDocumentsDirectory]; + NSMutableDictionary *mutableDict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath] ?: [NSMutableDictionary new]; + [mutableDict setObject:UIImagePNGRepresentation(coverImage) forKey:CID]; + [mutableDict writeToFile:plistPath atomically:YES]; +} + +%end + +%end + + +void SettingsChanged() { + togglePhoenix = [[TDTweakManager sharedInstance] boolForKey:@"togglePhoenix" defaultValue:NO ID:BID]; +} + +%ctor { + + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)SettingsChanged, CFSTR("com.TitanD3v.PhoenixPrefs.settingschanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + SettingsChanged(); + + if (togglePhoenix) { + %init(PhoenixHook); + } + +} diff --git a/Phoenix/control b/Phoenix/control new file mode 100644 index 0000000..3fbb720 --- /dev/null +++ b/Phoenix/control @@ -0,0 +1,11 @@ +Package: com.titand3v.phoenix +Name: Phoenix +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal (>= 1.8) +Version: 1.1 +Section: Tweaks +Description: A redesign of the contact list for the Phone app +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/phoenix/index.html +Icon: https://titand3v.github.io/depictions/phoenix/assets/icon.png diff --git a/Phoenix/layout/.DS_Store b/Phoenix/layout/.DS_Store new file mode 100644 index 0000000..717ddaf Binary files /dev/null and b/Phoenix/layout/.DS_Store differ diff --git a/Phoenix/layout/DEBIAN/postinst b/Phoenix/layout/DEBIAN/postinst new file mode 100755 index 0000000..e4a6963 --- /dev/null +++ b/Phoenix/layout/DEBIAN/postinst @@ -0,0 +1,8 @@ +echo "" +echo "" +echo "Thank you for installing Phoenix 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/Phoenix/layout/Library/Application Support/Phoenix.bundle/Assets/colour-wheel.png b/Phoenix/layout/Library/Application Support/Phoenix.bundle/Assets/colour-wheel.png new file mode 100644 index 0000000..6cee7ad Binary files /dev/null and b/Phoenix/layout/Library/Application Support/Phoenix.bundle/Assets/colour-wheel.png differ diff --git a/Phoenix/layout/Library/Application Support/Phoenix.bundle/DefaultCategories/Categories.plist b/Phoenix/layout/Library/Application Support/Phoenix.bundle/DefaultCategories/Categories.plist new file mode 100644 index 0000000..068afa7 --- /dev/null +++ b/Phoenix/layout/Library/Application Support/Phoenix.bundle/DefaultCategories/Categories.plist @@ -0,0 +1,39 @@ + + + + + 1634301645082 + + categoriesName + Work + categoriesColour + FFCC01 + categoriesIcon + briefcase.fill + id + 1634301645082 + + 1634301645081 + + categoriesName + Friends + categoriesColour + 04C7BE + categoriesIcon + person.circle.fill + id + 1634301645081 + + 1634301645080 + + categoriesName + Family + categoriesColour + FF3C2F + categoriesIcon + heart.fill + id + 1634301645080 + + + diff --git a/Speedy/.DS_Store b/Speedy/.DS_Store new file mode 100644 index 0000000..9ce45c7 Binary files /dev/null and b/Speedy/.DS_Store differ diff --git a/Speedy/Makefile b/Speedy/Makefile new file mode 100644 index 0000000..2c9082a --- /dev/null +++ b/Speedy/Makefile @@ -0,0 +1,15 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0:13.0 +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +FINALPACKAGE = 1 +DEBUG = 0 + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Speedy/Tweak/Headers.h b/Speedy/Tweak/Headers.h new file mode 100644 index 0000000..5d7fbde --- /dev/null +++ b/Speedy/Tweak/Headers.h @@ -0,0 +1,227 @@ +#import +#import +#import + +@interface FBProcessState : NSObject +@property (getter=isForeground,nonatomic,readonly) BOOL foreground; +@property (getter=isRunning,nonatomic,readonly) BOOL running; +@property (assign,nonatomic) long long taskState; +@end + +@interface FBProcess : NSObject +@property (nonatomic,copy,readonly) NSString * name; +@property (nonatomic,copy,readonly) NSString * bundleIdentifier; +@property (getter=isCurrentProcess,nonatomic,readonly) BOOL currentProcess; +-(void)_killForReason:(long long)arg1 andReport:(BOOL)arg2 withDescription:(id)arg3 completion:(/*^block*/id)arg4; +@end + +@interface SBClockApplicationIconImageView +-(void)presentAppDataVC:(UITapGestureRecognizer*)sender; +@end + +@interface UIApplication (Paradise) +- (BOOL)launchApplicationWithIdentifier:(NSString *)identifier suspended:(BOOL)suspend; +@end + +@interface SBApplication : NSObject +@property (nonatomic,readonly) NSString * displayName; +@property (assign,nonatomic) id badgeNumberOrString; +@property (nonatomic,copy) id badgeValue; +-(NSString *)bundleIdentifier; +-(void)purgeCaches; +@end + +@interface SBIcon : NSObject +- (NSString *)applicationBundleID; +- (SBApplication *)application; +- (NSInteger)badgeValue; +struct SBIconImageInfo { + CGFloat width; + CGFloat height; + CGFloat field1; + CGFloat field2; +}; +-(BOOL)isWidgetIcon; +-(UIImage *)getIconImage:(int)arg1 ; +-(UIImage *)iconImageWithInfo:(struct SBIconImageInfo)info; +@end + +@interface SBLeafIcon : SBIcon +-(id)leafIdentifier; +@end + +@interface SBWidgetIcon : SBLeafIcon +@end + +@interface SBBookmarkIcon : SBLeafIcon +@end + +@interface SBHLibraryPodCategoryIcon : SBLeafIcon +@end + +@interface SBSApplicationShortcutIcon: NSObject +@end + +@interface SBFolderIcon : SBIcon +-(id)nodeIdentifier; +@end + +@interface SBSApplicationShortcutItem : NSObject +@property (nonatomic, retain) NSString *type; +@property (nonatomic, copy) NSString * localizedTitle; +@property (nonatomic, copy) SBSApplicationShortcutIcon * icon; +@property (nonatomic, copy) NSString * bundleIdentifierToLaunch; +- (void)setIcon:(SBSApplicationShortcutIcon *)arg1; +@end + +@interface SBSApplicationShortcutCustomImageIcon : SBSApplicationShortcutIcon +@property (nonatomic, readwrite) BOOL isTemplate; +- (id)initWithImagePNGData:(id)arg1; +- (BOOL)isTemplate; +@end + +@interface SBIconLabelImageParameters : NSObject +@property (nonatomic,copy,readonly) NSString * iconLocation; +@property (nonatomic,copy) NSString * text; +-(unsigned long long)hash; +-(id)description; +@end + +@interface SBIconView : UIView +@property (nonatomic, retain) SBIcon *icon; +@property (nonatomic, retain) SBFolderIcon * folderIcon; +@property (nonatomic,readonly) UIImage * iconImageSnapshot; +@property (nonatomic,readonly) UIView * iconImageSnapshotView; +@property (nonatomic,copy,readonly) NSString * applicationBundleIdentifierForShortcuts; +- (id)_iconImageView; +- (void)_updateLabel; +- (BOOL)ad_isFolderIcon; +- (SBIconLabelImageParameters*)_labelImageParameters; +@end + +@interface SBIconLegibilityLabelView +-(SBIconView *)iconView; +-(SBIconLabelImageParameters *)imageParameters; +@end + +@interface SBMutableIconLabelImageParameters : SBIconLabelImageParameters +@property (nonatomic,copy) NSString * text; +@property (nonatomic,retain) UIColor * textColor; +@property (nonatomic,retain) UIColor * focusHighlightColor; + +-(void)setFocusHighlightColor:(UIColor *)arg1; +-(void)setTextColor:(UIColor *)arg1; +-(void)setText:(NSString *)arg1; +@end + +@interface SBApplicationIcon : SBLeafIcon + +// iOS 12 and below +- (UIImage *)generateIconImage:(int)arg1; +// iOS 13 +// - (id)generateIconImageWithInfo:(SBIconImageInfo)arg1; +@end + +@interface SBIconModel : NSObject +- (SBApplicationIcon *)expectedIconForDisplayIdentifier:(id)arg1; +-(SBIcon *)applicationIconForBundleIdentifier:(id)arg1 ; +-(void)layout; +-(void)purgeAllIconCaches; +-(void)loadAllIcons; +@end + +@interface SBIconViewMap : NSObject +@property (nonatomic,readonly) SBIconModel * iconModel; +@end + +@interface SBHIconModel : NSObject +-(void)removeAllIcons; +-(void)layout; +-(id)iconState; +@end + +@interface SBIconController : UIViewController +// @property (nonatomic, retain) SBIconModel *model; ++(id)sharedInstance; +-(SBIconViewMap *)homescreenIconViewMap; +-(id)model; +@end + +@interface SBIconImageView : UIView +@property (assign,nonatomic) SBIconView * iconView; +-(void)setIconView:(SBIconView *)arg1 ; +-(SBIconView *)iconView; +@end + +@interface SBApplicationController : NSObject ++ (instancetype)sharedInstance; +- (SBApplication *)applicationWithBundleIdentifier:(NSString *)identifier; +@end + +@interface UIImage () ++ (id)imageNamed:(id)arg1 inBundle:(id)arg2; +@end + +@interface UIView (Private) +- (UIViewController *)_viewControllerForAncestor; +@end + + +// Core Services + +@interface _LSBoundIconInfo +@property (nonatomic, copy) NSString *applicationIdentifier; +@end + +@interface LSResourceProxy : NSObject +@end + +@interface LSBundleProxy : LSResourceProxy +@property (nonatomic,readonly) NSString * localizedShortName; +@property (nonatomic,copy) NSArray * machOUUIDs; +@property (nonatomic,copy) NSString * sdkVersion; +@property (nonatomic,readonly) NSString * bundleIdentifier; +@property (nonatomic,readonly) NSString * bundleType; +@property (nonatomic,readonly) NSURL * bundleURL; +@property (nonatomic,readonly) NSString * bundleExecutable; +@property (nonatomic,readonly) NSString * canonicalExecutablePath; +@property (nonatomic,readonly) NSURL * containerURL; +@property (nonatomic,readonly) NSURL * dataContainerURL; +@property (nonatomic,readonly) NSURL * bundleContainerURL; +@property (nonatomic,readonly) NSURL * appStoreReceiptURL; +@property (nonatomic,readonly) NSString * bundleVersion; +@property (nonatomic,readonly) NSString * signerIdentity; +@property (nonatomic,readonly) NSDictionary * entitlements; +@property (nonatomic,readonly) NSDictionary * environmentVariables; +@property (nonatomic,readonly) NSDictionary * groupContainerURLs; +- (id)localizedName; +@end + +@interface LSApplicationProxy : LSBundleProxy +@property (nonatomic,readonly) NSString * applicationIdentifier; ++ (LSApplicationProxy *)applicationProxyForIdentifier:(NSString *)identifier; +@property (nonatomic,readonly) NSString *shortVersionString; +@property (nonatomic, strong) NSString *itemName; +@property (nonatomic, strong) NSNumber *itemID; +@property (nonatomic,readonly) NSNumber * staticDiskUsage; +@property (nonatomic,readonly) NSNumber * dynamicDiskUsage; +@property (nonatomic,readonly) NSNumber * ODRDiskUsage; +@property (getter=isAppStoreVendable,nonatomic,readonly) BOOL appStoreVendable; +@property (getter=isDeletable,nonatomic,readonly) BOOL deletable; + +// iOS 13 +@property (nonatomic,readonly) NSSet *claimedDocumentContentTypes; +@property (nonatomic,readonly) NSSet *claimedURLSchemes; +@end + +@interface IXAppInstallCoordinator : NSObject ++(BOOL)demoteAppToPlaceholderWithBundleID:(id)arg1 forReason:(unsigned long long)arg2 waitForDeletion:(BOOL)arg3 error:(id*)arg4 ; ++(BOOL)demoteAppToPlaceholderWithBundleID:(id)arg1 forReason:(unsigned long long)arg2 error:(id*)arg3 ; ++(void)demoteAppToPlaceholderWithBundleID:(id)arg1 forReason:(unsigned long long)arg2 waitForDeletion:(BOOL)arg3 completion:(/*^block*/id)arg4 ; ++(void)uninstallAppWithBundleID:(id)arg1 requestUserConfirmation:(BOOL)arg2 waitForDeletion:(BOOL)arg3 completion:(/*^block*/id)arg4 ; +@end + +@interface SpringBoard : UIApplication +- (id)_accessibilityFrontMostApplication; +-(void)frontDisplayDidChange: (id)arg1; +@end \ No newline at end of file diff --git a/Speedy/Tweak/Makefile b/Speedy/Tweak/Makefile new file mode 100644 index 0000000..24772ce --- /dev/null +++ b/Speedy/Tweak/Makefile @@ -0,0 +1,23 @@ +TWEAK_NAME = Speedy + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +dtoim = $(foreach d,$(1),-I$(d)) +_IMPORTS = $(shell /bin/ls -d ./*/) +_IMPORTS = $(shell /bin/ls -d ./SPEEDY/) +_IMPORTS = $(shell /bin/ls -d ./SPEEDY/*/) +_IMPORTS += $(shell /bin/ls -d ./SPEEDY/*/*/) +_IMPORTS += $(shell /bin/ls -d ./SPEEDY/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./SPEEDY/*/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./) +IMPORTS = -I$./SPEEDY $(call dtoim, $(_IMPORTS)) + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations $(IMPORTS) +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit SpringBoardServices +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Speedy/Tweak/SPEEDY/BlurEffects/BlurBaseView.h b/Speedy/Tweak/SPEEDY/BlurEffects/BlurBaseView.h new file mode 100644 index 0000000..3210f96 --- /dev/null +++ b/Speedy/Tweak/SPEEDY/BlurEffects/BlurBaseView.h @@ -0,0 +1,5 @@ +#import + +@interface BlurBaseView : UIView +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@end diff --git a/Speedy/Tweak/SPEEDY/BlurEffects/BlurBaseView.m b/Speedy/Tweak/SPEEDY/BlurEffects/BlurBaseView.m new file mode 100644 index 0000000..fd61cad --- /dev/null +++ b/Speedy/Tweak/SPEEDY/BlurEffects/BlurBaseView.m @@ -0,0 +1,43 @@ +#import "BlurBaseView.h" + +@implementation BlurBaseView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + self.blurEffectView = [[UIVisualEffectView alloc] initWithFrame:CGRectZero]; + [self insertSubview:self.blurEffectView atIndex:0]; + + self.blurEffectView.translatesAutoresizingMaskIntoConstraints = false; + [self.blurEffectView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0].active = YES; + [self.blurEffectView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0].active = YES; + [self.blurEffectView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:0].active = YES; + [self.blurEffectView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0].active = YES; + + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + } else { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + } + + } + + return self; + +} + + +- (void)traitCollectionDidChange:(UITraitCollection *) previousTraitCollection { + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialDark]; + } else { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemUltraThinMaterialLight]; + } + +} + +@end diff --git a/Speedy/Tweak/SPEEDY/UninstallApps/SpeedyUninstallAppsViewController.h b/Speedy/Tweak/SPEEDY/UninstallApps/SpeedyUninstallAppsViewController.h new file mode 100644 index 0000000..8cd5029 --- /dev/null +++ b/Speedy/Tweak/SPEEDY/UninstallApps/SpeedyUninstallAppsViewController.h @@ -0,0 +1,18 @@ +#import +#import "BlurBaseView.h" +#include "UninstallAppsCell.h" +#include "UninstallAppList.h" +#import "../../Headers.h" + +@interface SpeedyUninstallAppsViewController : UIViewController +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIButton *uninstallButton; +@property (nonatomic, retain) UIButton *cancelButton; +@property(nonatomic, strong) NSMutableDictionary *appsToUninstall; +@property(nonatomic, strong) NSMutableDictionary *selectedApps; +@property(nonatomic, strong) NSMutableArray *fullAppList; +@property (nonatomic, retain) BlurBaseView *baseView; +@property (nonatomic, retain) UITableView *tableView; +-(void)refreshTable; +-(void)deleteKey:(NSString*)key; +@end \ No newline at end of file diff --git a/Speedy/Tweak/SPEEDY/UninstallApps/SpeedyUninstallAppsViewController.m b/Speedy/Tweak/SPEEDY/UninstallApps/SpeedyUninstallAppsViewController.m new file mode 100644 index 0000000..c9544af --- /dev/null +++ b/Speedy/Tweak/SPEEDY/UninstallApps/SpeedyUninstallAppsViewController.m @@ -0,0 +1,257 @@ +#import "SpeedyUninstallAppsViewController.h" + +@implementation SpeedyUninstallAppsViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.clipsToBounds = true; + self.view.backgroundColor = UIColor.clearColor; + + self.baseView = [[BlurBaseView alloc] init]; + [self.view addSubview:self.baseView]; + [self.baseView fill]; + + [self layoutAccessoriesView]; + [self layoutTableView]; + +} + + +-(void)layoutAccessoriesView { + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.font = [UIFont boldSystemFontOfSize:18]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.text = @"All Applications"; + [self.view addSubview:self.titleLabel]; + + [self.titleLabel x:self.view.centerXAnchor]; + [self.titleLabel top:self.view.topAnchor padding:20]; + + + self.cancelButton = [[UIButton alloc] init]; + [self.cancelButton addTarget:self action:@selector(dismissVC) forControlEvents:UIControlEventTouchUpInside]; + [self.cancelButton setTitle:@"Cancel" forState:UIControlStateNormal]; + [self.cancelButton setTitleColor:UIColor.systemRedColor forState:UIControlStateNormal]; + self.cancelButton.titleLabel.font = [UIFont systemFontOfSize:16]; + [self.view addSubview:self.cancelButton]; + + [self.cancelButton size:CGSizeMake(70, 30)]; + [self.cancelButton x:self.view.centerXAnchor]; + [self.cancelButton bottom:self.view.bottomAnchor padding:-15]; + + + self.uninstallButton = [[UIButton alloc] init]; + [self.uninstallButton addTarget:self action:@selector(presentUninstallConfirmation) forControlEvents:UIControlEventTouchUpInside]; + [self.uninstallButton setTitle:@"Uninstall" forState:UIControlStateNormal]; + [self.uninstallButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; + self.uninstallButton.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + self.uninstallButton.backgroundColor = UIColor.systemBlueColor; + self.uninstallButton.enabled = NO; + self.uninstallButton.alpha = 0.7; + self.uninstallButton.layer.cornerRadius = 10; + self.uninstallButton.layer.cornerCurve = kCACornerCurveContinuous; + [self.view addSubview:self.uninstallButton]; + + [self.uninstallButton size:CGSizeMake(200, 50)]; + [self.uninstallButton x:self.view.centerXAnchor]; + [self.uninstallButton bottom:self.cancelButton.topAnchor padding:-10]; + +} + + +-(void)layoutTableView { + + self.fullAppList = [[UninstallAppList userApps] mutableCopy]; + _appsToUninstall = [NSMutableDictionary new]; + _selectedApps = [NSMutableDictionary new]; + + + self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + [self.tableView setAllowsMultipleSelection:YES]; + [self.tableView setAllowsMultipleSelectionDuringEditing:YES]; + + [self.tableView top:self.titleLabel.bottomAnchor padding:10]; + [self.tableView leading:self.view.leadingAnchor padding:0]; + [self.tableView trailing:self.view.trailingAnchor padding:0]; + [self.tableView bottom:self.uninstallButton.topAnchor padding:-10]; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [self.fullAppList count]; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + UninstallAppsCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[UninstallAppsCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + + NSString *BID = [NSString stringWithFormat:@"%@", [[self.fullAppList objectAtIndex:indexPath.row] objectForKey:@"bundleID"]]; + + cell.backgroundColor = UIColor.clearColor; + + cell.appImage.image = [UIImage _applicationIconImageForBundleIdentifier:BID format:2 scale:[UIScreen mainScreen].scale]; + cell.appnameLabel.text = [[self.fullAppList objectAtIndex:indexPath.row] objectForKey:@"name"]; + cell.appBIDLabel.text = [[self.fullAppList objectAtIndex:indexPath.row] objectForKey:@"bundleID"]; + + + if ([[_selectedApps valueForKey:[NSString stringWithFormat:@"%ld", indexPath.row]] boolValue]) { + + [cell setAccessoryType:UITableViewCellAccessoryCheckmark]; + } else { + [cell setAccessoryType:UITableViewCellAccessoryNone]; + } + + return cell; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath]; + + if (thisCell.accessoryType == UITableViewCellAccessoryNone) { + + thisCell.accessoryType = UITableViewCellAccessoryCheckmark; + NSString *BID = [self.fullAppList objectAtIndex:indexPath.row][@"bundleID"]; + [_appsToUninstall setValue:BID forKey:BID]; + [_selectedApps setValue:[NSNumber numberWithBool:YES] forKey:[NSString stringWithFormat:@"%ld", indexPath.row]]; + } + else if(_appsToUninstall.count !=0){ + NSString *BID = [self.fullAppList objectAtIndex:indexPath.row][@"bundleID"]; + thisCell.accessoryType = UITableViewCellAccessoryNone; + [_appsToUninstall removeObjectForKey:BID]; + [_selectedApps setValue:[NSNumber numberWithBool:NO] forKey:[NSString stringWithFormat:@"%ld", indexPath.row]]; + } + + + [self checkStatus]; + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 70; +} + + +-(void)presentUninstallConfirmation { + + UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"Speedy" message:@"Are you sure you want to uninstall those Applications?" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *uninstallAction = [UIAlertAction actionWithTitle:@"Uninstall" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [self uninstallApps]; + }]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) {}]; + + [alertController addAction:uninstallAction]; + [alertController addAction:cancelAction]; + [self presentViewController:alertController animated:YES completion:nil]; + +} + + +-(void)checkStatus { + + if (_appsToUninstall.count != 0) { + [UIView animateWithDuration:0.2 animations:^ { + self.uninstallButton.enabled = YES; + self.uninstallButton.alpha = 1.0; + }]; + } else { + [UIView animateWithDuration:0.2 animations:^ { + self.uninstallButton.enabled = NO; + self.uninstallButton.alpha = 0.7; + }]; + } + +} + + +-(void)uninstallApps { + + __block NSString *message = [NSString stringWithFormat:@"Uninstalling apps 0/%ld", _appsToUninstall.count]; + UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"Speedy" + message:message + preferredStyle:UIAlertControllerStyleAlert]; + + [self presentViewController:alertController animated:YES completion:nil]; + + long counts = 0; + + for (NSString *bundleIdentifier in _appsToUninstall.allKeys){ + counts++; + + [NSClassFromString(@"IXAppInstallCoordinator") uninstallAppWithBundleID:bundleIdentifier requestUserConfirmation:NO waitForDeletion:NO completion:^{ + dispatch_async(dispatch_get_main_queue(), ^{ + + message = [NSString stringWithFormat:@"Uninstalling apps %ld/%ld", counts, _appsToUninstall.count]; + NSLog(@"spotiLove bundleIdentifier:-%@, message:-%@", bundleIdentifier, message); + alertController.message = message; + [self deleteKey:bundleIdentifier]; + }); + }]; + } + + + [self refreshTable]; + [alertController dismissViewControllerAnimated:YES completion:nil]; + + [UIView animateWithDuration:0.2 animations:^ { + self.uninstallButton.enabled = NO; + self.uninstallButton.alpha = 0.7; + }]; + +} + + +-(void)refreshTable { + [self.tableView reloadData]; +} + + +-(void)deleteKey:(NSString*)key{ + for(NSMutableDictionary *appData in self.fullAppList) { + if([appData[@"bundleID"] isEqual:key]) { + [self.fullAppList removeObject:appData]; + [_appsToUninstall removeObjectForKey:key]; + break; + } + } + + if(_appsToUninstall.count == 0){ + self.navigationItem.rightBarButtonItem = nil; + } + [_selectedApps removeAllObjects]; + [self refreshTable]; +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppList.h b/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppList.h new file mode 100644 index 0000000..3a0cb7f --- /dev/null +++ b/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppList.h @@ -0,0 +1,9 @@ +#import + +@interface UninstallAppList : NSObject ++ (NSMutableArray *)allApps; ++ (NSMutableArray *)userApps; ++ (NSMutableArray *)systemApps; ++ (NSMutableArray *)audioApps; ++(NSMutableArray*)sortArray:(NSMutableArray*)arrayToSort; +@end \ No newline at end of file diff --git a/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppList.m b/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppList.m new file mode 100644 index 0000000..746fe1b --- /dev/null +++ b/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppList.m @@ -0,0 +1,213 @@ +#import "UninstallAppList.h" + +@interface _LSLazyPropertyList : NSObject +@property(readonly) NSDictionary *propertyList; +@end + +@interface LSApplicationProxy : NSObject +@property(setter=_setLocalizedName:, nonatomic, copy) NSString *localizedName; +@property(nonatomic, readonly) NSString *bundleIdentifier; +@property(nonatomic, readonly) NSString *primaryIconName; +@property(nonatomic, readonly) NSDictionary *iconsDictionary; +@property(nonatomic, readonly) NSArray *appTags; +@property(setter=_setInfoDictionary:, nonatomic, copy) +_LSLazyPropertyList *_infoDictionary; +- (NSArray *)_boundIconFileNames; +- (NSArray *)boundIconFileNames; +@end + +@interface LSApplicationWorkspace ++ (id)defaultWorkspace; +- (id)allInstalledApplications; +- (id)allApplications; +- (id)applicationsOfType:(unsigned long long)arg1; +- (id)applicationsWithUIBackgroundModes; +@end + +@interface UninstallAppList () ++ (NSString *)nameForApp:(LSApplicationProxy *)app; +@end + +@interface UIImage (Private) ++(id)_applicationIconImageForBundleIdentifier:(NSString*)displayIdentifier format:(int)form scale:(CGFloat)scale; +@end + +@implementation UninstallAppList + +int iOSVersion; ++ (NSMutableArray *)userApps { + + NSMutableArray *userApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + applicationsOfType:0]; + + for (LSApplicationProxy *app in defaultWorkspaceApps) { + [userApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + return [self sortArray:userApps]; +} + ++ (NSMutableArray *)audioApps { + + NSMutableArray *audioApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + applicationsWithUIBackgroundModes]; + + for (LSApplicationProxy *app in defaultWorkspaceApps) { + NSDictionary *info = app._infoDictionary.propertyList; + NSArray *background = info[@"UIBackgroundModes"]; + if (background && [background containsObject:@"audio"]) { + if ([self hasIconAndVisible:app.bundleIdentifier]) { + [audioApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + } + } + return [self sortArray:audioApps]; +} + ++ (NSMutableArray *)systemApps { + + NSMutableArray *systemApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + applicationsOfType:1]; + + for (LSApplicationProxy *app in defaultWorkspaceApps) { + if ([self hasIconAndVisible:app.bundleIdentifier]) { + [systemApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + } + + return [self sortArray:systemApps]; +} + ++ (NSMutableArray *)allApps { + + NSMutableArray *allApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + allApplications]; + for (LSApplicationProxy *app in defaultWorkspaceApps) { + if ([self hasIconAndVisible:app.bundleIdentifier]) { + [allApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + } + return [self sortArray:allApps]; +} + ++ (BOOL)hasIconAndVisible:(NSString *)bundleIdentifier { + NSArray *blacklist = [NSArray arrayWithObjects:@"com.apple.Magnifier", + @"com.apple.InCallService", + @"com.apple.RemoteiCloudQuotaUI", + @"com.apple.PublicHealthRemoteUI", + @"com.apple.CarPlaySplashScreen", + @"com.apple.iMessageAppsViewService", + @"com.apple.BarcodeScanner", + @"com.apple.HealthENLauncher", + @"com.apple.AXUIViewService", + @"com.apple.AppSSOUIService", + @"com.apple.CarPlaySettings", + @"com.apple.mobilesms.compose", + @"com.apple.BusinessChatViewService", + @"com.apple.DiagnosticsService", + @"com.apple.CTNotifyUIService", + @"com.apple.HealthPrivacyService", + @"com.apple.WebContentFilter.remoteUI.WebContentAnalysisUI", + @"com.apple.ScreenshotServicesService", + @"com.apple.FTMInternal", + @"com.apple.carkit.DNDBuddy", + @"com.apple.PreBoard", + @"com.apple.datadetectors.DDActionsService", + @"com.apple.DemoApp", + @"com.apple.CoreAuthUI", + @"com.apple.SubcredentialUIService", + @"com.apple.MailCompositionService", + @"com.apple.Diagnostics", + @"com.apple.AuthKitUIService", + @"com.apple.TVRemote", + @"com.apple.gamecenter.GameCenterUIService", + @"com.apple.PrintKit.Print-Center", + @"com.apple.sidecar", + @"com.apple.AccountAuthenticationDialog", + @"com.apple.PassbookUIService", + @"com.apple.siri", + @"com.apple.CloudKit.ShareBear", + @"com.apple.HealthENBuddy", + @"com.apple.SafariViewService", + @"com.apple.SIMSetupUIService", + @"com.apple.CompassCalibrationViewService", + @"com.apple.PhotosViewService", + @"com.apple.MusicUIService", + @"com.apple.TrustMe", + @"com.apple.Home.HomeUIService", + @"com.apple.CTCarrierSpaceAuth", + @"com.apple.StoreDemoViewService", + @"com.apple.susuiservice", + @"com.apple.social.SLYahooAuth", + @"com.apple.Spotlight", + @"com.apple.fieldtest", + @"com.apple.WebSheet", + @"com.apple.iad.iAdOptOut", + @"com.apple.dt.XcodePreviews", + @"com.apple.appleseed.FeedbackAssistant", + @"com.apple.FontInstallViewService", + @"com.apple.ScreenSharingViewService", + @"com.apple.SharedWebCredentialViewService", + @"com.apple.CheckerBoard", + @"com.apple.DataActivation", + @"com.apple.TVAccessViewService", + @"com.apple.VSViewService", + @"com.apple.TVRemoteUIService", + @"com.apple.SharingViewService", + @"com.apple.ios.StoreKitUIService", + @"com.apple.purplebuddy", + @"com.apple.ScreenTimeUnlock", + @"com.apple.webapp", + @"com.apple.ActivityMessagesApp", + @"com.apple.icloud.apps.messages.business", + @"com.apple.ClipViewService", + @"com.apple.CredentialSharingService", + @"com.apple.ctkui", + @"com.apple.FunCamera.EmojiStickers", + @"com.apple.siri.parsec.HashtagImagesApp", + @"com.apple.icq", + @"com.apple.Jellyfish", + @"com.apple.Animoji.StickersApp", + @"com.apple.PassbookSecureUIService", + @"com.apple.Photos.PhotosUIService", + @"com.apple.shortcuts.runtime", + @"com.apple.SleepLockScreen", + @"com.apple.FunCamera.TextPicker", + @"com.apple.FunCamera.ShapesPicker", + @"com.apple.smsFilter", + @"com.apple.AskPermissionUI", nil]; + UIImage *image = [UIImage _applicationIconImageForBundleIdentifier:bundleIdentifier format:2 scale:[UIScreen mainScreen].scale]; + NSData *imageData = UIImagePNGRepresentation(image); + if(imageData.length == 9762 || [blacklist containsObject:bundleIdentifier]) + return NO; + return YES; +} + ++ (NSString *)nameForApp:(LSApplicationProxy *)app { + return (app.localizedName ? app.localizedName : app.bundleIdentifier); +} + ++(NSMutableArray*)sortArray:(NSMutableArray*)arrayToSort{ + NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)]; + return [[arrayToSort sortedArrayUsingDescriptors:@[sort]] mutableCopy]; +} +@end diff --git a/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppsCell.h b/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppsCell.h new file mode 100644 index 0000000..5fd66c3 --- /dev/null +++ b/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppsCell.h @@ -0,0 +1,10 @@ +#import + +@interface UninstallAppsCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *appImage; +@property (nonatomic, retain) UILabel *appnameLabel; +@property (nonatomic, retain) UILabel *appBIDLabel; + +@end diff --git a/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppsCell.m b/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppsCell.m new file mode 100644 index 0000000..0ff7e2b --- /dev/null +++ b/Speedy/Tweak/SPEEDY/UninstallApps/UninstallAppsCell.m @@ -0,0 +1,67 @@ +#import "UninstallAppsCell.h" + +@implementation UninstallAppsCell + + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.baseView = [[UIView alloc] initWithFrame:CGRectZero]; + self.baseView.layer.cornerRadius = 15; + self.baseView.clipsToBounds = true; + self.baseView.backgroundColor = [UIColor clearColor]; + [self addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:5].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5].active = YES; + + + self.appImage = [[UIImageView alloc] initWithFrame:CGRectZero]; + self.appImage.layer.cornerRadius = 10; + self.appImage.clipsToBounds = true; + [self.baseView addSubview:self.appImage]; + + self.appImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.appImage.widthAnchor constraintEqualToConstant:50.0].active = YES; + [self.appImage.heightAnchor constraintEqualToConstant:50.0].active = YES; + [[self.appImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.appImage.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10].active = YES; + + + self.appnameLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.appnameLabel.textColor = UIColor.labelColor; + self.appnameLabel.font = [UIFont boldSystemFontOfSize:16]; + self.appnameLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.appnameLabel]; + + self.appnameLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.appnameLabel.heightAnchor constraintEqualToConstant:18.0].active = YES; + [self.appnameLabel.widthAnchor constraintEqualToConstant:220.0].active = YES; + [[self.appnameLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor constant:-10].active = true; + [self.appnameLabel.leadingAnchor constraintEqualToAnchor:self.appImage.trailingAnchor constant:10.0].active = YES; + + + self.appBIDLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.appBIDLabel.textColor = UIColor.labelColor; + self.appBIDLabel.font = [UIFont systemFontOfSize:12]; + self.appBIDLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.appBIDLabel]; + + self.appBIDLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.appBIDLabel.heightAnchor constraintEqualToConstant:14.0].active = YES; + [self.appBIDLabel.widthAnchor constraintEqualToConstant:220.0].active = YES; + [self.appBIDLabel.topAnchor constraintEqualToAnchor:self.appnameLabel.bottomAnchor constant:5.0].active = YES; + [self.appBIDLabel.leadingAnchor constraintEqualToAnchor:self.appImage.trailingAnchor constant:10.0].active = YES; + + } + + return self; +} + +@end diff --git a/Speedy/Tweak/Speedy.plist b/Speedy/Tweak/Speedy.plist new file mode 100644 index 0000000..10dc654 --- /dev/null +++ b/Speedy/Tweak/Speedy.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard" ); }; } diff --git a/Speedy/Tweak/Speedy.xm b/Speedy/Tweak/Speedy.xm new file mode 100644 index 0000000..f0a44a8 --- /dev/null +++ b/Speedy/Tweak/Speedy.xm @@ -0,0 +1,65 @@ +#import +#import "SpeedyUninstallAppsViewController.h" +#import "Headers.h" + + +%group Speedy +%hook SBIconView +- (void)setApplicationShortcutItems:(NSArray *)arg1 { + + NSMutableArray *newItems = [[NSMutableArray alloc] init]; + + for (SBSApplicationShortcutItem *item in arg1) { + [newItems addObject:item]; + } + + NSData *lightIcon = UIImagePNGRepresentation([[UIImage imageWithContentsOfFile:@"/Library/Application Support/Speedy.bundle/Assets/uninstall-light.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]); + NSData *darkIcon = UIImagePNGRepresentation([[UIImage imageWithContentsOfFile:@"/Library/Application Support/Speedy.bundle/Assets/uninstall-dark.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]); + + + SBSApplicationShortcutItem *appItem = [%c(SBSApplicationShortcutItem) alloc]; + appItem.localizedTitle = @"Batch Uninstall Apps"; + appItem.type = @"com.TitanD3v.Speedy.UninstallApps"; + + + SBSApplicationShortcutCustomImageIcon *speedyLightIcon = [[SBSApplicationShortcutCustomImageIcon alloc] initWithImagePNGData:lightIcon]; + SBSApplicationShortcutCustomImageIcon *speedyDarkIcon = [[SBSApplicationShortcutCustomImageIcon alloc] initWithImagePNGData:darkIcon]; + + + if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + [appItem setIcon:speedyDarkIcon]; + } else if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleLight) { + [appItem setIcon:speedyLightIcon]; + } + + [newItems addObject:appItem]; + + %orig(newItems); +} + ++ (void)activateShortcut:(SBSApplicationShortcutItem *)item withBundleIdentifier:(NSString *)bundleID forIconView:(SBIconView *)iconView { + + if ([[item type] isEqualToString:@"com.TitanD3v.Speedy.UninstallApps"]) { + + SpeedyUninstallAppsViewController *uVC = [[SpeedyUninstallAppsViewController alloc] init]; + uVC.modalInPresentation = YES; + [[%c(SBIconController) sharedInstance] presentViewController:uVC animated:YES completion:nil]; + + } else { + + %orig; + + } +} + +%end +%end + + +%ctor { + + NSString * path = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0]; + if ([path containsString:@"/Application"] || [path containsString:@"SpringBoard.app"]) { + %init(Speedy); + } +} diff --git a/Speedy/control b/Speedy/control new file mode 100644 index 0000000..1bf3dc7 --- /dev/null +++ b/Speedy/control @@ -0,0 +1,11 @@ +Package: com.titand3v.speedy +Name: Speedy +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal, firmware (>= 14.0) +Version: 1.0 +Section: Tweaks +Description: Batch uninstall applications on SpringBoard via 3D Touch Menu +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/speedy/index.html +Icon: https://titand3v.github.io/depictions/speedy/assets/icon.png diff --git a/Speedy/layout/.DS_Store b/Speedy/layout/.DS_Store new file mode 100644 index 0000000..d591303 Binary files /dev/null and b/Speedy/layout/.DS_Store differ diff --git a/Speedy/layout/DEBIAN/postinst b/Speedy/layout/DEBIAN/postinst new file mode 100755 index 0000000..ffe608c --- /dev/null +++ b/Speedy/layout/DEBIAN/postinst @@ -0,0 +1,8 @@ +echo "" +echo "" +echo "Thank you for installing Speedy 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/Speedy/layout/Library/Application Support/Speedy.bundle/Assets/uninstall-dark.png b/Speedy/layout/Library/Application Support/Speedy.bundle/Assets/uninstall-dark.png new file mode 100644 index 0000000..dc10bb5 Binary files /dev/null and b/Speedy/layout/Library/Application Support/Speedy.bundle/Assets/uninstall-dark.png differ diff --git a/Speedy/layout/Library/Application Support/Speedy.bundle/Assets/uninstall-light.png b/Speedy/layout/Library/Application Support/Speedy.bundle/Assets/uninstall-light.png new file mode 100644 index 0000000..b12a68b Binary files /dev/null and b/Speedy/layout/Library/Application Support/Speedy.bundle/Assets/uninstall-light.png differ diff --git a/Substia/.DS_Store b/Substia/.DS_Store new file mode 100644 index 0000000..e84efee Binary files /dev/null and b/Substia/.DS_Store differ diff --git a/Substia/Makefile b/Substia/Makefile new file mode 100644 index 0000000..2c9082a --- /dev/null +++ b/Substia/Makefile @@ -0,0 +1,15 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0:13.0 +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +FINALPACKAGE = 1 +DEBUG = 0 + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Substia/Tweak/Headers.h b/Substia/Tweak/Headers.h new file mode 100644 index 0000000..4580435 --- /dev/null +++ b/Substia/Tweak/Headers.h @@ -0,0 +1,91 @@ +#import + +@interface UICalloutBar : UIView +@property (nonatomic,readonly) bool isDisplayingVertically; +@property (nonatomic, retain) NSArray *extraItems; +@property (nonatomic, retain) UIMenuItem *substiaItem; +@end + +@interface UICalloutBarButton : UIButton +@property (nonatomic, assign) SEL action; +@end + +@interface NSDistributedNotificationCenter : NSNotificationCenter ++ (instancetype)defaultCenter; +- (void)postNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3 deliverImmediately:(BOOL)arg4; +- (void)addObserver:(id)arg1 selector:(SEL)arg2 name:(id)arg3 object:(id)arg4; +- (void)postNotificationName:(NSString *)name object:(NSString *)object userInfo:(NSDictionary *)userInfo; +@end + +@interface _KSTextReplacementEntry : NSObject +@property (nonatomic,retain) NSData * cloudData; +@property (assign) BOOL needsSaveToCloud; +@property (assign) BOOL wasDeleted; +@property (nonatomic,copy) NSString * cloudID; +@property (nonatomic,copy) NSString * phrase; +@property (nonatomic,copy) NSString * shortcut; +@property (nonatomic,copy) NSDate * timestamp; +@property (nonatomic,retain) _KSTextReplacementEntry * priorValue; ++(BOOL)supportsSecureCoding; ++(id)localEntryFromCloudEntry:(id)arg1 ; +-(void)setPhrase:(NSString *)arg1 ; +-(void)setWasDeleted:(BOOL)arg1 ; +-(id)copyWithZone:(NSZone*)arg1 ; +-(id)encryptedFields; +-(BOOL)isEquivalentTo:(id)arg1 ; +-(id)uniqueRecordName; +-(BOOL)wasDeleted; +-(id)uniqueRecordNameVer0; +-(id)unEncryptedFields; +-(NSDate *)timestamp; +-(void)setTimestamp:(NSDate *)arg1 ; +-(void)setCloudID:(NSString *)arg1 ; +-(_KSTextReplacementEntry *)priorValue; +-(void)setShortcut:(NSString *)arg1 ; +-(id)uniqueID; +-(id)init; +-(void)setCloudData:(NSData *)arg1 ; +-(NSString *)phrase; +-(void)setNeedsSaveToCloud:(BOOL)arg1 ; +-(BOOL)needsSaveToCloud; +-(id)initWithCoder:(id)arg1 ; +-(void)encodeWithCoder:(id)arg1 ; +-(NSString *)shortcut; +-(void)setPriorValue:(_KSTextReplacementEntry *)arg1 ; +-(NSData *)cloudData; +-(id)description; +-(NSString *)cloudID; +@end + +@interface _KSTextReplacementHelper : NSObject ++(id)errorWithCode:(long long)arg1 failedAdds:(id)arg2 failedDeletes:(id)arg3 ; ++(id)errorWithCode:(long long)arg1 forEntry:(id)arg2 ; ++(void)logAggdValueForSyncIsPull:(BOOL)arg1 success:(BOOL)arg2 ; ++(long long)validateTextReplacement:(id)arg1 ; ++(id)sampleShortcut; ++(id)fetchConfigurationPlist; ++(id)errorStringForCode:(long long)arg1 ; ++(id)aggdPrefix; ++(id)errorWithCode:(long long)arg1 description:(id)arg2 ; ++(void)fetchConfigurationPlistIfNeeded; ++(id)transactionFromTextReplacementEntry:(id)arg1 forDelete:(BOOL)arg2 ; ++(void)logPhraseWordCount:(long long)arg1 ; ++(void)extractAggdMetricsForTextReplacement:(id)arg1 ; ++(id)multipleAddErrors:(id)arg1 removeErrors:(id)arg2 ; ++(id)textReplaceEntryFromTIDictionaryValue:(id)arg1 ; ++(id)appleLanguagesPreference; +@end + +@interface _KSTextReplacementClientStore : NSObject +-(id)textReplacementEntries; +-(void)cancelPendingUpdates; +-(void)queryTextReplacementsWithCallback:(/*^block*/id)arg1 ; +-(void)requestSyncWithCompletionBlock:(/*^block*/id)arg1 ; +-(void)removeAllEntries; +-(void)queryTextReplacementsWithPredicate:(id)arg1 callback:(/*^block*/id)arg2 ; +-(id)init; +-(void)performTransaction:(id)arg1 completionHandler:(/*^block*/id)arg2 ; +-(void)addEntries:(id)arg1 removeEntries:(id)arg2 withCompletionHandler:(/*^block*/id)arg3 ; +-(void)modifyEntry:(id)arg1 toEntry:(id)arg2 withCompletionHandler:(/*^block*/id)arg3 ; +-(id)phraseShortcuts; +@end \ No newline at end of file diff --git a/Substia/Tweak/Makefile b/Substia/Tweak/Makefile new file mode 100644 index 0000000..8e4cf25 --- /dev/null +++ b/Substia/Tweak/Makefile @@ -0,0 +1,13 @@ +TWEAK_NAME = Substia + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit KeyboardServices +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Substia/Tweak/Substia.plist b/Substia/Tweak/Substia.plist new file mode 100644 index 0000000..0870e45 --- /dev/null +++ b/Substia/Tweak/Substia.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard", "com.apple.UIKit", "com.apple.kbd" ); }; } diff --git a/Substia/Tweak/Substia.xm b/Substia/Tweak/Substia.xm new file mode 100644 index 0000000..8c765a5 --- /dev/null +++ b/Substia/Tweak/Substia.xm @@ -0,0 +1,144 @@ +#import "Headers.h" + +%hook UICalloutBar + +%property (nonatomic, retain) UIMenuItem *substiaItem; + +-(id)initWithFrame:(CGRect)arg1 { + UICalloutBar *orig = %orig; + self.substiaItem = [[UIMenuItem alloc] initWithTitle:@"Substia" action:@selector(substiaSel:)]; + return orig; +} + +-(void)updateAvailableButtons { + %orig; + + if (!self.extraItems) { + self.extraItems = @[]; + } + + bool display = false; + NSArray *currentSystemButtons = MSHookIvar(self, "m_currentSystemButtons"); + + for (UICalloutBarButton *btn in currentSystemButtons) { + if (btn.action == @selector(cut:)) { + display = true; + } + } + + NSMutableArray *items = [self.extraItems mutableCopy]; + + if (display) { + if (![items containsObject:self.substiaItem]) { + [items addObject:self.substiaItem]; + } + } else { + [items removeObject:self.substiaItem]; + } + + self.extraItems = items; + + %orig; +} + +%end + + +%hook UIResponder +%new +-(void)substiaSel:(UIResponder *)sender { + NSLog(@"aaaaaaaaaaaaa substiaSel..."); + + NSString *originalText = [[UIPasteboard generalPasteboard].string copy]; + [[UIApplication sharedApplication] sendAction:@selector(cut:) to:nil from:self forEvent:nil]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + NSString *selectedText = [[UIPasteboard generalPasteboard].string copy]; + + if (selectedText) { + [[UIPasteboard generalPasteboard] setString:selectedText]; + + UIViewController * controller = [[UIApplication sharedApplication] keyWindow].rootViewController; + + UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Enter Shortcut and Phrase" + message:nil + preferredStyle:UIAlertControllerStyleAlert]; + + [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.placeholder = @"Enter New Shortcut"; + textField.text = selectedText; + }]; + + [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.placeholder = @"Enter New Phrase"; + }]; + + UIAlertAction* okButton = [UIAlertAction actionWithTitle:@"Add" + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) { + + NSString *shortcut = alert.textFields[0].text; + NSString *phrase = alert.textFields[1].text; + + if([shortcut length] != 0 && [phrase length] !=0){ + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.TitanD3v.substia/addTRData" object:nil userInfo:@{@"shortcut" : shortcut, @"phrase" : phrase}]; + } + else{ + UIAlertController * alertIN = [UIAlertController alertControllerWithTitle:@"Please enter Shortcut and Phrase" + message:nil + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* cancelButton = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) {}]; + + [alertIN addAction:cancelButton]; + [controller presentViewController:alertIN animated:YES completion:nil]; + } + + }]; + + UIAlertAction* cancelButton = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * action) {}]; + + [alert addAction:okButton]; + [alert addAction:cancelButton]; + [controller presentViewController:alert animated:YES completion:nil]; + [[UIApplication sharedApplication] sendAction:@selector(paste:) to:nil from:self forEvent:nil]; + } + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + if (originalText) { + [[UIPasteboard generalPasteboard] setString:originalText]; + } else { + [[UIPasteboard generalPasteboard] setString:@""]; + } + }); + }); +} +%end + + +%hook SBHomeScreenViewController +-(void)viewDidAppear:(bool)arg1 { + %orig; + [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.substia/addTRData" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + NSString *shortcutIn = [[[notification userInfo] objectForKey:@"shortcut"] stringValue]; + NSString *phraseIn = [[[notification userInfo] objectForKey:@"phrase"] stringValue]; + + + _KSTextReplacementClientStore *store = [[%c(_KSTextReplacementClientStore) alloc] init]; + _KSTextReplacementEntry *newEntry = [[%c(_KSTextReplacementEntry) alloc] init]; + newEntry.phrase = phraseIn; + newEntry.shortcut = shortcutIn; + newEntry.needsSaveToCloud = YES; + newEntry.timestamp = [NSDate date]; + + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + NSCAssert([%c(_KSTextReplacementHelper) validateTextReplacement:newEntry] == 0, + [%c(_KSTextReplacementHelper) errorStringForCode: + [%c(_KSTextReplacementHelper) validateTextReplacement:newEntry]]); + + [store addEntries:@[newEntry] removeEntries:nil withCompletionHandler:^(NSError *error) { + dispatch_semaphore_signal(sema); + }]; + }]; +} +%end \ No newline at end of file diff --git a/Substia/control b/Substia/control new file mode 100644 index 0000000..a8635bd --- /dev/null +++ b/Substia/control @@ -0,0 +1,11 @@ +Package: com.titand3v.substia +Name: Substia +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal +Version: 1.0 +Section: Tweaks +Description: Text replacement +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/substia/index.html +Icon: https://titand3v.github.io/depictions/substia/assets/icon.png diff --git a/Substia/layout/DEBIAN/postinst b/Substia/layout/DEBIAN/postinst new file mode 100755 index 0000000..5142238 --- /dev/null +++ b/Substia/layout/DEBIAN/postinst @@ -0,0 +1,8 @@ +echo "" +echo "" +echo "Thank you for installing Substia 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/Surge/.DS_Store b/Surge/.DS_Store new file mode 100644 index 0000000..b79d270 Binary files /dev/null and b/Surge/.DS_Store differ diff --git a/Surge/Makefile b/Surge/Makefile new file mode 100644 index 0000000..8e489d3 --- /dev/null +++ b/Surge/Makefile @@ -0,0 +1,17 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0:13.0 +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +FINALPACKAGE = 1 +DEBUG = 0 + +export CFLAGS = -include $(realpath NCCenter.h) + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak Prefs + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Surge/NCCenter.h b/Surge/NCCenter.h new file mode 100644 index 0000000..0b2feb1 --- /dev/null +++ b/Surge/NCCenter.h @@ -0,0 +1,9 @@ +#import + +@interface NSDistributedNotificationCenter : NSNotificationCenter ++ (instancetype)defaultCenter; +-(void)postNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3 deliverImmediately:(BOOL)arg4 ; +- (void)postNotificationName:(NSString *)name object:(NSString *)object userInfo:(NSDictionary *)userInfo; +-(id)addObserverForName:(id)arg1 object:(id)arg2 queue:(id)arg3 usingBlock:(/*^block*/id)arg4 ; +-(void)addObserver:(id)arg1 selector:(SEL)arg2 name:(id)arg3 object:(id)arg4 ; +@end \ No newline at end of file diff --git a/Surge/Prefs/Makefile b/Surge/Prefs/Makefile new file mode 100644 index 0000000..2953707 --- /dev/null +++ b/Surge/Prefs/Makefile @@ -0,0 +1,15 @@ +BUNDLE_NAME = SurgePrefs + +$(BUNDLE_NAME)_FILES = $(wildcard *.m Purchase/*.m) +$(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles +$(BUNDLE_NAME)_FRAMEWORKS = UIKit +$(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences OnBoardingKit +$(BUNDLE_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(BUNDLE_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/bundle.mk + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) + $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/SurgePrefs.plist$(ECHO_END) diff --git a/Surge/Prefs/Resources/Appearance.plist b/Surge/Prefs/Resources/Appearance.plist new file mode 100644 index 0000000..e506c3c --- /dev/null +++ b/Surge/Prefs/Resources/Appearance.plist @@ -0,0 +1,106 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Appearance Mode + + + + cellClass + TDAppearanceCell + key + surgeInterfaceAppearance + default + surgeLight + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + options + + light + + appearanceOption + surgeLight + title + Light + imageName + appearance-light + arrangement + 1 + + dark + + appearanceOption + surgeDark + title + Dark + imageName + appearance-dark + arrangement + 2 + + + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Style + + + + cellClass + TDAppearanceCell + key + surgeInterfaceStyle + default + surgeBanner + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + options + + banner + + appearanceOption + surgeBanner + title + Banner + imageName + banner + arrangement + 1 + + capsule + + appearanceOption + surgeCapsule + title + Capsule + imageName + capsule + arrangement + 2 + + + + + + title + + + diff --git a/Surge/Prefs/Resources/Assets/Banner/banner-icon.png b/Surge/Prefs/Resources/Assets/Banner/banner-icon.png new file mode 100644 index 0000000..bedf5d2 Binary files /dev/null and b/Surge/Prefs/Resources/Assets/Banner/banner-icon.png differ diff --git a/Surge/Prefs/Resources/Assets/Banner/cover-image.png b/Surge/Prefs/Resources/Assets/Banner/cover-image.png new file mode 100644 index 0000000..095eba7 Binary files /dev/null and b/Surge/Prefs/Resources/Assets/Banner/cover-image.png differ diff --git a/Surge/Prefs/Resources/Assets/Cell/prefs-icon@2x.png b/Surge/Prefs/Resources/Assets/Cell/prefs-icon@2x.png new file mode 100644 index 0000000..f328c71 Binary files /dev/null and b/Surge/Prefs/Resources/Assets/Cell/prefs-icon@2x.png differ diff --git a/Surge/Prefs/Resources/Assets/Cell/prefs-icon@3x.png b/Surge/Prefs/Resources/Assets/Cell/prefs-icon@3x.png new file mode 100644 index 0000000..1c5dbde Binary files /dev/null and b/Surge/Prefs/Resources/Assets/Cell/prefs-icon@3x.png differ diff --git a/Surge/Prefs/Resources/Assets/Changelog/changelog.plist b/Surge/Prefs/Resources/Assets/Changelog/changelog.plist new file mode 100644 index 0000000..9916d90 --- /dev/null +++ b/Surge/Prefs/Resources/Assets/Changelog/changelog.plist @@ -0,0 +1,37 @@ + + + + + + + Date + 21th June 2021 + Version + v1.1 + ChangelogDescription + + Removed volume up button to invoke Surge banner, I added it for test purpose and sorry about that guys. + + updateCategories + + 1 + + + + + Date + 19th June 2021 + Version + v1.0 + ChangelogDescription + + Initial Release... + + updateCategories + + 0 + + + + + diff --git a/Surge/Prefs/Resources/Assets/Payment/ss1.png b/Surge/Prefs/Resources/Assets/Payment/ss1.png new file mode 100644 index 0000000..0580eca Binary files /dev/null and b/Surge/Prefs/Resources/Assets/Payment/ss1.png differ diff --git a/Surge/Prefs/Resources/Assets/Payment/ss2.png b/Surge/Prefs/Resources/Assets/Payment/ss2.png new file mode 100644 index 0000000..a717f9f Binary files /dev/null and b/Surge/Prefs/Resources/Assets/Payment/ss2.png differ diff --git a/Surge/Prefs/Resources/Assets/Payment/ss3.png b/Surge/Prefs/Resources/Assets/Payment/ss3.png new file mode 100644 index 0000000..afdc8ae Binary files /dev/null and b/Surge/Prefs/Resources/Assets/Payment/ss3.png differ diff --git a/Surge/Prefs/Resources/Assets/Payment/ss4.png b/Surge/Prefs/Resources/Assets/Payment/ss4.png new file mode 100644 index 0000000..272d35e Binary files /dev/null and b/Surge/Prefs/Resources/Assets/Payment/ss4.png differ diff --git a/Surge/Prefs/Resources/Assets/Payment/ss5.png b/Surge/Prefs/Resources/Assets/Payment/ss5.png new file mode 100644 index 0000000..94edad3 Binary files /dev/null and b/Surge/Prefs/Resources/Assets/Payment/ss5.png differ diff --git a/Surge/Prefs/Resources/Assets/Payment/ss6.png b/Surge/Prefs/Resources/Assets/Payment/ss6.png new file mode 100644 index 0000000..f0dc103 Binary files /dev/null and b/Surge/Prefs/Resources/Assets/Payment/ss6.png differ diff --git a/Surge/Prefs/Resources/Colour.plist b/Surge/Prefs/Resources/Colour.plist new file mode 100644 index 0000000..f3710cb --- /dev/null +++ b/Surge/Prefs/Resources/Colour.plist @@ -0,0 +1,266 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Custom Colour + + + + cellClass + TDEnableCell + default + + key + toggleColourScheme + disabledTitle + Disable Colour + enabledTitle + Enable Colour + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Background + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Background + subtitle + Colour + default + FFFFFF + key + backgroundChroma + iconName + colour + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Font + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Font + subtitle + Colour + default + FFFFFF + key + fontChroma + iconName + colour + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Icon + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Icon + subtitle + Colour + default + FFFFFF + key + iconChroma + iconName + colour + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Disable Button + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Disable + subtitle + Colour + default + FFFFFF + key + disableChroma + iconName + colour + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable Button + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Enable + subtitle + Colour + default + FFFFFF + key + enableChroma + iconName + colour + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Battery + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Container + subtitle + Colour + default + FFFFFF + key + containerChroma + iconName + colour + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Body + subtitle + Colour + default + FFFFFF + key + bodyChroma + iconName + colour + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Pin + subtitle + Colour + default + FFFFFF + key + pinChroma + iconName + colour + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + title + + + diff --git a/Surge/Prefs/Resources/Info.plist b/Surge/Prefs/Resources/Info.plist new file mode 100644 index 0000000..b15ac9d --- /dev/null +++ b/Surge/Prefs/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + SurgePrefs + CFBundleIdentifier + com.titand3v.surgeprefs + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + SURPrimraryListController + + diff --git a/Surge/Prefs/Resources/Miscellaneous.plist b/Surge/Prefs/Resources/Miscellaneous.plist new file mode 100644 index 0000000..edda3e8 --- /dev/null +++ b/Surge/Prefs/Resources/Miscellaneous.plist @@ -0,0 +1,139 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Haptic + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleHaptic + title + Enable + subtitle + Haptic Feedback + iconName + switch + showTips + + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + surgeHapticStrength + default + 0 + validTitles + + Light + Medium + Heavy + + validValues + + 0 + 1 + 2 + + title + Type + showTips + + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Quick Action + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleQuickAction + title + Enable + subtitle + Quick action tap on battery + iconName + switch + showTips + + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Show Alert Percentage + + + + cellClass + TDEditCell + title + Alert + subtitle + Percentage + objectKey + alertPercentage + placeholderText + Default: show alert at 20% + default + 20 + keyboardType + numberpad + iconName + text + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + title + + + diff --git a/Surge/Prefs/Resources/Primrary.plist b/Surge/Prefs/Resources/Primrary.plist new file mode 100644 index 0000000..49d7e9b --- /dev/null +++ b/Surge/Prefs/Resources/Primrary.plist @@ -0,0 +1,82 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable + + + + cellClass + TDEnableCell + default + + key + toggleSurge + disabledTitle + Disable Surge + enabledTitle + Enable Surge + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + disabledIconPath + Assets/example-icon.png + enabledIconPath + Assets/example-icon.png + defaults + com.TitanD3v.SurgePrefs + PostNotification + com.TitanD3v.SurgePrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Categories + + + + cellClass + TDGridCell + leftTitle + Appearance + leftIconName + appearance + leftClass + SURAppearanceController + middleTitle + Colour + middleIconName + colour + middleClass + SURColourController + rightTitle + Miscellaneous + rightIconName + misc + rightClass + SURMiscellaneousController + classID + primrary + + + + title + + + diff --git a/Surge/Prefs/SURPrimraryListController.h b/Surge/Prefs/SURPrimraryListController.h new file mode 100644 index 0000000..3ea7b47 --- /dev/null +++ b/Surge/Prefs/SURPrimraryListController.h @@ -0,0 +1,29 @@ +#import +#import + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1;; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + + +@interface SURPrimraryListController : TDPrimraryController { + OBWelcomeController *onboardingController; + OBWelcomeController *updateController; +} + +@end diff --git a/Surge/Prefs/SURPrimraryListController.m b/Surge/Prefs/SURPrimraryListController.m new file mode 100644 index 0000000..ccf8fae --- /dev/null +++ b/Surge/Prefs/SURPrimraryListController.m @@ -0,0 +1,123 @@ +#include "SURPrimraryListController.h" + + +@implementation SURPrimraryListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Primrary" target:self]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[TDPrefsManager sharedInstance] initWithBundleID:@"com.TitanD3v.SurgePrefs" tweakName:@"Surge" prefsBundle:@"SurgePrefs.bundle"]; + + [[TDPrefsManager sharedInstance] bannerTitle:@"Surge" subtitle:@"Coded with 🤍" devName:@"TitanD3v" coverImagePath:@"/Assets/Banner/cover-image.png" showCoverImage:YES iconPath:@"" iconTint:YES]; + + [[TDPrefsManager sharedInstance] changelogPlistPath:@"/Assets/Changelog/changelog.plist" currentVersion:@"Version 1.1"]; + + [[TDPrefsManager sharedInstance] useAssetsFromLibrary:YES]; + +} + + +-(void)presentTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + onboardingController = [[OBWelcomeController alloc] initWithTitle:@"User Guide" detailText:@"A walk through tutorial how to use Surge" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/SurgePrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]]; + + [onboardingController addBulletedListItemWithTitle:@"Your time" description:@"Please take a few minutes of your time to read through to get started." image:[UIImage systemImageNamed:@"timer"]]; + + [onboardingController addBulletedListItemWithTitle:@"Main page" description:@"On the main page, there's menu icon on the navigation bar it will present the drawer when tapped. You will find the social media details, changelog, backup/restore, tweak list, profile and crew list." image:[UIImage systemImageNamed:@"square.stack.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Report a bug" description:@"If you are experiencing a bug or any other issues, you can report a bug from this page below the close button, it will bring up the Bug Report page. You can select the categories, write description about a bug, attach a .txt file, photo, provide URL link for the pastebin or any pasteboard website also you can attach all of them if you want. Once you submit a bug report and our team will be in touch with you within 48 hours. If you haven't heard anything from us and please don't hesitate to get in touch with us through social media." image:[UIImage systemImageNamed:@"ant.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Enable Surge" description:@"Enable Surge then choose your prefered appearance and style." image:[UIImage systemImageNamed:@"1.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Colour" description:@"You can colour entire Surge UI if you don't want to use light or dark mode." image:[UIImage systemImageNamed:@"2.circle.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Miscellaneous" description:@"You can set the battery percentage to show the alert and enable quick action to show the pop up when tap the battery on your status bar." image:[UIImage systemImageNamed:@"3.circle.fill"]]; + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [onboardingController.buttonTray addButton:dismissButton]; + + onboardingController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:onboardingController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [onboardingController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + onboardingController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [onboardingController.buttonTray addCaptionText:@"Thank you for installing Surge"]; + + onboardingController.modalPresentationStyle = UIModalPresentationPageSheet; + onboardingController.modalInPresentation = YES; + [self presentViewController:onboardingController animated:YES completion:nil]; + + UIView *reportView = [[UIView alloc] init]; + reportView.backgroundColor = UIColor.clearColor; + [onboardingController.buttonTray addSubview:reportView]; + + reportView.translatesAutoresizingMaskIntoConstraints = NO; + [reportView.topAnchor constraintEqualToAnchor:dismissButton.bottomAnchor constant:10].active = YES; + [[reportView centerXAnchor] constraintEqualToAnchor:onboardingController.buttonTray.centerXAnchor].active = true; + [reportView.widthAnchor constraintEqualToConstant:140].active = YES; + [reportView.heightAnchor constraintEqualToConstant:40].active = YES; + + + UIImageView *bugImage = [[UIImageView alloc] init]; + bugImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + bugImage.tintColor = [[TDAppearance sharedInstance] tintColour]; + [reportView addSubview:bugImage]; + + bugImage.translatesAutoresizingMaskIntoConstraints = NO; + [bugImage.leadingAnchor constraintEqualToAnchor:reportView.leadingAnchor constant:10].active = YES; + [[bugImage centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + [bugImage.widthAnchor constraintEqualToConstant:30].active = YES; + [bugImage.heightAnchor constraintEqualToConstant:30].active = YES; + + + UILabel *reportLabel = [[UILabel alloc] init]; + reportLabel.text = @"Report a bug"; + reportLabel.textColor = [[TDAppearance sharedInstance] tintColour]; + reportLabel.textAlignment = NSTextAlignmentLeft; + [reportView addSubview:reportLabel]; + + reportLabel.translatesAutoresizingMaskIntoConstraints = NO; + [reportLabel.leadingAnchor constraintEqualToAnchor:bugImage.trailingAnchor constant:5].active = YES; + [[reportLabel centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + + [reportView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentReportBugVC)]]; + +} + + +-(void)dismissTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentReportBugVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; + + TDReportBugViewController *bugVC = [[TDReportBugViewController alloc] init]; + bugVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [self presentViewController:bugVC animated:YES completion:nil]; +} + +@end diff --git a/Surge/Prefs/SURSecondaryListController.h b/Surge/Prefs/SURSecondaryListController.h new file mode 100644 index 0000000..3687704 --- /dev/null +++ b/Surge/Prefs/SURSecondaryListController.h @@ -0,0 +1,11 @@ +#import +#import + +@interface SURAppearanceController : TDSecondaryController +@end + +@interface SURColourController : TDSecondaryController +@end + +@interface SURMiscellaneousController : TDSecondaryController +@end diff --git a/Surge/Prefs/SURSecondaryListController.m b/Surge/Prefs/SURSecondaryListController.m new file mode 100644 index 0000000..d696a14 --- /dev/null +++ b/Surge/Prefs/SURSecondaryListController.m @@ -0,0 +1,39 @@ +#include "SURSecondaryListController.h" + +@implementation SURAppearanceController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Appearance" target:self]; + } + + return _specifiers; +} + +@end + + +@implementation SURColourController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Colour" target:self]; + } + + return _specifiers; +} + +@end + + +@implementation SURMiscellaneousController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Miscellaneous" target:self]; + } + + return _specifiers; +} + +@end diff --git a/Surge/Prefs/entry.plist b/Surge/Prefs/entry.plist new file mode 100644 index 0000000..117f3d3 --- /dev/null +++ b/Surge/Prefs/entry.plist @@ -0,0 +1,21 @@ + + + + + entry + + bundle + SurgePrefs + cell + PSLinkCell + detail + SURPrimraryListController + icon + Assets/Cell/prefs-icon.png + isController + + label + Surge + + + diff --git a/Surge/Tweak/.DS_Store b/Surge/Tweak/.DS_Store new file mode 100644 index 0000000..e2b114e Binary files /dev/null and b/Surge/Tweak/.DS_Store differ diff --git a/Surge/Tweak/Headers.h b/Surge/Tweak/Headers.h new file mode 100644 index 0000000..e5f1cc7 --- /dev/null +++ b/Surge/Tweak/Headers.h @@ -0,0 +1,15 @@ +@interface _UIBatteryView (Surge) +-(void)invokeHapticFeedback; +@end + +@interface SBIconController : UIViewController ++(id)sharedInstance; +@end + +@interface SpringBoard : NSObject +-(void)layoutDeviceSize; +-(void)invokeLPMBanner; +-(void)dismissAlert; +-(void)setupLPM; +-(void)dismissWindow; +@end \ No newline at end of file diff --git a/Surge/Tweak/Makefile b/Surge/Tweak/Makefile new file mode 100644 index 0000000..c28faf9 --- /dev/null +++ b/Surge/Tweak/Makefile @@ -0,0 +1,22 @@ +TWEAK_NAME = Surge + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +dtoim = $(foreach d,$(1),-I$(d)) +_IMPORTS = $(shell /bin/ls -d ./SURGE/*/) +_IMPORTS += $(shell /bin/ls -d ./SURGE/*/*/) +_IMPORTS += $(shell /bin/ls -d ./SURGE/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./SURGE/*/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./) +_IMPORTS += $(shell /bin/ls -d ./*/) +IMPORTS = -I$./SURGE $(call dtoim, $(_IMPORTS)) + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations $(IMPORTS) +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Surge/Tweak/SURGE/BannerView.h b/Surge/Tweak/SURGE/BannerView.h new file mode 100644 index 0000000..adafa02 --- /dev/null +++ b/Surge/Tweak/SURGE/BannerView.h @@ -0,0 +1,15 @@ +#import +#import "SURBlurBaseView.h" +#import "Battery.h" +#import "Global-Preferences.h" +#import "Colour-Scheme.h" + +@interface BannerView : UIView +@property (nonatomic, retain) SURBlurBaseView *baseView; +@property (nonatomic, retain) UIButton *disableButton; +@property (nonatomic, retain) UIButton *enableButton; +@property (nonatomic, retain) UIView *batteryBaseView; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, strong) _UIBatteryView *battery; +@property (nonatomic, retain) UILabel *percentageLabel; +@end diff --git a/Surge/Tweak/SURGE/BannerView.xm b/Surge/Tweak/SURGE/BannerView.xm new file mode 100644 index 0000000..38064fa --- /dev/null +++ b/Surge/Tweak/SURGE/BannerView.xm @@ -0,0 +1,236 @@ +#import "BannerView.h" + +static float FontSize; + +@implementation BannerView + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + loadPrefs(); + + self.layer.cornerRadius = 20; + self.clipsToBounds = true; + + + if([surgeInterfaceAppearance isEqualToString:@"surgeLight"]) { + + self.layer.shadowColor = UIColor.lightGrayColor.CGColor; + self.layer.shadowOpacity = 0.5; + self.layer.shadowOffset = CGSizeMake(0.0,0.0); + self.layer.shadowRadius = 3.0; + self.layer.masksToBounds = false; + } + + [self updatingInfo]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatingInfoNotification:) name:@"SurgePresented" object:nil]; + [self layoutViews]; + + } + return self; +} + + +-(void)updatingInfoNotification:(NSNotification *)notification { + + if ([[notification name] isEqualToString:@"SurgePresented"]) { + [self updatingInfo]; + } + +} + + +-(void)layoutViews { + + self.baseView = [[SURBlurBaseView alloc] initWithFrame:self.bounds]; + self.baseView.layer.cornerRadius = 20; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + + self.enableButton = [[UIButton alloc] init]; + self.enableButton.layer.cornerRadius = 25; + self.enableButton.clipsToBounds = true; + UIImage *enableImage = [[UIImage imageWithContentsOfFile:@"/Library/Application Support/Surge.bundle/Assets/enable.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [self.enableButton setImage:enableImage forState:UIControlStateNormal]; + self.enableButton.imageEdgeInsets = UIEdgeInsetsMake(15, 15, 15, 15); + [self.enableButton addTarget:self action:@selector(enableLPM) forControlEvents:UIControlEventTouchUpInside]; + [self.baseView addSubview:self.enableButton]; + + self.enableButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.enableButton.widthAnchor constraintEqualToConstant:50.0].active = YES; + [self.enableButton.heightAnchor constraintEqualToConstant:50.0].active = YES; + [[self.enableButton centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.enableButton.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + + + self.disableButton = [[UIButton alloc] init]; + self.disableButton.layer.cornerRadius = 25; + self.disableButton.clipsToBounds = true; + UIImage *disableImage = [[UIImage imageWithContentsOfFile:@"/Library/Application Support/Surge.bundle/Assets/disable.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [self.disableButton setImage:disableImage forState:UIControlStateNormal]; + self.disableButton.imageEdgeInsets = UIEdgeInsetsMake(15, 15, 15, 15); + [self.disableButton addTarget:self action:@selector(disableLPM) forControlEvents:UIControlEventTouchUpInside]; + [self.baseView addSubview:self.disableButton]; + + self.disableButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.disableButton.widthAnchor constraintEqualToConstant:50.0].active = YES; + [self.disableButton.heightAnchor constraintEqualToConstant:50.0].active = YES; + [[self.disableButton centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.disableButton.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-70].active = YES; + + + self.batteryBaseView = [[UIView alloc] init]; + self.batteryBaseView.layer.cornerRadius = 30; + [self.baseView addSubview:self.batteryBaseView]; + + self.batteryBaseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.batteryBaseView.widthAnchor constraintEqualToConstant:60.0].active = YES; + [self.batteryBaseView.heightAnchor constraintEqualToConstant:60.0].active = YES; + [[self.batteryBaseView centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.batteryBaseView.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10].active = YES; + + + self.battery = [[_UIBatteryView alloc] init]; + self.battery.showsInlineChargingIndicator = YES; + [self.batteryBaseView addSubview:self.battery]; + + self.battery.translatesAutoresizingMaskIntoConstraints = false; + [self.battery.widthAnchor constraintEqualToConstant:20].active = YES; + [self.battery.heightAnchor constraintEqualToConstant:10].active = YES; + [self.battery.centerYAnchor constraintEqualToAnchor:self.batteryBaseView.centerYAnchor constant:-3].active = YES; + [self.battery.centerXAnchor constraintEqualToAnchor:self.batteryBaseView.centerXAnchor constant:-3].active = true; + + + self.percentageLabel = [[UILabel alloc] init]; + self.percentageLabel.textColor = [UIColor surgeFontColor]; + self.percentageLabel.font = [UIFont systemFontOfSize:7]; + self.percentageLabel.textAlignment = NSTextAlignmentCenter; + [self.battery addSubview:self.percentageLabel]; + + self.percentageLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.percentageLabel centerXAnchor] constraintEqualToAnchor:self.batteryBaseView.centerXAnchor].active = true; + [self.percentageLabel.topAnchor constraintEqualToAnchor:self.battery.bottomAnchor constant:3].active = YES; + + + if (iPhone_6_8) { + FontSize = 11; + } else if (iPhone_6_8_Plus) { + FontSize = 14; + } else if (iPhone_X_XS_11Pro) { + FontSize = 11; + } else if (iPhone_XR_XS_11Pro) { + FontSize = 14; + } else if (iPhone_12_Pro) { +FontSize = 11; + } else if (iPhone_12_mini) { +FontSize = 11; + } else if (iPhone_12_Pro_Max) { +FontSize = 14; + } + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = [UIColor surgeFontColor]; + self.titleLabel.font = [UIFont boldSystemFontOfSize:FontSize]; + self.titleLabel.text = @"Enable Low Power Mode"; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.titleLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.batteryBaseView.trailingAnchor constant:10].active = YES; + + + if (toggleColourScheme) { + self.disableButton.tintColor = [UIColor surgeIconColor]; + self.enableButton.tintColor = [UIColor surgeIconColor]; + self.disableButton.backgroundColor = [UIColor surgeDisableColor]; + self.enableButton.backgroundColor = [UIColor surgeEnableColor]; + self.batteryBaseView.backgroundColor = [UIColor surgeContainerColor]; + + } else { + self.disableButton.tintColor = UIColor.whiteColor; + self.enableButton.tintColor = UIColor.whiteColor; + self.disableButton.backgroundColor = UIColor.systemRedColor; + self.enableButton.backgroundColor = UIColor.systemGreenColor; + + if([surgeInterfaceAppearance isEqualToString:@"surgeLight"]) { + self.batteryBaseView.backgroundColor = [UIColor colorWithRed: 0.90 green: 0.90 blue: 0.92 alpha: 0.5]; + } else if([surgeInterfaceAppearance isEqualToString:@"surgeDark"]) { + self.batteryBaseView.backgroundColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.2]; + } + + } + +} + + +-(void)updatingInfo { + + UIDevice *myDevice = [UIDevice currentDevice]; + [myDevice setBatteryMonitoringEnabled:YES]; + + double batteryUsage = [myDevice batteryLevel] * 100; + + NSString * batteryLevelLabel1 = [NSString stringWithFormat:@"%.f%%", batteryUsage]; + + self.battery.chargePercent = (batteryUsage * 0.01); + self.percentageLabel.text = batteryLevelLabel1; + + + if (toggleColourScheme) { + + self.battery.bodyColor = [UIColor surgeBodyColor]; + self.battery.pinColor = [UIColor surgePinColor]; + + } else { + + + if([surgeInterfaceAppearance isEqualToString:@"surgeLight"]) { + self.battery.bodyColor = UIColor.blackColor; + self.battery.pinColor = UIColor.blackColor; + } else if([surgeInterfaceAppearance isEqualToString:@"surgeDark"]) { + self.battery.bodyColor = UIColor.whiteColor; + self.battery.pinColor = UIColor.whiteColor; + } + + } + +} + + +-(void)disableLPM { + + [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissLPMAlert" object:self]; + [self invokeHapticFeedback]; +} + + +-(void)enableLPM { + + BOOL isEnabled = [[NSProcessInfo processInfo] isLowPowerModeEnabled]; + [%c(PSLowPowerModeSettingsDetail) setEnabled:!isEnabled]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissLPMAlert" object:self]; + [self invokeHapticFeedback]; +} + + +-(void)invokeHapticFeedback { + + if (toggleHaptic) { + + if (surgeHapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (surgeHapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (surgeHapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + + } +} + +@end diff --git a/Surge/Tweak/SURGE/Battery.h b/Surge/Tweak/SURGE/Battery.h new file mode 100644 index 0000000..0a21fa7 --- /dev/null +++ b/Surge/Tweak/SURGE/Battery.h @@ -0,0 +1,28 @@ +@interface _UIBatteryView : UIView +@property (nonatomic, assign) CGFloat chargePercent; +@property (nonatomic, assign) CGFloat bodyColorAlpha; +@property (nonatomic, assign) CGFloat pinColorAlpha; +@property (nonatomic, assign) BOOL showsPercentage; +@property (nonatomic, assign) BOOL saverModeActive; +@property (nonatomic, assign) BOOL showsInlineChargingIndicator; +@property (nonatomic, assign) NSInteger chargingState; +@property (nonatomic,copy) UIColor * fillColor; //@synthesize fillColor=_fillColor - In the implementation block +@property (nonatomic,copy) UIColor * bodyColor; //@synthesize bodyColor=_bodyColor - In the implementation block +@property (nonatomic,copy) UIColor * pinColor; //@synthesize pinColor=_pinColor - In the implementation block +@property (nonatomic,copy) UIColor * boltColor; +@end + +@interface BCBatteryDevice : NSObject +@property (nonatomic, strong) id kaiCell; +@property (nonatomic, strong) NSString *name; +@property (nonatomic, assign) long long percentCharge; +@property (nonatomic, assign, getter=isCharging) BOOL charging; +@property (nonatomic, assign, getter=isFake) BOOL fake; +@property (nonatomic, assign, getter=isInternal) BOOL internal; +@property (nonatomic, assign, getter=isBatterySaverModeActive) BOOL batterySaverModeActive; +@property (nonatomic, strong) NSString *identifier; +@end + +@interface PSLowPowerModeSettingsDetail ++(void)setEnabled:(BOOL)arg1; +@end \ No newline at end of file diff --git a/Surge/Tweak/SURGE/CapsuleView.h b/Surge/Tweak/SURGE/CapsuleView.h new file mode 100644 index 0000000..92b2a63 --- /dev/null +++ b/Surge/Tweak/SURGE/CapsuleView.h @@ -0,0 +1,15 @@ +#import +#import "SURBlurBaseView.h" +#import "Battery.h" +#import "Global-Preferences.h" +#import "Colour-Scheme.h" + +@interface CapsuleView : UIView +@property (nonatomic, retain) SURBlurBaseView *baseView; +@property (nonatomic, retain) UIButton *disableButton; +@property (nonatomic, retain) UIButton *enableButton; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *percentageLabel; +@property (nonatomic, strong) _UIBatteryView *battery; +@end + diff --git a/Surge/Tweak/SURGE/CapsuleView.xm b/Surge/Tweak/SURGE/CapsuleView.xm new file mode 100644 index 0000000..655b6db --- /dev/null +++ b/Surge/Tweak/SURGE/CapsuleView.xm @@ -0,0 +1,200 @@ +#import "CapsuleView.h" + +@implementation CapsuleView + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + loadPrefs(); + + self.layer.cornerRadius = 20; + self.clipsToBounds = true; + + + if([surgeInterfaceAppearance isEqualToString:@"surgeLight"]) { + + self.layer.shadowColor = UIColor.lightGrayColor.CGColor; + self.layer.shadowOpacity = 0.5; + self.layer.shadowOffset = CGSizeMake(0.0,0.0); + self.layer.shadowRadius = 3.0; + self.layer.masksToBounds = false; + } + + + [self layoutViews]; + [self updatingInfo]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatingInfoNotification:) name:@"SurgePresented" object:nil]; + + } + return self; +} + + +-(void)updatingInfoNotification:(NSNotification *)notification { + + if ([[notification name] isEqualToString:@"SurgePresented"]) { + [self updatingInfo]; + } + +} + + +-(void)layoutViews { + + self.baseView = [[SURBlurBaseView alloc] initWithFrame:self.bounds]; + self.baseView.layer.cornerRadius = 30; + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + + self.disableButton = [[UIButton alloc] init]; + self.disableButton.layer.cornerRadius = 25; + self.disableButton.clipsToBounds = true; + UIImage *disableImage = [[UIImage imageWithContentsOfFile:@"/Library/Application Support/Surge.bundle/Assets/disable.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [self.disableButton setImage:disableImage forState:UIControlStateNormal]; + self.disableButton.imageEdgeInsets = UIEdgeInsetsMake(15, 15, 15, 15); + [self.disableButton addTarget:self action:@selector(disableLPM) forControlEvents:UIControlEventTouchUpInside]; + [self.baseView addSubview:self.disableButton]; + + self.disableButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.disableButton.widthAnchor constraintEqualToConstant:50.0].active = YES; + [self.disableButton.heightAnchor constraintEqualToConstant:50.0].active = YES; + [[self.disableButton centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.disableButton.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:5].active = YES; + + + self.enableButton = [[UIButton alloc] init]; + self.enableButton.layer.cornerRadius = 25; + self.enableButton.clipsToBounds = true; + UIImage *enableImage = [[UIImage imageWithContentsOfFile:@"/Library/Application Support/Surge.bundle/Assets/enable.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [self.enableButton setImage:enableImage forState:UIControlStateNormal]; + self.enableButton.imageEdgeInsets = UIEdgeInsetsMake(15, 15, 15, 15); + [self.enableButton addTarget:self action:@selector(enableLPM) forControlEvents:UIControlEventTouchUpInside]; + [self.baseView addSubview:self.enableButton]; + + self.enableButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.enableButton.widthAnchor constraintEqualToConstant:50.0].active = YES; + [self.enableButton.heightAnchor constraintEqualToConstant:50.0].active = YES; + [[self.enableButton centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.enableButton.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-5].active = YES; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = [UIColor surgeFontColor]; + self.titleLabel.font = [UIFont boldSystemFontOfSize:10]; + self.titleLabel.text = @"Enable Low Power Mode"; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + [self.baseView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.titleLabel centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + [self.titleLabel.topAnchor constraintEqualToAnchor:self.baseView.topAnchor constant:10].active = YES; + + + self.percentageLabel = [[UILabel alloc] init]; + self.percentageLabel.textColor = [UIColor surgeFontColor]; + self.percentageLabel.font = [UIFont systemFontOfSize:10]; + self.percentageLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.percentageLabel]; + + self.percentageLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.percentageLabel centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor constant:15].active = true; + [[self.percentageLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor constant:5].active = true; + + + self.battery = [[_UIBatteryView alloc] init]; + self.battery.showsInlineChargingIndicator = YES; + [self.baseView addSubview:self.battery]; + + self.battery.translatesAutoresizingMaskIntoConstraints = false; + [self.battery.widthAnchor constraintEqualToConstant:20].active = YES; + [self.battery.heightAnchor constraintEqualToConstant:10].active = YES; + [self.battery.centerYAnchor constraintEqualToAnchor:self.baseView.centerYAnchor constant:5].active = YES; + [self.battery.centerXAnchor constraintEqualToAnchor:self.baseView.centerXAnchor constant:-15].active = true; + + + if (toggleColourScheme) { + self.disableButton.tintColor = [UIColor surgeIconColor]; + self.enableButton.tintColor = [UIColor surgeIconColor]; + self.disableButton.backgroundColor = [UIColor surgeDisableColor]; + self.enableButton.backgroundColor = [UIColor surgeEnableColor]; + + } else { + self.disableButton.tintColor = UIColor.whiteColor; + self.enableButton.tintColor = UIColor.whiteColor; + self.disableButton.backgroundColor = UIColor.systemRedColor; + self.enableButton.backgroundColor = UIColor.systemGreenColor; + } + +} + + +-(void)updatingInfo { + + UIDevice *myDevice = [UIDevice currentDevice]; + [myDevice setBatteryMonitoringEnabled:YES]; + + double batteryUsage = [myDevice batteryLevel] * 100; + + NSString * batteryLevelLabel1 = [NSString stringWithFormat:@"%.f%%", batteryUsage]; + + self.battery.chargePercent = (batteryUsage * 0.01); + self.percentageLabel.text = batteryLevelLabel1; + + + if (toggleColourScheme) { + + self.battery.bodyColor = [UIColor surgeBodyColor]; + self.battery.pinColor = [UIColor surgePinColor]; + + } else { + + + if([surgeInterfaceAppearance isEqualToString:@"surgeLight"]) { + self.battery.bodyColor = UIColor.blackColor; + self.battery.pinColor = UIColor.blackColor; + } else if([surgeInterfaceAppearance isEqualToString:@"surgeDark"]) { + self.battery.bodyColor = UIColor.whiteColor; + self.battery.pinColor = UIColor.whiteColor; + } + + } + +} + + +-(void)disableLPM { + + [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissLPMAlert" object:self]; + [self invokeHapticFeedback]; +} + + +-(void)enableLPM { + + BOOL isEnabled = [[NSProcessInfo processInfo] isLowPowerModeEnabled]; + [%c(PSLowPowerModeSettingsDetail) setEnabled:!isEnabled]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissLPMAlert" object:self]; + [self invokeHapticFeedback]; +} + + +-(void)invokeHapticFeedback { + + if (toggleHaptic) { + + if (surgeHapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (surgeHapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (surgeHapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + + } +} + +@end diff --git a/Surge/Tweak/SURGE/Colour-Scheme.h b/Surge/Tweak/SURGE/Colour-Scheme.h new file mode 100644 index 0000000..1a5bfb9 --- /dev/null +++ b/Surge/Tweak/SURGE/Colour-Scheme.h @@ -0,0 +1,34 @@ +#import "Global-Preferences.h" + +@interface UIColor (BackgroundColor) ++ (UIColor *)surgeBackgroundColor; +@end + +@interface UIColor (FontColor) ++ (UIColor *)surgeFontColor; +@end + +@interface UIColor (IconColor) ++ (UIColor *)surgeIconColor; +@end + +@interface UIColor (DisableColor) ++ (UIColor *)surgeDisableColor; +@end + +@interface UIColor (EnableColor) ++ (UIColor *)surgeEnableColor; +@end + +@interface UIColor (BodyColor) ++ (UIColor *)surgeBodyColor; +@end + +@interface UIColor (PinColor) ++ (UIColor *)surgePinColor; +@end + +@interface UIColor (ContainerColor) ++ (UIColor *)surgeContainerColor; +@end + diff --git a/Surge/Tweak/SURGE/Colour-Scheme.xm b/Surge/Tweak/SURGE/Colour-Scheme.xm new file mode 100644 index 0000000..7ff2bc9 --- /dev/null +++ b/Surge/Tweak/SURGE/Colour-Scheme.xm @@ -0,0 +1,156 @@ +#import "Colour-Scheme.h" + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +// Background color +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + +@implementation UIColor (BackgroundColor) ++ (UIColor *)surgeBackgroundColor { + static UIColor* backgroundColor; + +loadPrefs(); + + backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"backgroundChroma" defaultValue:@"FFFFFF" ID:BID]; + + return backgroundColor; +} +@end + + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +// Font color +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + +@implementation UIColor (FontColor) ++ (UIColor *)surgeFontColor { + static UIColor* backgroundColor; + + loadPrefs(); + + if([surgeInterfaceAppearance isEqualToString:@"surgeLight"]) { + + backgroundColor = UIColor.blackColor; + + } else if([surgeInterfaceAppearance isEqualToString:@"surgeDark"]) { + + backgroundColor = UIColor.whiteColor; + } + + if (toggleColourScheme) { + backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"fontChroma" defaultValue:@"FFFFFF" ID:BID]; + } + + return backgroundColor; +} +@end + + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +// Icon color +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + +@implementation UIColor (IconColor) ++ (UIColor *)surgeIconColor { + static UIColor* backgroundColor; + + loadPrefs(); + + backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"iconChroma" defaultValue:@"FFFFFF" ID:BID]; + + return backgroundColor; +} +@end + + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +// Disable color +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + +@implementation UIColor (DisableColor) ++ (UIColor *)surgeDisableColor { + static UIColor* backgroundColor; + + loadPrefs(); + + backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"disableChroma" defaultValue:@"FFFFFF" ID:BID]; + + return backgroundColor; +} +@end + + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +// Enable color +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + +@implementation UIColor (EnableColor) ++ (UIColor *)surgeEnableColor { + static UIColor* backgroundColor; + + loadPrefs(); + + backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"enableChroma" defaultValue:@"FFFFFF" ID:BID]; + + return backgroundColor; +} +@end + + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +// Body color +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + +@implementation UIColor (BodyColor) ++ (UIColor *)surgeBodyColor { + static UIColor* backgroundColor; + + loadPrefs(); + + backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"bodyChroma" defaultValue:@"FFFFFF" ID:BID]; + + return backgroundColor; +} +@end + + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +// Pin color +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + +@implementation UIColor (PinColor) ++ (UIColor *)surgePinColor { + static UIColor* backgroundColor; + + loadPrefs(); + + backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"pinChroma" defaultValue:@"FFFFFF" ID:BID]; + + return backgroundColor; +} +@end + + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +// Container color +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + +@implementation UIColor (ContainerColor) ++ (UIColor *)surgeContainerColor { + static UIColor* backgroundColor; + + loadPrefs(); + + backgroundColor = [[TDTweakManager sharedInstance] colourForKey:@"containerChroma" defaultValue:@"FFFFFF" ID:BID]; + + return backgroundColor; +} +@end + diff --git a/Surge/Tweak/SURGE/Global-Preferences.h b/Surge/Tweak/SURGE/Global-Preferences.h new file mode 100644 index 0000000..a411e4d --- /dev/null +++ b/Surge/Tweak/SURGE/Global-Preferences.h @@ -0,0 +1,21 @@ +#import + +static NSString *BID = @"com.TitanD3v.SurgePrefs"; + +static BOOL toggleSurge; +static NSString *surgeInterfaceAppearance; +static BOOL toggleColourScheme; +static BOOL toggleHaptic; +static NSInteger surgeHapticStrength; +static BOOL showSBTutorial; + +static void loadPrefs() { + + toggleSurge = [[TDTweakManager sharedInstance] boolForKey:@"toggleSurge" defaultValue:NO ID:BID]; + showSBTutorial = [[TDTweakManager sharedInstance] boolForKey:@"showSBTutorial" defaultValue:YES ID:BID]; + surgeInterfaceAppearance = [[TDTweakManager sharedInstance] objectForKey:@"surgeInterfaceAppearance" defaultValue:@"surgeLight" ID:BID]; + toggleColourScheme = [[TDTweakManager sharedInstance] boolForKey:@"toggleColourScheme" defaultValue:NO ID:BID]; + toggleHaptic = [[TDTweakManager sharedInstance] boolForKey:@"toggleHaptic" defaultValue:YES ID:BID]; + surgeHapticStrength = [[TDTweakManager sharedInstance] intForKey:@"surgeHapticStrength" defaultValue:0 ID:BID]; + +} \ No newline at end of file diff --git a/Surge/Tweak/SURGE/SURBlurBaseView.h b/Surge/Tweak/SURGE/SURBlurBaseView.h new file mode 100644 index 0000000..7483eae --- /dev/null +++ b/Surge/Tweak/SURGE/SURBlurBaseView.h @@ -0,0 +1,7 @@ +#import +#import "Global-Preferences.h" +#import "Colour-Scheme.h" + +@interface SURBlurBaseView : UIView +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@end diff --git a/Surge/Tweak/SURGE/SURBlurBaseView.m b/Surge/Tweak/SURGE/SURBlurBaseView.m new file mode 100644 index 0000000..aeb35b7 --- /dev/null +++ b/Surge/Tweak/SURGE/SURBlurBaseView.m @@ -0,0 +1,46 @@ +#import "SURBlurBaseView.h" + +@implementation SURBlurBaseView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + loadPrefs(); + + + self.blurEffectView = [[UIVisualEffectView alloc] initWithFrame:CGRectZero]; + [self insertSubview:self.blurEffectView atIndex:0]; + + + self.blurEffectView.translatesAutoresizingMaskIntoConstraints = false; + [self.blurEffectView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0].active = YES; + [self.blurEffectView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0].active = YES; + [self.blurEffectView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:0].active = YES; + [self.blurEffectView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0].active = YES; + + + if([surgeInterfaceAppearance isEqualToString:@"surgeLight"]) { + + self.blurEffectView.alpha = 0; + self.backgroundColor = UIColor.whiteColor; + + } else if([surgeInterfaceAppearance isEqualToString:@"surgeDark"]) { + + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + } + + + if (toggleColourScheme) { + self.blurEffectView.alpha = 0; + self.backgroundColor = [UIColor surgeBackgroundColor]; + } + + + } + return self; +} + +@end diff --git a/Surge/Tweak/Surge.plist b/Surge/Tweak/Surge.plist new file mode 100644 index 0000000..10dc654 --- /dev/null +++ b/Surge/Tweak/Surge.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard" ); }; } diff --git a/Surge/Tweak/Surge.xm b/Surge/Tweak/Surge.xm new file mode 100644 index 0000000..5831e88 --- /dev/null +++ b/Surge/Tweak/Surge.xm @@ -0,0 +1,388 @@ +#import +#import "./SURGE/BannerView.h" +#import "./SURGE/CapsuleView.h" +#import "./SURGE/Colour-Scheme.h" +#import "Headers.h" + + +static NSString *surgeInterfaceStyle; +static BOOL toggleQuickAction; +static NSInteger alertPercentage; + +static UIWindow *lpmWindow = nil; +BannerView *bannerView; +CapsuleView *capsuleView; +UIViewController *lpmBaseVC; +UIButton *lpmButton; +UILabel *lpmLabel; +static float bannerSize; +static float bannerYOffset; + + +@interface LPMPopViewController : UIViewController +@end + +@implementation LPMPopViewController +- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller +traitCollection:(UITraitCollection *)traitCollection { + return UIModalPresentationNone; +} +@end + + +%group RemoveDefaultAlert + +%hook SBLowPowerAlertItem + ++(unsigned)_thresholdForLevel:(unsigned)level { + + [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; + + if (!([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging)) { + + NSInteger firstLowAlert = 20; + + if (level == firstLowAlert) { + + NSLog(@"Battery at 20 percent"); + + } else if ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging) { + + NSLog(@"Battery is charging"); + + } + + if ((level == firstLowAlert -1 || level == firstLowAlert +1)) { + + NSLog(@"Battery is below 20 percent"); + } + + } + + return 99; + +} + +%end +%end + + +%group Surge + +%hook SpringBoard + +- (void)applicationDidFinishLaunching:(id)arg1 { + + %orig; + + [self layoutDeviceSize]; + [self setupLPM]; + + [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryLevelChanged) name:UIDeviceBatteryLevelDidChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveDismissNotification:) name:@"DismissLPMAlert" object:nil]; + +} + + +%new +- (void)batteryLevelChanged { + + float batteryLevel = [UIDevice currentDevice].batteryLevel * 100; + NSInteger batteryCurrentLevel = batteryLevel; + + if (batteryCurrentLevel == alertPercentage) { + [self invokeLPMBanner]; + } + +} + + +%new +- (void)receiveDismissNotification:(NSNotification *) notification { + + if ([[notification name] isEqualToString:@"DismissLPMAlert"]) { + [self dismissAlert]; + } + +} + + +%new +-(void)layoutDeviceSize { + + if (iPhone_6_8) { + bannerSize = 100; + bannerYOffset = 25; + } else if (iPhone_6_8_Plus) { + bannerSize = 110; + bannerYOffset = 25; + } else if (iPhone_X_XS_11Pro) { + bannerSize = 110; + bannerYOffset = 40; + } else if (iPhone_XR_XS_11Pro) { + bannerSize = 120; + bannerYOffset = 40; + } else if (iPhone_12_Pro) { + bannerSize = 110; + bannerYOffset = 40; + } else if (iPhone_12_mini) { + bannerSize = 110; + bannerYOffset = 25; + } else if (iPhone_12_Pro_Max) { + bannerSize = 120; + bannerYOffset = 40; + } + +} + + +%new +-(void)setupLPM { + + if (!lpmWindow) { + + lpmWindow = [[UIWindow alloc] initWithFrame: CGRectMake(0, 0, MAIN_SCREEN_WIDTH, 160)]; + lpmWindow.backgroundColor = [UIColor clearColor]; + lpmWindow.hidden = YES; + lpmWindow.windowLevel = UIWindowLevelStatusBar + 100; + [lpmWindow setUserInteractionEnabled:YES]; + + if([surgeInterfaceStyle isEqualToString:@"surgeBanner"]) { + + bannerView = [[BannerView alloc] initWithFrame:CGRectMake(10, -150, MAIN_SCREEN_WIDTH -20, bannerSize)]; + [lpmWindow addSubview:bannerView]; + + } else if([surgeInterfaceStyle isEqualToString:@"surgeCapsule"]) { + + capsuleView = [[CapsuleView alloc] initWithFrame:CGRectMake(MAIN_SCREEN_WIDTH /2 -135, -150, 270, 60)]; + [lpmWindow addSubview:capsuleView]; + + } + + } + +} + + +%new +-(void)invokeLPMBanner { + + + [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; + + if (!([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateCharging)) { + + [[NSNotificationCenter defaultCenter] postNotificationName:@"SurgePresented" object:self]; + + lpmWindow.hidden = NO; + + [UIView animateWithDuration:0.3 animations:^{ + + if([surgeInterfaceStyle isEqualToString:@"surgeBanner"]) { + bannerView.frame = CGRectMake(10, bannerYOffset, MAIN_SCREEN_WIDTH -20, bannerSize); + } else if([surgeInterfaceStyle isEqualToString:@"surgeCapsule"]) { + capsuleView.frame = CGRectMake(MAIN_SCREEN_WIDTH /2 -135, 40, 270, 60); + } + + }]; + + } + +} + + +%new +-(void)dismissAlert { + + [UIView animateWithDuration:0.3 animations:^{ + + if([surgeInterfaceStyle isEqualToString:@"surgeBanner"]) { + bannerView.frame = CGRectMake(10, -150, MAIN_SCREEN_WIDTH -20, bannerSize); + } else if([surgeInterfaceStyle isEqualToString:@"surgeCapsule"]) { + capsuleView.frame = CGRectMake(MAIN_SCREEN_WIDTH /2 -135, -150, 270, 60); + } + + }]; + + + [self performSelector:@selector(dismissWindow) withObject:nil afterDelay:0.4]; + +} + + +%new +-(void)dismissWindow { + + lpmWindow.hidden = YES; +} + +%end +%end + + +%group QuickAction +%hook _UIBatteryView + +-(void)layoutSubviews { + + %orig; + self.userInteractionEnabled = YES; + [self addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(invokeLPMSheet)]]; + +} + + +%new +-(void)invokeLPMSheet { + + + BOOL isEnabled = [[NSProcessInfo processInfo] isLowPowerModeEnabled]; + + + UIViewController *lpmBaseVC = [[UIViewController alloc] init]; + lpmBaseVC.modalPresentationStyle = UIModalPresentationPopover; + lpmBaseVC.preferredContentSize = CGSizeMake(170,65); + + + lpmButton = [[UIButton alloc] init]; + lpmButton.layer.cornerRadius = 25; + lpmButton.clipsToBounds = true; + if (isEnabled) { + UIImage *disableImage = [[UIImage imageWithContentsOfFile:@"/Library/Application Support/Surge.bundle/Assets/disable.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [lpmButton setImage:disableImage forState:UIControlStateNormal]; + lpmButton.backgroundColor = UIColor.systemRedColor; + if (toggleColourScheme) { + lpmButton.backgroundColor = [UIColor surgeDisableColor]; + } + } else { + UIImage *enableImage = [[UIImage imageWithContentsOfFile:@"/Library/Application Support/Surge.bundle/Assets/enable.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [lpmButton setImage:enableImage forState:UIControlStateNormal]; + lpmButton.backgroundColor = UIColor.systemGreenColor; + if (toggleColourScheme) { + lpmButton.backgroundColor = [UIColor surgeEnableColor]; + } + } + lpmButton.imageEdgeInsets = UIEdgeInsetsMake(15, 15, 15, 15); + [lpmButton addTarget:self action:@selector(lpmAction) forControlEvents:UIControlEventTouchUpInside]; + [lpmBaseVC.view addSubview:lpmButton]; + + lpmButton.translatesAutoresizingMaskIntoConstraints = NO; + [lpmButton.widthAnchor constraintEqualToConstant:50.0].active = YES; + [lpmButton.heightAnchor constraintEqualToConstant:50.0].active = YES; + [[lpmButton centerYAnchor] constraintEqualToAnchor:lpmBaseVC.view.centerYAnchor].active = true; + [lpmButton.trailingAnchor constraintEqualToAnchor:lpmBaseVC.view.trailingAnchor constant:-10].active = YES; + + + lpmLabel = [[UILabel alloc] init]; + if (@available(iOS 13, *)) { + lpmLabel.textColor = UIColor.labelColor; + } else { + lpmLabel.textColor = UIColor.blackColor; + } + lpmLabel.font = [UIFont boldSystemFontOfSize:14]; + if (isEnabled) { + lpmLabel.text = @"Disable LPM"; + } else { + lpmLabel.text = @"Enable LPM"; + } + lpmLabel.textAlignment = NSTextAlignmentLeft; + [lpmBaseVC.view addSubview:lpmLabel]; + + lpmLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[lpmLabel centerYAnchor] constraintEqualToAnchor:lpmBaseVC.view.centerYAnchor].active = true; + [lpmLabel.leadingAnchor constraintEqualToAnchor:lpmBaseVC.view.leadingAnchor constant:10].active = YES; + + + UIPopoverPresentationController *lpmPopUp = lpmBaseVC.popoverPresentationController; + LPMPopViewController *vc = [[LPMPopViewController alloc] init]; + lpmPopUp.delegate = vc; + lpmPopUp.permittedArrowDirections = UIPopoverArrowDirectionUp; + lpmPopUp.sourceView = self; + + [[%c(SBIconController) sharedInstance] presentViewController:lpmBaseVC animated:YES completion:nil]; + + + if (toggleColourScheme) { + + lpmPopUp.backgroundColor = [UIColor surgeBackgroundColor]; + lpmButton.tintColor = [UIColor surgeIconColor]; + lpmLabel.textColor = [UIColor surgeFontColor]; + + } else { + lpmButton.tintColor = UIColor.whiteColor; + } + + [self invokeHapticFeedback]; + +} + + +%new +-(void)lpmAction { + + [self invokeHapticFeedback]; + BOOL isEnabled = [[NSProcessInfo processInfo] isLowPowerModeEnabled]; + [%c(PSLowPowerModeSettingsDetail) setEnabled:!isEnabled]; + [[%c(SBIconController) sharedInstance] dismissViewControllerAnimated:lpmBaseVC completion:nil]; + +} + + +%new +-(void)invokeHapticFeedback { + + if (toggleHaptic) { + + if (surgeHapticStrength == 0) { + [[TDUtilities sharedInstance] haptic:0]; + } else if (surgeHapticStrength == 1) { + [[TDUtilities sharedInstance] haptic:1]; + } else if (surgeHapticStrength == 2) { + [[TDUtilities sharedInstance] haptic:2]; + } + + } +} + +%end + + +%hook UIApplication +-(void)applicationWillSuspend { + %orig; + [[%c(SBIconController) sharedInstance] dismissViewControllerAnimated:lpmBaseVC completion:nil]; +} +%end +%end + + +void SettingsChanged() { + + toggleSurge = [[TDTweakManager sharedInstance] boolForKey:@"toggleSurge" defaultValue:NO ID:BID]; + surgeInterfaceStyle = [[TDTweakManager sharedInstance] objectForKey:@"surgeInterfaceStyle" defaultValue:@"surgeBanner" ID:BID]; + toggleColourScheme = [[TDTweakManager sharedInstance] boolForKey:@"toggleColourScheme" defaultValue:NO ID:BID]; + toggleHaptic = [[TDTweakManager sharedInstance] boolForKey:@"toggleHaptic" defaultValue:YES ID:BID]; + toggleQuickAction = [[TDTweakManager sharedInstance] boolForKey:@"toggleQuickAction" defaultValue:YES ID:BID]; + surgeHapticStrength = [[TDTweakManager sharedInstance] intForKey:@"surgeHapticStrength" defaultValue:0 ID:BID]; + alertPercentage = [[TDTweakManager sharedInstance] intForKey:@"alertPercentage" defaultValue:20 ID:BID]; + +} + +%ctor { + + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)SettingsChanged, CFSTR("com.TitanD3v.SurgePrefs.settingschanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + SettingsChanged(); + + if (toggleSurge) { + %init(RemoveDefaultAlert); + %init(Surge); + + if (toggleQuickAction) { + %init(QuickAction); + } + + } + +} diff --git a/Surge/Tweak/Tutorial/Tutorial.xm b/Surge/Tweak/Tutorial/Tutorial.xm new file mode 100644 index 0000000..088de3f --- /dev/null +++ b/Surge/Tweak/Tutorial/Tutorial.xm @@ -0,0 +1,98 @@ +#import +#import "Global-Preferences.h" + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + +@interface SpringBoard : UIView +-(void)presentSurgeTutorialVC; +@end + + +OBWelcomeController *tutorialController; + + +%group Tutorial +%hook SpringBoard + +- (void)applicationDidFinishLaunching:(id)application { + %orig; + + loadPrefs(); + +if ((toggleSurge) && (showSBTutorial)) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self presentSurgeTutorialVC]; + }); +} +} + +%new +-(void)presentSurgeTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + tutorialController = [[OBWelcomeController alloc] initWithTitle:@"Surge" detailText:@"Tutorial" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/SurgePrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]]; + tutorialController.view.tintColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + + [tutorialController addBulletedListItemWithTitle:@"LPM" description:@"Just tap on the battery icon from the statusbar to enable/disable LPM, you can only do that if your device isn't charging." image:[UIImage systemImageNamed:@"battery.100"]]; + + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissSurgeTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [tutorialController.buttonTray addButton:dismissButton]; + + tutorialController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:tutorialController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [tutorialController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + tutorialController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [tutorialController.buttonTray addCaptionText:@"Thank you for installing Surge"]; + + tutorialController.modalPresentationStyle = UIModalPresentationPageSheet; + tutorialController.modalInPresentation = YES; + [[%c(SBIconController) sharedInstance] presentViewController:tutorialController animated:YES completion:nil]; + +} + +%new +-(void)dismissSurgeTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [tutorialController dismissViewControllerAnimated:YES completion:nil]; + [[TDTweakManager sharedInstance] setBool:NO forKey:@"showSBTutorial" ID:BID]; +} +%end +%end + + +%ctor { + loadPrefs(); + NSString * path = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0]; + if ([path containsString:@"/Application"] || [path containsString:@"SpringBoard.app"]) { + %init(Tutorial); + } +} diff --git a/Surge/control b/Surge/control new file mode 100644 index 0000000..d183280 --- /dev/null +++ b/Surge/control @@ -0,0 +1,11 @@ +Package: com.titand3v.surge +Name: Surge +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal +Version: 1.1 +Section: Tweaks +Description: Low Power alert +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/surge/index.html +Icon: https://titand3v.github.io/depictions/surge/assets/icon.png diff --git a/Surge/layout/.DS_Store b/Surge/layout/.DS_Store new file mode 100644 index 0000000..09aee05 Binary files /dev/null and b/Surge/layout/.DS_Store differ diff --git a/Surge/layout/DEBIAN/postinst b/Surge/layout/DEBIAN/postinst new file mode 100755 index 0000000..c3aef53 --- /dev/null +++ b/Surge/layout/DEBIAN/postinst @@ -0,0 +1,8 @@ +echo "" +echo "" +echo "Thank you for installing Surge 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/Surge/layout/Library/Application Support/Surge.bundle/Assets/disable.png b/Surge/layout/Library/Application Support/Surge.bundle/Assets/disable.png new file mode 100644 index 0000000..5ad046a Binary files /dev/null and b/Surge/layout/Library/Application Support/Surge.bundle/Assets/disable.png differ diff --git a/Surge/layout/Library/Application Support/Surge.bundle/Assets/enable.png b/Surge/layout/Library/Application Support/Surge.bundle/Assets/enable.png new file mode 100644 index 0000000..e186066 Binary files /dev/null and b/Surge/layout/Library/Application Support/Surge.bundle/Assets/enable.png differ diff --git a/Unique/.DS_Store b/Unique/.DS_Store new file mode 100644 index 0000000..7443f80 Binary files /dev/null and b/Unique/.DS_Store differ diff --git a/Unique/Makefile b/Unique/Makefile new file mode 100644 index 0000000..2c9082a --- /dev/null +++ b/Unique/Makefile @@ -0,0 +1,15 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0:13.0 +export PREFIX = $(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ + +FINALPACKAGE = 1 +DEBUG = 0 + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/Unique/Tweak/Makefile b/Unique/Tweak/Makefile new file mode 100644 index 0000000..6f31da5 --- /dev/null +++ b/Unique/Tweak/Makefile @@ -0,0 +1,13 @@ +TWEAK_NAME = Unique + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Unique/Tweak/Unique.plist b/Unique/Tweak/Unique.plist new file mode 100644 index 0000000..e5c60ee --- /dev/null +++ b/Unique/Tweak/Unique.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.UIKit" ); }; } diff --git a/Unique/Tweak/Unique.xm b/Unique/Tweak/Unique.xm new file mode 100644 index 0000000..105cebb --- /dev/null +++ b/Unique/Tweak/Unique.xm @@ -0,0 +1,55 @@ +#import + +@interface UIKeyboardImpl : UIView ++ (id)activeInstance; +- (void)insertText:(NSString *)text; ++ (Class)layoutClassForCurrentInputMode; +@end + +@interface UIKeyboardInputMode : NSObject +- (NSString *)identifier; ++ (id)keyboardInputModeWithIdentifier:(id)arg1; +@end + +@interface UIKeyboardLayoutStar : UIView +@end + + +UISwipeGestureRecognizer* upSwipe; + +%group Unique +%hook UIKeyboardLayoutStar + +- (id)initWithFrame:(CGRect)arg1 { + + if (!upSwipe) { + upSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)]; + [upSwipe setDirection:UISwipeGestureRecognizerDirectionUp]; + [self addGestureRecognizer:upSwipe]; + } + + return %orig; + +} + +%new +- (void)handleSwipe:(UISwipeGestureRecognizer *)sender { + + if (sender.direction == UISwipeGestureRecognizerDirectionUp) { + + NSString *udid = (__bridge_transfer NSString *)MGCopyAnswer(kMGUniqueDeviceID); + UIKeyboardImpl* impl = [NSClassFromString(@"UIKeyboardImpl") activeInstance]; + [impl insertText:udid]; + } + +} +%end +%end + +%ctor { + + NSString * path = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0]; + if ([path containsString:@"/Application"] || [path containsString:@"SpringBoard.app"]) { + %init(Unique); + } +} diff --git a/Unique/control b/Unique/control new file mode 100644 index 0000000..0394fae --- /dev/null +++ b/Unique/control @@ -0,0 +1,11 @@ +Package: com.titand3v.unique +Name: Unique +Architecture: iphoneos-arm +Depends: mobilesubstrate, com.titand3v.libtitand3vuniversal +Version: 1.0 +Section: Tweaks +Description: Swipe up on keyboard to paste your device's UDID +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/unique/index.html +Icon: https://titand3v.github.io/depictions/unique/assets/icon.png diff --git a/Unique/layout/DEBIAN/postinst b/Unique/layout/DEBIAN/postinst new file mode 100755 index 0000000..4658909 --- /dev/null +++ b/Unique/layout/DEBIAN/postinst @@ -0,0 +1,8 @@ +echo "" +echo "" +echo "Thank you for installing Unique 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/iDevices/.DS_Store b/iDevices/.DS_Store new file mode 100644 index 0000000..6d23389 Binary files /dev/null and b/iDevices/.DS_Store differ diff --git a/iDevices/Makefile b/iDevices/Makefile new file mode 100644 index 0000000..4ca5c85 --- /dev/null +++ b/iDevices/Makefile @@ -0,0 +1,16 @@ +export ARCHS = arm64 arm64e +export TARGET = iphone:clang:14.0 + +FINALPACKAGE = 1 +DEBUG = 0 + +export CFLAGS = -include $(realpath NCCenter.h) + +INSTALL_TARGET_PROCESSES = SpringBoard +SUBPROJECTS += Tweak Prefs + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-stage:: + find . -name ".DS_STORE" -delete \ No newline at end of file diff --git a/iDevices/NCCenter.h b/iDevices/NCCenter.h new file mode 100644 index 0000000..0b2feb1 --- /dev/null +++ b/iDevices/NCCenter.h @@ -0,0 +1,9 @@ +#import + +@interface NSDistributedNotificationCenter : NSNotificationCenter ++ (instancetype)defaultCenter; +-(void)postNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3 deliverImmediately:(BOOL)arg4 ; +- (void)postNotificationName:(NSString *)name object:(NSString *)object userInfo:(NSDictionary *)userInfo; +-(id)addObserverForName:(id)arg1 object:(id)arg2 queue:(id)arg3 usingBlock:(/*^block*/id)arg4 ; +-(void)addObserver:(id)arg1 selector:(SEL)arg2 name:(id)arg3 object:(id)arg4 ; +@end \ No newline at end of file diff --git a/iDevices/Prefs/DVCPrimraryListController.h b/iDevices/Prefs/DVCPrimraryListController.h new file mode 100644 index 0000000..d88bad8 --- /dev/null +++ b/iDevices/Prefs/DVCPrimraryListController.h @@ -0,0 +1,29 @@ +#import +#import + +@interface OBButtonTray : UIView +@property (nonatomic,retain) UIVisualEffectView * effectView; +- (void)addButton:(id)arg1; +- (void)addCaptionText:(id)arg1;; +@end + +@interface OBBoldTrayButton : UIButton +-(void)setTitle:(id)arg1 forState:(unsigned long long)arg2; ++(id)buttonWithType:(long long)arg1; +@end + +@interface OBWelcomeController : UIViewController +@property (nonatomic,retain) UIView * viewIfLoaded; +@property (nonatomic,strong) UIColor * backgroundColor; +- (OBButtonTray *)buttonTray; +- (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3; +- (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3; +@end + + +@interface DVCPrimraryListController : TDPrimraryController { + OBWelcomeController *onboardingController; + OBWelcomeController *updateController; +} + +@end diff --git a/iDevices/Prefs/DVCPrimraryListController.m b/iDevices/Prefs/DVCPrimraryListController.m new file mode 100644 index 0000000..8f524c5 --- /dev/null +++ b/iDevices/Prefs/DVCPrimraryListController.m @@ -0,0 +1,115 @@ +#include "DVCPrimraryListController.h" + +@implementation DVCPrimraryListController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Primrary" target:self]; + } + + return _specifiers; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[TDPrefsManager sharedInstance] initWithBundleID:@"com.TitanD3v.iDevicesPrefs" tweakName:@"iDevices" prefsBundle:@"iDevicesPrefs.bundle"]; + + [[TDPrefsManager sharedInstance] bannerTitle:@"iDevices" subtitle:@"Coded with 🤍" devName:@"TitanD3v" coverImagePath:@"/Assets/Banner/cover-image.png" showCoverImage:YES iconPath:@"/Assets/Banner/banner-icon.png" iconTint:NO]; + + [[TDPrefsManager sharedInstance] changelogPlistPath:@"/Assets/Changelog/changelog.plist" currentVersion:@"Version 1.0"]; + + [[TDPrefsManager sharedInstance] useAssetsFromLibrary:YES]; + +} + +-(void)presentTutorialVC { + + [[TDUtilities sharedInstance] haptic:0]; + + onboardingController = [[OBWelcomeController alloc] initWithTitle:@"User Guide" detailText:@"A walk through tutorial how to use iDevices" icon:[[UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/iDevicesPrefs.bundle/Assets/Banner/banner-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]]; + + [onboardingController addBulletedListItemWithTitle:@"Your time" description:@"Please take a few minutes of your time to read through to get started." image:[UIImage systemImageNamed:@"timer"]]; + + [onboardingController addBulletedListItemWithTitle:@"Main page" description:@"On the main page, there's menu icon on the navigation bar it will present the drawer when tapped. You will find the social media details, changelog, backup/restore, tweak list, profile and crew list." image:[UIImage systemImageNamed:@"square.stack.fill"]]; + + [onboardingController addBulletedListItemWithTitle:@"Report a bug" description:@"If you are experiencing a bug or any other issues, you can report a bug from this page below the close button, it will bring up the Bug Report page. You can select the categories, write description about a bug, attach a .txt file, photo, provide URL link for the pastebin or any pasteboard website also you can attach all of them if you want. Once you submit a bug report and our team will be in touch with you within 48 hours. If you haven't heard anything from us and please don't hesitate to get in touch with us through social media." image:[UIImage systemImageNamed:@"ant.circle.fill"]]; + + OBBoldTrayButton* dismissButton = [OBBoldTrayButton buttonWithType:1]; + [dismissButton addTarget:self action:@selector(dismissTutorialVC) forControlEvents:UIControlEventTouchUpInside]; + [dismissButton setTitle:@"Close" forState:UIControlStateNormal]; + [dismissButton setClipsToBounds:YES]; + [dismissButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [dismissButton.layer setCornerRadius:15]; + [onboardingController.buttonTray addButton:dismissButton]; + + onboardingController.buttonTray.effectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + UIVisualEffectView *tutorialVisualEffectView = [[UIVisualEffectView alloc] initWithFrame:onboardingController.viewIfLoaded.bounds]; + + tutorialVisualEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + + [onboardingController.viewIfLoaded insertSubview:tutorialVisualEffectView atIndex:0]; + onboardingController.viewIfLoaded.backgroundColor = UIColor.clearColor; + + [onboardingController.buttonTray addCaptionText:@"Thank you for installing iDevices"]; + + onboardingController.modalPresentationStyle = UIModalPresentationPageSheet; + onboardingController.modalInPresentation = YES; + [self presentViewController:onboardingController animated:YES completion:nil]; + + UIView *reportView = [[UIView alloc] init]; + reportView.backgroundColor = UIColor.clearColor; + [onboardingController.buttonTray addSubview:reportView]; + + reportView.translatesAutoresizingMaskIntoConstraints = NO; + [reportView.topAnchor constraintEqualToAnchor:dismissButton.bottomAnchor constant:10].active = YES; + [[reportView centerXAnchor] constraintEqualToAnchor:onboardingController.buttonTray.centerXAnchor].active = true; + [reportView.widthAnchor constraintEqualToConstant:140].active = YES; + [reportView.heightAnchor constraintEqualToConstant:40].active = YES; + + + UIImageView *bugImage = [[UIImageView alloc] init]; + bugImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + bugImage.tintColor = [[TDAppearance sharedInstance] tintColour]; + [reportView addSubview:bugImage]; + + bugImage.translatesAutoresizingMaskIntoConstraints = NO; + [bugImage.leadingAnchor constraintEqualToAnchor:reportView.leadingAnchor constant:10].active = YES; + [[bugImage centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + [bugImage.widthAnchor constraintEqualToConstant:30].active = YES; + [bugImage.heightAnchor constraintEqualToConstant:30].active = YES; + + + UILabel *reportLabel = [[UILabel alloc] init]; + reportLabel.text = @"Report a bug"; + reportLabel.textColor = [[TDAppearance sharedInstance] tintColour]; + reportLabel.textAlignment = NSTextAlignmentLeft; + [reportView addSubview:reportLabel]; + + reportLabel.translatesAutoresizingMaskIntoConstraints = NO; + [reportLabel.leadingAnchor constraintEqualToAnchor:bugImage.trailingAnchor constant:5].active = YES; + [[reportLabel centerYAnchor] constraintEqualToAnchor:reportView.centerYAnchor].active = true; + + [reportView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentReportBugVC)]]; + +} + + +-(void)dismissTutorialVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentReportBugVC { + [[TDUtilities sharedInstance] haptic:0]; + [onboardingController dismissViewControllerAnimated:YES completion:nil]; + + TDReportBugViewController *bugVC = [[TDReportBugViewController alloc] init]; + bugVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + [self presentViewController:bugVC animated:YES completion:nil]; +} + +@end diff --git a/iDevices/Prefs/DVCSecondaryListController.h b/iDevices/Prefs/DVCSecondaryListController.h new file mode 100644 index 0000000..ea770ae --- /dev/null +++ b/iDevices/Prefs/DVCSecondaryListController.h @@ -0,0 +1,12 @@ +#import +#import + +@interface DVCGestureController : TDSecondaryController +@end + +@interface DVCColourController : TDSecondaryController +@end + +@interface DVCMiscellaneousController : TDSecondaryController +@end + diff --git a/iDevices/Prefs/DVCSecondaryListController.m b/iDevices/Prefs/DVCSecondaryListController.m new file mode 100644 index 0000000..0bc6765 --- /dev/null +++ b/iDevices/Prefs/DVCSecondaryListController.m @@ -0,0 +1,39 @@ +#include "DVCSecondaryListController.h" + +@implementation DVCGestureController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Gesture" target:self]; + } + + return _specifiers; +} + +@end + + +@implementation DVCColourController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Colour" target:self]; + } + + return _specifiers; +} + +@end + + +@implementation DVCMiscellaneousController + +- (NSArray *)specifiers { + if (!_specifiers) { + _specifiers = [self loadSpecifiersFromPlistName:@"Miscellaneous" target:self]; + } + + return _specifiers; +} + +@end diff --git a/iDevices/Prefs/Makefile b/iDevices/Prefs/Makefile new file mode 100644 index 0000000..1f9d671 --- /dev/null +++ b/iDevices/Prefs/Makefile @@ -0,0 +1,15 @@ +BUNDLE_NAME = iDevicesPrefs + +$(BUNDLE_NAME)_FILES = $(wildcard *.m Purchase/*.m) +$(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles +$(BUNDLE_NAME)_FRAMEWORKS = UIKit +$(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences OnBoardingKit +$(BUNDLE_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations +$(BUNDLE_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/bundle.mk + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) + $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/iDevicesPrefs.plist$(ECHO_END) diff --git a/iDevices/Prefs/Resources/Assets/Banner/banner-icon.png b/iDevices/Prefs/Resources/Assets/Banner/banner-icon.png new file mode 100644 index 0000000..cece39c Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Banner/banner-icon.png differ diff --git a/iDevices/Prefs/Resources/Assets/Banner/cover-image.png b/iDevices/Prefs/Resources/Assets/Banner/cover-image.png new file mode 100644 index 0000000..4987a4d Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Banner/cover-image.png differ diff --git a/iDevices/Prefs/Resources/Assets/Cell/cell-banner.png b/iDevices/Prefs/Resources/Assets/Cell/cell-banner.png new file mode 100644 index 0000000..67f24fc Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Cell/cell-banner.png differ diff --git a/iDevices/Prefs/Resources/Assets/Cell/prefs-icon@2x.png b/iDevices/Prefs/Resources/Assets/Cell/prefs-icon@2x.png new file mode 100644 index 0000000..65412d6 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Cell/prefs-icon@2x.png differ diff --git a/iDevices/Prefs/Resources/Assets/Cell/prefs-icon@3x.png b/iDevices/Prefs/Resources/Assets/Cell/prefs-icon@3x.png new file mode 100644 index 0000000..7756a81 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Cell/prefs-icon@3x.png differ diff --git a/iDevices/Prefs/Resources/Assets/Changelog/changelog.plist b/iDevices/Prefs/Resources/Assets/Changelog/changelog.plist new file mode 100644 index 0000000..61d43ad --- /dev/null +++ b/iDevices/Prefs/Resources/Assets/Changelog/changelog.plist @@ -0,0 +1,22 @@ + + + + + + + Date + 9th May 2021 + Version + v1.0 + ChangelogDescription + + Initial Release... + + updateCategories + + 0 + + + + + diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss1.png b/iDevices/Prefs/Resources/Assets/Payment/ss1.png new file mode 100644 index 0000000..e66c519 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss1.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss10.png b/iDevices/Prefs/Resources/Assets/Payment/ss10.png new file mode 100644 index 0000000..da68570 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss10.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss11.png b/iDevices/Prefs/Resources/Assets/Payment/ss11.png new file mode 100644 index 0000000..613fa9b Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss11.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss12.png b/iDevices/Prefs/Resources/Assets/Payment/ss12.png new file mode 100644 index 0000000..bb52c42 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss12.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss13.png b/iDevices/Prefs/Resources/Assets/Payment/ss13.png new file mode 100644 index 0000000..ecda753 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss13.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss2.png b/iDevices/Prefs/Resources/Assets/Payment/ss2.png new file mode 100644 index 0000000..5168053 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss2.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss3.png b/iDevices/Prefs/Resources/Assets/Payment/ss3.png new file mode 100644 index 0000000..fc35f35 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss3.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss4.png b/iDevices/Prefs/Resources/Assets/Payment/ss4.png new file mode 100644 index 0000000..a17fdc2 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss4.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss5.png b/iDevices/Prefs/Resources/Assets/Payment/ss5.png new file mode 100644 index 0000000..5dd1323 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss5.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss6.png b/iDevices/Prefs/Resources/Assets/Payment/ss6.png new file mode 100644 index 0000000..828c5c7 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss6.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss7.png b/iDevices/Prefs/Resources/Assets/Payment/ss7.png new file mode 100644 index 0000000..808a4e0 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss7.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss8.png b/iDevices/Prefs/Resources/Assets/Payment/ss8.png new file mode 100644 index 0000000..55301f2 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss8.png differ diff --git a/iDevices/Prefs/Resources/Assets/Payment/ss9.png b/iDevices/Prefs/Resources/Assets/Payment/ss9.png new file mode 100644 index 0000000..48b3769 Binary files /dev/null and b/iDevices/Prefs/Resources/Assets/Payment/ss9.png differ diff --git a/iDevices/Prefs/Resources/Colour.plist b/iDevices/Prefs/Resources/Colour.plist new file mode 100644 index 0000000..0dbe63d --- /dev/null +++ b/iDevices/Prefs/Resources/Colour.plist @@ -0,0 +1,621 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable Colour + + + + cellClass + TDEnableCell + default + + key + toggleCustomColour + disabledTitle + Disable Colour + enabledTitle + Enable Colour + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Custom Colour + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Cover Icon + subtitle + Colour + default + FFFFFF + key + coverIconColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Cover Title + subtitle + Colour + default + FFFFFF + key + coverTitleColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Accent + subtitle + Colour + default + FFFFFF + key + accentColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Background + subtitle + Colour + default + FFFFFF + key + backgroundColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Grabber + subtitle + Colour + default + FFFFFF + key + grabberColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Font + subtitle + Colour + default + FFFFFF + key + fontColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Secondary Font + subtitle + Colour + default + FFFFFF + key + secondaryFontColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Title Font + subtitle + Colour + default + FFFFFF + key + titleFontColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Subtitle Font + subtitle + Colour + default + FFFFFF + key + subtitleFontColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Cell + subtitle + Colour + default + FFFFFF + key + cellColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Nav Bar Button + subtitle + Colour + default + FFFFFF + key + navBarButtonColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Backup Start Button + subtitle + Colour + default + FFFFFF + key + backupStartButtonColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Backup Cancel Button + subtitle + Colour + default + FFFFFF + key + backupCancelButtonColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Backup Progress + subtitle + Colour + default + FFFFFF + key + backupProgressColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Battery Ring + subtitle + Colour + default + FFFFFF + key + batteryRingColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Low Battery + subtitle + Colour + default + FFFFFF + key + batteryLowColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Normal Battery + subtitle + Colour + default + FFFFFF + key + batteryNormalColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Total RAM + subtitle + Colour + default + FFFFFF + key + totalRamColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Free RAM + subtitle + Colour + default + FFFFFF + key + freeRamColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Used RAM + subtitle + Colour + default + FFFFFF + key + usedRamColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Red + subtitle + Colour + default + FFFFFF + key + redColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Orange + subtitle + Colour + default + FFFFFF + key + orangeColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Yellow + subtitle + Colour + default + FFFFFF + key + yellowColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Green + subtitle + Colour + default + FFFFFF + key + greenColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Teal + subtitle + Colour + default + FFFFFF + key + tealColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Indigo + subtitle + Colour + default + FFFFFF + key + indigoColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDColourPickerCell + title + Pink + subtitle + Colour + default + FFFFFF + key + pinkColour + iconName + colour + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + title + + + diff --git a/iDevices/Prefs/Resources/Gesture.plist b/iDevices/Prefs/Resources/Gesture.plist new file mode 100644 index 0000000..57c4bb4 --- /dev/null +++ b/iDevices/Prefs/Resources/Gesture.plist @@ -0,0 +1,209 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Stausbar + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleStatusbarLongPressGesture + title + Enable + subtitle + Long press + iconName + switch + showTips + + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleStatusbarDoubleTapGesture + title + Enable + subtitle + Double tap + iconName + switch + showTips + + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleStatusbarTripleTapGesture + title + Enable + subtitle + Triple tap + iconName + switch + showTips + + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Dock + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleDockGesture + title + Enable + subtitle + Double tap + iconName + switch + showTips + + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Volume + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleVolumeUpGesture + title + Enable + subtitle + Volume Up Button + iconName + switch + showTips + + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleVolumeDownGesture + title + Enable + subtitle + Volume Down Button + iconName + switch + showTips + + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Shake + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleShakeGesture + title + Enable + subtitle + Shake Motion + iconName + switch + showTips + + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + title + + + diff --git a/iDevices/Prefs/Resources/Info.plist b/iDevices/Prefs/Resources/Info.plist new file mode 100644 index 0000000..8e83309 --- /dev/null +++ b/iDevices/Prefs/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + iDevicesPrefs + CFBundleIdentifier + com.titand3v.idevicesprefs + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSPrincipalClass + DVCPrimraryListController + + diff --git a/iDevices/Prefs/Resources/Miscellaneous.plist b/iDevices/Prefs/Resources/Miscellaneous.plist new file mode 100644 index 0000000..41a85b0 --- /dev/null +++ b/iDevices/Prefs/Resources/Miscellaneous.plist @@ -0,0 +1,132 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Cover + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleCustomCoverImage + title + Enable + subtitle + Custom Cover Image + iconName + switch + showTips + + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSLinkCell + cellClass + TDImagePickerCell + title + Choose + subtitle + Cover Image + action + chooseImage + key + customCoverImage + usesJPEG + + compressionQuality + 1.0 + iconName + photo + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Haptic + + + + cell + PSSwitchCell + cellClass + TDSwitchCell + default + + key + toggleHapticFeedback + title + Enable + subtitle + Haptic Feedback + iconName + switch + showTips + + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + cell + PSSegmentCell + cellClass + TDSegmentCell + key + hapticFeedbackStrength + default + 0 + validTitles + + Light + Medium + Heavy + + validValues + + 0 + 1 + 2 + + title + Type + showTips + + defaults + com.TitanD3v.iDevicesPrefs + PostNotification + com.TitanD3v.iDevicesPrefs.settingschanged + + + + title + + + diff --git a/iDevices/Prefs/Resources/Primrary.plist b/iDevices/Prefs/Resources/Primrary.plist new file mode 100644 index 0000000..1ab824f --- /dev/null +++ b/iDevices/Prefs/Resources/Primrary.plist @@ -0,0 +1,82 @@ + + + + + items + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Enable/Disable + + + + cellClass + TDEnableCell + default + + key + toggleiDevices + disabledTitle + Disable iDevices + enabledTitle + Enable iDevices + disabledColour + B92F2F + enabledColour + 43EB1F + customIcon + + disabledIconPath + Assets/example-icon.png + enabledIconPath + Assets/example-icon.png + defaults + com.TitanD3v.iDevicesPrefsPrefs + PostNotification + com.TitanD3v.iDevicesPrefsPrefs.settingschanged + + + + cell + PSGroupCell + headerCellClass + TDHeaderCell + title + Categories + + + + cellClass + TDGridCell + leftTitle + Gesture + leftIconName + button + leftClass + DVCGestureController + middleTitle + Colour + middleIconName + colour + middleClass + DVCColourController + rightTitle + Miscellaneous + rightIconName + misc + rightClass + DVCMiscellaneousController + classID + primrary + + + + title + + + diff --git a/iDevices/Prefs/entry.plist b/iDevices/Prefs/entry.plist new file mode 100644 index 0000000..4881b74 --- /dev/null +++ b/iDevices/Prefs/entry.plist @@ -0,0 +1,21 @@ + + + + + entry + + bundle + iDevicesPrefs + cell + PSLinkCell + detail + DVCPrimraryListController + icon + Assets/Cell/prefs-icon.png + isController + + label + iDevices + + + diff --git a/iDevices/Tweak/IDEVICES/About/AboutViewController.h b/iDevices/Tweak/IDEVICES/About/AboutViewController.h new file mode 100644 index 0000000..463a41e --- /dev/null +++ b/iDevices/Tweak/IDEVICES/About/AboutViewController.h @@ -0,0 +1,24 @@ +#import +#import "Colour-Scheme.h" +#import "DataManager.h" +#import "CDHeaderView.h" +#import "AboutCell.h" +#import "SectionCellHeaderView.h" +#import "AboutDeviceInfo.h" + +@interface AboutViewController : UIViewController +@property (nonatomic, retain) CDHeaderView *headerView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *generalArray; +@property (nonatomic, retain) NSMutableArray *networkArray; +@property (nonatomic, retain) NSMutableArray *batteryArray; +@property (nonatomic, retain) NSMutableArray *accessoriesArray; +@property (nonatomic, retain) NSMutableArray *screenArray; +@property (nonatomic, retain) NSMutableArray *processorArray; +@property (nonatomic, retain) NSMutableArray *motionArray; +@property (nonatomic, retain) NSMutableArray *localisationArray; +@property (nonatomic, retain) NSMutableArray *debugArray; +@property (nonatomic, retain) UIView *containerView; +@property (nonatomic, retain) UIImageView *headerIcon; +@property (nonatomic, retain) UILabel *headerTitle; +@end diff --git a/iDevices/Tweak/IDEVICES/About/AboutViewController.m b/iDevices/Tweak/IDEVICES/About/AboutViewController.m new file mode 100644 index 0000000..dbdb9ed --- /dev/null +++ b/iDevices/Tweak/IDEVICES/About/AboutViewController.m @@ -0,0 +1,414 @@ +#import "AboutViewController.h" + +@implementation AboutViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [UIColor accentColour]; + self.view.tintColor = [UIColor accentColour]; + + [self getInfoData]; + [self layoutHeaderView]; + [self layoutCollectionView]; +} + + +-(void)getInfoData { + + self.generalArray = [[AboutDeviceInfo sharedInstance] generalArray]; + self.networkArray = [[AboutDeviceInfo sharedInstance] networkArray]; + self.batteryArray = [[AboutDeviceInfo sharedInstance] batteryArray]; + self.accessoriesArray = [[AboutDeviceInfo sharedInstance] accessoriesArray]; + self.screenArray = [[AboutDeviceInfo sharedInstance] screenArray]; + self.processorArray = [[AboutDeviceInfo sharedInstance] processorArray]; + self.motionArray = [[AboutDeviceInfo sharedInstance] motionArray]; + self.localisationArray = [[AboutDeviceInfo sharedInstance] localisationArray]; + self.debugArray = [[AboutDeviceInfo sharedInstance] debugArray]; +} + + +-(void)layoutHeaderView { + + self.containerView = [[UIView alloc] init]; + self.containerView.layer.cornerRadius = 25; + self.containerView.layer.cornerCurve = kCACornerCurveContinuous; + self.containerView.layer.maskedCorners = 12; + self.containerView.clipsToBounds = YES; + [self.view addSubview:self.containerView]; + + [self.containerView size:CGSizeMake(self.view.frame.size.width, 200)]; + [self.containerView x:self.view.centerXAnchor]; + [self.containerView top:self.view.topAnchor padding:0]; + + + UIImageView *wallpaper = [[UIImageView alloc] init]; + if (toggleCustomCoverImage) { + wallpaper.image = [UIImage imageWithData:customCoverImage]; + } else { + wallpaper.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/iDevices.bundle/Assets/Default/cover-image.png"]; + } + wallpaper.contentMode = UIViewContentModeScaleAspectFill; + [self.containerView addSubview:wallpaper]; + + [wallpaper fill]; + + + self.headerView = [[CDHeaderView alloc] initWithTitle:@"" accent:[UIColor accentColour] leftIcon:@"chevron.left" leftAction:@selector(pushBackVC)]; + self.headerView.leftButton.backgroundColor = [UIColor.navBarButtonColour colorWithAlphaComponent:0.5]; + [self.containerView addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.containerView.centerXAnchor]; + [self.headerView top:self.containerView.topAnchor padding:0]; + + + self.headerIcon = [[UIImageView alloc] init]; + self.headerIcon.contentMode = UIViewContentModeScaleAspectFit; + self.headerIcon.image = [UIImage systemImageNamed:@"info.circle.fill"]; + self.headerIcon.tintColor = UIColor.coverIconColour; + [self.containerView addSubview:self.headerIcon]; + + [self.headerIcon size:CGSizeMake(75, 75)]; + [self.headerIcon x:self.containerView.centerXAnchor]; + [self.headerIcon top:self.headerView.bottomAnchor padding:-10]; + + + self.headerTitle = [[UILabel alloc] init]; + self.headerTitle.textAlignment = NSTextAlignmentCenter; + self.headerTitle.font = [UIFont systemFontOfSize:18 weight:UIFontWeightBold]; + self.headerTitle.textColor = UIColor.coverTitleColour; + self.headerTitle.text = @"About"; + [self.containerView addSubview:self.headerTitle]; + + [self.headerTitle x:self.containerView.centerXAnchor]; + [self.headerTitle top:self.headerIcon.bottomAnchor padding:10]; + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[AboutCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.collectionView registerClass:[SectionCellHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; + [self.view addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + + [self.collectionView top:self.containerView.bottomAnchor padding:0]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + [self.collectionView bottom:self.view.bottomAnchor padding:-5]; +} + + +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { + return 9; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { + return CGSizeMake(self.view.frame.size.width, 45); +} + + +-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + UICollectionReusableView *reusableview = nil; + + if (kind == UICollectionElementKindSectionHeader) { + + SectionCellHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; + if (indexPath.section == 0) { + headerView.headerLabel.text = @"iPhone"; + } else if (indexPath.section == 1) { + headerView.headerLabel.text = @"Network"; + } else if (indexPath.section == 2) { + headerView.headerLabel.text = @"Battery"; + } else if (indexPath.section == 3) { + headerView.headerLabel.text = @"Accessories"; + } else if (indexPath.section == 4) { + headerView.headerLabel.text = @"Screen"; + } else if (indexPath.section == 5) { + headerView.headerLabel.text = @"Processors"; + } else if (indexPath.section == 6) { + headerView.headerLabel.text = @"Motion"; + } else if (indexPath.section == 7) { + headerView.headerLabel.text = @"Localisation"; + } else if (indexPath.section == 8) { + headerView.headerLabel.text = @"Debug"; + } + reusableview = headerView; + } + + return reusableview; + +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + if (section == 0) { + return self.generalArray.count; + } else if (section == 1) { + return self.networkArray.count; + } else if (section == 2) { + return self.batteryArray.count; + } else if (section == 3) { + return self.accessoriesArray.count; + } else if (section == 4) { + return self.screenArray.count; + } else if (section == 5) { + return self.processorArray.count; + } else if (section == 6) { + return self.motionArray.count; + } else if (section == 7) { + return self.localisationArray.count; + } else { + return self.debugArray.count; + } +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + AboutCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + if (indexPath.section == 0) { + + InfoModel *info = self.generalArray[indexPath.row]; + cell.iconView.backgroundColor = [info.colour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = info.colour; + cell.iconImage.image = [UIImage systemImageNamed:info.icon]; + cell.titleLabel.text = info.title; + cell.subtitleLabel.text = info.subtitle; + + } else if (indexPath.section == 1) { + + InfoModel *info = self.networkArray[indexPath.row]; + cell.iconView.backgroundColor = [info.colour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = info.colour; + cell.iconImage.image = [UIImage systemImageNamed:info.icon]; + cell.titleLabel.text = info.title; + cell.subtitleLabel.text = info.subtitle; + + } else if (indexPath.section == 2) { + + InfoModel *info = self.batteryArray[indexPath.row]; + cell.iconView.backgroundColor = [info.colour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = info.colour; + cell.iconImage.image = [UIImage systemImageNamed:info.icon]; + cell.titleLabel.text = info.title; + cell.subtitleLabel.text = info.subtitle; + + } else if (indexPath.section == 3) { + + InfoModel *info = self.accessoriesArray[indexPath.row]; + cell.iconView.backgroundColor = [info.colour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = info.colour; + cell.iconImage.image = [UIImage systemImageNamed:info.icon]; + cell.titleLabel.text = info.title; + cell.subtitleLabel.text = info.subtitle; + + } else if (indexPath.section == 4) { + + InfoModel *info = self.screenArray[indexPath.row]; + cell.iconView.backgroundColor = [info.colour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = info.colour; + cell.iconImage.image = [UIImage systemImageNamed:info.icon]; + cell.titleLabel.text = info.title; + cell.subtitleLabel.text = info.subtitle; + + } else if (indexPath.section == 5) { + + InfoModel *info = self.processorArray[indexPath.row]; + cell.iconView.backgroundColor = [info.colour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = info.colour; + cell.iconImage.image = [UIImage systemImageNamed:info.icon]; + cell.titleLabel.text = info.title; + cell.subtitleLabel.text = info.subtitle; + + } else if (indexPath.section == 6) { + + InfoModel *info = self.motionArray[indexPath.row]; + cell.iconView.backgroundColor = [info.colour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = info.colour; + cell.iconImage.image = [UIImage systemImageNamed:info.icon]; + cell.titleLabel.text = info.title; + cell.subtitleLabel.text = info.subtitle; + + } else if (indexPath.section == 7) { + + InfoModel *info = self.localisationArray[indexPath.row]; + cell.iconView.backgroundColor = [info.colour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = info.colour; + cell.iconImage.image = [UIImage systemImageNamed:info.icon]; + cell.titleLabel.text = info.title; + cell.subtitleLabel.text = info.subtitle; + + } else if (indexPath.section == 8) { + + InfoModel *info = self.debugArray[indexPath.row]; + cell.iconView.backgroundColor = [info.colour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = info.colour; + cell.iconImage.image = [UIImage systemImageNamed:info.icon]; + cell.titleLabel.text = info.title; + cell.subtitleLabel.text = info.subtitle; + + } + + + return cell; + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat width = self.view.frame.size.width-40; + return CGSizeMake(width, 65); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 20.0; +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + if (indexPath.section == 0) { + + InfoModel *info = self.generalArray[indexPath.row]; + NSString *title = info.title; + NSString *subtitle = info.subtitle; + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = [NSString stringWithFormat:@"%@\n%@", title, subtitle]; + [self showAlertWithTitle:@"" subtitle:[NSString stringWithFormat:@"The details for %@ was copied to your clipboard.", title]]; + + } else if (indexPath.section == 1) { + + InfoModel *info = self.networkArray[indexPath.row]; + NSString *title = info.title; + NSString *subtitle = info.subtitle; + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = [NSString stringWithFormat:@"%@\n%@", title, subtitle]; + [self showAlertWithTitle:@"" subtitle:[NSString stringWithFormat:@"The details for %@ was copied to your clipboard.", title]]; + + } else if (indexPath.section == 2) { + + InfoModel *info = self.batteryArray[indexPath.row]; + NSString *title = info.title; + NSString *subtitle = info.subtitle; + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = [NSString stringWithFormat:@"%@\n%@", title, subtitle]; + [self showAlertWithTitle:@"" subtitle:[NSString stringWithFormat:@"The details for %@ was copied to your clipboard.", title]]; + + } else if (indexPath.section == 3) { + + InfoModel *info = self.accessoriesArray[indexPath.row]; + NSString *title = info.title; + NSString *subtitle = info.subtitle; + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = [NSString stringWithFormat:@"%@\n%@", title, subtitle]; + [self showAlertWithTitle:@"" subtitle:[NSString stringWithFormat:@"The details for %@ was copied to your clipboard.", title]]; + + } else if (indexPath.section == 4) { + + InfoModel *info = self.screenArray[indexPath.row]; + NSString *title = info.title; + NSString *subtitle = info.subtitle; + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = [NSString stringWithFormat:@"%@\n%@", title, subtitle]; + [self showAlertWithTitle:@"" subtitle:[NSString stringWithFormat:@"The details for %@ was copied to your clipboard.", title]]; + + } else if (indexPath.section == 5) { + + InfoModel *info = self.processorArray[indexPath.row]; + NSString *title = info.title; + NSString *subtitle = info.subtitle; + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = [NSString stringWithFormat:@"%@\n%@", title, subtitle]; + [self showAlertWithTitle:@"" subtitle:[NSString stringWithFormat:@"The details for %@ was copied to your clipboard.", title]]; + + } else if (indexPath.section == 6) { + + InfoModel *info = self.motionArray[indexPath.row]; + NSString *title = info.title; + NSString *subtitle = info.subtitle; + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = [NSString stringWithFormat:@"%@\n%@", title, subtitle]; + [self showAlertWithTitle:@"" subtitle:[NSString stringWithFormat:@"The details for %@ was copied to your clipboard.", title]]; + + } else if (indexPath.section == 7) { + + InfoModel *info = self.localisationArray[indexPath.row]; + NSString *title = info.title; + NSString *subtitle = info.subtitle; + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = [NSString stringWithFormat:@"%@\n%@", title, subtitle]; + [self showAlertWithTitle:@"" subtitle:[NSString stringWithFormat:@"The details for %@ was copied to your clipboard.", title]]; + + } else if (indexPath.section == 8) { + + InfoModel *info = self.debugArray[indexPath.row]; + NSString *title = info.title; + NSString *subtitle = info.subtitle; + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = [NSString stringWithFormat:@"%@\n%@", title, subtitle]; + [self showAlertWithTitle:@"" subtitle:[NSString stringWithFormat:@"The details for %@ was copied to your clipboard.", title]]; + + } + +} + + +-(void)pushBackVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Apps/AppsViewController.h b/iDevices/Tweak/IDEVICES/Apps/AppsViewController.h new file mode 100644 index 0000000..68e0fdb --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Apps/AppsViewController.h @@ -0,0 +1,51 @@ +#import +#import "Colour-Scheme.h" +#import "DataManager.h" +#import "CDHeaderView.h" +#import "AppCell.h" +#import + +@interface AppsViewController : UIViewController +@property (nonatomic, retain) CDHeaderView *headerView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) UIView *containerView; +@property (nonatomic, retain) UIImageView *headerIcon; +@property (nonatomic, retain) UILabel *headerTitle; +@end + + +@interface SBIconController: UIViewController +- (UIImage *)iconImageForIdentifier:(NSString *)identifier; +@property (nonatomic, copy, readonly) NSArray * allApplications; ++ (id)sharedInstance; +@end + +@interface UIImage (Private) ++(id)_applicationIconImageForBundleIdentifier:(NSString*)displayIdentifier format:(int)form scale:(CGFloat)scale; +@end + +@interface UIApplication (Libra) +- (BOOL)launchApplicationWithIdentifier:(id)arg1 suspended:(BOOL)arg2; +@end + +@interface SBApplication +@property (nonatomic,readonly) NSString * displayName; +@property (nonatomic,readonly) NSString * bundleIdentifier; +- (BOOL)isSystemApplication; +- (BOOL)isInternalApplication; +- (id)badgeValue; +@end + +@interface LSBundleProxy +@property(readonly, nonatomic) NSURL *bundleContainerURL; +@property(readonly, nonatomic) NSURL *bundleURL; +@property(readonly, nonatomic) NSURL *dataContainerURL; +- (id)localizedName; +@end + +@interface LSApplicationProxy : LSBundleProxy ++ (LSApplicationProxy *)applicationProxyForIdentifier:(id)arg1; +@end + + + diff --git a/iDevices/Tweak/IDEVICES/Apps/AppsViewController.xm b/iDevices/Tweak/IDEVICES/Apps/AppsViewController.xm new file mode 100644 index 0000000..1bcbf35 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Apps/AppsViewController.xm @@ -0,0 +1,255 @@ +#import "AppsViewController.h" +#import + +NSMutableDictionary *appsDict; + +@implementation AppsViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [UIColor accentColour]; + self.view.tintColor = [UIColor accentColour]; + + appsDict = [[NSMutableDictionary alloc] init]; + [self getSystemApps]; + + + [self layoutHeaderView]; + [self layoutCollectionView]; +} + + +-(void)layoutHeaderView { + + self.containerView = [[UIView alloc] init]; + self.containerView.layer.cornerRadius = 25; + self.containerView.layer.cornerCurve = kCACornerCurveContinuous; + self.containerView.layer.maskedCorners = 12; + self.containerView.clipsToBounds = YES; + [self.view addSubview:self.containerView]; + + [self.containerView size:CGSizeMake(self.view.frame.size.width, 200)]; + [self.containerView x:self.view.centerXAnchor]; + [self.containerView top:self.view.topAnchor padding:0]; + + + UIImageView *wallpaper = [[UIImageView alloc] init]; + if (toggleCustomCoverImage) { + wallpaper.image = [UIImage imageWithData:customCoverImage]; + } else { + wallpaper.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/iDevices.bundle/Assets/Default/cover-image.png"]; + } + wallpaper.contentMode = UIViewContentModeScaleAspectFill; + [self.containerView addSubview:wallpaper]; + + [wallpaper fill]; + + + self.headerView = [[CDHeaderView alloc] initWithTitle:@"" accent:[UIColor accentColour] leftIcon:@"chevron.left" leftAction:@selector(pushBackVC)]; + self.headerView.leftButton.backgroundColor = [UIColor.navBarButtonColour colorWithAlphaComponent:0.5]; + [self.containerView addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.containerView.centerXAnchor]; + [self.headerView top:self.containerView.topAnchor padding:0]; + + + self.headerIcon = [[UIImageView alloc] init]; + self.headerIcon.contentMode = UIViewContentModeScaleAspectFit; + self.headerIcon.image = [UIImage systemImageNamed:@"apps.iphone"]; + self.headerIcon.tintColor = UIColor.coverIconColour; + [self.containerView addSubview:self.headerIcon]; + + [self.headerIcon size:CGSizeMake(75, 75)]; + [self.headerIcon x:self.containerView.centerXAnchor]; + [self.headerIcon top:self.headerView.bottomAnchor padding:-10]; + + + self.headerTitle = [[UILabel alloc] init]; + self.headerTitle.textAlignment = NSTextAlignmentCenter; + self.headerTitle.font = [UIFont systemFontOfSize:18 weight:UIFontWeightBold]; + self.headerTitle.textColor = UIColor.coverTitleColour; + self.headerTitle.text = @"Apps"; + [self.containerView addSubview:self.headerTitle]; + + [self.headerTitle x:self.containerView.centerXAnchor]; + [self.headerTitle top:self.headerIcon.bottomAnchor padding:10]; + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[AppCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.view addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + + [self.collectionView top:self.containerView.bottomAnchor padding:5]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + [self.collectionView bottom:self.view.bottomAnchor padding:-5]; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return [appsDict count]; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + AppCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + NSArray *arrayList = [appsDict allKeys]; + arrayList = [arrayList sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + NSMutableDictionary *appData = appsDict[arrayList[indexPath.row]]; + + NSString *openedString = [[TDTweakManager sharedInstance] objectForKey:appData[@"appId"] defaultValue:@"N/A" ID:BID]; + + cell.titleLabel.text = appData[@"appName"]; + if ([openedString isEqualToString:@"N/A"]) { + cell.subtitleLabel.text = @"You haven't opened this app yet."; + } else { + cell.subtitleLabel.text = [NSString stringWithFormat:@"Last opened on %@", openedString]; + } + cell.iconImage.image = [UIImage _applicationIconImageForBundleIdentifier:appData[@"appId"] format:2 scale:[UIScreen mainScreen].scale]; + + return cell; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat width = self.view.frame.size.width-40; + return CGSizeMake(width, 65); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 20.0; +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +-(void)pushBackVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + + +- (void)getSystemApps { + + NSDictionary *apps = [[ALApplicationList sharedApplicationList] applications]; + NSArray *blacklist = [NSArray arrayWithObjects:@"com.apple.Magnifier", + @"com.apple.InCallService", + @"com.apple.RemoteiCloudQuotaUI", + @"com.apple.PublicHealthRemoteUI", + @"com.apple.CarPlaySplashScreen", + @"com.apple.iMessageAppsViewService", + @"com.apple.BarcodeScanner", + @"com.apple.HealthENLauncher", + @"com.apple.AXUIViewService", + @"com.apple.AppSSOUIService", + @"com.apple.CarPlaySettings", + @"com.apple.mobilesms.compose", + @"com.apple.BusinessChatViewService", + @"com.apple.DiagnosticsService", + @"com.apple.CTNotifyUIService", + @"com.apple.HealthPrivacyService", + @"com.apple.WebContentFilter.remoteUI.WebContentAnalysisUI", + @"com.apple.ScreenshotServicesService", + @"com.apple.FTMInternal", + @"com.apple.carkit.DNDBuddy", + @"com.apple.PreBoard", + @"com.apple.datadetectors.DDActionsService", + @"com.apple.DemoApp", + @"com.apple.CoreAuthUI", + @"com.apple.SubcredentialUIService", + @"com.apple.MailCompositionService", + @"com.apple.Diagnostics", + @"com.apple.AuthKitUIService", + @"com.apple.TVRemote", + @"com.apple.gamecenter.GameCenterUIService", + @"com.apple.PrintKit.Print-Center", + @"com.apple.sidecar", + @"com.apple.AccountAuthenticationDialog", + @"com.apple.PassbookUIService", + @"com.apple.siri", + @"com.apple.CloudKit.ShareBear", + @"com.apple.HealthENBuddy", + @"com.apple.SafariViewService", + @"com.apple.SIMSetupUIService", + @"com.apple.CompassCalibrationViewService", + @"com.apple.PhotosViewService", + @"com.apple.MusicUIService", + @"com.apple.TrustMe", + @"com.apple.Home.HomeUIService", + @"com.apple.CTCarrierSpaceAuth", + @"com.apple.StoreDemoViewService", + @"com.apple.susuiservice", + @"com.apple.social.SLYahooAuth", + @"com.apple.Spotlight", + @"com.apple.fieldtest", + @"com.apple.WebSheet", + @"com.apple.iad.iAdOptOut", + @"com.apple.dt.XcodePreviews", + @"com.apple.appleseed.FeedbackAssistant", + @"com.apple.FontInstallViewService", + @"com.apple.ScreenSharingViewService", + @"com.apple.SharedWebCredentialViewService", + @"com.apple.CheckerBoard", + @"com.apple.DataActivation", + @"com.apple.TVAccessViewService", + @"com.apple.VSViewService", + @"com.apple.TVRemoteUIService", + @"com.apple.SharingViewService", + @"com.apple.ios.StoreKitUIService", + @"com.apple.purplebuddy", + @"com.apple.ScreenTimeUnlock", + @"com.apple.webapp", + @"com.apple.AskPermissionUI", nil]; + + for (NSString *appId in [apps allKeys]) { + if (![blacklist containsObject:appId]) { + NSString *appName = [LSApplicationProxy applicationProxyForIdentifier:appId].localizedName; + NSDictionary *dict = @{@"appName" : appName, @"appId" : appId}; + [appsDict setObject:dict forKey:appName]; + } + } +} + + +@end diff --git a/iDevices/Tweak/IDEVICES/Battery/BatteryViewController.h b/iDevices/Tweak/IDEVICES/Battery/BatteryViewController.h new file mode 100644 index 0000000..b1c44b3 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Battery/BatteryViewController.h @@ -0,0 +1,52 @@ +#import +#import "Colour-Scheme.h" +#import "DataManager.h" +#import "CDHeaderView.h" +#import "BatteryCell.h" +#import "SectionCellHeaderView.h" + +@interface BatteryViewController : UIViewController +@property (nonatomic, retain) CDHeaderView *headerView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) UIView *containerView; +@property (nonatomic, retain) UIImageView *headerIcon; +@property (nonatomic, retain) UILabel *headerTitle; +@end + +@interface BCBatteryDevice : NSObject +@property (assign,getter=isFake,nonatomic) BOOL fake; +//ONLY IN IOS 13 +@property (nonatomic,readonly) UIImage * glyph; +//ONLY IN IOS 14 +-(id)batteryWidgetGlyph; +-(long long)percentCharge; +-(BOOL)isBatterySaverModeActive; +-(BOOL)isCharging; +-(BOOL)isLowBattery; +-(BOOL)isInternal; +-(NSString *)identifier; +-(NSString *)name; +-(BOOL)isConnected; +-(NSString *)accessoryIdentifier; +-(NSString *)matchIdentifier; +-(NSString *)groupName; +-(NSString *)modelNumber; +-(unsigned long long)parts; +-(BOOL)isFake; +-(void)setPercentCharge:(long long)arg1; +-(void)updateScrollWidthAndTouchPassthrough; +@end + +@interface BCBatteryDeviceController : NSObject ++(id)sharedInstance; +-(NSArray *)connectedDevices; +@property (setter=_setSortedDevices:,getter=_sortedDevices,nonatomic,retain) NSArray * sortedDevices; +// -(id)_sortedDevices; +//only supported on iOS 13 +-(void)removeDeviceChangeHandlerWithIdentifier:(id)arg1; +@end + +@interface UIImageAsset () +@property(nonatomic, assign) NSString *assetName; +@end + diff --git a/iDevices/Tweak/IDEVICES/Battery/BatteryViewController.xm b/iDevices/Tweak/IDEVICES/Battery/BatteryViewController.xm new file mode 100644 index 0000000..c889ddb --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Battery/BatteryViewController.xm @@ -0,0 +1,277 @@ +#import "BatteryViewController.h" + +NSArray *connectedBluetoothDevices; +BCBatteryDevice *currentDevice; + +@implementation BatteryViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [UIColor accentColour]; + self.view.tintColor = [UIColor accentColour]; + + + UIDevice *device = [UIDevice currentDevice]; + device.batteryMonitoringEnabled = YES; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshData) name:@"BCBatteryDeviceControllerConnectedDevicesDidChange" object: nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshData) name:@"UIDeviceBatteryLevelDidChangeNotification" object:device]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshData) name:@"UIDeviceBatteryStateDidChangeNotification" object:device]; + + + [self getBatteryData]; + [self layoutHeaderView]; + [self layoutCollectionView]; +} + + +-(void)getBatteryData { + // self.connectedBluetoothDevices = [[NSMutableArray alloc] init]; + // [self.connectedBluetoothDevices addObject:@"Hi1"]; + // [self.connectedBluetoothDevices addObject:@"Hi1"]; + // [self.connectedBluetoothDevices addObject:@"Hi1"]; + // [self.connectedBluetoothDevices addObject:@"Hi1"]; + // [self.connectedBluetoothDevices addObject:@"Hi1"]; + + connectedBluetoothDevices = [[%c(BCBatteryDeviceController) sharedInstance] connectedDevices]; +} + + +-(void)layoutHeaderView { + + self.containerView = [[UIView alloc] init]; + self.containerView.layer.cornerRadius = 25; + self.containerView.layer.cornerCurve = kCACornerCurveContinuous; + self.containerView.layer.maskedCorners = 12; + self.containerView.clipsToBounds = YES; + [self.view addSubview:self.containerView]; + + [self.containerView size:CGSizeMake(self.view.frame.size.width, 200)]; + [self.containerView x:self.view.centerXAnchor]; + [self.containerView top:self.view.topAnchor padding:0]; + + + UIImageView *wallpaper = [[UIImageView alloc] init]; + if (toggleCustomCoverImage) { + wallpaper.image = [UIImage imageWithData:customCoverImage]; + } else { + wallpaper.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/iDevices.bundle/Assets/Default/cover-image.png"]; + } + wallpaper.contentMode = UIViewContentModeScaleAspectFill; + [self.containerView addSubview:wallpaper]; + + [wallpaper fill]; + + + self.headerView = [[CDHeaderView alloc] initWithTitle:@"" accent:[UIColor accentColour] leftIcon:@"chevron.left" leftAction:@selector(pushBackVC)]; + self.headerView.leftButton.backgroundColor = [UIColor.navBarButtonColour colorWithAlphaComponent:0.5]; + [self.containerView addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.containerView.centerXAnchor]; + [self.headerView top:self.containerView.topAnchor padding:0]; + + + self.headerIcon = [[UIImageView alloc] init]; + self.headerIcon.contentMode = UIViewContentModeScaleAspectFit; + self.headerIcon.image = [UIImage systemImageNamed:@"battery.100"]; + self.headerIcon.tintColor = UIColor.coverIconColour; + [self.containerView addSubview:self.headerIcon]; + + [self.headerIcon size:CGSizeMake(75, 75)]; + [self.headerIcon x:self.containerView.centerXAnchor]; + [self.headerIcon top:self.headerView.bottomAnchor padding:-10]; + + + self.headerTitle = [[UILabel alloc] init]; + self.headerTitle.textAlignment = NSTextAlignmentCenter; + self.headerTitle.font = [UIFont systemFontOfSize:18 weight:UIFontWeightBold]; + self.headerTitle.textColor = UIColor.coverTitleColour; + self.headerTitle.text = @"Battery"; + [self.containerView addSubview:self.headerTitle]; + + [self.headerTitle x:self.containerView.centerXAnchor]; + [self.headerTitle top:self.headerIcon.bottomAnchor padding:10]; + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[BatteryCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.collectionView registerClass:[SectionCellHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; + [self.view addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + + [self.collectionView top:self.containerView.bottomAnchor padding:0]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + [self.collectionView bottom:self.view.bottomAnchor padding:-5]; +} + + +- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView { + return 1; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { + return CGSizeMake(self.view.frame.size.width, 45); +} + + +-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + UICollectionReusableView *reusableview = nil; + + if (kind == UICollectionElementKindSectionHeader) { + + SectionCellHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; + if ([connectedBluetoothDevices count] > 0) { + headerView.headerLabel.text = [NSString stringWithFormat:@"%lu Devices", [connectedBluetoothDevices count]]; + } else { + headerView.headerLabel.text = @"No Devices"; + } + reusableview = headerView; + } + + return reusableview; + +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return connectedBluetoothDevices.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + BatteryCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + //cell.secondLabel.text = @"Hello"; + + // cell.deviceLabel.text = @"iPhone"; + // cell.batteryLabel.text = @"80%"; + // cell.nameLabel.text = @"SGWC's iPhone"; + + + currentDevice = connectedBluetoothDevices[indexPath.row]; + + cell.deviceImage.image = [[UIImageView alloc] initWithImage:[currentDevice batteryWidgetGlyph]].image; + cell.deviceLabel.text = [NSString stringWithFormat: @"%@", [self getDeviceName:[[[currentDevice batteryWidgetGlyph] imageAsset] assetName]]]; + NSString *percentageString = @"%"; + cell.batteryLabel.text = [NSString stringWithFormat: @"%lld%@", [currentDevice percentCharge], percentageString]; + cell.nameLabel.text = [currentDevice name]; + + + + [UIView animateWithDuration:0.1 animations:^{ + + // NSArray *testArray = [[NSArray alloc] initWithObjects:@"37", @"10", @"80", @"75", @"95", nil]; + + // NSString *batteryValue = [testArray objectAtIndex:indexPath.row]; + + double batteryPercentage = [currentDevice percentCharge]; + + cell.usageView.value = batteryPercentage; + cell.usageView.maxValue = 100; + + + if (batteryPercentage <20) { + cell.usageView.progressColor = [UIColor batteryLowColour]; + cell.usageView.progressStrokeColor = [UIColor batteryLowColour]; + cell.batteryLabel.textColor = [UIColor batteryLowColour]; + } else { + cell.usageView.progressColor = [UIColor batteryNormalColour]; + cell.usageView.progressStrokeColor = [UIColor batteryNormalColour]; + cell.batteryLabel.textColor = [UIColor batteryNormalColour]; + } + + + + }]; + + return cell; + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat width = self.view.frame.size.width /2 -30; + return CGSizeMake(width, 100); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 20.0; +} + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 20.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + +} + + +-(void)pushBackVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + + +- (NSString*)getDeviceName: (NSString*)assetName { + + if([assetName containsString: @"case"] || [assetName containsString: @"r7x"]) return @"Case"; + else if([assetName containsString: @"iphone"]) return @"iPhone"; + else if(([assetName containsString: @"airpods"] || [assetName containsString: @"b298"]) && [assetName containsString: @"left"] && [assetName containsString: @"right"]) return @"Airpods"; + else if(([assetName containsString: @"airpods"] || [assetName containsString: @"b298"]) && [assetName containsString: @"left"]) return @"L Airpod"; + else if(([assetName containsString: @"airpods"] || [assetName containsString: @"b298"]) && [assetName containsString: @"right"]) return @"R Airpod"; + else if([assetName containsString: @"ipad"]) return @"iPad"; + else if([assetName containsString: @"watch"]) return @"Watch"; + else if([assetName containsString: @"beats"] && [assetName containsString: @"left"] && [assetName containsString: @"right"]) return @"Beats"; + else if([assetName containsString: @"beatspro"] && [assetName containsString: @"left"]) return @"L Beats"; + else if([assetName containsString: @"beatspro"] && [assetName containsString: @"right"]) return @"R Beats"; + else if([assetName containsString: @"beats"] || [assetName containsString: @"b419"] || [assetName containsString: @"b364"]) return @"Beats"; + else if([assetName containsString: @"gamecontroller"]) return @"Controller"; + else if([assetName containsString: @"pencil"]) return @"Pencil"; + else if([assetName containsString: @"ipod"]) return @"iPod"; + else if([assetName containsString: @"mouse"] || [assetName containsString: @"a125"]) return @"Mouse"; + else if([assetName containsString: @"trackpad"]) return @"Trackpad"; + else if([assetName containsString: @"keyboard"]) return @"Keyboard"; + else return @"Device"; + } + +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/AboutCell.h b/iDevices/Tweak/IDEVICES/Cells/AboutCell.h new file mode 100644 index 0000000..d04156d --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/AboutCell.h @@ -0,0 +1,10 @@ +#import +#import "Colour-Scheme.h" + +@interface AboutCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/AboutCell.m b/iDevices/Tweak/IDEVICES/Cells/AboutCell.m new file mode 100644 index 0000000..0977383 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/AboutCell.m @@ -0,0 +1,85 @@ +#import "AboutCell.h" + +@implementation AboutCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 20; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = true; + + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor cellColour]; + self.baseView.layer.cornerRadius = 20; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 10; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + self.iconView.clipsToBounds = YES; + [self.baseView addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(40, 40)]; + [self.iconView y:self.baseView.centerYAnchor]; + [self.iconView leading:self.baseView.leadingAnchor padding:10]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.iconView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(30, 30)]; + [self.iconImage x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.textColor = [UIColor titleColour]; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.titleLabel top:self.iconView.topAnchor padding:2]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.subtitleLabel = [[UILabel alloc] init]; + self.subtitleLabel.textAlignment = NSTextAlignmentLeft; + self.subtitleLabel.font = [UIFont systemFontOfSize:13]; + self.subtitleLabel.textColor = [UIColor subtitleColour]; + [self.baseView addSubview:self.subtitleLabel]; + + [self.subtitleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.subtitleLabel bottom:self.iconView.bottomAnchor padding:-2]; + [self.subtitleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + } + return self; +} + + +- (void)prepareForReuse { + [super prepareForReuse]; + self.iconView.backgroundColor = UIColor.clearColor; + self.iconImage.image = nil; + self.titleLabel.text = nil; + self.subtitleLabel.text = nil; +} + + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.backgroundColor = highlighted ? [UIColor cellColour] : [UIColor cellColour]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/AppCell.h b/iDevices/Tweak/IDEVICES/Cells/AppCell.h new file mode 100644 index 0000000..aa83a06 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/AppCell.h @@ -0,0 +1,9 @@ +#import +#import "Colour-Scheme.h" + +@interface AppCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/AppCell.m b/iDevices/Tweak/IDEVICES/Cells/AppCell.m new file mode 100644 index 0000000..f7713e4 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/AppCell.m @@ -0,0 +1,77 @@ +#import "AppCell.h" + +@implementation AppCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 20; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = true; + + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor cellColour]; + self.baseView.layer.cornerRadius = 20; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + self.iconImage.layer.cornerRadius = 10; + self.iconImage.layer.cornerCurve = kCACornerCurveContinuous; + self.iconImage.clipsToBounds = YES; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(40, 40)]; + [self.iconImage y:self.baseView.centerYAnchor]; + [self.iconImage leading:self.baseView.leadingAnchor padding:20]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.textColor = [UIColor titleColour]; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.iconImage.trailingAnchor padding:10]; + [self.titleLabel top:self.iconImage.topAnchor padding:2]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.subtitleLabel = [[UILabel alloc] init]; + self.subtitleLabel.textAlignment = NSTextAlignmentLeft; + self.subtitleLabel.font = [UIFont systemFontOfSize:13]; + self.subtitleLabel.textColor = [UIColor subtitleColour]; + [self.baseView addSubview:self.subtitleLabel]; + + [self.subtitleLabel leading:self.iconImage.trailingAnchor padding:10]; + [self.subtitleLabel bottom:self.iconImage.bottomAnchor padding:-2]; + [self.subtitleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + } + return self; +} + + +- (void)prepareForReuse { + [super prepareForReuse]; + self.iconImage.image = nil; + self.titleLabel.text = nil; + self.subtitleLabel.text = nil; +} + + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.backgroundColor = highlighted ? [UIColor cellColour] : [UIColor cellColour]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/BatteryCell.h b/iDevices/Tweak/IDEVICES/Cells/BatteryCell.h new file mode 100644 index 0000000..80fdb21 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/BatteryCell.h @@ -0,0 +1,12 @@ +#import +#import "DeviceUsageView.h" +#import "Colour-Scheme.h" + +@interface BatteryCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) DeviceUsageView *usageView; +@property (nonatomic, retain) UIImageView *deviceImage; +@property (nonatomic, retain) UILabel *deviceLabel; +@property (nonatomic, retain) UILabel *batteryLabel; +@property (nonatomic, retain) UILabel *nameLabel; +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/BatteryCell.m b/iDevices/Tweak/IDEVICES/Cells/BatteryCell.m new file mode 100644 index 0000000..1fcc349 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/BatteryCell.m @@ -0,0 +1,99 @@ +#import "BatteryCell.h" + +@implementation BatteryCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor cellColour]; + self.baseView.layer.cornerRadius = 20; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.usageView = [[DeviceUsageView alloc] initWithFrame:CGRectZero]; + self.usageView.backgroundColor = UIColor.clearColor; + self.usageView.progressColor = UIColor.systemGreenColor; + self.usageView.progressStrokeColor = UIColor.systemGreenColor; + self.usageView.emptyLineStrokeColor = UIColor.clearColor; + self.usageView.emptyLineColor = [UIColor batteryRingColour]; + self.usageView.fontColor = UIColor.clearColor; + self.usageView.progressLineWidth = 3; + self.usageView.valueFontSize = 10; + self.usageView.unitFontSize = 8; + self.usageView.emptyLineWidth = 3; + self.usageView.emptyCapType = kCGLineCapRound; + self.usageView.progressAngle = 100; + self.usageView.progressRotationAngle = 50; + [self.baseView addSubview:self.usageView]; + + + [self.usageView size:CGSizeMake(55, 55)]; + [self.usageView top:self.baseView.topAnchor padding:10]; + [self.usageView leading:self.baseView.leadingAnchor padding:10]; + + + self.deviceImage = [[UIImageView alloc] init]; + self.deviceImage.image = [UIImage systemImageNamed:@"gear"]; + self.deviceImage.contentMode = UIViewContentModeScaleAspectFit; + self.deviceImage.tintColor = [UIColor accentColour]; + [self.baseView addSubview:self.deviceImage]; + + [self.deviceImage size:CGSizeMake(30, 30)]; + [self.deviceImage x:self.usageView.centerXAnchor y:self.usageView.centerYAnchor]; + + + self.deviceLabel = [[UILabel alloc] init]; + self.deviceLabel.textColor = [UIColor fontColour]; + self.deviceLabel.font = [UIFont boldSystemFontOfSize:14]; + self.deviceLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.deviceLabel]; + + [self.deviceLabel top:self.usageView.topAnchor padding:10]; + [self.deviceLabel leading:self.usageView.trailingAnchor padding:10]; + [self.deviceLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.batteryLabel = [[UILabel alloc] init]; + self.batteryLabel.textColor = UIColor.systemGreenColor; + self.batteryLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightSemibold]; + self.batteryLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.batteryLabel]; + + [self.batteryLabel bottom:self.usageView.bottomAnchor padding:-10]; + [self.batteryLabel leading:self.usageView.trailingAnchor padding:10]; + [self.batteryLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.textColor = [UIColor subtitleColour]; + self.nameLabel.font = [UIFont systemFontOfSize:12]; + self.nameLabel.textAlignment = NSTextAlignmentCenter; + [self.baseView addSubview:self.nameLabel]; + + [self.nameLabel bottom:self.baseView.bottomAnchor padding:-5]; + [self.nameLabel leading:self.baseView.leadingAnchor padding:10]; + [self.nameLabel trailing:self.baseView.trailingAnchor padding:-10]; + [self.nameLabel x:self.baseView.centerXAnchor]; + + } + return self; +} + + +- (void)prepareForReuse { + [super prepareForReuse]; + self.deviceImage.image = nil; + self.nameLabel.text = nil; + self.deviceLabel.text = nil; + self.batteryLabel.text = nil; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/DevicesCell.h b/iDevices/Tweak/IDEVICES/Cells/DevicesCell.h new file mode 100644 index 0000000..71038de --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/DevicesCell.h @@ -0,0 +1,11 @@ +#import +#import "Colour-Scheme.h" + +@interface DevicesCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *deviceImage; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UILabel *deviceLabel; +@property (nonatomic, retain) UILabel *modelLabel; +@property (nonatomic, retain) UILabel *versionLabel; +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/DevicesCell.m b/iDevices/Tweak/IDEVICES/Cells/DevicesCell.m new file mode 100644 index 0000000..b01dae0 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/DevicesCell.m @@ -0,0 +1,103 @@ +#import "DevicesCell.h" + +@implementation DevicesCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 20; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = true; + + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor cellColour]; + self.baseView.layer.cornerRadius = 20; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.deviceImage = [[UIImageView alloc] init]; + self.deviceImage.contentMode = UIViewContentModeScaleAspectFill; + self.deviceImage.tintColor = [UIColor accentColour]; + [self.baseView addSubview:self.deviceImage]; + + [self.deviceImage size:CGSizeMake(50, 50)]; + [self.deviceImage x:self.baseView.centerXAnchor]; + [self.deviceImage top:self.baseView.topAnchor padding:10]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.textColor = [UIColor titleColour]; + self.nameLabel.font = [UIFont systemFontOfSize:12 weight:UIFontWeightSemibold]; + self.nameLabel.textAlignment = NSTextAlignmentCenter; + [self.baseView addSubview:self.nameLabel]; + + [self.nameLabel x:self.baseView.centerXAnchor]; + [self.nameLabel top:self.deviceImage.bottomAnchor padding:5]; + [self.nameLabel leading:self.baseView.leadingAnchor padding:5]; + [self.nameLabel trailing:self.baseView.trailingAnchor padding:-5]; + + + self.deviceLabel = [[UILabel alloc] init]; + self.deviceLabel.textColor = [UIColor subtitleColour]; + self.deviceLabel.font = [UIFont systemFontOfSize:12]; + self.deviceLabel.textAlignment = NSTextAlignmentCenter; + [self.baseView addSubview:self.deviceLabel]; + + [self.deviceLabel x:self.baseView.centerXAnchor]; + [self.deviceLabel top:self.nameLabel.bottomAnchor padding:5]; + [self.deviceLabel leading:self.baseView.leadingAnchor padding:5]; + [self.deviceLabel trailing:self.baseView.trailingAnchor padding:-5]; + + + self.modelLabel = [[UILabel alloc] init]; + self.modelLabel.textColor = [UIColor subtitleColour]; + self.modelLabel.font = [UIFont systemFontOfSize:12]; + self.modelLabel.textAlignment = NSTextAlignmentCenter; + [self.baseView addSubview:self.modelLabel]; + + [self.modelLabel x:self.baseView.centerXAnchor]; + [self.modelLabel top:self.deviceLabel.bottomAnchor padding:5]; + [self.modelLabel leading:self.baseView.leadingAnchor padding:5]; + [self.modelLabel trailing:self.baseView.trailingAnchor padding:-5]; + + + self.versionLabel = [[UILabel alloc] init]; + self.versionLabel.textColor = [UIColor subtitleColour]; + self.versionLabel.font = [UIFont systemFontOfSize:12]; + self.versionLabel.textAlignment = NSTextAlignmentCenter; + [self.baseView addSubview:self.versionLabel]; + + [self.versionLabel x:self.baseView.centerXAnchor]; + [self.versionLabel top:self.modelLabel.bottomAnchor padding:5]; + [self.versionLabel leading:self.baseView.leadingAnchor padding:5]; + [self.versionLabel trailing:self.baseView.trailingAnchor padding:-5]; + + + } + return self; +} + + +- (void)prepareForReuse { + [super prepareForReuse]; + self.deviceImage.image = nil; + self.nameLabel.text = nil; + self.deviceLabel.text = nil; + self.modelLabel.text = nil; + self.versionLabel.text = nil; +} + + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.backgroundColor = highlighted ? [UIColor cellColour] : [UIColor cellColour]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/SectionCellHeaderView.h b/iDevices/Tweak/IDEVICES/Cells/SectionCellHeaderView.h new file mode 100644 index 0000000..c780e0f --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/SectionCellHeaderView.h @@ -0,0 +1,9 @@ +#import +#import "Colour-Scheme.h" + +@interface SectionCellHeaderView : UICollectionReusableView +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *headerLabel; +@end + + diff --git a/iDevices/Tweak/IDEVICES/Cells/SectionCellHeaderView.m b/iDevices/Tweak/IDEVICES/Cells/SectionCellHeaderView.m new file mode 100644 index 0000000..c3bbfb7 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/SectionCellHeaderView.m @@ -0,0 +1,28 @@ +#import "SectionCellHeaderView.h" + +@implementation SectionCellHeaderView + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] initWithFrame:self.bounds]; + self.baseView.clipsToBounds = YES; + [self addSubview:self.baseView]; + + + self.headerLabel = [[UILabel alloc] init]; + self.headerLabel.textColor = [UIColor subtitleColour]; + self.headerLabel.font = [UIFont boldSystemFontOfSize:18]; + [self.baseView addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = YES; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:20].active = YES; + + } + return self; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/StorageCell.h b/iDevices/Tweak/IDEVICES/Cells/StorageCell.h new file mode 100644 index 0000000..2a10c53 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/StorageCell.h @@ -0,0 +1,10 @@ +#import +#import "Colour-Scheme.h" + +@interface StorageCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/StorageCell.m b/iDevices/Tweak/IDEVICES/Cells/StorageCell.m new file mode 100644 index 0000000..662563b --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/StorageCell.m @@ -0,0 +1,84 @@ +#import "StorageCell.h" + +@implementation StorageCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 20; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = true; + + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor cellColour]; + self.baseView.layer.cornerRadius = 20; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 10; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + self.iconView.clipsToBounds = YES; + [self.baseView addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(40, 40)]; + [self.iconView y:self.baseView.centerYAnchor]; + [self.iconView leading:self.baseView.leadingAnchor padding:10]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.iconView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(30, 30)]; + [self.iconImage x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.textColor = [UIColor titleColour]; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.titleLabel top:self.iconView.topAnchor padding:2]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.subtitleLabel = [[UILabel alloc] init]; + self.subtitleLabel.textAlignment = NSTextAlignmentLeft; + self.subtitleLabel.font = [UIFont systemFontOfSize:13]; + self.subtitleLabel.textColor = [UIColor subtitleColour]; + [self.baseView addSubview:self.subtitleLabel]; + + [self.subtitleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.subtitleLabel bottom:self.iconView.bottomAnchor padding:-2]; + [self.subtitleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + } + return self; +} + + +- (void)prepareForReuse { + [super prepareForReuse]; + self.iconImage.image = nil; + self.titleLabel.text = nil; + self.subtitleLabel.text = nil; +} + + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.backgroundColor = highlighted ? [UIColor cellColour] : [UIColor cellColour]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/TweakCell.h b/iDevices/Tweak/IDEVICES/Cells/TweakCell.h new file mode 100644 index 0000000..bd3aaf6 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/TweakCell.h @@ -0,0 +1,10 @@ +#import +#import "Colour-Scheme.h" + +@interface TweakCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@end diff --git a/iDevices/Tweak/IDEVICES/Cells/TweakCell.m b/iDevices/Tweak/IDEVICES/Cells/TweakCell.m new file mode 100644 index 0000000..dfe18ee --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cells/TweakCell.m @@ -0,0 +1,85 @@ +#import "TweakCell.h" + +@implementation TweakCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = 20; + self.layer.cornerCurve = kCACornerCurveContinuous; + self.clipsToBounds = true; + + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor cellColour]; + self.baseView.layer.cornerRadius = 20; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 10; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + self.iconView.clipsToBounds = YES; + [self.baseView addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(40, 40)]; + [self.iconView y:self.baseView.centerYAnchor]; + [self.iconView leading:self.baseView.leadingAnchor padding:10]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.iconView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(30, 30)]; + [self.iconImage x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.textColor = [UIColor titleColour]; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.titleLabel top:self.iconView.topAnchor padding:2]; + [self.titleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.subtitleLabel = [[UILabel alloc] init]; + self.subtitleLabel.textAlignment = NSTextAlignmentLeft; + self.subtitleLabel.font = [UIFont systemFontOfSize:13]; + self.subtitleLabel.textColor = [UIColor subtitleColour]; + [self.baseView addSubview:self.subtitleLabel]; + + [self.subtitleLabel leading:self.iconView.trailingAnchor padding:10]; + [self.subtitleLabel bottom:self.iconView.bottomAnchor padding:-2]; + [self.subtitleLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + } + return self; +} + + +- (void)prepareForReuse { + [super prepareForReuse]; + self.iconView.backgroundColor = UIColor.clearColor; + self.iconImage.image = nil; + self.titleLabel.text = nil; + self.subtitleLabel.text = nil; +} + + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + self.backgroundColor = highlighted ? [UIColor cellColour] : [UIColor cellColour]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Cloud/CloudButton.h b/iDevices/Tweak/IDEVICES/Cloud/CloudButton.h new file mode 100644 index 0000000..6ffd69b --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cloud/CloudButton.h @@ -0,0 +1,7 @@ +#import + +@interface CloudButton : UIControl +-(instancetype)initWithAction:(SEL)customAction; +@property (nonatomic, retain) UILabel *title; +@end + diff --git a/iDevices/Tweak/IDEVICES/Cloud/CloudButton.m b/iDevices/Tweak/IDEVICES/Cloud/CloudButton.m new file mode 100644 index 0000000..1e331b7 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cloud/CloudButton.m @@ -0,0 +1,62 @@ +#import "CloudButton.h" + +@implementation CloudButton + +-(instancetype)initWithAction:(SEL)customAction { + + self = [super init]; + if (self) { + + self.clipsToBounds = YES; + + + self.title = [[UILabel alloc] init]; + self.title.textAlignment = NSTextAlignmentCenter; + self.title.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold]; + self.title.textColor = UIColor.whiteColor; + self.title.numberOfLines = 2; + [self addSubview:self.title]; + + [self.title x:self.centerXAnchor]; + [self.title y:self.centerYAnchor]; + [self.title leading:self.leadingAnchor padding:5]; + [self.title trailing:self.trailingAnchor padding:-5]; + + [self addTarget:self.superview action:customAction forControlEvents:UIControlEventTouchUpInside]; + + } + + return self; +} + + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesBegan:touches withEvent:event]; + [self touchAnimateWithHighlighted:YES]; +} + + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesEnded:touches withEvent:event]; + [self touchAnimateWithHighlighted:NO]; +} + + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesCancelled:touches withEvent:event]; + [self touchAnimateWithHighlighted:NO]; +} + + +-(void)touchAnimateWithHighlighted:(BOOL)isHighlighted { + + [UIView animateWithDuration:0.3 animations:^{ + self.alpha = isHighlighted ? 0.8 : 1.0; + CGAffineTransform transform = self.transform; + transform = isHighlighted ? CGAffineTransformScale(transform, 0.94, 0.94) : CGAffineTransformIdentity; + self.transform = transform; + }]; + +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Cloud/CloudViewController.h b/iDevices/Tweak/IDEVICES/Cloud/CloudViewController.h new file mode 100644 index 0000000..fc53812 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cloud/CloudViewController.h @@ -0,0 +1,50 @@ +#import +#import "Colour-Scheme.h" +#import "DataManager.h" +#import "CDHeaderView.h" +#import "MemoryView.h" +#import "CloudButton.h" +#import "DeviceUsageView.h" + +@interface CloudViewController : UIViewController +@property (nonatomic, retain) CDHeaderView *headerView; +@property (nonatomic, retain) UIView *containerView; +@property (nonatomic, retain) MemoryView *toggleView; +@property (nonatomic, retain) MemoryView *dateView; +@property (nonatomic, retain) UILabel *statusLabel; +@property (nonatomic, retain) UISwitch *toggleSwitch; +@property (nonatomic, retain) CloudButton *cloudButton; +@property (nonatomic, retain) DeviceUsageView *backupProgressView; +@property (nonatomic, retain) NSTimer *icloudTimer; +@end + +@interface MBManager : NSObject +-(id)init; +-(id)_init; +-(id)backupState; +-(id)getBackupListWithError:(id*)arg1 ; +@end + +@interface MBStateInfo : NSObject +@property (assign,nonatomic) int state; +@property (assign,nonatomic) BOOL isBackground; +@property (assign,nonatomic) BOOL isCloud; +@property (assign,nonatomic) float progress; +@property (assign,nonatomic) unsigned long long estimatedTimeRemaining; +@property (nonatomic,retain) NSDate * date; +@property (nonatomic,retain) NSError * error; +@property (nonatomic,retain) NSMutableArray * errors; +@end + +@interface MBManagerClient : NSObject +-(void)cancel; +-(id)backupList; +-(id)backupState; +-(id)dateOfLastBackup; +-(BOOL)isBackupEnabled; +-(id)nextBackupSizeInfo; +-(void)setBackupEnabled:(BOOL)arg1 ; +-(unsigned long long)nextBackupSize; +-(BOOL)startBackupWithError:(id*)arg1 ; +-(BOOL)startBackupWithOptions:(id)arg1 error:(id*)arg2 ; +@end diff --git a/iDevices/Tweak/IDEVICES/Cloud/CloudViewController.xm b/iDevices/Tweak/IDEVICES/Cloud/CloudViewController.xm new file mode 100644 index 0000000..5ecfec8 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Cloud/CloudViewController.xm @@ -0,0 +1,318 @@ +#import "CloudViewController.h" + +// static MBManagerClient *mbManagerClient; +// static MBStateInfo *mbSInfo; + +@implementation CloudViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [UIColor accentColour]; + self.view.tintColor = [UIColor accentColour]; + + self.icloudTimer = nil; + + [self layoutViews]; + [self layoutHeaderView]; + [self checkStatus]; +} + + +-(void)layoutHeaderView { + + self.headerView = [[CDHeaderView alloc] initWithTitle:@"iCloud" accent:[UIColor accentColour] leftIcon:@"chevron.left" leftAction:@selector(pushBackVC)]; + self.headerView.leftButton.backgroundColor = [UIColor.navBarButtonColour colorWithAlphaComponent:0.5]; + self.headerView.titleLabel.textColor = UIColor.coverTitleColour; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.topAnchor padding:0]; +} + + +-(void)layoutViews { + + self.containerView = [[UIView alloc] init]; + self.containerView.layer.cornerRadius = 25; + self.containerView.layer.cornerCurve = kCACornerCurveContinuous; + self.containerView.layer.maskedCorners = 12; + self.containerView.clipsToBounds = YES; + [self.view addSubview:self.containerView]; + + [self.containerView size:CGSizeMake(self.view.frame.size.width, 380)]; + [self.containerView x:self.view.centerXAnchor]; + [self.containerView top:self.view.topAnchor padding:0]; + + + UIImageView *wallpaper = [[UIImageView alloc] init]; + if (toggleCustomCoverImage) { + wallpaper.image = [UIImage imageWithData:customCoverImage]; + } else { + wallpaper.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/iDevices.bundle/Assets/Default/cover-image.png"]; + } + wallpaper.contentMode = UIViewContentModeScaleAspectFill; + [self.containerView addSubview:wallpaper]; + + [wallpaper fill]; + + + self.backupProgressView = [[DeviceUsageView alloc] initWithFrame:CGRectZero]; + self.backupProgressView.backgroundColor = UIColor.clearColor; + self.backupProgressView.progressColor = UIColor.backupProgressColour; + self.backupProgressView.progressStrokeColor = UIColor.backupProgressColour; + self.backupProgressView.emptyLineStrokeColor = UIColor.clearColor; + self.backupProgressView.emptyLineColor = [UIColor.backupProgressColour colorWithAlphaComponent:0.4]; + self.backupProgressView.fontColor = UIColor.clearColor; + self.backupProgressView.progressLineWidth = 14; + self.backupProgressView.valueFontSize = 10; + self.backupProgressView.unitFontSize = 8; + self.backupProgressView.emptyLineWidth = 14; + self.backupProgressView.emptyCapType = kCGLineCapRound; + self.backupProgressView.progressAngle = 100; + self.backupProgressView.progressRotationAngle = 50; + self.backupProgressView.alpha = 0; + [self.containerView addSubview:self.backupProgressView]; + + [self.backupProgressView size:CGSizeMake(210, 210)]; + [self.backupProgressView x:self.containerView.centerXAnchor]; + [self.backupProgressView y:self.containerView.centerYAnchor padding:15]; + + + self.cloudButton = [[CloudButton alloc] initWithAction:@selector(prepareBackUp)]; + self.cloudButton.layer.cornerRadius = 80; + [self.containerView addSubview:self.cloudButton]; + + [self.cloudButton size:CGSizeMake(160, 160)]; + [self.cloudButton x:self.containerView.centerXAnchor]; + [self.cloudButton y:self.containerView.centerYAnchor padding:15]; + + + self.statusLabel = [[UILabel alloc] init]; + self.statusLabel.textAlignment = NSTextAlignmentCenter; + self.statusLabel.textColor = [UIColor.coverTitleColour colorWithAlphaComponent:0.6]; + self.statusLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold]; + self.statusLabel.text = @"Back up in progress"; + self.statusLabel.alpha = 0; + [self.containerView addSubview:self.statusLabel]; + + [self.statusLabel x:self.containerView.centerXAnchor]; + [self.statusLabel bottom:self.containerView.bottomAnchor padding:-20]; + + + self.toggleView = [[MemoryView alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"switch.2"]]; + self.toggleView.title.text = @"Enable/Disable"; + self.toggleView.subtitle.text = @"iCloud back up"; + self.toggleView.iconView.backgroundColor = [UIColor.tealColour colorWithAlphaComponent:0.4]; + self.toggleView.icon.tintColor = UIColor.tealColour; + [self.view addSubview:self.toggleView]; + + [self.toggleView size:CGSizeMake(self.view.frame.size.width-40, 60)]; + [self.toggleView x:self.view.centerXAnchor]; + [self.toggleView top:self.containerView.bottomAnchor padding:20]; + + + MBManagerClient *mbManagerClient = [[%c(MBManager) alloc] init]; + BOOL isBackupEnabled = [mbManagerClient isBackupEnabled]; + self.toggleSwitch = [[UISwitch alloc] init]; + self.toggleSwitch.thumbTintColor = UIColor.secondarySystemBackgroundColor; + [self.toggleSwitch addTarget:self action:@selector(toggleBackup:) forControlEvents:UIControlEventValueChanged]; + [self.toggleSwitch setOn:isBackupEnabled animated:NO]; + self.toggleSwitch.onTintColor = UIColor.tealColour; + [self.toggleView addSubview:self.toggleSwitch]; + + [self.toggleSwitch y:self.toggleView.centerYAnchor]; + [self.toggleSwitch trailing:self.toggleView.trailingAnchor padding:-10]; + + + self.dateView = [[MemoryView alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"calendar"]]; + self.dateView.title.text = @"Last Backup"; + self.dateView.subtitle.text = [[DataManager sharedInstance] lastiCloudBackUpDate]; + self.dateView.iconView.backgroundColor = [UIColor.redColour colorWithAlphaComponent:0.4]; + self.dateView.icon.tintColor = UIColor.redColour; + [self.view addSubview:self.dateView]; + + [self.dateView size:CGSizeMake(self.view.frame.size.width-40, 60)]; + [self.dateView x:self.view.centerXAnchor]; + [self.dateView top:self.toggleView.bottomAnchor padding:10]; + + //[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(updateStatus) userInfo:nil repeats:YES]; + +} + + +-(void)checkStatus { + + MBManagerClient *mbManagerClient = [[%c(MBManager) alloc] init]; + MBStateInfo *mbSInfo = [mbManagerClient backupState]; + + bool isBackupEnabled = [mbManagerClient isBackupEnabled]; + int state = mbSInfo.state; + + + if(isBackupEnabled && state != 2) { + + self.cloudButton.title.text = @"Start\nBackup"; + self.cloudButton.backgroundColor = UIColor.backupStartButtonColour; + [UIView animateWithDuration:0.1 animations:^{ + self.statusLabel.alpha = 0; + self.backupProgressView.alpha = 0; + }]; + + self.icloudTimer = nil; + [self.icloudTimer invalidate]; + } + + +if(!isBackupEnabled) { + + self.cloudButton.title.text = @"Start\nBackup"; + self.cloudButton.backgroundColor = UIColor.backupStartButtonColour; + [UIView animateWithDuration:0.1 animations:^{ + self.statusLabel.alpha = 0; + self.backupProgressView.alpha = 0; + }]; + + self.icloudTimer = nil; + [self.icloudTimer invalidate]; + } + + + if (state == 2) { + + self.cloudButton.title.text = @"Cancel\nBackup"; + self.cloudButton.backgroundColor = UIColor.backupCancelButtonColour; + [UIView animateWithDuration:0.1 animations:^{ + self.statusLabel.alpha = 1; + self.backupProgressView.alpha = 1; + }]; + + if (!self.icloudTimer) { + self.icloudTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(updateStatus) userInfo:nil repeats:YES]; + } + + } + + + self.dateView.subtitle.text = [[DataManager sharedInstance] lastiCloudBackUpDate]; + + +} + + +-(void)prepareBackUp { + + MBManagerClient *mbManagerClient = [[%c(MBManager) alloc] init]; + MBStateInfo *mbSInfo = [mbManagerClient backupState]; + + bool isBackupEnabled = [mbManagerClient isBackupEnabled]; + int state = mbSInfo.state; + NSError *error = nil; + + if(isBackupEnabled && state != 2) { + [mbManagerClient startBackupWithError:&error]; + } + + + if (state == 2) { + [mbManagerClient cancel]; + } + + + if (!isBackupEnabled) { + [self showAlertWithTitle:@"Sorry!" subtitle:@"Your iCloud backup is disabled, please enable iCloud backup if you wish to backup."]; + } + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self checkStatus]; + }); + +} + + +-(void)updateStatus { + + MBManagerClient *mbManagerClient = [[%c(MBManager) alloc] init]; + MBStateInfo *mbSInfo = [mbManagerClient backupState]; + + bool isBackupEnabled = [mbManagerClient isBackupEnabled]; + int state = mbSInfo.state; + float progress = mbSInfo.progress; + +//self.statusLabel.text = [NSString stringWithFormat:@"%f", progress]; + +if (state == 2) { + + [UIView animateWithDuration:0.1 animations:^{ + + self.backupProgressView.value = progress; + self.backupProgressView.maxValue = 1.000000; + }]; + +} + + +if(isBackupEnabled && state != 2) { + +self.icloudTimer = nil; +[self.icloudTimer invalidate]; +[UIView animateWithDuration:0.1 animations:^{ +self.backupProgressView.alpha = 0; +}]; + +dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self checkStatus]; + }); + +} + + +} + + + + + +-(void)toggleBackup:(UISwitch *)sender { + MBManagerClient *mbManagerClient = [[%c(MBManager) alloc] init]; + [mbManagerClient setBackupEnabled:sender.on]; + +dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self checkStatus]; + }); + +} + + +-(void)pushBackVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + + +@end diff --git a/iDevices/Tweak/IDEVICES/ColourScheme/Colour-Scheme.h b/iDevices/Tweak/IDEVICES/ColourScheme/Colour-Scheme.h new file mode 100644 index 0000000..14387f4 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/ColourScheme/Colour-Scheme.h @@ -0,0 +1,31 @@ +#import "GlobalPreferences.h" + +@interface UIColor (Cloudy) ++ (UIColor *)accentColour; ++ (UIColor *)backgroundColour; ++ (UIColor *)grabberColour; ++ (UIColor *)fontColour; ++ (UIColor *)secondaryFontColour; ++ (UIColor *)titleColour; ++ (UIColor *)subtitleColour; ++ (UIColor *)cellColour; ++ (UIColor *)navBarButtonColour; ++ (UIColor *)batteryRingColour; ++ (UIColor *)batteryLowColour; ++ (UIColor *)batteryNormalColour; ++ (UIColor *)redColour; ++ (UIColor *)orangeColour; ++ (UIColor *)yellowColour; ++ (UIColor *)greenColour; ++ (UIColor *)tealColour; ++ (UIColor *)indigoColour; ++ (UIColor *)pinkColour; ++ (UIColor *)totalRamColour; ++ (UIColor *)usedRamColour; ++ (UIColor *)freeRamColour; ++ (UIColor *)coverIconColour; ++ (UIColor *)coverTitleColour; ++ (UIColor *)backupStartButtonColour; ++ (UIColor *)backupCancelButtonColour; ++ (UIColor *)backupProgressColour; +@end diff --git a/iDevices/Tweak/IDEVICES/ColourScheme/Colour-Scheme.m b/iDevices/Tweak/IDEVICES/ColourScheme/Colour-Scheme.m new file mode 100644 index 0000000..9634dc1 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/ColourScheme/Colour-Scheme.m @@ -0,0 +1,411 @@ +#import "Colour-Scheme.h" + +@implementation UIColor (Cloudy) + ++ (UIColor *)accentColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"accentColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemBlueColor; + } + + return customColour; +} + + ++ (UIColor *)backgroundColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"backgroundColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemBackgroundColor; + } + + return customColour; +} + + ++ (UIColor *)grabberColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"grabberColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.tertiarySystemFillColor; + } + + return customColour; +} + + ++ (UIColor *)fontColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"fontColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.labelColor; + } + + return customColour; +} + + ++ (UIColor *)secondaryFontColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"secondaryFontColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.secondaryLabelColor; + } + + return customColour; +} + + ++ (UIColor *)titleColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"titleColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.labelColor; + } + + return customColour; +} + + ++ (UIColor *)subtitleColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"subtitleColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.tertiaryLabelColor; + } + + return customColour; +} + + ++ (UIColor *)cellColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"cellColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.secondarySystemBackgroundColor; + } + + return customColour; +} + + ++ (UIColor *)navBarButtonColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"navBarButtonColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.secondarySystemBackgroundColor; + } + + return customColour; +} + + ++ (UIColor *)batteryRingColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"batteryRingColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.tertiarySystemFillColor; + } + + return customColour; +} + + ++ (UIColor *)batteryLowColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"batteryLowColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemRedColor; + } + + return customColour; +} + + ++ (UIColor *)batteryNormalColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"batteryNormalColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemGreenColor; + } + + return customColour; +} + + ++ (UIColor *)redColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"redColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemRedColor; + } + + return customColour; +} + + ++ (UIColor *)orangeColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"orangeColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemOrangeColor; + } + + return customColour; +} + + ++ (UIColor *)yellowColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"yellowColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemYellowColor; + } + + return customColour; +} + + ++ (UIColor *)greenColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"greenColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemGreenColor; + } + + return customColour; +} + + ++ (UIColor *)tealColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"tealColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemTealColor; + } + + return customColour; +} + + ++ (UIColor *)indigoColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"indigoColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemIndigoColor; + } + + return customColour; +} + + ++ (UIColor *)pinkColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"pinkColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemPinkColor; + } + + return customColour; +} + + ++ (UIColor *)totalRamColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"totalRamColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemPinkColor; + } + + return customColour; +} + + ++ (UIColor *)freeRamColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"freeRamColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemGreenColor; + } + + return customColour; +} + + ++ (UIColor *)usedRamColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"usedRamColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemTealColor; + } + + return customColour; +} + + ++ (UIColor *)coverIconColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"coverIconColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.whiteColor; + } + + return customColour; +} + + ++ (UIColor *)coverTitleColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"coverTitleColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.whiteColor; + } + + return customColour; +} + + ++ (UIColor *)backupStartButtonColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"backupStartButtonColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemTealColor; + } + + return customColour; +} + + ++ (UIColor *)backupCancelButtonColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"backupCancelButtonColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemRedColor; + } + + return customColour; +} + + ++ (UIColor *)backupProgressColour { + static UIColor *customColour; + + loadPrefs(); + + if (toggleCustomColour) { + customColour = [[TDTweakManager sharedInstance] colourForKey:@"backupProgressColour" defaultValue:@"FFFFFF" ID:BID]; + } else { + customColour = UIColor.systemTealColor; + } + + return customColour; +} + + +@end + diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/CDHeaderView.h b/iDevices/Tweak/IDEVICES/CustomClasses/CDHeaderView.h new file mode 100644 index 0000000..fdc2aad --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/CDHeaderView.h @@ -0,0 +1,14 @@ +#import +#import "Colour-Scheme.h" + +@interface CDHeaderView : UIView +@property (nonatomic, retain) UIView *grabberView; +@property (nonatomic, retain) UIView *headerView; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIButton *leftButton; +@property (nonatomic, retain) UIButton *rightButton; + +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction; +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction rightIcon:(NSString *)rightIconString rightAction:(SEL)rightAction; +@end + diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/CDHeaderView.m b/iDevices/Tweak/IDEVICES/CustomClasses/CDHeaderView.m new file mode 100644 index 0000000..f651e4a --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/CDHeaderView.m @@ -0,0 +1,129 @@ +#import "CDHeaderView.h" + +@implementation CDHeaderView + + +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction { + + self = [super init]; + if (self) { + + self.clipsToBounds = YES; + + self.headerView = [[UIView alloc] init]; + [self addSubview:self.headerView]; + + [self.headerView fill]; + + + self.grabberView = [[UIView alloc] init]; + self.grabberView.backgroundColor = [UIColor grabberColour]; + self.grabberView.layer.cornerRadius = 3; + [self.headerView addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.headerView.centerXAnchor]; + [self.grabberView top:self.headerView.topAnchor padding:10]; + + + self.leftButton = [[UIButton alloc] init]; + self.leftButton.backgroundColor = [UIColor navBarButtonColour]; + self.leftButton.layer.cornerRadius = 12; + self.leftButton.layer.cornerCurve = kCACornerCurveContinuous; + UIImage *leftIcon = [UIImage systemImageNamed:leftIconString]; + [self.leftButton setImage:leftIcon forState:UIControlStateNormal]; + self.leftButton.tintColor = accent; + [self.leftButton addTarget:self.superview action:leftAction forControlEvents:UIControlEventTouchUpInside]; + [self.headerView addSubview:self.leftButton]; + + [self.leftButton size:CGSizeMake(40, 40)]; + [self.leftButton y:self.headerView.centerYAnchor padding:5]; + [self.leftButton leading:self.headerView.leadingAnchor padding:20]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = [UIColor fontColour]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold]; + self.titleLabel.text = title; + [self.headerView addSubview:self.titleLabel]; + + [self.titleLabel y:self.headerView.centerYAnchor padding:5]; + [self.titleLabel x:self.headerView.centerXAnchor]; + + } + + return self; +} + + +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction rightIcon:(NSString *)rightIconString rightAction:(SEL)rightAction { + + self = [super init]; + if (self) { + + self.clipsToBounds = YES; + + self.headerView = [[UIView alloc] init]; + [self addSubview:self.headerView]; + + [self.headerView fill]; + + + self.grabberView = [[UIView alloc] init]; + self.grabberView.backgroundColor = [UIColor grabberColour]; + self.grabberView.layer.cornerRadius = 3; + [self.headerView addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.headerView.centerXAnchor]; + [self.grabberView top:self.headerView.topAnchor padding:10]; + + + self.leftButton = [[UIButton alloc] init]; + self.leftButton.backgroundColor = [UIColor navBarButtonColour]; + self.leftButton.layer.cornerRadius = 12; + self.leftButton.layer.cornerCurve = kCACornerCurveContinuous; + UIImage *leftIcon = [UIImage systemImageNamed:leftIconString]; + [self.leftButton setImage:leftIcon forState:UIControlStateNormal]; + self.leftButton.tintColor = accent; + [self.leftButton addTarget:self.superview action:leftAction forControlEvents:UIControlEventTouchUpInside]; + [self.headerView addSubview:self.leftButton]; + + [self.leftButton size:CGSizeMake(40, 40)]; + [self.leftButton y:self.headerView.centerYAnchor padding:5]; + [self.leftButton leading:self.headerView.leadingAnchor padding:20]; + + + self.rightButton = [[UIButton alloc] init]; + self.rightButton.backgroundColor = [UIColor navBarButtonColour]; + self.rightButton.layer.cornerRadius = 12; + self.rightButton.layer.cornerCurve = kCACornerCurveContinuous; + UIImage *rightIcon = [UIImage systemImageNamed:rightIconString]; + [self.rightButton setImage:rightIcon forState:UIControlStateNormal]; + [self.rightButton addTarget:self.superview action:rightAction forControlEvents:UIControlEventTouchUpInside]; + self.rightButton.tintColor = accent; + [self.headerView addSubview:self.rightButton]; + + [self.rightButton size:CGSizeMake(40, 40)]; + [self.rightButton y:self.headerView.centerYAnchor padding:5]; + [self.rightButton trailing:self.headerView.trailingAnchor padding:-20]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = [UIColor fontColour]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold]; + self.titleLabel.text = title; + [self.headerView addSubview:self.titleLabel]; + + [self.titleLabel y:self.headerView.centerYAnchor padding:5]; + [self.titleLabel x:self.headerView.centerXAnchor]; + + } + + return self; +} + + +@end diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageLayer.h b/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageLayer.h new file mode 100644 index 0000000..214ba45 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageLayer.h @@ -0,0 +1,39 @@ +@import QuartzCore; + +typedef NS_ENUM(NSInteger, DeviceUsageAppearanceType) { + DeviceUsageAppearanceTypeOverlaysEmptyLine = 0, + DeviceUsageAppearanceTypeAboveEmptyLine = 1, + DeviceUsageAppearanceTypeUnderEmptyLine = 2 +}; + +@interface DeviceUsageLayer : CALayer + +@property (nonatomic,assign) CGFloat progressAngle; +@property (nonatomic,assign) CGFloat progressRotationAngle; +@property (nonatomic,assign) DeviceUsageAppearanceType progressAppearanceType; +@property (nonatomic,assign) CGFloat value; +@property (nonatomic,assign) CGFloat maxValue; +@property (nonatomic,assign) CGFloat borderPadding; +@property (nonatomic,assign) NSTimeInterval animationDuration; +@property (nonatomic,assign) CGFloat valueFontSize; +@property (nonatomic,assign) CGFloat unitFontSize; +@property (nonatomic,copy) NSString *unitString; +@property (nonatomic,strong) UIColor *fontColor; +@property (nonatomic,assign) CGFloat progressLineWidth; +@property (nonatomic,strong) UIColor *progressColor; +@property (nonatomic,strong) UIColor *progressStrokeColor; +@property (nonatomic,assign) CGLineCap progressCapType; +@property (nonatomic,assign) CGFloat emptyLineWidth; +@property (nonatomic,assign) CGLineCap emptyCapType; +@property (nonatomic,strong) UIColor *emptyLineColor; +@property (nonatomic,strong) UIColor *emptyLineStrokeColor; +@property (nonatomic,assign) NSInteger decimalPlaces; +@property (nonatomic,assign) CGFloat valueDecimalFontSize; +@property (nonatomic,copy) NSString *unitFontName; +@property (nonatomic,copy) NSString *valueFontName; +@property (nonatomic,assign) BOOL showUnitString; +@property (nonatomic,assign) CGPoint textOffset; +@property (nonatomic,assign) BOOL showValueString; +@property (nonatomic,assign) BOOL countdown; + +@end diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageLayer.m b/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageLayer.m new file mode 100644 index 0000000..e3e2bbe --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageLayer.m @@ -0,0 +1,216 @@ +@import UIKit; +@import CoreGraphics; + +#import "DeviceUsageLayer.h" + +@implementation DeviceUsageLayer +@dynamic value; +@dynamic maxValue; +@dynamic borderPadding; +@dynamic valueFontSize; +@dynamic unitString; +@dynamic unitFontSize; +@dynamic progressLineWidth; +@dynamic progressColor; +@dynamic progressStrokeColor; +@dynamic emptyLineWidth; +@dynamic progressAngle; +@dynamic emptyLineColor; +@dynamic emptyLineStrokeColor; +@dynamic emptyCapType; +@dynamic progressCapType; +@dynamic fontColor; +@dynamic progressRotationAngle; +@dynamic progressAppearanceType; +@dynamic decimalPlaces; +@dynamic valueDecimalFontSize; +@dynamic unitFontName; +@dynamic valueFontName; +@dynamic showUnitString; +@dynamic showValueString; +@dynamic textOffset; +@dynamic countdown; + +#pragma mark - Drawing + +//-(void)setValue:(CGFloat)value{ +// [self drawProgressBar:<#(CGSize)#> context:<#(CGContextRef)#>] +//} + +- (void) drawInContext:(CGContextRef) context{ + [super drawInContext:context]; + + UIGraphicsPushContext(context); + + CGRect rect = CGContextGetClipBoundingBox(context); + rect = CGRectIntegral(CGRectInset(rect, self.borderPadding, self.borderPadding)); + + [self drawEmptyBar:rect context:context]; + [self drawProgressBar:rect context:context]; + + if (self.showValueString){ + [self drawText:rect context:context]; + } + + UIGraphicsPopContext(); +} + +- (void)drawEmptyBar:(CGRect)rect context:(CGContextRef)c{ + + if(self.emptyLineWidth <= 0){ + return; + } + + CGPoint center = {CGRectGetMidX(rect), CGRectGetMidY(rect)}; + CGFloat radius = MIN(CGRectGetWidth(rect), CGRectGetHeight(rect))/2; + if (self.progressAppearanceType == DeviceUsageAppearanceTypeOverlaysEmptyLine) { + radius = radius - MAX(self.emptyLineWidth, self.progressLineWidth)/2.f; + } else if (self.progressAppearanceType == DeviceUsageAppearanceTypeAboveEmptyLine) { + radius = radius - self.progressLineWidth - self.emptyLineWidth/2.f; + } else { + radius = radius - self.emptyLineWidth/2.f; + } + + CGMutablePathRef arc = CGPathCreateMutable(); + CGPathAddArc(arc, NULL, + center.x, center.y, radius, + (self.progressAngle/100.f)*M_PI-((-self.progressRotationAngle/100.f)*2.f+0.5)*M_PI, + -(self.progressAngle/100.f)*M_PI-((-self.progressRotationAngle/100.f)*2.f+0.5)*M_PI, + YES); + + + CGPathRef strokedArc = + CGPathCreateCopyByStrokingPath(arc, NULL, + self.emptyLineWidth, + (CGLineCap)self.emptyCapType, + kCGLineJoinMiter, + 10); + + + CGContextAddPath(c, strokedArc); + CGContextSetStrokeColorWithColor(c, self.emptyLineStrokeColor.CGColor); + CGContextSetFillColorWithColor(c, self.emptyLineColor.CGColor); + CGContextDrawPath(c, kCGPathFillStroke); + + CGPathRelease(arc); + CGPathRelease(strokedArc); + } + + - (void)drawProgressBar:(CGRect)rect context:(CGContextRef)c{ + if(self.progressLineWidth <= 0){ + return; + } + + CGPoint center = {CGRectGetMidX(rect), CGRectGetMidY(rect)}; + CGFloat radius = MIN(CGRectGetWidth(rect), CGRectGetHeight(rect))/2; + if (self.progressAppearanceType == DeviceUsageAppearanceTypeOverlaysEmptyLine) { + radius = radius - MAX(self.emptyLineWidth, self.progressLineWidth)/2.f; + } else if (self.progressAppearanceType == DeviceUsageAppearanceTypeAboveEmptyLine) { + radius = radius - self.progressLineWidth/2.f; + } else { + radius = radius - self.emptyLineWidth - self.progressLineWidth/2.f; + } + + CGMutablePathRef arc = CGPathCreateMutable(); + CGPathAddArc(arc, NULL, + center.x, center.y, radius, + (self.progressAngle/100.f)*M_PI-((-self.progressRotationAngle/100.f)*2.f+0.5)*M_PI-(2.f*M_PI)*(self.progressAngle/100.f)*(100.f-100.f*self.value/self.maxValue)/100.f, + -(self.progressAngle/100.f)*M_PI-((-self.progressRotationAngle/100.f)*2.f+0.5)*M_PI, + YES); + + CGPathRef strokedArc = + CGPathCreateCopyByStrokingPath(arc, NULL, + self.progressLineWidth, + (CGLineCap)self.progressCapType, + kCGLineJoinMiter, + 10); + + + CGContextAddPath(c, strokedArc); + CGContextSetFillColorWithColor(c, self.progressColor.CGColor); + CGContextSetStrokeColorWithColor(c, self.progressStrokeColor.CGColor); + CGContextDrawPath(c, kCGPathFillStroke); + + CGPathRelease(arc); + CGPathRelease(strokedArc); + + } + + - (void)drawText:(CGRect)rect context:(CGContextRef)c{ + NSMutableParagraphStyle* textStyle = NSMutableParagraphStyle.defaultParagraphStyle.mutableCopy; + textStyle.alignment = NSTextAlignmentLeft; + + CGFloat valueFontSize = self.valueFontSize == -1 ? CGRectGetHeight(rect)/5 : self.valueFontSize; + + NSDictionary* valueFontAttributes = @{NSFontAttributeName: [UIFont fontWithName: self.valueFontName size:valueFontSize], NSForegroundColorAttributeName: self.fontColor, NSParagraphStyleAttributeName: textStyle}; + + NSMutableAttributedString *text = [NSMutableAttributedString new]; + + NSString *formatString = [NSString stringWithFormat:@"%%.%df", (int)self.decimalPlaces]; + + NSString* textToPresent; + if (self.countdown) { + textToPresent = [NSString stringWithFormat:formatString, (self.maxValue - self.value)]; + } else { + textToPresent = [NSString stringWithFormat:formatString, self.value]; + } + NSAttributedString* value = [[NSAttributedString alloc] initWithString:textToPresent + attributes:valueFontAttributes]; + [text appendAttributedString:value]; + + // set the decimal font size + NSUInteger decimalLocation = [text.string rangeOfString:@"."].location; + if (decimalLocation != NSNotFound){ + NSDictionary* valueDecimalFontAttributes = @{NSFontAttributeName: [UIFont fontWithName: self.valueFontName size:self.valueDecimalFontSize == -1 ? valueFontSize : self.valueDecimalFontSize], NSForegroundColorAttributeName: self.fontColor, NSParagraphStyleAttributeName: textStyle}; + NSRange decimalRange = NSMakeRange(decimalLocation, text.length - decimalLocation); + [text setAttributes:valueDecimalFontAttributes range:decimalRange]; + } + + // ad the unit only if specified + if (self.showUnitString) { + NSDictionary* unitFontAttributes = @{NSFontAttributeName: [UIFont fontWithName: self.unitFontName size:self.unitFontSize == -1 ? CGRectGetHeight(rect)/7 : self.unitFontSize], NSForegroundColorAttributeName: self.fontColor, NSParagraphStyleAttributeName: textStyle}; + + NSAttributedString* unit = + [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@", self.unitString] attributes:unitFontAttributes]; + [text appendAttributedString:unit]; + } + + CGSize percentSize = [text size]; + CGPoint textCenter = CGPointMake( + CGRectGetMidX(rect)-percentSize.width/2 + self.textOffset.x, + CGRectGetMidY(rect)-percentSize.height/2 + self.textOffset.y + ); + + [text drawAtPoint:textCenter]; + } + + #pragma mark - Override methods to support animations + + + (BOOL)needsDisplayForKey:(NSString *)key { + if ([key isEqualToString:@"value"]) { + return YES; + } + return [super needsDisplayForKey:key]; + } + + - (id)actionForKey:(NSString *)event{ + if ([self presentationLayer] != nil) { + if ([event isEqualToString:@"value"]) { + id animation = [super actionForKey:@"backgroundColor"]; + + if (animation == nil || [animation isEqual:[NSNull null]]) + { + [self setNeedsDisplay]; + return [NSNull null]; + } + [animation setKeyPath:event]; + [animation setFromValue:[self.presentationLayer valueForKey:@"value"]]; + [animation setToValue:nil]; + return animation; + } + } + + return [super actionForKey:event]; + } + + @end diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageView.h b/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageView.h new file mode 100644 index 0000000..2fac6d1 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageView.h @@ -0,0 +1,31 @@ +@import UIKit; + +@interface DeviceUsageView : UIView +@property (nonatomic,assign) BOOL showValueString; +@property (nonatomic,assign) CGFloat value; +@property (nonatomic,assign) CGFloat maxValue; +@property (nonatomic,assign) CGFloat borderPadding; +@property (nonatomic,assign) NSInteger decimalPlaces; +@property (nonatomic,copy) NSString *valueFontName; +@property (nonatomic,assign) CGFloat valueFontSize; +@property (nonatomic,assign) CGFloat valueDecimalFontSize; +@property (nonatomic,assign) BOOL showUnitString; +@property (nonatomic,copy) NSString *unitFontName; +@property (nonatomic,assign) CGFloat unitFontSize; +@property (nonatomic,copy) NSString *unitString; +@property (nonatomic,strong) UIColor *fontColor; +@property (nonatomic,assign) NSInteger progressAppearanceType; +@property (nonatomic,assign) CGFloat progressRotationAngle; +@property (nonatomic,assign) CGFloat progressAngle; +@property (nonatomic,assign) CGFloat progressLineWidth; +@property (nonatomic,strong) UIColor *progressColor; +@property (nonatomic,strong) UIColor *progressStrokeColor; +@property (nonatomic,assign) NSInteger progressCapType; +@property (nonatomic,assign) CGFloat emptyLineWidth; +@property (nonatomic,strong) UIColor *emptyLineColor; +@property (nonatomic,strong) UIColor *emptyLineStrokeColor; +@property (nonatomic,assign) NSInteger emptyCapType; +@property (nonatomic,assign) CGPoint textOffset; +@property (nonatomic,assign) BOOL countdown; + +@end diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageView.m b/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageView.m new file mode 100644 index 0000000..efcc6fb --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/DeviceUsageView.m @@ -0,0 +1,311 @@ +#import "DeviceUsageView.h" +#import "DeviceUsageLayer.h" + +@implementation DeviceUsageView + +-(instancetype)initWithCoder:(NSCoder *)coder{ + self = [super initWithCoder:coder]; + if (self) { + [self initView:[self frame]]; + } + return self; +} + +-(instancetype)init{ + self = [super init]; + if (self) { + [self initView:CGRectNull]; + } + return self; +} + +-(instancetype)initWithFrame:(CGRect)frame{ + self = [super initWithFrame:frame]; + if (self) { + [self initView:frame]; + } + return self; +} + +-(void)initView:(CGRect)frame{ + //Without setting the content scale factor the layer would be pixelated + [self setContentScaleFactor:[[UIScreen mainScreen] scale]]; + + //This mode forces redrawing when bounds change (e.g. bounds change in animation) + [self setContentMode:UIViewContentModeRedraw]; + + [self setUnitString:@"%"]; + [self setValue:0.f]; + [self setMaxValue:100.f]; + [self setBorderPadding:1.f]; + [self setProgressAppearanceType:0]; + [self setProgressRotationAngle:0.f]; + [self setProgressStrokeColor:[UIColor orangeColor]]; + [self setProgressColor:[UIColor orangeColor]]; + [self setProgressCapType:kCGLineCapRound]; + [self setEmptyLineColor:[UIColor lightGrayColor]]; + [self setEmptyLineStrokeColor:[UIColor lightGrayColor]]; + [self setFontColor:[UIColor blackColor]]; + [self setEmptyLineWidth:1.f]; + [self setProgressLineWidth:14.f]; + [self setProgressAngle:80.f]; + [self setUnitFontSize:-1]; + [self setValueFontSize:-1]; + [self setValueDecimalFontSize:-1]; + [self setDecimalPlaces:0]; + [self setShowUnitString:YES]; + [self setShowValueString:YES]; + [self setValueFontName:@"HelveticaNeue-Thin"]; + [self setTextOffset:CGPointMake(0, 0)]; + [self setUnitFontName:@"HelveticaNeue-Thin"]; + [self setCountdown:NO]; +} + +#pragma mark - Getters and Setters for layer properties + +-(void)setShowValueString:(BOOL)showValueString{ + self.progressLayer.showValueString = showValueString; + [self.layer setNeedsDisplay]; +} + +-(BOOL)showValueString{ + return self.progressLayer.showValueString; +} + +-(void)setValue:(CGFloat)value{ + self.progressLayer.value = value; + + //CALayer autogenerated setter using @dynamic doesn't refresh the layer when the value is 0 + if(value == 0){ + [self.layer setNeedsDisplay]; + } +} + +-(CGFloat)value{ + return self.progressLayer.value; +} + +-(void)setMaxValue:(CGFloat)maxValue{ + self.progressLayer.maxValue = maxValue; + + //CALayer autogenerated setter using @dynamic doesn't refresh the layer when the value is 0 + if(maxValue == 0){ + [self.layer setNeedsDisplay]; + } +} + +-(CGFloat)maxValue{ + return self.progressLayer.maxValue; +} + +-(void)setBorderPadding:(CGFloat)borderPadding{ + self.progressLayer.borderPadding = borderPadding; +} + +-(CGFloat)borderPadding{ + return self.progressLayer.borderPadding; +} + +-(void)setProgressLineWidth:(CGFloat)width{ + self.progressLayer.progressLineWidth = width; +} + +-(CGFloat)progressLineWidth{ + return self.progressLayer.progressLineWidth; +} + +-(void)setEmptyLineWidth:(CGFloat)width{ + self.progressLayer.emptyLineWidth = width; +} + +-(CGFloat)emptyLineWidth{ + return self.progressLayer.emptyLineWidth; +} + +-(void)setProgressColor:(UIColor*)color{ + self.progressLayer.progressColor = color; +} + +-(UIColor*)progressColor{ + return self.progressLayer.progressColor; +} + +-(void)setUnitFontSize:(CGFloat)unitFontSize{ + self.progressLayer.unitFontSize = unitFontSize; +} + +-(CGFloat)unitFontSize{ + return self.progressLayer.unitFontSize; +} + +-(void)setValueFontSize:(CGFloat)valueFontSize{ + self.progressLayer.valueFontSize = valueFontSize; +} + +-(CGFloat)valueFontSize{ + return self.progressLayer.valueFontSize; +} + +-(void)setUnitString:(NSString *)unitString{ + self.progressLayer.unitString = unitString; +} + +-(NSString*)unitString{ + return self.progressLayer.unitString; +} + +-(void)setFontColor:(UIColor*)color{ + self.progressLayer.fontColor = color; +} + +-(UIColor*)fontColor{ + return self.progressLayer.fontColor; +} + +-(void)setProgressStrokeColor:(UIColor*)color{ + self.progressLayer.progressStrokeColor = color; +} + +-(UIColor*)progressStrokeColor{ + return self.progressLayer.progressStrokeColor; +} + +-(void)setEmptyLineColor:(UIColor *)emptyLineColor{ + self.progressLayer.emptyLineColor = emptyLineColor; +} + +-(UIColor*)emptyLineColor{ + return self.progressLayer.emptyLineColor; +} + +-(void)setEmptyLineStrokeColor:(UIColor *)emptyLineStrokeColor{ + self.progressLayer.emptyLineStrokeColor = emptyLineStrokeColor; +} + +-(UIColor*)emptyLineStrokeColor{ + return self.progressLayer.emptyLineStrokeColor; +} + +-(void)setProgressAngle:(CGFloat)progressAngle{ + self.progressLayer.progressAngle = progressAngle; +} + +-(CGFloat)progressAngle{ + return self.progressLayer.progressAngle; +} + +-(void)setProgressAppearanceType:(NSInteger)progressAppearanceType{ + self.progressLayer.progressAppearanceType = [self safeProgressAppearanceType:progressAppearanceType]; +} + +-(NSInteger)progressAppearanceType{ + return self.progressLayer.progressAppearanceType; +} + +-(DeviceUsageAppearanceType)safeProgressAppearanceType:(NSInteger)progressAppearanceType{ + if(DeviceUsageAppearanceTypeOverlaysEmptyLine <= progressAppearanceType && progressAppearanceType <= DeviceUsageAppearanceTypeUnderEmptyLine){ + return (DeviceUsageAppearanceType)progressAppearanceType; + } + + return DeviceUsageAppearanceTypeOverlaysEmptyLine; +} + +-(void)setProgressRotationAngle:(CGFloat)progressRootationAngle{ + self.progressLayer.progressRotationAngle = progressRootationAngle; +} + +-(CGFloat)progressRotationAngle{ + return self.progressLayer.progressRotationAngle; +} + +-(void)setProgressCapType:(NSInteger)progressCapType{ + self.progressLayer.progressCapType = [self safeCapType:progressCapType]; +} + +-(NSInteger)progressCapType{ + return self.progressLayer.progressCapType; +} + +-(void)setEmptyCapType:(NSInteger)emptyCapType{ + self.progressLayer.emptyCapType = [self safeCapType:emptyCapType]; +} + +-(NSInteger)emptyCapType{ + return self.progressLayer.emptyCapType; +} + +-(CGLineCap)safeCapType:(NSInteger)type{ + if(kCGLineCapButt <= type && type <= kCGLineCapSquare){ + return (CGLineCap)type; + } + + return kCGLineCapRound; +} + +-(void)setDecimalPlaces:(NSInteger)decimalPlaces{ + self.progressLayer.decimalPlaces = decimalPlaces; +} +-(NSInteger)decimalPlaces{ + return self.progressLayer.decimalPlaces; +} + +-(void)setValueDecimalFontSize:(CGFloat)valueDecimalFontSize{ + self.progressLayer.valueDecimalFontSize = valueDecimalFontSize; +} + +-(CGFloat)valueDecimalFontSize{ + return self.progressLayer.valueDecimalFontSize; +} + +-(void)setUnitFontName:(NSString *)unitFontName{ + self.progressLayer.unitFontName = unitFontName; +} + +-(NSString *)unitFontName{ + return self.progressLayer.unitFontName; +} + +-(void)setValueFontName:(NSString *)valueFontName{ + self.progressLayer.valueFontName = valueFontName; +} + +-(NSString *)valueFontName{ + return self.progressLayer.valueFontName; +} + +-(void)setShowUnitString:(BOOL)showUnitString{ + self.progressLayer.showUnitString = showUnitString; +} + +-(BOOL)showUnitString{ + return self.progressLayer.showUnitString; +} + +-(void)setTextOffset:(CGPoint)textOffset{ + self.progressLayer.textOffset = textOffset; +} + +-(CGPoint)textOffset{ + return self.progressLayer.textOffset; +} + +-(void)setCountdown:(BOOL)countdown { + self.progressLayer.countdown = countdown; +} + +-(BOOL)countdown { + return self.progressLayer.countdown; +} + +#pragma mark - CALayer + +-(DeviceUsageLayer*)progressLayer{ + DeviceUsageLayer* layer = (DeviceUsageLayer*) self.layer; + return layer; +} + ++ (Class) layerClass { + return [DeviceUsageLayer class]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/GridView.h b/iDevices/Tweak/IDEVICES/CustomClasses/GridView.h new file mode 100644 index 0000000..2356f1c --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/GridView.h @@ -0,0 +1,13 @@ +#import +#import + +@interface GridView : UIView +-(instancetype)initWithFrame:(CGRect)frame bg:(UIColor *)background icon:(UIImage *)icon iconSize:(CGFloat)size iconPadding:(CGFloat)iconPadding titleTop:(CGFloat)titleTop titleFont:(UIFont *)titleFont; +@property (nonatomic, retain) UIImageView *icon; +@property (nonatomic, retain) UILabel *title; +@property (nonatomic, retain) UIImage *iconImage; +@property (nonatomic) CGFloat iconSize; +@property (nonatomic) CGFloat iconPadding; +@property (nonatomic) CGFloat titleTopPadding; +@property (nonatomic, retain) UIFont *titleFont; +@end diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/GridView.m b/iDevices/Tweak/IDEVICES/CustomClasses/GridView.m new file mode 100644 index 0000000..bc2ac10 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/GridView.m @@ -0,0 +1,55 @@ +#import "GridView.h" + +@implementation GridView + +-(instancetype)initWithFrame:(CGRect)frame bg:(UIColor *)background icon:(UIImage *)icon iconSize:(CGFloat)size iconPadding:(CGFloat)iconPadding titleTop:(CGFloat)titleTop titleFont:(UIFont *)titleFont { + + self = [super initWithFrame:frame]; + if (self) { + + self.clipsToBounds = YES; + self.backgroundColor = background; + self.layer.cornerRadius = 20; + self.layer.cornerCurve = kCACornerCurveContinuous; + + self.iconPadding = iconPadding; + self.iconSize = size; + self.iconImage = icon; + self.titleTopPadding = titleTop; + self.titleFont = titleFont; + + [self layoutViews]; + + } + return self; +} + + +-(void)layoutViews { + + self.icon = [[UIImageView alloc] init]; + self.icon.contentMode = UIViewContentModeScaleAspectFit; + self.icon.tintColor = UIColor.whiteColor; + self.icon.image = self.iconImage; + [self addSubview:self.icon]; + + [self.icon size:CGSizeMake(self.iconSize, self.iconSize)]; + [self.icon top:self.topAnchor padding:self.iconPadding]; + [self.icon x:self.centerXAnchor]; + + + self.title = [[UILabel alloc] init]; + self.title.textAlignment = NSTextAlignmentCenter; + self.title.numberOfLines = 3; + self.title.font = self.titleFont; + self.title.textColor = UIColor.whiteColor; + [self addSubview:self.title]; + + [self.title x:self.centerXAnchor]; + [self.title top:self.icon.bottomAnchor padding:self.titleTopPadding]; + [self.title leading:self.leadingAnchor padding:20]; + [self.title trailing:self.trailingAnchor padding:-20]; + +} + +@end diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/HomeNavigationViewController.h b/iDevices/Tweak/IDEVICES/CustomClasses/HomeNavigationViewController.h new file mode 100644 index 0000000..c832a40 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/HomeNavigationViewController.h @@ -0,0 +1,5 @@ +#import + +@interface HomeNavigationViewController : UINavigationController +@end + diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/HomeNavigationViewController.m b/iDevices/Tweak/IDEVICES/CustomClasses/HomeNavigationViewController.m new file mode 100644 index 0000000..3995326 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/HomeNavigationViewController.m @@ -0,0 +1,25 @@ +#import "HomeNavigationViewController.h" + + +@implementation HomeNavigationViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + +} + + +- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated { + [super setNavigationBarHidden:hidden animated:animated]; + self.interactivePopGestureRecognizer.delegate = self; +} + + +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { + if (self.viewControllers.count > 1) { + return YES; + } + return NO; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/MemoryView.h b/iDevices/Tweak/IDEVICES/CustomClasses/MemoryView.h new file mode 100644 index 0000000..f37d26c --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/MemoryView.h @@ -0,0 +1,12 @@ +#import +#import "Colour-Scheme.h" + +@interface MemoryView : UIView +-(instancetype)initWithFrame:(CGRect)frame icon:(UIImage *)icon; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *icon; +@property (nonatomic, retain) UILabel *title; +@property (nonatomic, retain) UILabel *subtitle; +@property (nonatomic, retain) UIImage *iconImage; +@end + diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/MemoryView.m b/iDevices/Tweak/IDEVICES/CustomClasses/MemoryView.m new file mode 100644 index 0000000..e2c6f71 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/MemoryView.m @@ -0,0 +1,67 @@ +#import "MemoryView.h" + +@implementation MemoryView + +-(instancetype)initWithFrame:(CGRect)frame icon:(UIImage *)icon { + + self = [super initWithFrame:frame]; + if (self) { + + self.clipsToBounds = YES; + self.backgroundColor = [UIColor cellColour]; + self.layer.cornerRadius = 14; + self.layer.cornerCurve = kCACornerCurveContinuous; + + self.iconImage = icon; + + [self layoutViews]; + + } + return self; +} + + +-(void)layoutViews { + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 12.5; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + [self addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(45, 45)]; + [self.iconView y:self.centerYAnchor]; + [self.iconView leading:self.leadingAnchor padding:15]; + + + self.icon = [[UIImageView alloc] init]; + self.icon.contentMode = UIViewContentModeScaleAspectFit; + self.icon.image = self.iconImage; + [self addSubview:self.icon]; + + [self.icon size:CGSizeMake(30, 30)]; + [self.icon x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.title = [[UILabel alloc] init]; + self.title.textAlignment = NSTextAlignmentLeft; + self.title.textColor = UIColor.titleColour; + self.title.font = [UIFont systemFontOfSize:18 weight:UIFontWeightSemibold]; + [self addSubview:self.title]; + + [self.title top:self.iconView.topAnchor padding:2]; + [self.title leading:self.icon.trailingAnchor padding:15]; + + + self.subtitle = [[UILabel alloc] init]; + self.subtitle.textAlignment = NSTextAlignmentLeft; + self.subtitle.textColor = UIColor.subtitleColour; + self.subtitle.font = [UIFont systemFontOfSize:16 weight:UIFontWeightRegular]; + [self addSubview:self.subtitle]; + + [self.subtitle bottom:self.iconView.bottomAnchor padding:-2]; + [self.subtitle leading:self.icon.trailingAnchor padding:15]; + + +} + +@end diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/SummaryView.h b/iDevices/Tweak/IDEVICES/CustomClasses/SummaryView.h new file mode 100644 index 0000000..3bd700d --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/SummaryView.h @@ -0,0 +1,12 @@ +#import +#import "Colour-Scheme.h" + +@interface SummaryView : UIView +-(instancetype)initWithFrame:(CGRect)frame icon:(UIImage *)icon; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIImageView *icon; +@property (nonatomic, retain) UILabel *title; +@property (nonatomic, retain) UILabel *subtitle; +@property (nonatomic, retain) UIImage *iconImage; +@end + diff --git a/iDevices/Tweak/IDEVICES/CustomClasses/SummaryView.m b/iDevices/Tweak/IDEVICES/CustomClasses/SummaryView.m new file mode 100644 index 0000000..09da22c --- /dev/null +++ b/iDevices/Tweak/IDEVICES/CustomClasses/SummaryView.m @@ -0,0 +1,66 @@ +#import "SummaryView.h" + +@implementation SummaryView + +-(instancetype)initWithFrame:(CGRect)frame icon:(UIImage *)icon { + + self = [super initWithFrame:frame]; + if (self) { + + self.clipsToBounds = YES; + self.backgroundColor = [UIColor cellColour]; + self.layer.cornerRadius = 14; + self.layer.cornerCurve = kCACornerCurveContinuous; + + self.iconImage = icon; + + [self layoutViews]; + + } + return self; +} + + +-(void)layoutViews { + + self.iconView = [[UIView alloc] init]; + self.iconView.layer.cornerRadius = 12.5; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + [self addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(45, 45)]; + [self.iconView y:self.centerYAnchor]; + [self.iconView leading:self.leadingAnchor padding:15]; + + + self.icon = [[UIImageView alloc] init]; + self.icon.contentMode = UIViewContentModeScaleAspectFit; + self.icon.image = self.iconImage; + [self addSubview:self.icon]; + + [self.icon size:CGSizeMake(30, 30)]; + [self.icon x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.title = [[UILabel alloc] init]; + self.title.textAlignment = NSTextAlignmentLeft; + self.title.textColor = UIColor.titleColour; + self.title.font = [UIFont systemFontOfSize:17 weight:UIFontWeightSemibold]; + [self addSubview:self.title]; + + [self.title top:self.iconView.topAnchor padding:2]; + [self.title leading:self.icon.trailingAnchor padding:15]; + + + self.subtitle = [[UILabel alloc] init]; + self.subtitle.textAlignment = NSTextAlignmentLeft; + self.subtitle.textColor = UIColor.subtitleColour; + self.subtitle.font = [UIFont systemFontOfSize:14 weight:UIFontWeightRegular]; + [self addSubview:self.subtitle]; + + [self.subtitle bottom:self.iconView.bottomAnchor padding:-2]; + [self.subtitle leading:self.icon.trailingAnchor padding:15]; + +} + +@end diff --git a/iDevices/Tweak/IDEVICES/DataManager/DataManager.h b/iDevices/Tweak/IDEVICES/DataManager/DataManager.h new file mode 100644 index 0000000..38da930 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/DataManager/DataManager.h @@ -0,0 +1,15 @@ +#import +#import "GlobalPreferences.h" + +@interface DataManager : NSObject + ++(instancetype)sharedInstance; +-(id)init; +-(NSString *)icloudFullName; +-(UIImage *)icloudAvatar; +-(NSString *)lastLockedDevice; +-(NSString *)lastUnlockedDevice; +-(NSString *)lastRespringDevice; +-(NSString *)lastOpenedApp; +-(NSString *)lastiCloudBackUpDate; +@end diff --git a/iDevices/Tweak/IDEVICES/DataManager/DataManager.m b/iDevices/Tweak/IDEVICES/DataManager/DataManager.m new file mode 100644 index 0000000..3212b5e --- /dev/null +++ b/iDevices/Tweak/IDEVICES/DataManager/DataManager.m @@ -0,0 +1,54 @@ +#import "DataManager.h" + +@implementation DataManager + ++(instancetype)sharedInstance { + static DataManager *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[DataManager alloc] init]; + }); + return sharedInstance; +} + +-(id)init { + return self; +} + + +-(NSString *)icloudFullName { + return [[TDTweakManager sharedInstance] objectForKey:@"icloudName" defaultValue:@"Username" ID:BID]; +} + + +-(UIImage *)icloudAvatar { + NSData *profileAvatar = [[TDTweakManager sharedInstance] objectForKey:@"icloudAvatar" defaultValue:nil ID:BID]; + return [UIImage imageWithData:profileAvatar]; +} + + +-(NSString *)lastLockedDevice { + return [[TDTweakManager sharedInstance] objectForKey:@"lastTimeLocked" defaultValue:@"You haven't locked your device yet." ID:BID]; +} + + +-(NSString *)lastUnlockedDevice { + return [[TDTweakManager sharedInstance] objectForKey:@"lastTimeUnlocked" defaultValue:@"You haven't unlocked your device yet." ID:BID]; +} + + +-(NSString *)lastRespringDevice { + return [[TDTweakManager sharedInstance] objectForKey:@"lastTimeRespring" defaultValue:@"You haven't respring yet." ID:BID]; +} + + +-(NSString *)lastOpenedApp { + return [[TDTweakManager sharedInstance] objectForKey:@"lastOpenedApp" defaultValue:@"You haven't opened app yet." ID:BID]; +} + + +-(NSString *)lastiCloudBackUpDate { + return [[TDTweakManager sharedInstance] objectForKey:@"lastiCloudBackUpDate" defaultValue:@"You haven't backup yet." ID:BID]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Devices/DeviceViewController.h b/iDevices/Tweak/IDEVICES/Devices/DeviceViewController.h new file mode 100644 index 0000000..a40750a --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Devices/DeviceViewController.h @@ -0,0 +1,15 @@ +#import +#import "Colour-Scheme.h" +#import "DataManager.h" +#import "CDHeaderView.h" +#import "DevicesCell.h" +#import "SectionCellHeaderView.h" + +@interface DeviceViewController : UIViewController +@property (nonatomic, retain) CDHeaderView *headerView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *devicesArray; +@property (nonatomic, retain) UIView *containerView; +@property (nonatomic, retain) UIImageView *headerIcon; +@property (nonatomic, retain) UILabel *headerTitle; +@end diff --git a/iDevices/Tweak/IDEVICES/Devices/DeviceViewController.m b/iDevices/Tweak/IDEVICES/Devices/DeviceViewController.m new file mode 100644 index 0000000..13d5009 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Devices/DeviceViewController.m @@ -0,0 +1,245 @@ +#import "DeviceViewController.h" + +@implementation DeviceViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [UIColor accentColour]; + self.view.tintColor = [UIColor accentColour]; + + [self getDevicesData]; + [self layoutHeaderView]; + [self layoutCollectionView]; +} + + +-(void)getDevicesData { + + NSString *plistPath = @"/tmp/EMPGetDevices.plist"; //[IMPORTANT] Need to change plist path to wherever it was saved to + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + self.devicesArray = [NSMutableArray new]; + self.devicesArray = [mutableDict objectForKey:@"devices"]; + +} + + +-(void)layoutHeaderView { + + self.containerView = [[UIView alloc] init]; + self.containerView.layer.cornerRadius = 25; + self.containerView.layer.cornerCurve = kCACornerCurveContinuous; + self.containerView.layer.maskedCorners = 12; + self.containerView.clipsToBounds = YES; + [self.view addSubview:self.containerView]; + + [self.containerView size:CGSizeMake(self.view.frame.size.width, 200)]; + [self.containerView x:self.view.centerXAnchor]; + [self.containerView top:self.view.topAnchor padding:0]; + + + UIImageView *wallpaper = [[UIImageView alloc] init]; + if (toggleCustomCoverImage) { + wallpaper.image = [UIImage imageWithData:customCoverImage]; + } else { + wallpaper.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/iDevices.bundle/Assets/Default/cover-image.png"]; + } + wallpaper.contentMode = UIViewContentModeScaleAspectFill; + [self.containerView addSubview:wallpaper]; + + [wallpaper fill]; + + + self.headerView = [[CDHeaderView alloc] initWithTitle:@"" accent:[UIColor accentColour] leftIcon:@"chevron.left" leftAction:@selector(pushBackVC)]; + self.headerView.leftButton.backgroundColor = [UIColor.navBarButtonColour colorWithAlphaComponent:0.5]; + [self.containerView addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.containerView.centerXAnchor]; + [self.headerView top:self.containerView.topAnchor padding:0]; + + + self.headerIcon = [[UIImageView alloc] init]; + self.headerIcon.contentMode = UIViewContentModeScaleAspectFit; + self.headerIcon.image = [UIImage systemImageNamed:@"laptopcomputer.and.iphone"]; + self.headerIcon.tintColor = UIColor.coverIconColour; + [self.containerView addSubview:self.headerIcon]; + + [self.headerIcon size:CGSizeMake(75, 75)]; + [self.headerIcon x:self.containerView.centerXAnchor]; + [self.headerIcon top:self.headerView.bottomAnchor padding:-10]; + + + self.headerTitle = [[UILabel alloc] init]; + self.headerTitle.textAlignment = NSTextAlignmentCenter; + self.headerTitle.font = [UIFont systemFontOfSize:18 weight:UIFontWeightBold]; + self.headerTitle.textColor = UIColor.coverTitleColour; + self.headerTitle.text = @"Devices"; + [self.containerView addSubview:self.headerTitle]; + + [self.headerTitle x:self.containerView.centerXAnchor]; + [self.headerTitle top:self.headerIcon.bottomAnchor padding:10]; + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[DevicesCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.collectionView registerClass:[SectionCellHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; + [self.view addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + + [self.collectionView top:self.containerView.bottomAnchor padding:0]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + [self.collectionView bottom:self.view.bottomAnchor padding:-5]; +} + + +- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView { + return 1; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { + return CGSizeMake(self.view.frame.size.width, 45); +} + + +-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + UICollectionReusableView *reusableview = nil; + + if (kind == UICollectionElementKindSectionHeader) { + + SectionCellHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; + if ([self.devicesArray count] > 1) { + headerView.headerLabel.text = [NSString stringWithFormat:@"%lu Devices", [self.devicesArray count]]; + } else { + headerView.headerLabel.text = @"No Devices"; + } + reusableview = headerView; + } + + return reusableview; + +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.devicesArray.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + DevicesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + NSData *imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:self.devicesArray[indexPath.row][@"modelLargePhotoURL1x"]]]; + cell.deviceImage.image = [UIImage imageWithData: imageData]; + + cell.nameLabel.text = self.devicesArray[indexPath.row][@"name"]; + cell.deviceLabel.text = self.devicesArray[indexPath.row][@"modelDisplayName"]; + cell.modelLabel.text = self.devicesArray[indexPath.row][@"model"]; + NSString *versionString = [self.devicesArray[indexPath.row][@"swVersion"] stringByReplacingOccurrencesOfString:@";" withString:@" "]; + cell.versionLabel.text = versionString; + + return cell; + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat width = self.view.frame.size.width /2 -30; + return CGSizeMake(width, 150); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 20.0; +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 20.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + +} + + +- (UIContextMenuConfiguration *)collectionView:(UICollectionView *)collectionView contextMenuConfigurationForItemAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point { + + UIContextMenuConfiguration* config = [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil actionProvider:^UIMenu* _Nullable(NSArray* _Nonnull suggestedActions) { + + NSString *menuTitle = self.devicesArray[indexPath.row][@"name"]; + + UIAction *copyAction = [UIAction actionWithTitle:@"Copy Details" image:[UIImage systemImageNamed:@"paperclip"] identifier:nil handler:^(UIAction *action) { + + NSString *versionString = [self.devicesArray[indexPath.row][@"swVersion"] stringByReplacingOccurrencesOfString:@";" withString:@" "]; + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = [NSString stringWithFormat:@"%@\n%@\n%@\n%@", self.devicesArray[indexPath.row][@"name"], self.devicesArray[indexPath.row][@"modelDisplayName"], self.devicesArray[indexPath.row][@"model"], versionString]; + [self showAlertWithTitle:@"" subtitle:[NSString stringWithFormat:@"The details for %@ was copied to your clipboard.", menuTitle]]; + }]; + + return [UIMenu menuWithTitle:menuTitle children:@[copyAction]]; + + }]; + + return config; +} + + +-(void)pushBackVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + + +-(void)showAlertWithTitle:(NSString *)title subtitle:(NSString *)subtitle { // iloveya + UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:subtitle preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + }]; + + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Global/GlobalPreferences.h b/iDevices/Tweak/IDEVICES/Global/GlobalPreferences.h new file mode 100644 index 0000000..8a42470 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Global/GlobalPreferences.h @@ -0,0 +1,99 @@ +#import + +static NSString *BID = @"com.TitanD3v.iDevicesPrefs"; + + +static BOOL toggleCustomColour; +static BOOL toggleHapticFeedback; +static NSInteger hapticFeedbackStrength; +static BOOL toggleCustomCoverImage; +static NSData *customCoverImage = nil; + +static void loadPrefs() { + + toggleCustomColour = [[TDTweakManager sharedInstance] boolForKey:@"toggleCustomColour" defaultValue:NO ID:BID]; + toggleHapticFeedback = [[TDTweakManager sharedInstance] boolForKey:@"toggleHapticFeedback" defaultValue:YES ID:BID]; + hapticFeedbackStrength = [[TDTweakManager sharedInstance] intForKey:@"hapticFeedbackStrength" defaultValue:0 ID:BID]; + toggleCustomCoverImage = [[TDTweakManager sharedInstance] boolForKey:@"toggleCustomCoverImage" defaultValue:NO ID:BID]; + customCoverImage = [[TDTweakManager sharedInstance] objectForKey:@"customCoverImage" ID:BID]; +} + + +static void invokeHaptic() { + + toggleHapticFeedback = [[TDTweakManager sharedInstance] boolForKey:@"toggleHapticFeedback" defaultValue:YES ID:BID]; + hapticFeedbackStrength = [[TDTweakManager sharedInstance] intForKey:@"hapticFeedbackStrength" defaultValue:0 ID:BID]; + + if (toggleHapticFeedback) { + UIImpactFeedbackGenerator *haptic; + if (hapticFeedbackStrength == 0) { + haptic = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; + } else if (hapticFeedbackStrength == 1) { + haptic = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium]; + } else if (hapticFeedbackStrength == 2) { + haptic = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleHeavy]; + } + [haptic impactOccurred]; + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +//static BOOL toggleParadise; +//static NSString *appdataAppearance; +//static BOOL toggleAppdataColour; +//static BOOL toggleAppdataBackgroundImage; +//static NSData *appdataBackgroundImage = nil; +//static BOOL toggleAppdataHaptic; +//static NSInteger appdataHapticStrength; +//static BOOL toggleAppdataCustomFont; +//static NSData *appdataCustomFont; +//static BOOL toggleBlurEffect; +//static float bottomSheetCornerRadius; +//static BOOL toggle3DMenu; +//static BOOL showSBTutorial; +// +//static void loadPrefs() { +// +// toggleParadise = [[TDTweakManager sharedInstance] boolForKey:@"toggleParadise" defaultValue:NO ID:BID]; +// appdataAppearance = [[TDTweakManager sharedInstance] objectForKey:@"appdataAppearance" defaultValue:@"appdataLight" ID:BID]; +// toggleAppdataColour = [[TDTweakManager sharedInstance] boolForKey:@"toggleAppdataColour" defaultValue:NO ID:BID]; +// toggleAppdataBackgroundImage = [[TDTweakManager sharedInstance] boolForKey:@"toggleAppdataBackgroundImage" defaultValue:NO ID:BID]; +// appdataBackgroundImage = [[TDTweakManager sharedInstance] objectForKey:@"appdataBackgroundImage" ID:BID]; +// toggleAppdataHaptic = [[TDTweakManager sharedInstance] boolForKey:@"toggleAppdataHaptic" defaultValue:YES ID:BID]; +// appdataHapticStrength = [[TDTweakManager sharedInstance] intForKey:@"appdataHapticStrength" defaultValue:0 ID:BID]; +// toggleAppdataCustomFont = [[TDTweakManager sharedInstance] boolForKey:@"toggleAppdataCustomFont" defaultValue:NO ID:BID]; +// appdataCustomFont = [[TDTweakManager sharedInstance] objectForKey:@"appdataCustomFont" ID:BID]; +// toggleBlurEffect = [[TDTweakManager sharedInstance] boolForKey:@"toggleBlurEffect" defaultValue:YES ID:BID]; +// bottomSheetCornerRadius = [[TDTweakManager sharedInstance] floatForKey:@"bottomSheetCornerRadius" defaultValue:30 ID:BID]; +// toggle3DMenu = [[TDTweakManager sharedInstance] boolForKey:@"toggle3DMenu" defaultValue:NO ID:BID]; +// showSBTutorial = [[TDTweakManager sharedInstance] boolForKey:@"showSBTutorial" defaultValue:YES ID:BID]; +//} diff --git a/iDevices/Tweak/IDEVICES/Home/HomeViewController.h b/iDevices/Tweak/IDEVICES/Home/HomeViewController.h new file mode 100644 index 0000000..e7561a3 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Home/HomeViewController.h @@ -0,0 +1,37 @@ +#import +#import "GridView.h" +#import "SummaryView.h" +#import "Colour-Scheme.h" +#import "DataManager.h" +#import "CloudViewController.h" +#import "DeviceViewController.h" +#import "BatteryViewController.h" +#import "StorageViewController.h" +#import "MemoryViewController.h" +#import "AboutViewController.h" +#import "AppsViewController.h" +#import "TweaksViewController.h" + +@interface HomeViewController : UIViewController +@property (nonatomic, retain) UIView *headerView; +@property (nonatomic, retain) UIView *grabberView; +@property (nonatomic, retain) UIImageView *avatarImage; +@property (nonatomic, retain) UILabel *welcomeTitle; +@property (nonatomic, retain) UILabel *welcomeSubtitle; +@property (nonatomic, retain) UIScrollView *scrollView; +@property (nonatomic, retain) UIView *containerView; +@property (nonatomic, retain) GridView *icloudView; +@property (nonatomic, retain) GridView *deviceView; +@property (nonatomic, retain) GridView *batteryView; +@property (nonatomic, retain) GridView *storageView; +@property (nonatomic, retain) GridView *memoryView; +@property (nonatomic, retain) GridView *aboutView; +@property (nonatomic, retain) GridView *appsView; +@property (nonatomic, retain) GridView *tweaksView; +@property (nonatomic, retain) UILabel *summaryLabel; +@property (nonatomic, retain) SummaryView *lockedView; +@property (nonatomic, retain) SummaryView *unlockedView; +@property (nonatomic, retain) SummaryView *respringView; +@property (nonatomic, retain) SummaryView *appView; +@property (nonatomic, retain) UIView *footerView; +@end diff --git a/iDevices/Tweak/IDEVICES/Home/HomeViewController.m b/iDevices/Tweak/IDEVICES/Home/HomeViewController.m new file mode 100644 index 0000000..18cd27b --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Home/HomeViewController.m @@ -0,0 +1,371 @@ +#import "HomeViewController.h" + +@implementation HomeViewController + +-(void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self.navigationController setNavigationBarHidden:YES animated:NO]; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [UIColor accentColour]; + self.view.tintColor = [UIColor accentColour]; + + [self layoutHeaderView]; + [self layoutScrollView]; + [self layoutGridViews]; + [self initGestures]; +} + + +-(void)layoutHeaderView { + + self.grabberView = [[UIView alloc] init]; + self.grabberView.backgroundColor = [UIColor grabberColour]; + self.grabberView.layer.cornerRadius = 3; + [self.view addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.view.centerXAnchor]; + [self.grabberView top:self.view.topAnchor padding:10]; + + + self.headerView = [[UIView alloc] init]; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 60)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.safeAreaLayoutGuide.topAnchor padding:15]; + + + self.avatarImage = [[UIImageView alloc] init]; + self.avatarImage.layer.cornerRadius = 25; + self.avatarImage.clipsToBounds = YES; + self.avatarImage.image = [[DataManager sharedInstance] icloudAvatar]; + self.avatarImage.userInteractionEnabled = YES; + self.avatarImage.tintColor = [UIColor accentColour]; + [self.headerView addSubview:self.avatarImage]; + + [self.avatarImage size:CGSizeMake(50, 50)]; + [self.avatarImage y:self.headerView.centerYAnchor]; + [self.avatarImage trailing:self.headerView.trailingAnchor padding:-20]; + + + self.welcomeTitle = [[UILabel alloc] init]; + self.welcomeTitle.text = @"WELCOME"; + self.welcomeTitle.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium]; + self.welcomeTitle.textColor = [UIColor secondaryFontColour]; + self.welcomeTitle.textAlignment = NSTextAlignmentLeft; + [self.headerView addSubview:self.welcomeTitle]; + + [self.welcomeTitle top:self.avatarImage.topAnchor padding:0]; + [self.welcomeTitle leading:self.headerView.leadingAnchor padding:20]; + [self.welcomeTitle trailing:self.avatarImage.leadingAnchor padding:-20]; + + + self.welcomeSubtitle = [[UILabel alloc] init]; + self.welcomeSubtitle.text = [[DataManager sharedInstance] icloudFullName]; + self.welcomeSubtitle.font = [UIFont systemFontOfSize:26 weight:UIFontWeightBold]; + self.welcomeSubtitle.textColor = [UIColor fontColour]; + self.welcomeSubtitle.textAlignment = NSTextAlignmentLeft; + [self.headerView addSubview:self.welcomeSubtitle]; + + [self.welcomeSubtitle bottom:self.avatarImage.bottomAnchor padding:0]; + [self.welcomeSubtitle leading:self.headerView.leadingAnchor padding:20]; + [self.welcomeSubtitle trailing:self.avatarImage.leadingAnchor padding:-20]; + +} + + +-(void)layoutScrollView { + + self.scrollView = [[UIScrollView alloc] init]; + self.scrollView.showsVerticalScrollIndicator = NO; + self.scrollView.showsHorizontalScrollIndicator = NO; + self.scrollView.backgroundColor = UIColor.clearColor; + [self.view addSubview:self.scrollView]; + + [self.scrollView top:self.headerView.bottomAnchor padding:0]; + [self.scrollView leading:self.view.leadingAnchor padding:0]; + [self.scrollView trailing:self.view.trailingAnchor padding:0]; + [self.scrollView bottom:self.view.bottomAnchor padding:0]; + + + self.containerView = [[UIView alloc] init]; + self.containerView.backgroundColor = UIColor.clearColor; + [self.scrollView addSubview:self.containerView]; + + [self.containerView size:CGSizeMake(self.view.frame.size.width, 860)]; + [self.containerView x:self.scrollView.centerXAnchor]; + [self.containerView top:self.scrollView.topAnchor padding:0]; + +} + + +-(void)layoutGridViews { + + self.icloudView = [[GridView alloc] initWithFrame:CGRectZero bg:[UIColor.tealColour colorWithAlphaComponent:0.4] icon:[UIImage systemImageNamed:@"cloud.fill"] iconSize:70 iconPadding:10 titleTop:5 titleFont:[UIFont systemFontOfSize:16 weight:UIFontWeightBold]]; + self.icloudView.title.text = @"iCloud"; + self.icloudView.icon.tintColor = UIColor.tealColour; + [self.containerView addSubview:self.icloudView]; + + [self.icloudView size:CGSizeMake(self.view.frame.size.width/2-30, 110)]; + [self.icloudView top:self.containerView.topAnchor padding:20]; + [self.icloudView leading:self.containerView.leadingAnchor padding:20]; + + + self.deviceView = [[GridView alloc] initWithFrame:CGRectZero bg:[UIColor.indigoColour colorWithAlphaComponent:0.4] icon:[UIImage systemImageNamed:@"laptopcomputer.and.iphone"] iconSize:70 iconPadding:10 titleTop:5 titleFont:[UIFont systemFontOfSize:16 weight:UIFontWeightBold]]; + self.deviceView.title.text = @"Devices"; + self.deviceView.icon.tintColor = UIColor.indigoColour; + [self.containerView addSubview:self.deviceView]; + + [self.deviceView size:CGSizeMake(self.view.frame.size.width/2-30, 110)]; + [self.deviceView top:self.containerView.topAnchor padding:20]; + [self.deviceView trailing:self.containerView.trailingAnchor padding:-20]; + + + self.batteryView = [[GridView alloc] initWithFrame:CGRectZero bg:[UIColor.greenColour colorWithAlphaComponent:0.4] icon:[UIImage systemImageNamed:@"battery.100"] iconSize:70 iconPadding:10 titleTop:5 titleFont:[UIFont systemFontOfSize:16 weight:UIFontWeightBold]]; + self.batteryView.title.text = @"Battery"; + self.batteryView.icon.tintColor = UIColor.greenColour; + [self.containerView addSubview:self.batteryView]; + + [self.batteryView size:CGSizeMake(self.view.frame.size.width/2-30, 110)]; + [self.batteryView top:self.icloudView.bottomAnchor padding:20]; + [self.batteryView leading:self.containerView.leadingAnchor padding:20]; + + + self.storageView = [[GridView alloc] initWithFrame:CGRectZero bg:[UIColor.yellowColour colorWithAlphaComponent:0.4] icon:[UIImage systemImageNamed:@"chart.pie.fill"] iconSize:70 iconPadding:10 titleTop:5 titleFont:[UIFont systemFontOfSize:16 weight:UIFontWeightBold]]; + self.storageView.title.text = @"Storage"; + self.storageView.icon.tintColor = UIColor.yellowColour; + [self.containerView addSubview:self.storageView]; + + [self.storageView size:CGSizeMake(self.view.frame.size.width/2-30, 110)]; + [self.storageView top:self.deviceView.bottomAnchor padding:20]; + [self.storageView trailing:self.containerView.trailingAnchor padding:-20]; + + + self.memoryView = [[GridView alloc] initWithFrame:CGRectZero bg:[UIColor.redColour colorWithAlphaComponent:0.4] icon:[UIImage systemImageNamed:@"chart.bar.xaxis"] iconSize:70 iconPadding:10 titleTop:5 titleFont:[UIFont systemFontOfSize:16 weight:UIFontWeightBold]]; + self.memoryView.title.text = @"RAM Usage"; + self.memoryView.icon.tintColor = UIColor.redColour; + [self.containerView addSubview:self.memoryView]; + + [self.memoryView size:CGSizeMake(self.view.frame.size.width/2-30, 110)]; + [self.memoryView top:self.batteryView.bottomAnchor padding:20]; + [self.memoryView leading:self.containerView.leadingAnchor padding:20]; + + + self.aboutView = [[GridView alloc] initWithFrame:CGRectZero bg:[UIColor.orangeColour colorWithAlphaComponent:0.4] icon:[UIImage systemImageNamed:@"info.circle.fill"] iconSize:70 iconPadding:10 titleTop:5 titleFont:[UIFont systemFontOfSize:16 weight:UIFontWeightBold]]; + self.aboutView.title.text = @"About"; + self.aboutView.icon.tintColor = UIColor.orangeColour; + [self.containerView addSubview:self.aboutView]; + + [self.aboutView size:CGSizeMake(self.view.frame.size.width/2-30, 110)]; + [self.aboutView top:self.storageView.bottomAnchor padding:20]; + [self.aboutView trailing:self.containerView.trailingAnchor padding:-20]; + + + self.appsView = [[GridView alloc] initWithFrame:CGRectZero bg:[UIColor.accentColour colorWithAlphaComponent:0.4] icon:[UIImage systemImageNamed:@"apps.iphone"] iconSize:70 iconPadding:10 titleTop:5 titleFont:[UIFont systemFontOfSize:16 weight:UIFontWeightBold]]; + self.appsView.title.text = @"Apps"; + self.appsView.icon.tintColor = UIColor.accentColour; + [self.containerView addSubview:self.appsView]; + + [self.appsView size:CGSizeMake(self.view.frame.size.width/2-30, 110)]; + [self.appsView top:self.memoryView.bottomAnchor padding:20]; + [self.appsView leading:self.containerView.leadingAnchor padding:20]; + + + self.tweaksView = [[GridView alloc] initWithFrame:CGRectZero bg:[UIColor.pinkColour colorWithAlphaComponent:0.4] icon:[UIImage systemImageNamed:@"hammer.fill"] iconSize:70 iconPadding:10 titleTop:5 titleFont:[UIFont systemFontOfSize:16 weight:UIFontWeightBold]]; + self.tweaksView.title.text = @"Tweaks"; + self.tweaksView.icon.tintColor = UIColor.pinkColour; + [self.containerView addSubview:self.tweaksView]; + + [self.tweaksView size:CGSizeMake(self.view.frame.size.width/2-30, 110)]; + [self.tweaksView top:self.aboutView.bottomAnchor padding:20]; + [self.tweaksView trailing:self.containerView.trailingAnchor padding:-20]; + + + self.summaryLabel = [[UILabel alloc] init]; + self.summaryLabel.text = @"Summary"; + self.summaryLabel.font = [UIFont systemFontOfSize:28 weight:UIFontWeightHeavy]; + self.summaryLabel.textColor = [UIColor subtitleColour]; + self.summaryLabel.textAlignment = NSTextAlignmentLeft; + [self.containerView addSubview:self.summaryLabel]; + + [self.summaryLabel top:self.appsView.bottomAnchor padding:25]; + [self.summaryLabel leading:self.containerView.leadingAnchor padding:20]; + + + self.lockedView = [[SummaryView alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"lock.fill"]]; + self.lockedView.title.text = @"Last time locked"; + self.lockedView.subtitle.text = [[DataManager sharedInstance] lastLockedDevice]; + self.lockedView.iconView.backgroundColor = [UIColor.redColour colorWithAlphaComponent:0.4]; + self.lockedView.icon.tintColor = UIColor.redColour; + [self.containerView addSubview:self.lockedView]; + + [self.lockedView size:CGSizeMake(self.view.frame.size.width-40, 60)]; + [self.lockedView x:self.containerView.centerXAnchor]; + [self.lockedView top:self.summaryLabel.bottomAnchor padding:10]; + + + self.unlockedView = [[SummaryView alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"lock.open.fill"]]; + self.unlockedView.title.text = @"Last time unlocked"; + self.unlockedView.subtitle.text = [[DataManager sharedInstance] lastUnlockedDevice]; + self.unlockedView.iconView.backgroundColor = [UIColor.greenColour colorWithAlphaComponent:0.4]; + self.unlockedView.icon.tintColor = UIColor.greenColour; + [self.containerView addSubview:self.unlockedView]; + + [self.unlockedView size:CGSizeMake(self.view.frame.size.width-40, 60)]; + [self.unlockedView x:self.containerView.centerXAnchor]; + [self.unlockedView top:self.lockedView.bottomAnchor padding:10]; + + + self.respringView = [[SummaryView alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"rays"]]; + self.respringView.title.text = @"Last time respring"; + self.respringView.subtitle.text = [[DataManager sharedInstance] lastRespringDevice]; + self.respringView.iconView.backgroundColor = [UIColor.tealColour colorWithAlphaComponent:0.4]; + self.respringView.icon.tintColor = UIColor.tealColour; + [self.containerView addSubview:self.respringView]; + + [self.respringView size:CGSizeMake(self.view.frame.size.width-40, 60)]; + [self.respringView x:self.containerView.centerXAnchor]; + [self.respringView top:self.unlockedView.bottomAnchor padding:10]; + + + self.appView = [[SummaryView alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"apps.iphone"]]; + self.appView.title.text = @"Last opened app"; + self.appView.subtitle.text = [[DataManager sharedInstance] lastOpenedApp]; + self.appView.iconView.backgroundColor = [UIColor.indigoColour colorWithAlphaComponent:0.4]; + self.appView.icon.tintColor = UIColor.indigoColour; + [self.containerView addSubview:self.appView]; + + [self.appView size:CGSizeMake(self.view.frame.size.width-40, 60)]; + [self.appView x:self.containerView.centerXAnchor]; + [self.appView top:self.respringView.bottomAnchor padding:10]; + + + self.footerView = [[UIView alloc] init]; + [self.scrollView addSubview:self.footerView]; + + [self.footerView size:CGSizeMake(self.view.frame.size.width, 20)]; + [self.footerView x:self.scrollView.centerXAnchor]; + [self.footerView bottom:self.scrollView.bottomAnchor padding:0]; + [self.footerView top:self.containerView.bottomAnchor padding:0]; + +} + + +-(void)initGestures { + + [self.icloudView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentIcloudVC)]]; + [self.deviceView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentDeviceVC)]]; + [self.batteryView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentBatteryVC)]]; + [self.storageView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentStorageVC)]]; + [self.memoryView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentMemoryVC)]]; + [self.aboutView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentAboutVC)]]; + [self.appsView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentAppsVC)]]; + [self.tweaksView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentTweaksVC)]]; +} + + +-(void)presentIcloudVC { + invokeHaptic(); + CloudViewController *vc = [[CloudViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +-(void)presentDeviceVC { + invokeHaptic(); + DeviceViewController *vc = [[DeviceViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +-(void)presentBatteryVC { + invokeHaptic(); + BatteryViewController *vc = [[BatteryViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +-(void)presentStorageVC { + invokeHaptic(); + StorageViewController *vc = [[StorageViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +-(void)presentMemoryVC { + invokeHaptic(); + MemoryViewController *vc = [[MemoryViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +-(void)presentAboutVC { + invokeHaptic(); + AboutViewController *vc = [[AboutViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +-(void)presentAppsVC { + invokeHaptic(); + AppsViewController *vc = [[AppsViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +-(void)presentTweaksVC { + invokeHaptic(); + TweaksViewController *vc = [[TweaksViewController alloc] init]; + [self.navigationController pushViewController:vc animated:YES]; +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Memory/MemoryData.h b/iDevices/Tweak/IDEVICES/Memory/MemoryData.h new file mode 100644 index 0000000..e0bb2fe --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Memory/MemoryData.h @@ -0,0 +1,9 @@ +#import + +@interface MemoryData : NSObject + ++ (nullable NSString *)getTotalRam; ++ (nullable NSString *)getFreeRam; ++ (nullable NSString *)getUsedRam; + +@end diff --git a/iDevices/Tweak/IDEVICES/Memory/MemoryData.m b/iDevices/Tweak/IDEVICES/Memory/MemoryData.m new file mode 100644 index 0000000..0b3ef52 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Memory/MemoryData.m @@ -0,0 +1,79 @@ +#import "MemoryData.h" + +#import +#import + +static const unsigned int MEGABYTES = 1 << 20; +static unsigned long long PHYSICAL_MEMORY; +__strong static id ramInfoObject; + +@implementation MemoryData + ++ (nullable NSString *)getTotalRam { + mach_port_t host_port; + mach_msg_type_number_t host_size; + vm_size_t pagesize; + vm_statistics_data_t vm_stat; + NSMutableString* mutableString = [[NSMutableString alloc] init]; + + host_port = mach_host_self(); + host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t); + host_page_size(host_port, &pagesize); + if(host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) == KERN_SUCCESS) + { + + [mutableString appendString: [NSString stringWithFormat:@"%lluMB", PHYSICAL_MEMORY]]; + + PHYSICAL_MEMORY = [NSProcessInfo processInfo].physicalMemory / MEGABYTES; + + } + return [mutableString copy]; +} + + ++ (nullable NSString *) getUsedRam { + + mach_port_t host_port; + mach_msg_type_number_t host_size; + vm_size_t pagesize; + vm_statistics_data_t vm_stat; + natural_t mem_used; + NSMutableString* mutableString = [[NSMutableString alloc] init]; + + host_port = mach_host_self(); + host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t); + host_page_size(host_port, &pagesize); + if(host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) == KERN_SUCCESS) + { + + mem_used = (vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count) * pagesize / MEGABYTES; + [mutableString appendString: [NSString stringWithFormat:@"%uMB", mem_used]]; + + } + return [mutableString copy]; +} + + ++ (nullable NSString *) getFreeRam { + + mach_port_t host_port; + mach_msg_type_number_t host_size; + vm_size_t pagesize; + vm_statistics_data_t vm_stat; + natural_t mem_free; + NSMutableString* mutableString = [[NSMutableString alloc] init]; + + host_port = mach_host_self(); + host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t); + host_page_size(host_port, &pagesize); + if(host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size) == KERN_SUCCESS) + { + + mem_free = vm_stat.free_count * pagesize / MEGABYTES; + [mutableString appendString: [NSString stringWithFormat:@"%uMB", mem_free]]; + + } + return [mutableString copy]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Memory/MemoryViewController.h b/iDevices/Tweak/IDEVICES/Memory/MemoryViewController.h new file mode 100644 index 0000000..2bbc6b3 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Memory/MemoryViewController.h @@ -0,0 +1,18 @@ +#import +#import "Colour-Scheme.h" +#import "DataManager.h" +#import "CDHeaderView.h" +#import "DeviceUsageView.h" +#import "RamManager.h" +#import "MemoryView.h" + +@interface MemoryViewController : UIViewController +@property (nonatomic, retain) CDHeaderView *headerView; +@property (nonatomic, retain) DeviceUsageView *totalProgressView; +@property (nonatomic, retain) DeviceUsageView *usedProgressView; +@property (nonatomic, retain) DeviceUsageView *freeProgressView; +@property (nonatomic, retain) MemoryView *totalView; +@property (nonatomic, retain) MemoryView *usedView; +@property (nonatomic, retain) MemoryView *freeView; +@property (nonatomic, retain) UIView *containerView; +@end diff --git a/iDevices/Tweak/IDEVICES/Memory/MemoryViewController.m b/iDevices/Tweak/IDEVICES/Memory/MemoryViewController.m new file mode 100644 index 0000000..cd3b582 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Memory/MemoryViewController.m @@ -0,0 +1,207 @@ +#import "MemoryViewController.h" + +@implementation MemoryViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [UIColor accentColour]; + self.view.tintColor = [UIColor accentColour]; + + [self layoutHeaderView]; + [self layoutRamUsage]; + [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateRamUsage) userInfo: nil repeats:YES]; +} + + +-(void)layoutHeaderView { + + self.containerView = [[UIView alloc] init]; + self.containerView.layer.cornerRadius = 25; + self.containerView.layer.cornerCurve = kCACornerCurveContinuous; + self.containerView.layer.maskedCorners = 12; + self.containerView.clipsToBounds = YES; + [self.view addSubview:self.containerView]; + + [self.containerView size:CGSizeMake(self.view.frame.size.width, 370)]; + [self.containerView x:self.view.centerXAnchor]; + [self.containerView top:self.view.topAnchor padding:0]; + + + UIImageView *wallpaper = [[UIImageView alloc] init]; + if (toggleCustomCoverImage) { + wallpaper.image = [UIImage imageWithData:customCoverImage]; + } else { + wallpaper.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/iDevices.bundle/Assets/Default/cover-image.png"]; + } + wallpaper.contentMode = UIViewContentModeScaleAspectFill; + [self.containerView addSubview:wallpaper]; + + [wallpaper fill]; + + + self.headerView = [[CDHeaderView alloc] initWithTitle:@"RAM Usage" accent:[UIColor accentColour] leftIcon:@"chevron.left" leftAction:@selector(pushBackVC)]; + self.headerView.leftButton.backgroundColor = [UIColor.navBarButtonColour colorWithAlphaComponent:0.5]; + self.headerView.titleLabel.textColor = UIColor.coverTitleColour; + [self.containerView addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.containerView.centerXAnchor]; + [self.headerView top:self.containerView.topAnchor padding:0]; + +} + + +-(void)layoutRamUsage { + + self.totalProgressView = [[DeviceUsageView alloc] initWithFrame:CGRectZero]; + self.totalProgressView.backgroundColor = UIColor.clearColor; + self.totalProgressView.progressColor = UIColor.totalRamColour; + self.totalProgressView.progressStrokeColor = UIColor.totalRamColour; + self.totalProgressView.emptyLineStrokeColor = UIColor.clearColor; + self.totalProgressView.emptyLineColor = [UIColor.totalRamColour colorWithAlphaComponent:0.4]; + self.totalProgressView.fontColor = UIColor.clearColor; + self.totalProgressView.progressLineWidth = 14; + self.totalProgressView.valueFontSize = 10; + self.totalProgressView.unitFontSize = 8; + self.totalProgressView.emptyLineWidth = 14; + self.totalProgressView.emptyCapType = kCGLineCapRound; + self.totalProgressView.progressAngle = 100; + self.totalProgressView.progressRotationAngle = 50; + [self.view addSubview:self.totalProgressView]; + + [self.totalProgressView size:CGSizeMake(250, 250)]; + [self.totalProgressView x:self.view.centerXAnchor]; + [self.totalProgressView top:self.headerView.bottomAnchor padding:20]; + + + self.usedProgressView = [[DeviceUsageView alloc] initWithFrame:CGRectZero]; + self.usedProgressView.backgroundColor = UIColor.clearColor; + self.usedProgressView.progressColor = UIColor.usedRamColour; + self.usedProgressView.progressStrokeColor = UIColor.usedRamColour; + self.usedProgressView.emptyLineStrokeColor = UIColor.clearColor; + self.usedProgressView.emptyLineColor = [UIColor.usedRamColour colorWithAlphaComponent:0.4]; + self.usedProgressView.fontColor = UIColor.clearColor; + self.usedProgressView.progressLineWidth = 14; + self.usedProgressView.valueFontSize = 10; + self.usedProgressView.unitFontSize = 8; + self.usedProgressView.emptyLineWidth = 14; + self.usedProgressView.emptyCapType = kCGLineCapRound; + self.usedProgressView.progressAngle = 100; + self.usedProgressView.progressRotationAngle = 50; + [self.view addSubview:self.usedProgressView]; + + [self.usedProgressView size:CGSizeMake(210, 210)]; + [self.usedProgressView x:self.totalProgressView.centerXAnchor y:self.totalProgressView.centerYAnchor];; + + + self.freeProgressView = [[DeviceUsageView alloc] initWithFrame:CGRectZero]; + self.freeProgressView.backgroundColor = UIColor.clearColor; + self.freeProgressView.progressColor = UIColor.freeRamColour; + self.freeProgressView.progressStrokeColor = UIColor.freeRamColour; + self.freeProgressView.emptyLineStrokeColor = UIColor.clearColor; + self.freeProgressView.emptyLineColor = [UIColor.freeRamColour colorWithAlphaComponent:0.4]; + self.freeProgressView.fontColor = UIColor.clearColor; + self.freeProgressView.unitString = @" MB"; + self.freeProgressView.valueFontSize = 18; + self.freeProgressView.unitFontSize = 18; + self.freeProgressView.progressLineWidth = 14; + self.freeProgressView.valueFontSize = 10; + self.freeProgressView.unitFontSize = 8; + self.freeProgressView.emptyLineWidth = 14; + self.freeProgressView.emptyCapType = kCGLineCapRound; + self.freeProgressView.progressAngle = 100; + self.freeProgressView.progressRotationAngle = 50; + [self.view addSubview:self.freeProgressView]; + + [self.freeProgressView size:CGSizeMake(170, 170)]; + [self.freeProgressView x:self.totalProgressView.centerXAnchor y:self.totalProgressView.centerYAnchor];; + + + self.totalView = [[MemoryView alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"chart.bar.xaxis"]]; + self.totalView.title.text = @"Total"; + self.totalView.subtitle.text = @""; + self.totalView.iconView.backgroundColor = [UIColor.totalRamColour colorWithAlphaComponent:0.4]; + self.totalView.icon.tintColor = UIColor.totalRamColour; + [self.view addSubview:self.totalView]; + + [self.totalView size:CGSizeMake(self.view.frame.size.width-40, 60)]; + [self.totalView x:self.view.centerXAnchor]; + [self.totalView top:self.containerView.bottomAnchor padding:20]; + + + self.usedView = [[MemoryView alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"chart.bar.xaxis"]]; + self.usedView.title.text = @"Used"; + self.usedView.subtitle.text = @""; + self.usedView.iconView.backgroundColor = [UIColor.usedRamColour colorWithAlphaComponent:0.4]; + self.usedView.icon.tintColor = UIColor.usedRamColour; + [self.view addSubview:self.usedView]; + + [self.usedView size:CGSizeMake(self.view.frame.size.width-40, 60)]; + [self.usedView x:self.view.centerXAnchor]; + [self.usedView top:self.totalView.bottomAnchor padding:10]; + + + self.freeView = [[MemoryView alloc] initWithFrame:CGRectZero icon:[UIImage systemImageNamed:@"chart.bar.xaxis"]]; + self.freeView.title.text = @"Free"; + self.freeView.subtitle.text = @""; + self.freeView.iconView.backgroundColor = [UIColor.freeRamColour colorWithAlphaComponent:0.4]; + self.freeView.icon.tintColor = UIColor.freeRamColour; + [self.view addSubview:self.freeView]; + + [self.freeView size:CGSizeMake(self.view.frame.size.width-40, 60)]; + [self.freeView x:self.view.centerXAnchor]; + [self.freeView top:self.usedView.bottomAnchor padding:10]; + +} + + +-(void)updateRamUsage { + + NSString *freeRamString = [NSString stringWithFormat:@"%@",[[RamManager sharedManager] getFreeRam]]; + NSString *usedRamString = [NSString stringWithFormat:@"%@",[[RamManager sharedManager] getUsedRam]]; + NSString *totalRamString = [NSString stringWithFormat:@"%@",[[RamManager sharedManager] getTotalRam]]; + + float freeRamFloat = [freeRamString floatValue]; + float usedRamFloat = [usedRamString floatValue]; + float totalRamFloat = [totalRamString floatValue]; + + + [UIView animateWithDuration:0.7 animations:^{ + + self.freeProgressView.value = freeRamFloat; + self.freeProgressView.maxValue = usedRamFloat; + + self.usedProgressView.value = usedRamFloat; + self.usedProgressView.maxValue = totalRamFloat; + + self.totalProgressView.value = totalRamFloat; + self.totalProgressView.maxValue = totalRamFloat; + + }]; + + self.totalView.subtitle.text = totalRamString; + self.usedView.subtitle.text = usedRamString; + self.freeView.subtitle.text = freeRamString; + +} + + +-(void)pushBackVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/Memory/RamManager.h b/iDevices/Tweak/IDEVICES/Memory/RamManager.h new file mode 100644 index 0000000..5698344 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Memory/RamManager.h @@ -0,0 +1,8 @@ +#import "MemoryData.h" + +@interface RamManager : NSObject ++ (nonnull instancetype)sharedManager; +@property (nonatomic, readonly, nullable) NSString *getTotalRam; +@property (nonatomic, readonly, nullable) NSString *getFreeRam; +@property (nonatomic, readonly, nullable) NSString *getUsedRam; +@end diff --git a/iDevices/Tweak/IDEVICES/Memory/RamManager.m b/iDevices/Tweak/IDEVICES/Memory/RamManager.m new file mode 100644 index 0000000..7cbd489 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Memory/RamManager.m @@ -0,0 +1,29 @@ +#import "RamManager.h" + +@implementation RamManager + + ++ (nonnull instancetype)sharedManager { + static RamManager *sharedManagerServices = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedManagerServices = [[self alloc] init]; + }); + return sharedManagerServices; +} + + +- (nullable NSString *)getTotalRam { + return [MemoryData getTotalRam]; +} + +- (nullable NSString *)getFreeRam { + return [MemoryData getFreeRam]; +} + +- (nullable NSString *)getUsedRam { + return [MemoryData getUsedRam]; +} + + +@end diff --git a/iDevices/Tweak/IDEVICES/Storage/StorageViewController.h b/iDevices/Tweak/IDEVICES/Storage/StorageViewController.h new file mode 100644 index 0000000..c506dd8 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Storage/StorageViewController.h @@ -0,0 +1,15 @@ +#import +#import "Colour-Scheme.h" +#import "DataManager.h" +#import "CDHeaderView.h" +#import "StorageCell.h" +#import "SectionCellHeaderView.h" + +@interface StorageViewController : UIViewController +@property (nonatomic, retain) CDHeaderView *headerView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *mediaArray; +@property (nonatomic, retain) UIView *containerView; +@property (nonatomic, retain) UIImageView *headerIcon; +@property (nonatomic, retain) UILabel *headerTitle; +@end diff --git a/iDevices/Tweak/IDEVICES/Storage/StorageViewController.m b/iDevices/Tweak/IDEVICES/Storage/StorageViewController.m new file mode 100644 index 0000000..842b7a5 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Storage/StorageViewController.m @@ -0,0 +1,406 @@ +#import "StorageViewController.h" + +static NSString *plistStorage = @"/tmp/EMPStorageUsageInfo.plist"; +static double const DECIMAL_GIGABYTE = 1024 * 1024 * 1024; + +static NSString *storageFormater(double storage){ + storage = storage/DECIMAL_GIGABYTE; + + if(storage < 1){ + return [NSString stringWithFormat:@"%.2f MB", storage * 1024]; + } + else if(storage > 1 && storage < 1024){ + return [NSString stringWithFormat:@"%.2f GB", storage]; + } + else if(storage >= 1024){ + return [NSString stringWithFormat:@"%.2f TB", storage / 1024]; + } + + return [NSString stringWithFormat:@"Could not get the iCloud Storage details"]; +} + + +static NSDictionary *readiCloudPlist(){ + return [NSDictionary dictionaryWithContentsOfFile:plistStorage]; +} + + +@implementation StorageViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [UIColor accentColour]; + self.view.tintColor = [UIColor accentColour]; + + [self getDevicesData]; + [self layoutHeaderView]; + [self layoutCollectionView]; +} + + +-(void)getDevicesData { + + NSString *plistPath = @"/tmp/EMPStorageUsageInfo.plist"; //[IMPORTANT] Need to change plist path to wherever it was saved to + NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath]; + NSMutableDictionary *mutableDict = dict ? [dict mutableCopy] : [NSMutableDictionary dictionary]; + + self.mediaArray = [NSMutableArray new]; + self.mediaArray = [mutableDict objectForKey:@"storage_usage_by_media"]; + +} + + +-(void)layoutHeaderView { + + self.containerView = [[UIView alloc] init]; + self.containerView.layer.cornerRadius = 25; + self.containerView.layer.cornerCurve = kCACornerCurveContinuous; + self.containerView.layer.maskedCorners = 12; + self.containerView.clipsToBounds = YES; + [self.view addSubview:self.containerView]; + + [self.containerView size:CGSizeMake(self.view.frame.size.width, 200)]; + [self.containerView x:self.view.centerXAnchor]; + [self.containerView top:self.view.topAnchor padding:0]; + + + UIImageView *wallpaper = [[UIImageView alloc] init]; + if (toggleCustomCoverImage) { + wallpaper.image = [UIImage imageWithData:customCoverImage]; + } else { + wallpaper.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/iDevices.bundle/Assets/Default/cover-image.png"]; + } + wallpaper.contentMode = UIViewContentModeScaleAspectFill; + [self.containerView addSubview:wallpaper]; + + [wallpaper fill]; + + + self.headerView = [[CDHeaderView alloc] initWithTitle:@"" accent:[UIColor accentColour] leftIcon:@"chevron.left" leftAction:@selector(pushBackVC)]; + self.headerView.leftButton.backgroundColor = [UIColor.navBarButtonColour colorWithAlphaComponent:0.5]; + [self.containerView addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.containerView.centerXAnchor]; + [self.headerView top:self.containerView.topAnchor padding:0]; + + + self.headerIcon = [[UIImageView alloc] init]; + self.headerIcon.contentMode = UIViewContentModeScaleAspectFit; + self.headerIcon.image = [UIImage systemImageNamed:@"chart.pie.fill"]; + self.headerIcon.tintColor = UIColor.coverIconColour; + [self.containerView addSubview:self.headerIcon]; + + [self.headerIcon size:CGSizeMake(75, 75)]; + [self.headerIcon x:self.containerView.centerXAnchor]; + [self.headerIcon top:self.headerView.bottomAnchor padding:-10]; + + + self.headerTitle = [[UILabel alloc] init]; + self.headerTitle.textAlignment = NSTextAlignmentCenter; + self.headerTitle.font = [UIFont systemFontOfSize:18 weight:UIFontWeightBold]; + self.headerTitle.textColor = UIColor.coverTitleColour; + self.headerTitle.text = @"Storage"; + [self.containerView addSubview:self.headerTitle]; + + [self.headerTitle x:self.containerView.centerXAnchor]; + [self.headerTitle top:self.headerIcon.bottomAnchor padding:10]; + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[StorageCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.collectionView registerClass:[SectionCellHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; + [self.view addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + + [self.collectionView top:self.containerView.bottomAnchor padding:0]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + [self.collectionView bottom:self.view.bottomAnchor padding:-5]; +} + + +- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView { + return 3; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { + return CGSizeMake(self.view.frame.size.width, 45); +} + + +-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + UICollectionReusableView *reusableview = nil; + + if (kind == UICollectionElementKindSectionHeader) { + + SectionCellHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; + if (indexPath.section == 0) { + headerView.headerLabel.text = @"iPhone"; + } else if (indexPath.section == 1) { + headerView.headerLabel.text = @"iCloud Capacity"; + } else if (indexPath.section == 2) { + headerView.headerLabel.text = @"iCloud Media"; + } + reusableview = headerView; + } + + return reusableview; + +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + if (section == 0) { + return 3; + } else if (section == 1) { + return 3; + } else { + return self.mediaArray.count; + } +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + StorageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + if (indexPath.section == 0) { + + NSDictionary *storageData = [self deviceStorageData]; + cell.iconImage.image = [UIImage systemImageNamed:@"iphone"]; + + if (indexPath.row == 0) { + + cell.titleLabel.text = @"Total"; + cell.subtitleLabel.text = [NSString stringWithFormat:@"%ld GB", [[storageData objectForKey:@"TotalSpace"] integerValue]]; + cell.iconView.backgroundColor = [UIColor.indigoColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.indigoColour; + + } else if (indexPath.row == 1) { + + cell.titleLabel.text = @"Used"; + cell.subtitleLabel.text = [NSString stringWithFormat:@"%ld GB", [[storageData objectForKey:@"UsedSpace"] integerValue]]; + cell.iconView.backgroundColor = [UIColor.redColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.redColour; + + } else if (indexPath.row == 2) { + + cell.titleLabel.text = @"Available"; + cell.subtitleLabel.text = [NSString stringWithFormat:@"%ld GB", [[storageData objectForKey:@"FreeSpace"] integerValue]]; + cell.iconView.backgroundColor = [UIColor.greenColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.greenColour; + } + + + } else if (indexPath.section == 1) { + + NSDictionary *storage_data = readiCloudPlist()[@"storage_data"][@"quota_info_in_bytes"]; + + double total_quota = [storage_data[@"total_quota"] doubleValue]; + double total_used = [storage_data[@"total_used"] doubleValue]; + double total_available = [storage_data[@"total_available"] doubleValue]; + + NSString *total_quota_Str = storageFormater(total_quota); + NSString *total_used_Str = storageFormater(total_used); + NSString *total_available_Str = storageFormater(total_available); + + cell.iconImage.image = [UIImage systemImageNamed:@"chart.pie.fill"]; + + if (indexPath.row == 0) { + + cell.titleLabel.text = @"Total"; + cell.subtitleLabel.text = total_quota_Str; + cell.iconView.backgroundColor = [UIColor.yellowColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.yellowColour; + + } else if (indexPath.row == 1) { + + cell.titleLabel.text = @"Used"; + cell.subtitleLabel.text = total_used_Str; + cell.iconView.backgroundColor = [UIColor.orangeColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.orangeColour; + + } else if (indexPath.row == 2) { + + cell.titleLabel.text = @"Available"; + cell.subtitleLabel.text = total_available_Str; + cell.iconView.backgroundColor = [UIColor.pinkColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.pinkColour; + + } + + + } else if (indexPath.section == 2) { + + cell.titleLabel.text = [[self.mediaArray objectAtIndex:indexPath.row] objectForKey:@"display_label"]; + + double mediaSize = [[[self.mediaArray objectAtIndex:indexPath.row] objectForKey:@"usage_in_bytes"] doubleValue]; + NSString *mediaSizeString = storageFormater(mediaSize); + cell.subtitleLabel.text = mediaSizeString; + + + NSString *icons = [[self.mediaArray objectAtIndex:indexPath.row] objectForKey:@"display_label"]; + + if ([icons isEqualToString:@"Photos"]) { + cell.iconImage.image = [UIImage systemImageNamed:@"photo.fill.on.rectangle.fill"]; + cell.iconView.backgroundColor = [UIColor.yellowColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.yellowColour; + } else if ([icons isEqualToString:@"Backups"]) { + cell.iconImage.image = [UIImage systemImageNamed:@"cloud.fill"]; + cell.iconView.backgroundColor = [UIColor.indigoColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.indigoColour; + } else if ([icons isEqualToString:@"Docs"]) { + cell.iconImage.image = [UIImage systemImageNamed:@"folder.fill"]; + cell.iconView.backgroundColor = [UIColor.orangeColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.orangeColour; + } else if ([icons isEqualToString:@"Messages"]) { + cell.iconImage.image = [UIImage systemImageNamed:@"message.fill"]; + cell.iconView.backgroundColor = [UIColor.greenColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.greenColour; + } else if ([icons isEqualToString:@"Mail"]) { + cell.iconImage.image = [UIImage systemImageNamed:@"envelope.fill"]; + cell.iconView.backgroundColor = [UIColor.tealColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.tealColour; + } else if ([icons isEqualToString:@"Others"]) { + cell.iconImage.image = [UIImage systemImageNamed:@"cloud.fill"]; + cell.iconView.backgroundColor = [UIColor.pinkColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.pinkColour; + } else if ([icons isEqualToString:@"Family"]) { + cell.iconImage.image = [UIImage systemImageNamed:@"person.2.fill"]; + cell.iconView.backgroundColor = [UIColor.redColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.redColour; + } else { + cell.iconImage.image = [UIImage systemImageNamed:@"cloud.fill"]; + cell.iconView.backgroundColor = [UIColor.accentColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.accentColour; + } + + } + + + return cell; + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat width = self.view.frame.size.width-40; + return CGSizeMake(width, 65); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 20.0; +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + +} + + +-(void)pushBackVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + + +-(NSDictionary*)deviceStorageData { + unsigned long long totalSpace = 0; + unsigned long long totalFreeSpace = 0; + unsigned long long usedSpace = 0; + + NSError *error = nil; + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error: &error]; + + NSNumber *fileSystemSizeInBytes = [dictionary objectForKey: NSFileSystemSize]; + + totalSpace = [fileSystemSizeInBytes unsignedLongLongValue]; + + NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:@"/private/var/"]; + NSDictionary *results = [fileURL resourceValuesForKeys:@[NSURLVolumeAvailableCapacityForImportantUsageKey] error:&error]; + + totalFreeSpace = [results[NSURLVolumeAvailableCapacityForImportantUsageKey] longLongValue]; + + usedSpace = totalSpace - totalFreeSpace; + + NSDictionary *spaceDict = @{@"FreeSpace":[NSNumber numberWithDouble:totalFreeSpace*(pow(10,-9))],@"TotalSpace":[NSNumber numberWithDouble:totalSpace*(pow(10,-9))],@"UsedSpace":[NSNumber numberWithDouble:usedSpace*(pow(10,-9))]}; + + return spaceDict; +} + + +@end diff --git a/iDevices/Tweak/IDEVICES/SystemInfo/AboutDeviceInfo.h b/iDevices/Tweak/IDEVICES/SystemInfo/AboutDeviceInfo.h new file mode 100644 index 0000000..3eb3d82 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/SystemInfo/AboutDeviceInfo.h @@ -0,0 +1,39 @@ +#import +#import +#import "SystemServices.h" +#import "Colour-Scheme.h" +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface SBWiFiManager : NSObject ++ (id)sharedInstance; +- (id)currentNetworkName; +@end + + +@interface InfoModel : NSObject +-(id)initWithTitle:(NSString *)title subtitle:(NSString *)subtitle icon:(NSString *)icon colour:(UIColor *)colour; +@property (nonatomic, retain) NSString *title; +@property (nonatomic, retain) NSString *subtitle; +@property (nonatomic, retain) NSString *icon; +@property (nonatomic, retain) UIColor *colour; +@end + + +@interface AboutDeviceInfo : NSObject ++(instancetype)sharedInstance; +-(id)init; +-(NSMutableArray *)generalArray; +-(NSMutableArray *)networkArray; +-(NSMutableArray *)batteryArray; +-(NSMutableArray *)accessoriesArray; +-(NSMutableArray *)screenArray; +-(NSMutableArray *)processorArray; +-(NSMutableArray *)motionArray; +-(NSMutableArray *)localisationArray; +-(NSMutableArray *)debugArray; +@end + +NS_ASSUME_NONNULL_END diff --git a/iDevices/Tweak/IDEVICES/SystemInfo/AboutDeviceInfo.m b/iDevices/Tweak/IDEVICES/SystemInfo/AboutDeviceInfo.m new file mode 100644 index 0000000..b181585 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/SystemInfo/AboutDeviceInfo.m @@ -0,0 +1,232 @@ +#import "AboutDeviceInfo.h" + +@implementation InfoModel + +-(id)initWithTitle:(NSString *)title subtitle:(NSString *)subtitle icon:(NSString *)icon colour:(UIColor *)colour { + self = [super init]; + if(self) { + self.title = title; + self.subtitle = subtitle; + self.icon = icon; + self.colour = colour; + } + return self; +} +@end + + +@implementation AboutDeviceInfo + ++(instancetype)sharedInstance { + static AboutDeviceInfo *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[AboutDeviceInfo alloc] init]; + }); + return sharedInstance; +} + +-(id)init { + return self; +} + + +-(NSMutableArray *)generalArray { + + NSString *DeviceName = [NSString stringWithFormat:@"%@", [[SystemServices sharedServices] deviceName]]; + NSString *DeviceModel = [NSString stringWithFormat:@"%@", [[SystemServices sharedServices] deviceModel]]; + NSString *SystemName = [NSString stringWithFormat:@"%@", [[SystemServices sharedServices] systemName]]; + NSString *SystemVersion = [NSString stringWithFormat:@"%@", [[SystemServices sharedServices] systemsVersion]]; + NSString *SystemDeviceTypeFormattedNO = [NSString stringWithFormat:@"%@", [[SystemServices sharedServices] systemDeviceTypeNotFormatted]]; + NSString *SystemDeviceTypeFormattedYES = [NSString stringWithFormat:@"%@", [[SystemServices sharedServices] systemDeviceTypeFormatted]]; + NSArray *uptimeFormat = [[[SystemServices sharedServices] systemsUptime] componentsSeparatedByString:@" "]; + NSString *UDID = (__bridge_transfer NSString *)MGCopyAnswer(kMGUniqueDeviceID); + NSString *SystemUptime = [NSString stringWithFormat:@"%@ Days %@ Hours %@ Minutes", [uptimeFormat objectAtIndex:0], [uptimeFormat objectAtIndex:1], [uptimeFormat objectAtIndex:2]]; + + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + [array addObject:[[InfoModel alloc] initWithTitle:@"Device Name" subtitle:DeviceName icon:@"apps.iphone" colour:UIColor.indigoColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Device Model" subtitle:DeviceModel icon:@"apps.iphone" colour:UIColor.indigoColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"System Name" subtitle:SystemName icon:@"apps.iphone" colour:UIColor.indigoColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"System Version" subtitle:SystemVersion icon:@"apps.iphone" colour:UIColor.indigoColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Model Name Unformatted" subtitle:SystemDeviceTypeFormattedNO icon:@"apps.iphone" colour:UIColor.indigoColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Model Name Formatted" subtitle:SystemDeviceTypeFormattedYES icon:@"apps.iphone" colour:UIColor.indigoColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"UDID" subtitle:UDID icon:@"apps.iphone" colour:UIColor.indigoColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"System Uptime" subtitle:SystemUptime icon:@"apps.iphone" colour:UIColor.indigoColour]]; + + return array; +} + + +-(NSMutableArray *)networkArray { + + NSString *WiFiName = [[objc_getClass("SBWiFiManager") sharedInstance] currentNetworkName] ?: @"Not connected"; + NSString *ConnectedToWiFi = ([[SystemServices sharedServices] connectedToWiFi]) ? @"Yes" : @"No"; + NSString *WiFiIPAddress = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] wiFiIPAddress]]; + NSString *WiFiNetmaskAddress = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] wiFiNetmaskAddress]]; + NSString *WiFiBroadcastAddress = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] wiFiBroadcastAddress]]; + NSString *WiFiRouterAddress = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] wiFiRouterAddress]]; + + NSString *CarrierName = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] carrierName]]; + NSString *ConnectedToCellNetwork = ([[SystemServices sharedServices] connectedToCellNetwork]) ? @"Yes" : @"No"; + NSString *CellIPAddress = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] cellIPAddress]]; + NSString *CarrierCountry = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] carrierCountry]]; + NSString *CarrierMobileCountryCode = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] carrierMobileCountryCode]]; + NSString *CarrierISOCountryCode = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] carrierISOCountryCode]]; + NSString *CarrierMobileNetworkCode = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] carrierMobileNetworkCode]]; + NSString *CarrierAllowsVOIP = ([[SystemServices sharedServices] carrierAllowsVOIP]) ? @"Yes" : @"No"; + NSString *CellNetmaskAddress = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] cellNetmaskAddress]]; + NSString *CellBroadcastAddress = [NSString stringWithFormat:@"%@",[[SystemServices sharedServices] cellBroadcastAddress]]; + + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + [array addObject:[[InfoModel alloc] initWithTitle:@"WiFi Name" subtitle:WiFiName icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Connected to WiFi" subtitle:ConnectedToWiFi icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"WiFi IP Address" subtitle:WiFiIPAddress icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"WiFi Netmask Address" subtitle:WiFiNetmaskAddress icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"WiFi Broadcast Address" subtitle:WiFiBroadcastAddress icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"WiFi Router Address" subtitle:WiFiRouterAddress icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Carrier Name" subtitle:CarrierName icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Connected to Cell Network" subtitle:ConnectedToCellNetwork icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Cell IP Address" subtitle:CellIPAddress icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Carrier Country" subtitle:CarrierCountry icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Carrier Mobile Country" subtitle:CarrierMobileCountryCode icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Carrier ISO Country Code" subtitle:CarrierISOCountryCode icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Carrier Mobile Network Code" subtitle:CarrierMobileNetworkCode icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Carrier Allows VOIP" subtitle:CarrierAllowsVOIP icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Cell Netmask Address" subtitle:CellNetmaskAddress icon:@"wifi" colour:UIColor.tealColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Cell Broadcast Address" subtitle:CellBroadcastAddress icon:@"wifi" colour:UIColor.tealColour]]; + + return array; +} + + +-(NSMutableArray *)batteryArray { + + NSString *BatteryLevel = [NSString stringWithFormat:@"%f%%", [[SystemServices sharedServices] batteryLevel]]; + NSString *Charging = ([[SystemServices sharedServices] charging]) ? @"Yes" : @"No"; + NSString *FullyCharged = ([[SystemServices sharedServices] fullyCharged]) ? @"Yes" : @"No"; + NSString *PluggedIn = ([[SystemServices sharedServices] pluggedIn]) ? @"Yes" : @"No"; + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + [array addObject:[[InfoModel alloc] initWithTitle:@"Battery Level" subtitle:BatteryLevel icon:@"battery.100" colour:UIColor.greenColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Charging" subtitle:Charging icon:@"battery.100" colour:UIColor.greenColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Fully Charged" subtitle:FullyCharged icon:@"battery.100" colour:UIColor.greenColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Plugged In" subtitle:PluggedIn icon:@"battery.100" colour:UIColor.greenColour]]; + + return array; +} + + +-(NSMutableArray *)accessoriesArray { + + NSString *AccessoriesAttached = ([[SystemServices sharedServices] accessoriesAttached]) ? @"Yes" : @"No"; + NSString *HeadphonesAttached = ([[SystemServices sharedServices] headphonesAttached]) ? @"Yes" : @"No"; + NSString *NumberAttachedAccessories = [NSString stringWithFormat:@"%ld", (long)[[SystemServices sharedServices] numberAttachedAccessories]]; + NSString *NameAttachedAccessories = [NSString stringWithFormat:@"%@", [[SystemServices sharedServices] nameAttachedAccessories]]; + + NSString *name; + + if ([NameAttachedAccessories isEqualToString:@"(null)"]) { + name = @"None"; + } else { + name = NameAttachedAccessories; + } + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + [array addObject:[[InfoModel alloc] initWithTitle:@"Accessories Attached" subtitle:AccessoriesAttached icon:@"headphones" colour:UIColor.pinkColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Headphones Attached" subtitle:HeadphonesAttached icon:@"headphones" colour:UIColor.pinkColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Number of Attached Accessories" subtitle:NumberAttachedAccessories icon:@"headphones" colour:UIColor.pinkColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Name of Attached Accessories" subtitle:name icon:@"headphones" colour:UIColor.pinkColour]]; + + return array; +} + + +-(NSMutableArray *)screenArray { + + NSString *ScreenBrightness = [NSString stringWithFormat:@"%.0f%%", [[SystemServices sharedServices] screenBrightness]]; + NSString *ScreenWidth = [NSString stringWithFormat:@"%ld Pts", (long)[[SystemServices sharedServices] screenWidth]]; + NSString *ScreenHeight = [NSString stringWithFormat:@"%ld Pts", (long)[[SystemServices sharedServices] screenHeight]]; + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + [array addObject:[[InfoModel alloc] initWithTitle:@"Screen Brightness" subtitle:ScreenBrightness icon:@"iphone" colour:UIColor.yellowColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Screen Width" subtitle:ScreenWidth icon:@"iphone" colour:UIColor.yellowColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Screen Height" subtitle:ScreenHeight icon:@"iphone" colour:UIColor.yellowColour]]; + + return array; +} + + +-(NSMutableArray *)processorArray { + + NSString *NumberProcessors = [NSString stringWithFormat:@"%ld", (long)[[SystemServices sharedServices] numberProcessors]]; + NSString *NumberActiveProcessors = [NSString stringWithFormat:@"%ld", (long)[[SystemServices sharedServices] numberActiveProcessors]]; + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + [array addObject:[[InfoModel alloc] initWithTitle:@"Number of Processors" subtitle:NumberProcessors icon:@"chart.bar.xaxis" colour:UIColor.redColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Number of Active Processors" subtitle:NumberActiveProcessors icon:@"chart.bar.xaxis" colour:UIColor.redColour]]; + + return array; +} + + +-(NSMutableArray *)motionArray { + + NSString *MultitaskingEnabled = ([[SystemServices sharedServices] multitaskingEnabled]) ? @"Yes" : @"No"; + NSString *ProximitySensorEnabled = ([[SystemServices sharedServices] proximitySensorEnabled]) ? @"Yes" : @"No"; + NSString *stepCountingAvailable = ([[SystemServices sharedServices] stepCountingAvailable]) ? @"Yes" : @"No"; + NSString *distanceAvailable = ([[SystemServices sharedServices] distanceAvailable]) ? @"Yes" : @"No"; + NSString *floorCountingAvailable = ([[SystemServices sharedServices] floorCountingAvailable]) ? @"Yes" : @"No"; + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + [array addObject:[[InfoModel alloc] initWithTitle:@"Multitasking" subtitle:MultitaskingEnabled icon:@"figure.walk" colour:UIColor.orangeColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Proximity Sensor" subtitle:ProximitySensorEnabled icon:@"figure.walk" colour:UIColor.orangeColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Step Counting Available" subtitle:stepCountingAvailable icon:@"figure.walk" colour:UIColor.orangeColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Distance Available" subtitle:distanceAvailable icon:@"figure.walk" colour:UIColor.orangeColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Floor Counting Available" subtitle:floorCountingAvailable icon:@"figure.walk" colour:UIColor.orangeColour]]; + + return array; +} + + +-(NSMutableArray *)localisationArray { + + NSString *Country = [NSString stringWithFormat:@"%@", [[SystemServices sharedServices] country]]; + NSString *Language = [NSString stringWithFormat:@"%@", [[SystemServices sharedServices] language]]; + NSString *TimeZone = [NSString stringWithFormat:@"%@", [[SystemServices sharedServices] timeZoneSS]]; + NSString *Currency = [NSString stringWithFormat:@"%@", [[SystemServices sharedServices] currency]]; + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + [array addObject:[[InfoModel alloc] initWithTitle:@"Country" subtitle:Country icon:@"coloncurrencysign.circle.fill" colour:UIColor.indigoColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Language" subtitle:Language icon:@"coloncurrencysign.circle.fill" colour:UIColor.indigoColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"TimeZone" subtitle:TimeZone icon:@"coloncurrencysign.circle.fill" colour:UIColor.indigoColour]]; + [array addObject:[[InfoModel alloc] initWithTitle:@"Currency" subtitle:Currency icon:@"coloncurrencysign.circle.fill" colour:UIColor.indigoColour]]; + + return array; +} + + +-(NSMutableArray *)debugArray { + + NSString *DebuggerAttached = ([[SystemServices sharedServices] debuggerAttached]) ? @"Yes" : @"No"; + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + [array addObject:[[InfoModel alloc] initWithTitle:@"Debugger Attached" subtitle:DebuggerAttached icon:@"ant.fill" colour:UIColor.tealColour]]; + + + return array; +} + +@end + + diff --git a/iDevices/Tweak/IDEVICES/SystemInfo/SSNetworkInfo.h b/iDevices/Tweak/IDEVICES/SystemInfo/SSNetworkInfo.h new file mode 100755 index 0000000..b768060 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/SystemInfo/SSNetworkInfo.h @@ -0,0 +1,54 @@ +// +// SSNetworkInfo.h +// SystemServicesDemo +// +// Created by Shmoopi LLC on 9/18/12. +// Copyright (c) 2012 Shmoopi LLC. All rights reserved. +// + +#import + +@interface SSNetworkInfo : NSObject + +// Network Information + +// Get Current IP Address ++ (nullable NSString *)currentIPAddress; + +// Get the External IP Address ++ (nullable NSString *)externalIPAddress; + +// Get Cell IP Address ++ (nullable NSString *)cellIPAddress; + +// Get Cell IPv6 Address ++ (nullable NSString *)cellIPv6Address; + +// Get Cell Netmask Address ++ (nullable NSString *)cellNetmaskAddress; + +// Get Cell Broadcast Address ++ (nullable NSString *)cellBroadcastAddress; + +// Get WiFi IP Address ++ (nullable NSString *)wiFiIPAddress; + +// Get WiFi IPv6 Address ++ (nullable NSString *)wiFiIPv6Address; + +// Get WiFi Netmask Address ++ (nullable NSString *)wiFiNetmaskAddress; + +// Get WiFi Broadcast Address ++ (nullable NSString *)wiFiBroadcastAddress; + +// Get WiFi Router Address ++ (nullable NSString *)wiFiRouterAddress; + +// Connected to WiFi? ++ (BOOL)connectedToWiFi; + +// Connected to Cellular Network? ++ (BOOL)connectedToCellNetwork; + +@end diff --git a/iDevices/Tweak/IDEVICES/SystemInfo/SSNetworkInfo.m b/iDevices/Tweak/IDEVICES/SystemInfo/SSNetworkInfo.m new file mode 100755 index 0000000..0e8bb73 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/SystemInfo/SSNetworkInfo.m @@ -0,0 +1,839 @@ +// +// SSNetworkInfo.m +// SystemServicesDemo +// +// Created by Shmoopi LLC on 9/18/12. +// Copyright (c) 2012 Shmoopi LLC. All rights reserved. +// + +#import "SSNetworkInfo.h" + +// ifaddrs +#import + +// inet +#import + +// route +#include "route.h" + +// sysctl +#import + +#include +#include +#include + +# pragma mark - Router Info + +#define RTF_PRCLONING 0x10000 /* protocol requires cloning */ +#define RTF_WASCLONED 0x20000 /* route generated through cloning */ +#define RTF_PROTO3 0x40000 /* protocol specific routing flag */ + +#define RTAX_DST 0 /* destination sockaddr present */ +#define RTAX_GATEWAY 1 /* gateway sockaddr present */ +#define RTAX_NETMASK 2 /* netmask sockaddr present */ +#define RTAX_GENMASK 3 /* cloning mask sockaddr present */ +#define RTAX_IFP 4 /* interface name sockaddr present */ +#define RTAX_IFA 5 /* interface addr sockaddr present */ +#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */ +#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */ +#define RTAX_MAX 8 /* size of array to allocate */ + +#define RTA_DST 0x1 /* destination sockaddr present */ +#define RTA_GATEWAY 0x2 /* gateway sockaddr present */ +#define RTA_NETMASK 0x4 /* netmask sockaddr present */ +#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */ +#define RTA_IFP 0x10 /* interface name sockaddr present */ +#define RTA_IFA 0x20 /* interface addr sockaddr present */ +#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */ +#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */ + +@interface Route_Info : NSObject +{ + struct sockaddr m_addrs[RTAX_MAX]; + struct rt_msghdr2 m_rtm; + int m_len; /* length of the sockaddr array */ +} +- initWithRtm: (struct rt_msghdr2*) rtm; + ++ (NSMutableArray*) getRoutes; ++ (nullable Route_Info*) getRoute:(struct rt_msghdr2 *)rtm; + +- (nullable NSString*) getDestination; +- (nullable NSString*) getNetmask; +- (nullable NSString*) getGateway; +- (nullable NSString*) getAddrStringByIndex: (int)rtax_index; + +- (void) setAddr:(struct sockaddr*)sa index:(int)rtax_index; +@end + + +@implementation Route_Info + +-initWithRtm: (struct rt_msghdr2*) rtm +{ + int i; + struct sockaddr* sa = (struct sockaddr*)(rtm + 1); + + memcpy(&(m_rtm), rtm, sizeof(struct rt_msghdr2)); + for(i = 0; i < RTAX_MAX; i++) + { + [self setAddr:&(sa[i]) index:i]; + } + + return self; +} + ++ (NSMutableArray*) getRoutes +{ + NSMutableArray* routeArray = [NSMutableArray array]; + Route_Info* route = nil; + + size_t len; + int mib[6]; + char *buf; + register struct rt_msghdr2 *rtm; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_DUMP2; + mib[5] = 0; + + sysctl(mib, 6, NULL, &len, NULL, 0); + buf = malloc(len); + if (buf && sysctl(mib, 6, buf, &len, NULL, 0) == 0) + { + for (char * ptr = buf; ptr < buf + len; ptr += rtm->rtm_msglen) + { + rtm = (struct rt_msghdr2 *)ptr; + route = [self getRoute:rtm]; + if(route != nil) + { + [routeArray addObject:route]; + break; + } + } + } + + free(buf); + + return routeArray; +} + + ++ (nullable Route_Info*) getRoute:(struct rt_msghdr2 *)rtm +{ + struct sockaddr* dst_sa = (struct sockaddr *)(rtm + 1); + Route_Info* route = nil; + + if(rtm->rtm_addrs & RTA_DST) + { + if(dst_sa->sa_family == AF_INET && !((rtm->rtm_flags & RTF_WASCLONED) && (rtm->rtm_parentflags & RTF_PRCLONING))) + { + route = [[Route_Info alloc] initWithRtm:rtm]; + } + } + + return route; +} + +-(void) setAddr:(struct sockaddr*)sa index:(int)rtax_index +{ + if(rtax_index >= 0 && rtax_index < RTAX_MAX) + { + memcpy(&(m_addrs[rtax_index]), sa, sizeof(struct sockaddr)); + } +} + +-(nullable NSString*) getDestination +{ + return [self getAddrStringByIndex:RTAX_DST]; +} + +-(nullable NSString*) getNetmask +{ + return [self getAddrStringByIndex:RTAX_NETMASK]; +} + +-(nullable NSString*) getGateway +{ + return [self getAddrStringByIndex:RTAX_GATEWAY]; +} + + +-(nullable NSString*) getAddrStringByIndex: (int)rtax_index +{ + NSString * routeString = nil; + struct sockaddr* sa = &(m_addrs[rtax_index]); + int flagVal = 1 << rtax_index; + + if(!(m_rtm.rtm_addrs & flagVal)) + { + return nil; + } + + if(rtax_index >= 0 && rtax_index < RTAX_MAX) + { + switch(sa->sa_family) + { + case AF_INET: + { + struct sockaddr_in* si = (struct sockaddr_in *)sa; + if(si->sin_addr.s_addr == INADDR_ANY) + routeString = @"default"; + else + routeString = [NSString stringWithCString:(char *)inet_ntoa(si->sin_addr) encoding:NSASCIIStringEncoding]; + } + break; + + case AF_LINK: + { + struct sockaddr_dl* sdl = (struct sockaddr_dl*)sa; + if(sdl->sdl_nlen + sdl->sdl_alen + sdl->sdl_slen == 0) + { + routeString = [NSString stringWithFormat: @"link #%d", sdl->sdl_index]; + } + else + routeString = [NSString stringWithCString:link_ntoa(sdl) encoding:NSASCIIStringEncoding]; + } + break; + + default: + { + char a[3 * sa->sa_len]; + char *cp; + char *sep = ""; + int i; + + if(sa->sa_len == 0) + { + routeString = nil; + } + else + { + a[0] = '\0'; + for(i = 0, cp = a; i < sa->sa_len; i++) + { + cp += sprintf(cp, "%s%02x", sep, (unsigned char)sa->sa_data[i]); + sep = ":"; + } + routeString = [NSString stringWithCString:a encoding:NSASCIIStringEncoding]; + } + } + } + } + + return routeString; +} + +@end + +@implementation SSNetworkInfo + +// Network Information + +// Get Current IP Address ++ (nullable NSString *)currentIPAddress { + // Get the current IP Address + + // Check which interface is currently in use + if ([self connectedToWiFi]) { + // WiFi is in use + + // Get the WiFi IP Address + NSString *wiFiAddress = [self wiFiIPAddress]; + + // Check that you get something back + if (wiFiAddress == nil || wiFiAddress.length <= 0) { + // Error, no address found + return nil; + } + + // Return Wifi address + return wiFiAddress; + } else if ([self connectedToCellNetwork]) { + // Cell Network is in use + + // Get the Cell IP Address + NSString *cellAddress = [self cellIPAddress]; + + // Check that you get something back + if (cellAddress == nil || cellAddress.length <= 0) { + // Error, no address found + return nil; + } + + // Return Cell address + return cellAddress; + } else { + // No interface in use + return nil; + } +} + +// Get the External IP Address ++ (nullable NSString *)externalIPAddress { + @try { + // Check if we have an internet connection then try to get the External IP Address + if (![self connectedToCellNetwork] && ![self connectedToWiFi]) { + // Not connected to anything, return nil + return nil; + } + + // Get the external IP Address based on icanhazip.com + NSError *error = nil; + + // Using https://icanhazip.com + NSString *externalIP = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"https://icanhazip.com/"] encoding:NSUTF8StringEncoding error:&error]; + + if (!error) { + + // Format the IP Address + externalIP = [externalIP stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + + // Check that you get something back + if (externalIP == nil || externalIP.length <= 0) { + // Error, no address found + return nil; + } + + // Return External IP + return externalIP; + } else { + // Error, no address found + return nil; + } + } + @catch (NSException *exception) { + // Error, no address found + return nil; + } +} + +// Get Cell IP Address ++ (nullable NSString *)cellIPAddress { + // Get the Cell IP Address + @try { + // Set a string for the address + NSString *ipAddress; + // Set up structs to hold the interfaces and the temporary address + struct ifaddrs *interfaces; + struct ifaddrs *temp; + struct sockaddr_in *s4; + char buf[64]; + + // If it's 0, then it's good + if (!getifaddrs(&interfaces)) + { + // Loop through the list of interfaces + temp = interfaces; + + // Run through it while it's still available + while(temp != NULL) + { + // If the temp interface is a valid interface + if(temp->ifa_addr->sa_family == AF_INET) + { + // Check if the interface is Cell + if([[NSString stringWithUTF8String:temp->ifa_name] isEqualToString:@"pdp_ip0"]) + { + s4 = (struct sockaddr_in *)temp->ifa_addr; + + if (inet_ntop(temp->ifa_addr->sa_family, (void *)&(s4->sin_addr), buf, sizeof(buf)) == NULL) { + // Failed to find it + ipAddress = nil; + } else { + // Got the Cell IP Address + ipAddress = [NSString stringWithUTF8String:buf]; + } + } + } + + // Set the temp value to the next interface + temp = temp->ifa_next; + } + } + + // Free the memory of the interfaces + freeifaddrs(interfaces); + + // Check to make sure it's not empty + if (ipAddress == nil || ipAddress.length <= 0) { + // Empty, return not found + return nil; + } + + // Return the IP Address of the WiFi + return ipAddress; + } + @catch (NSException *exception) { + // Error, IP Not found + return nil; + } +} + +// Get Cell IPv6 Address ++ (nullable NSString *)cellIPv6Address { + // Get the Cell IP Address + @try { + // Set a string for the address + NSString *ipAddress; + // Set up structs to hold the interfaces and the temporary address + struct ifaddrs *interfaces; + struct ifaddrs *temp; + struct sockaddr_in6 *s6; + char buf[INET6_ADDRSTRLEN]; + + // If it's 0, then it's good + if (!getifaddrs(&interfaces)) + { + // Loop through the list of interfaces + temp = interfaces; + + // Run through it while it's still available + while(temp != NULL) + { + // If the temp interface is a valid interface + if(temp->ifa_addr->sa_family == AF_INET6) + { + // Check if the interface is Cell + if([[NSString stringWithUTF8String:temp->ifa_name] isEqualToString:@"pdp_ip0"]) + { + s6 = (struct sockaddr_in6 *)temp->ifa_addr; + + if (inet_ntop(AF_INET6, (void *)&(s6->sin6_addr), buf, sizeof(buf)) == NULL) { + // Failed to find it + ipAddress = nil; + } else { + // Got the Cell IP Address + ipAddress = [NSString stringWithUTF8String:buf]; + } + } + } + + // Set the temp value to the next interface + temp = temp->ifa_next; + } + } + + // Free the memory of the interfaces + freeifaddrs(interfaces); + + // Check to make sure it's not empty + if (ipAddress == nil || ipAddress.length <= 0) { + // Empty, return not found + return nil; + } + + // Return the IP Address of the WiFi + return ipAddress; + } + @catch (NSException *exception) { + // Error, IP Not found + return nil; + } +} + +// Get Cell Netmask Address ++ (nullable NSString *)cellNetmaskAddress { + // Get the Cell Netmask Address + @try { + // Set up the variable + struct ifreq afr; + // Copy the string + strncpy(afr.ifr_name, [@"pdp_ip0" UTF8String], IFNAMSIZ-1); + // Open a socket + int afd = socket(AF_INET, SOCK_DGRAM, 0); + + // Check the socket + if (afd == -1) { + // Error, socket failed to open + return nil; + } + + // Check the netmask output + if (ioctl(afd, SIOCGIFNETMASK, &afr) == -1) { + // Error, netmask wasn't found + // Close the socket + close(afd); + // Return error + return nil; + } + + // Close the socket + close(afd); + + // Create a char for the netmask + char *netstring = inet_ntoa(((struct sockaddr_in *)&afr.ifr_addr)->sin_addr); + + // Create a string for the netmask + NSString *Netmask = [NSString stringWithUTF8String:netstring]; + + // Check to make sure it's not nil + if (Netmask == nil || Netmask.length <= 0) { + // Error, netmask not found + return nil; + } + + // Return successful + return Netmask; + } + @catch (NSException *exception) { + // Error + return nil; + } +} + +// Get Cell Broadcast Address ++ (nullable NSString *)cellBroadcastAddress { + // Get the Cell Broadcast Address + @try { + // Set up strings for the IP and Netmask + NSString *ipAddress = [self cellIPAddress]; + NSString *nmAddress = [self cellNetmaskAddress]; + + // Check to make sure they aren't nil + if (ipAddress == nil || ipAddress.length <= 0) { + // Error, IP Address can't be nil + return nil; + } + if (nmAddress == nil || nmAddress.length <= 0) { + // Error, NM Address can't be nil + return nil; + } + + // Check the formatting of the IP and NM Addresses + NSArray *ipCheck = [ipAddress componentsSeparatedByString:@"."]; + NSArray *nmCheck = [nmAddress componentsSeparatedByString:@"."]; + + // Make sure the IP and NM Addresses are correct + if (ipCheck.count != 4 || nmCheck.count != 4) { + // Incorrect IP Addresses + return nil; + } + + // Set up the variables + NSUInteger ip = 0; + NSUInteger nm = 0; + NSUInteger cs = 24; + + // Make the address based on the other addresses + for (NSUInteger i = 0; i < 4; i++, cs -= 8) { + ip |= [[ipCheck objectAtIndex:i] intValue] << cs; + nm |= [[nmCheck objectAtIndex:i] intValue] << cs; + } + + // Set it equal to the formatted raw addresses + NSUInteger ba = ~nm | ip; + + // Make a string for the address + NSString *broadcastAddress = [NSString stringWithFormat:@"%ld.%ld.%ld.%ld", (long)(ba & 0xFF000000) >> 24, + (long)(ba & 0x00FF0000) >> 16, (long)(ba & 0x0000FF00) >> 8, (long)(ba & 0x000000FF)]; + + // Check to make sure the string is valid + if (broadcastAddress == nil || broadcastAddress.length <= 0) { + // Error, no address + return nil; + } + + // Return Successful + return broadcastAddress; + } + @catch (NSException *exception) { + // Error + return nil; + } +} + +// Get WiFi IP Address ++ (nullable NSString *)wiFiIPAddress { + // Get the WiFi IP Address + @try { + // Set a string for the address + NSString *ipAddress; + // Set up structs to hold the interfaces and the temporary address + struct ifaddrs *interfaces; + struct ifaddrs *temp; + // Set up int for success or fail + int Status = 0; + + // Get all the network interfaces + Status = getifaddrs(&interfaces); + + // If it's 0, then it's good + if (Status == 0) + { + // Loop through the list of interfaces + temp = interfaces; + + // Run through it while it's still available + while(temp != NULL) + { + // If the temp interface is a valid interface + if(temp->ifa_addr->sa_family == AF_INET) + { + // Check if the interface is WiFi + if([[NSString stringWithUTF8String:temp->ifa_name] isEqualToString:@"en0"]) + { + // Get the WiFi IP Address + ipAddress = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp->ifa_addr)->sin_addr)]; + } + } + + // Set the temp value to the next interface + temp = temp->ifa_next; + } + } + + // Free the memory of the interfaces + freeifaddrs(interfaces); + + // Check to make sure it's not empty + if (ipAddress == nil || ipAddress.length <= 0) { + // Empty, return not found + return nil; + } + + // Return the IP Address of the WiFi + return ipAddress; + } + @catch (NSException *exception) { + // Error, IP Not found + return nil; + } +} + +// Get WiFi IPv6 Address ++ (nullable NSString *)wiFiIPv6Address { + // Get the WiFi IP Address + @try { + // Set a string for the address + NSString *ipAddress; + // Set up structs to hold the interfaces and the temporary address + struct ifaddrs *interfaces; + struct ifaddrs *temp; + // Set up int for success or fail + int status = 0; + + // Get all the network interfaces + status = getifaddrs(&interfaces); + + // If it's 0, then it's good + if (status == 0) + { + // Loop through the list of interfaces + temp = interfaces; + + // Run through it while it's still available + while(temp != NULL) + { + // If the temp interface is a valid interface + if(temp->ifa_addr->sa_family == AF_INET6) + { + // Check if the interface is WiFi + if([[NSString stringWithUTF8String:temp->ifa_name] isEqualToString:@"en0"]) + { + // Get the WiFi IP Address + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)temp->ifa_addr; + char buf[INET6_ADDRSTRLEN]; + if (inet_ntop(AF_INET6, (void *)&(addr6->sin6_addr), buf, sizeof(buf)) == NULL) { + // Failed to find it + ipAddress = nil; + } else { + // Got the Cell IP Address + ipAddress = [NSString stringWithUTF8String:buf]; + } + } + } + + // Set the temp value to the next interface + temp = temp->ifa_next; + } + } + + // Free the memory of the interfaces + freeifaddrs(interfaces); + + // Check to make sure it's not empty + if (ipAddress == nil || ipAddress.length <= 0) { + // Empty, return not found + return nil; + } + + // Return the IP Address of the WiFi + return ipAddress; + } + @catch (NSException *exception) { + // Error, IP Not found + return nil; + } +} + +// Get WiFi Netmask Address ++ (nullable NSString *)wiFiNetmaskAddress { + // Get the WiFi Netmask Address + @try { + // Set up the variable + struct ifreq afr; + // Copy the string + strncpy(afr.ifr_name, [@"en0" UTF8String], IFNAMSIZ-1); + // Open a socket + int afd = socket(AF_INET, SOCK_DGRAM, 0); + + // Check the socket + if (afd == -1) { + // Error, socket failed to open + return nil; + } + + // Check the netmask output + if (ioctl(afd, SIOCGIFNETMASK, &afr) == -1) { + // Error, netmask wasn't found + // Close the socket + close(afd); + // Return error + return nil; + } + + // Close the socket + close(afd); + + // Create a char for the netmask + char *netstring = inet_ntoa(((struct sockaddr_in *)&afr.ifr_addr)->sin_addr); + + // Create a string for the netmask + NSString *netmask = [NSString stringWithUTF8String:netstring]; + + // Check to make sure it's not nil + if (netmask == nil || netmask.length <= 0) { + // Error, netmask not found + return nil; + } + + // Return successful + return netmask; + } + @catch (NSException *exception) { + // Error + return nil; + } +} + +// Get WiFi Broadcast Address ++ (nullable NSString *)wiFiBroadcastAddress { + // Get the WiFi Broadcast Address + @try { + // Set up strings for the IP and Netmask + NSString *ipAddress = [self wiFiIPAddress]; + NSString *nmAddress = [self wiFiNetmaskAddress]; + + // Check to make sure they aren't nil + if (ipAddress == nil || ipAddress.length <= 0) { + // Error, IP Address can't be nil + return nil; + } + if (nmAddress == nil || nmAddress.length <= 0) { + // Error, NM Address can't be nil + return nil; + } + + // Check the formatting of the IP and NM Addresses + NSArray *ipCheck = [ipAddress componentsSeparatedByString:@"."]; + NSArray *nmCheck = [nmAddress componentsSeparatedByString:@"."]; + + // Make sure the IP and NM Addresses are correct + if (ipCheck.count != 4 || nmCheck.count != 4) { + // Incorrect IP Addresses + return nil; + } + + // Set up the variables + NSUInteger ip = 0; + NSUInteger nm = 0; + NSUInteger cs = 24; + + // Make the address based on the other addresses + for (NSUInteger i = 0; i < 4; i++, cs -= 8) { + ip |= [[ipCheck objectAtIndex:i] intValue] << cs; + nm |= [[nmCheck objectAtIndex:i] intValue] << cs; + } + + // Set it equal to the formatted raw addresses + NSUInteger ba = ~nm | ip; + + // Make a string for the address + NSString *broadcastAddress = [NSString stringWithFormat:@"%lu.%lu.%lu.%lu", (long)(ba & 0xFF000000) >> 24, + (long)(ba & 0x00FF0000) >> 16, (long)(ba & 0x0000FF00) >> 8, (long)(ba & 0x000000FF)]; + + // Check to make sure the string is valid + if (broadcastAddress == nil || broadcastAddress.length <= 0) { + // Error, no address + return nil; + } + + // Return Successful + return broadcastAddress; + } + @catch (NSException *exception) { + // Error + return nil; + } +} + +// Connected to WiFi? ++ (BOOL)connectedToWiFi { + // Check if we're connected to WiFi + NSString *wiFiAddress = [self wiFiIPAddress]; + // Check if the string is populated + if (wiFiAddress == nil || wiFiAddress.length <= 0) { + // Nothing found + return false; + } else { + // WiFi in use + return true; + } +} + +// Connected to Cellular Network? ++ (BOOL)connectedToCellNetwork { + // Check if we're connected to cell network + NSString *cellAddress = [self cellIPAddress]; + // Check if the string is populated + if (cellAddress == nil || cellAddress.length <= 0) { + // Nothing found + return false; + } else { + // Cellular Network in use + return true; + } +} + ++ (nullable NSString *)wiFiRouterAddress { + // Get the WiFi Router Address + @try { + // Set the ip address variable + NSString *routerIP = nil; + // Set the router array variable with the routing information + NSMutableArray *routerArray = [Route_Info getRoutes]; + // Run through the array + for(int i = 0; i < (int)[routerArray count]; i++) + { + // Set the router info + Route_Info* router = (Route_Info*)[routerArray objectAtIndex:i]; + routerIP = [router getGateway]; + } + // Return Successful + return routerIP; + } + @catch (NSException *exception) { + // Error + return nil; + } +} + +@end + + diff --git a/iDevices/Tweak/IDEVICES/SystemInfo/SSProcessorInfo.h b/iDevices/Tweak/IDEVICES/SystemInfo/SSProcessorInfo.h new file mode 100755 index 0000000..5e84c8b --- /dev/null +++ b/iDevices/Tweak/IDEVICES/SystemInfo/SSProcessorInfo.h @@ -0,0 +1,117 @@ +#import +#import +#include +#import +#import +#import +#import +#import +#import + +// AVFoundation +#import + +@interface SSProcessorInfo : NSObject + ++ (NSInteger)numberProcessors; ++ (NSInteger)numberActiveProcessors; + ++ (nullable NSString *)country; + +// Language ++ (nullable NSString *)language; + +// TimeZone ++ (nullable NSString *)timeZone; + +// Currency Symbol ++ (nullable NSString *)currency; + + +// System Uptime (dd hh mm) ++ (nullable NSString *)systemUptime; + +// Model of Device ++ (nullable NSString *)deviceModel; + +// Device Name ++ (nullable NSString *)deviceName; + +// System Name ++ (nullable NSString *)systemName; + +// System Version ++ (nullable NSString *)systemVersion; + +// System Device Type (iPhone1,0) (Formatted = iPhone 1) ++ (nullable NSString *)systemDeviceTypeFormatted:(BOOL)formatted; + +// Get the Screen Width (X) ++ (NSInteger)screenWidth; + +// Get the Screen Height (Y) ++ (NSInteger)screenHeight; + +// Get the Screen Brightness ++ (float)screenBrightness; + +// Multitasking enabled? ++ (BOOL)multitaskingEnabled; + +// Proximity sensor enabled? ++ (BOOL)proximitySensorEnabled; + +// Debugger Attached? ++ (BOOL)debuggerAttached; + +// Plugged In? ++ (BOOL)pluggedIn; + +// Step-Counting Available? ++ (BOOL)stepCountingAvailable; + +// Distance Available ++ (BOOL)distanceAvailable; + +// Floor Counting Available ++ (BOOL)floorCountingAvailable; + +// Carrier Name ++ (nullable NSString *)carrierName; + +// Carrier Country ++ (nullable NSString *)carrierCountry; + +// Carrier Mobile Country Code ++ (nullable NSString *)carrierMobileCountryCode; + +// Carrier ISO Country Code ++ (nullable NSString *)carrierISOCountryCode; + +// Carrier Mobile Network Code ++ (nullable NSString *)carrierMobileNetworkCode; + +// Carrier Allows VOIP ++ (BOOL)carrierAllowsVOIP; + ++ (float)batteryLevel; + +// Charging? ++ (BOOL)charging; + +// Fully Charged? ++ (BOOL)fullyCharged; ++ (nullable NSString *)clipboardContent; + ++ (BOOL)accessoriesAttached; + +// Are headphone attached? ++ (BOOL)headphonesAttached; + +// Number of attached accessories ++ (NSInteger)numberAttachedAccessories; + +// Name of attached accessory/accessories (seperated by , comma's) ++ (nullable NSString *)nameAttachedAccessories; + +@end diff --git a/iDevices/Tweak/IDEVICES/SystemInfo/SSProcessorInfo.m b/iDevices/Tweak/IDEVICES/SystemInfo/SSProcessorInfo.m new file mode 100755 index 0000000..aaa4e21 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/SystemInfo/SSProcessorInfo.m @@ -0,0 +1,992 @@ +#import "SSProcessorInfo.h" + + +@implementation SSProcessorInfo + + ++ (NSInteger)numberProcessors { + // See if the process info responds to selector + if ([[NSProcessInfo processInfo] respondsToSelector:@selector(processorCount)]) { + // Get the number of processors + NSInteger processorCount = [[NSProcessInfo processInfo] processorCount]; + // Return the number of processors + return processorCount; + } else { + // Return -1 (not found) + return -1; + } +} + + ++ (NSInteger)numberActiveProcessors { + // See if the process info responds to selector + if ([[NSProcessInfo processInfo] respondsToSelector:@selector(activeProcessorCount)]) { + // Get the number of active processors + NSInteger activeprocessorCount = [[NSProcessInfo processInfo] activeProcessorCount]; + // Return the number of active processors + return activeprocessorCount; + } else { + // Return -1 (not found) + return -1; + } +} + + ++ (NSArray *)processorsUsage { + + // Try to get Processor Usage Info + @try { + // Variables + processor_info_array_t _cpuInfo, _prevCPUInfo = nil; + mach_msg_type_number_t _numCPUInfo, _numPrevCPUInfo = 0; + unsigned _numCPUs; + NSLock *_cpuUsageLock; + + // Get the number of processors from sysctl + int _mib[2U] = { CTL_HW, HW_NCPU }; + size_t _sizeOfNumCPUs = sizeof(_numCPUs); + int _status = sysctl(_mib, 2U, &_numCPUs, &_sizeOfNumCPUs, NULL, 0U); + if (_status) + _numCPUs = 1; + + // Allocate the lock + _cpuUsageLock = [[NSLock alloc] init]; + + // Get the processor info + natural_t _numCPUsU = 0U; + kern_return_t err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &_numCPUsU, &_cpuInfo, &_numCPUInfo); + if (err == KERN_SUCCESS) { + [_cpuUsageLock lock]; + + // Go through info for each processor + NSMutableArray *processorInfo = [NSMutableArray new]; + for (unsigned i = 0U; i < _numCPUs; ++i) { + Float32 _inUse, _total; + if (_prevCPUInfo) { + _inUse = ( + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER]) + + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM]) + + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE]) + ); + _total = _inUse + (_cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE] - _prevCPUInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE]); + } else { + _inUse = _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_USER] + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_SYSTEM] + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_NICE]; + _total = _inUse + _cpuInfo[(CPU_STATE_MAX * i) + CPU_STATE_IDLE]; + } + // Add to the processor usage info + [processorInfo addObject:@(_inUse / _total)]; + } + + [_cpuUsageLock unlock]; + if (_prevCPUInfo) { + size_t prevCpuInfoSize = sizeof(integer_t) * _numPrevCPUInfo; + vm_deallocate(mach_task_self(), (vm_address_t)_prevCPUInfo, prevCpuInfoSize); + } + // Retrieved processor information + return processorInfo; + } else { + // Unable to get processor information + return nil; + } + } @catch (NSException *exception) { + // Getting processor information failed + return nil; + } +} + + +// Country ++ (NSString *)country { + // Get the user's country + @try { + // Get the locale + NSLocale *locale = [NSLocale currentLocale]; + // Get the country from the locale + NSString *country = [locale localeIdentifier]; + // Check for validity + if (country == nil || country.length <= 0) { + // Error, invalid country + return nil; + } + // Completed Successfully + return country; + } + @catch (NSException *exception) { + // Error + return nil; + } +} + +// Language ++ (NSString *)language { + // Get the user's language + @try { + // Get the list of languages + NSArray *languageArray = [NSLocale preferredLanguages]; + // Get the user's language + NSString *language = [languageArray objectAtIndex:0]; + // Check for validity + if (language == nil || language.length <= 0) { + // Error, invalid language + return nil; + } + // Completed Successfully + return language; + } + @catch (NSException *exception) { + // Error + return nil; + } +} + +// TimeZone ++ (NSString *)timeZone { + // Get the user's timezone + @try { + // Get the system timezone + NSTimeZone *localTime = [NSTimeZone systemTimeZone]; + // Convert the time zone to a string + NSString *timeZone = [localTime name]; + // Check for validity + if (timeZone == nil || timeZone.length <= 0) { + // Error, invalid TimeZone + return nil; + } + // Completed Successfully + return timeZone; + } + @catch (NSException *exception) { + // Error + return nil; + } +} + +// Currency Symbol ++ (NSString *)currency { + // Get the user's currency + @try { + // Get the system currency + NSString *currency = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencySymbol]; + // Check for validity + if (currency == nil || currency.length <= 0) { + // Error, invalid Currency + return nil; + } + // Completed Successfully + return currency; + } + @catch (NSException *exception) { + // Error + return nil; + } +} + + ++ (NSString *)systemUptime { + // Set up the days/hours/minutes + NSNumber *days, *hours, *minutes; + + // Get the info about a process + NSProcessInfo *processInfo = [NSProcessInfo processInfo]; + // Get the uptime of the system + NSTimeInterval uptimeInterval = [processInfo systemUptime]; + // Get the calendar + NSCalendar *calendar = [NSCalendar currentCalendar]; + // Create the Dates + NSDate *date = [[NSDate alloc] initWithTimeIntervalSinceNow:(0-uptimeInterval)]; + unsigned int unitFlags = NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute; + NSDateComponents *components = [calendar components:unitFlags fromDate:date toDate:[NSDate date] options:0]; + + // Get the day, hour and minutes + days = [NSNumber numberWithLong:[components day]]; + hours = [NSNumber numberWithLong:[components hour]]; + minutes = [NSNumber numberWithLong:[components minute]]; + + // Format the dates + NSString *uptime = [NSString stringWithFormat:@"%@ %@ %@", + [days stringValue], + [hours stringValue], + [minutes stringValue]]; + + // Error checking + if (!uptime) { + // No uptime found + // Return nil + return nil; + } + + // Return the uptime + return uptime; +} + +// Model of Device ++ (NSString *)deviceModel { + // Get the device model + if ([[UIDevice currentDevice] respondsToSelector:@selector(model)]) { + // Make a string for the device model + NSString *deviceModel = [[UIDevice currentDevice] model]; + // Set the output to the device model + return deviceModel; + } else { + // Device model not found + return nil; + } +} + +// Device Name ++ (NSString *)deviceName { + // Get the current device name + if ([[UIDevice currentDevice] respondsToSelector:@selector(name)]) { + // Make a string for the device name + NSString *deviceName = [[UIDevice currentDevice] name]; + // Set the output to the device name + return deviceName; + } else { + // Device name not found + return nil; + } +} + +// System Name ++ (NSString *)systemName { + // Get the current system name + if ([[UIDevice currentDevice] respondsToSelector:@selector(systemName)]) { + // Make a string for the system name + NSString *systemName = [[UIDevice currentDevice] systemName]; + // Set the output to the system name + return systemName; + } else { + // System name not found + return nil; + } +} + +// System Version ++ (NSString *)systemVersion { + // Get the current system version + if ([[UIDevice currentDevice] respondsToSelector:@selector(systemVersion)]) { + // Make a string for the system version + NSString *systemVersion = [[UIDevice currentDevice] systemVersion]; + // Set the output to the system version + return systemVersion; + } else { + // System version not found + return nil; + } +} + +// System Device Type (iPhone1,0) (Formatted = iPhone 1) ++ (NSString *)systemDeviceTypeFormatted:(BOOL)formatted { + // Set up a Device Type String + NSString *deviceType; + + // Check if it should be formatted + if (formatted) { + // Formatted + @try { + // Set up a new Device Type String + NSString *newDeviceType; + // Set up a struct + struct utsname dt; + // Get the system information + uname(&dt); + // Set the device type to the machine type + deviceType = [NSString stringWithFormat:@"%s", dt.machine]; + + if ([deviceType isEqualToString:@"iPhone8,1"]) + newDeviceType = @"iPhone 6s"; + else if ([deviceType isEqualToString:@"iPhone8,2"]) + newDeviceType = @"iPhone 6s Plus"; + else if ([deviceType isEqualToString:@"iPhone8,4"]) + newDeviceType = @"iPhone SE"; + else if ([deviceType isEqualToString:@"iPhone9,1"]) + newDeviceType = @"iPhone 7 (CDMA+GSM/LTE)"; + else if ([deviceType isEqualToString:@"iPhone9,3"]) + newDeviceType = @"iPhone 7 (GSM/LTE)"; + else if ([deviceType isEqualToString:@"iPhone9,2"]) + newDeviceType = @"iPhone 7 Plus (CDMA+GSM/LTE)"; + else if ([deviceType isEqualToString:@"iPhone9,4"]) + newDeviceType = @"iPhone 7 Plus (GSM/LTE)"; + else if ([deviceType isEqualToString:@"iPhone10,1"]) + newDeviceType = @"iPhone 8 (CDMA+GSM/LTE)"; + else if ([deviceType isEqualToString:@"iPhone10,2"]) + newDeviceType = @"iPhone 8 Plus (CDMA+GSM/LTE)"; + else if ([deviceType isEqualToString:@"iPhone10,3"]) + newDeviceType = @"iPhone X (CDMA+GSM/LTE)"; + else if ([deviceType isEqualToString:@"iPhone10,4"]) + newDeviceType = @"iPhone 8 (GSM/LTE)"; + else if ([deviceType isEqualToString:@"iPhone10,5"]) + newDeviceType = @"iPhone 8 Plus (GSM/LTE)"; + else if ([deviceType isEqualToString:@"iPhone10,6"]) + newDeviceType = @"iPhone X (GSM/LTE)"; + else if ([deviceType isEqualToString:@"iPhone11,2"]) + newDeviceType = @"iPhone XS"; + else if ([deviceType isEqualToString:@"iPhone11,4"]) + newDeviceType = @"iPhone XS MAX"; + else if ([deviceType isEqualToString:@"iPhone11,6"]) + newDeviceType = @"iPhone XS MAX (CDMA+GSM/LTE)"; + else if ([deviceType isEqualToString:@"iPhone11,8"]) + newDeviceType = @"iPhone XR"; + else if ([deviceType isEqualToString:@"iPhone12,1"]) + newDeviceType = @"iPhone 11"; + else if ([deviceType isEqualToString:@"iPhone12,3"]) + newDeviceType = @"iPhone 11 Pro"; + else if ([deviceType isEqualToString:@"iPhone12,5"]) + newDeviceType = @"iPhone 11 Pro Max"; + else if ([deviceType isEqualToString:@"iPhone12,8"]) + newDeviceType = @"iPhone SE 2nd Gen"; + else if ([deviceType isEqualToString:@"iPhone13,1"]) + newDeviceType = @"iPhone 12 Mini"; + else if ([deviceType isEqualToString:@"iPhone13,2"]) + newDeviceType = @"iPhone 12"; + else if ([deviceType isEqualToString:@"iPhone13,3"]) + newDeviceType = @"iPhone 12 Pro"; + else if ([deviceType isEqualToString:@"iPhone13,4"]) + newDeviceType = @"iPhone 12 Pro Max"; + else if ([deviceType isEqualToString:@"iPhone14,2"]) + newDeviceType = @"iPhone 13 Pro"; + else if ([deviceType isEqualToString:@"iPhone14,3"]) + newDeviceType = @"iPhone 13 Pro Max"; + else if ([deviceType isEqualToString:@"iPhone14,4"]) + newDeviceType = @"iPhone 13 Mini"; + else if ([deviceType isEqualToString:@"iPhone14,5"]) + newDeviceType = @"iPhone 13"; + + + + // Return the new device type + return newDeviceType; + } + @catch (NSException *exception) { + // Error + return nil; + } + } else { + // Unformatted + @try { + // Set up a struct + struct utsname dt; + // Get the system information + uname(&dt); + // Set the device type to the machine type + deviceType = [NSString stringWithFormat:@"%s", dt.machine]; + + // Return the device type + return deviceType; + } + @catch (NSException *exception) { + // Error + return nil; + } + } +} + +// Get the Screen Width (X) ++ (NSInteger)screenWidth { + // Get the screen width + @try { + // Screen bounds + CGRect Rect = [[UIScreen mainScreen] bounds]; + // Find the width (X) + NSInteger Width = Rect.size.width; + // Verify validity + if (Width <= 0) { + // Invalid Width + return -1; + } + + // Successful + return Width; + } + @catch (NSException *exception) { + // Error + return -1; + } +} + +// Get the Screen Height (Y) ++ (NSInteger)screenHeight { + // Get the screen height + @try { + // Screen bounds + CGRect Rect = [[UIScreen mainScreen] bounds]; + // Find the Height (Y) + NSInteger Height = Rect.size.height; + // Verify validity + if (Height <= 0) { + // Invalid Height + return -1; + } + + // Successful + return Height; + } + @catch (NSException *exception) { + // Error + return -1; + } +} + +// Get the Screen Brightness ++ (float)screenBrightness { + // Get the screen brightness + @try { + // Brightness + float brightness = [UIScreen mainScreen].brightness; + // Verify validity + if (brightness < 0.0 || brightness > 1.0) { + // Invalid brightness + return -1; + } + + // Successful + return (brightness * 100); + } + @catch (NSException *exception) { + // Error + return -1; + } +} + +// Multitasking enabled? ++ (BOOL)multitaskingEnabled { + // Is multitasking enabled? + if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)]) { + // Create a bool + BOOL MultitaskingSupported = [UIDevice currentDevice].multitaskingSupported; + // Return the value + return MultitaskingSupported; + } else { + // Doesn't respond to selector + return false; + } +} + +// Proximity sensor enabled? ++ (BOOL)proximitySensorEnabled { + // Is the proximity sensor enabled? + if ([[UIDevice currentDevice] respondsToSelector:@selector(setProximityMonitoringEnabled:)]) { + // Create a UIDevice variable + UIDevice *device = [UIDevice currentDevice]; + + // Make a Bool for the proximity Sensor + BOOL ProximitySensor; + + // Turn the sensor on, if not already on, and see if it works + if (device.proximityMonitoringEnabled != YES) { + // Sensor is off + // Turn it on + [device setProximityMonitoringEnabled:YES]; + // See if it turned on + if (device.proximityMonitoringEnabled == YES) { + // It turned on! Turn it off + [device setProximityMonitoringEnabled:NO]; + // It works + ProximitySensor = true; + } else { + // Didn't turn on, no good + ProximitySensor = false; + } + } else { + // Sensor is already on + ProximitySensor = true; + } + + // Return on or off + return ProximitySensor; + } else { + // Doesn't respond to selector + return false; + } +} + +// Debugging attached? ++ (BOOL)debuggerAttached { + // Is the debugger attached? + @try { + // Set up the variables + int ret; + int mib[4]; + struct kinfo_proc info; + size_t size; + info.kp_proc.p_flag = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + size = sizeof(info); + ret = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); + + // Verify ret + if (ret) { + // Sysctl() failed + // Return the output of sysctl + return ret; + } + + // Return whether the process is being traced or not + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + + } + @catch (NSException *exception) { + // Error + return false; + } +} + +// Plugged In? ++ (BOOL)pluggedIn { + // Is the device plugged in? + if ([[UIDevice currentDevice] respondsToSelector:@selector(batteryState)]) { + // Create a bool + BOOL PluggedIn; + // Set the battery monitoring enabled + [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; + // Get the battery state + UIDeviceBatteryState batteryState = [UIDevice currentDevice].batteryState; + // Check if it's plugged in or finished charging + if (batteryState == UIDeviceBatteryStateCharging || batteryState == UIDeviceBatteryStateFull) { + // We're plugged in + PluggedIn = true; + } else { + PluggedIn = false; + } + // Return the value + return PluggedIn; + } else { + // Doesn't respond to selector + return false; + } +} + +// Step-Counting Available? ++ (BOOL)stepCountingAvailable { + @try { + // Make sure the Pedometer class exists + if ([CMPedometer class]) { + // Make sure the selector exists + if ([CMPedometer respondsToSelector:@selector(isStepCountingAvailable)]) { + // Return whether it's available + return [CMPedometer isStepCountingAvailable]; + } + } + // Not available + return false; + } + @catch (NSException *exception) { + // Error + return false; + } +} + +// Distance Available ++ (BOOL)distanceAvailable { + @try { + // Make sure the Pedometer class exists + if ([CMPedometer class]) { + // Make sure the selector exists + if ([CMPedometer respondsToSelector:@selector(isDistanceAvailable)]) { + // Return whether it's available + return [CMPedometer isDistanceAvailable]; + } + } + // Not available + return false; + } + @catch (NSException *exception) { + // Error + return false; + } +} + +// Floor Counting Available ++ (BOOL)floorCountingAvailable { + @try { + // Make sure the Pedometer class exists + if ([CMPedometer class]) { + // Make sure the selector exists + if ([CMPedometer respondsToSelector:@selector(isFloorCountingAvailable)]) { + // Return whether it's available + return [CMPedometer isFloorCountingAvailable]; + } + } + // Not available + return false; + } + @catch (NSException *exception) { + // Error + return false; + } +} + + ++ (NSString *)carrierName { + // Get the carrier name + @try { + // Get the Telephony Network Info + CTTelephonyNetworkInfo *telephonyInfo = [[CTTelephonyNetworkInfo alloc] init]; + // Get the carrier + CTCarrier *carrier = [telephonyInfo subscriberCellularProvider]; + // Get the carrier name + NSString *carrierName = [carrier carrierName]; + + // Check to make sure it's valid + if (carrierName == nil || carrierName.length <= 0) { + // Return unknown + return nil; + } + + // Return the name + return carrierName; + } + @catch (NSException *exception) { + // Error finding the name + return nil; + } +} + +// Carrier Country ++ (NSString *)carrierCountry { + // Get the country that the carrier is located in + @try { + // Get the locale + NSLocale *currentCountry = [NSLocale currentLocale]; + // Get the country Code + NSString *country = [currentCountry objectForKey:NSLocaleCountryCode]; + // Check if it returned anything + if (country == nil || country.length <= 0) { + // No country found + return nil; + } + // Return the country + return country; + } + @catch (NSException *exception) { + // Failed, return nil + return nil; + } +} + +// Carrier Mobile Country Code ++ (NSString *)carrierMobileCountryCode { + // Get the carrier mobile country code + @try { + // Get the Telephony Network Info + CTTelephonyNetworkInfo *telephonyInfo = [[CTTelephonyNetworkInfo alloc] init]; + // Get the carrier + CTCarrier *carrier = [telephonyInfo subscriberCellularProvider]; + // Get the carrier mobile country code + NSString *carrierCode = [carrier mobileCountryCode]; + + // Check to make sure it's valid + if (carrierCode == nil || carrierCode.length <= 0) { + // Return unknown + return nil; + } + + // Return the name + return carrierCode; + } + @catch (NSException *exception) { + // Error finding the name + return nil; + } +} + +// Carrier ISO Country Code ++ (NSString *)carrierISOCountryCode { + // Get the carrier ISO country code + @try { + // Get the Telephony Network Info + CTTelephonyNetworkInfo *telephonyInfo = [[CTTelephonyNetworkInfo alloc] init]; + // Get the carrier + CTCarrier *carrier = [telephonyInfo subscriberCellularProvider]; + // Get the carrier ISO country code + NSString *carrierCode = [carrier isoCountryCode]; + + // Check to make sure it's valid + if (carrierCode == nil || carrierCode.length <= 0) { + // Return unknown + return nil; + } + + // Return the name + return carrierCode; + } + @catch (NSException *exception) { + // Error finding the name + return nil; + } +} + +// Carrier Mobile Network Code ++ (NSString *)carrierMobileNetworkCode { + // Get the carrier mobile network code + @try { + // Get the Telephony Network Info + CTTelephonyNetworkInfo *telephonyInfo = [[CTTelephonyNetworkInfo alloc] init]; + // Get the carrier + CTCarrier *carrier = [telephonyInfo subscriberCellularProvider]; + // Get the carrier mobile network code + NSString *carrierCode = [carrier mobileNetworkCode]; + + // Check to make sure it's valid + if (carrierCode == nil || carrierCode.length <= 0) { + // Return unknown + return nil; + } + + // Return the name + return carrierCode; + } + @catch (NSException *exception) { + // Error finding the name + return nil; + } +} + +// Carrier Allows VOIP ++ (BOOL)carrierAllowsVOIP { + // Check if the carrier allows VOIP + @try { + // Get the Telephony Network Info + CTTelephonyNetworkInfo *telephonyInfo = [[CTTelephonyNetworkInfo alloc] init]; + // Get the carrier + CTCarrier *carrier = [telephonyInfo subscriberCellularProvider]; + // Get the carrier VOIP Status + BOOL carrierVOIP = [carrier allowsVOIP]; + + // Return the VOIP Status + return carrierVOIP; + } + @catch (NSException *exception) { + // Error finding the VOIP Status + return false; + } +} + + ++ (float)batteryLevel { + // Find the battery level + @try { + // Get the device + UIDevice *device = [UIDevice currentDevice]; + // Set battery monitoring on + device.batteryMonitoringEnabled = YES; + + // Set up the battery level float + float batteryLevel = 0.0; + // Get the battery level + float batteryCharge = [device batteryLevel]; + + // Check to make sure the battery level is more than zero + if (batteryCharge > 0.0f) { + // Make the battery level float equal to the charge * 100 + batteryLevel = batteryCharge * 100; + } else { + // Unable to find the battery level + return -1; + } + + // Output the battery level + return batteryLevel; + } + @catch (NSException *exception) { + // Error out + return -1; + } +} + +// Charging? ++ (BOOL)charging { + // Is the battery charging? + @try { + // Get the device + UIDevice *device = [UIDevice currentDevice]; + // Set battery monitoring on + device.batteryMonitoringEnabled = YES; + + // Check the battery state + if ([device batteryState] == UIDeviceBatteryStateCharging || [device batteryState] == UIDeviceBatteryStateFull) { + // Device is charging + return true; + } else { + // Device is not charging + return false; + } + } + @catch (NSException *exception) { + // Error out + return false; + } +} + +// Fully Charged? ++ (BOOL)fullyCharged { + // Is the battery fully charged? + @try { + // Get the device + UIDevice *device = [UIDevice currentDevice]; + // Set battery monitoring on + device.batteryMonitoringEnabled = YES; + + // Check the battery state + if ([device batteryState] == UIDeviceBatteryStateFull) { + // Device is fully charged + return true; + } else { + // Device is not fully charged + return false; + } + } + @catch (NSException *exception) { + // Error out + return false; + } +} + + ++ (NSString *)clipboardContent { + // Get the string content of the clipboard (copy, paste) + @try { + // Get the Pasteboard + UIPasteboard *pasteBoard = [UIPasteboard generalPasteboard]; + // Get the string value of the pasteboard + NSString *clipboardContent = [pasteBoard string]; + // Check for validity + if (clipboardContent == nil || clipboardContent.length <= 0) { + // Error, invalid pasteboard + return nil; + } + // Successful + return clipboardContent; + } + @catch (NSException *exception) { + // Error + return nil; + } +} + + +// Are any accessories attached? ++ (BOOL)accessoriesAttached { + // Check if any accessories are connected + @try { + // Set up the accessory manger + EAAccessoryManager *accessoryManager = [EAAccessoryManager sharedAccessoryManager]; + // Get the number of accessories connected + int numberOfAccessoriesConnected = (int)[accessoryManager.connectedAccessories count]; + // Check if there are any connected + if (numberOfAccessoriesConnected > 0) { + // There are accessories connected + return true; + } else { + // There are no accessories connected + return false; + } + } + @catch (NSException *exception) { + // Error, return false + return false; + } +} + +// Are headphone attached? ++ (BOOL)headphonesAttached { + // Check if the headphones are connected + @try { + // Get the audiosession route information + AVAudioSessionRouteDescription *route = [[AVAudioSession sharedInstance] currentRoute]; + + // Run through all the route outputs + for (AVAudioSessionPortDescription *desc in [route outputs]) { + + // Check if any of the ports are equal to the string headphones + if ([[desc portType] isEqualToString:AVAudioSessionPortHeadphones]) { + + // Return YES + return YES; + } + } + + // No headphones attached + return NO; + } + @catch (NSException *exception) { + // Error, return false + return false; + } +} + +// Number of attached accessories ++ (NSInteger)numberAttachedAccessories { + // Get the number of attached accessories + @try { + // Set up the accessory manger + EAAccessoryManager *accessoryManager = [EAAccessoryManager sharedAccessoryManager]; + // Get the number of accessories connected + int numberOfAccessoriesConnected = (int)[accessoryManager.connectedAccessories count]; + // Return how many accessories are attached + return numberOfAccessoriesConnected; + } + @catch (NSException *exception) { + // Error, return false + return false; + } +} + +// Name of attached accessory/accessories (seperated by , comma's) ++ (NSString *)nameAttachedAccessories { + // Get the name of the attached accessories + @try { + // Set up the accessory manger + EAAccessoryManager *accessoryManager = [EAAccessoryManager sharedAccessoryManager]; + // Set up an accessory (for later use) + EAAccessory *accessory; + // Get the number of accessories connected + int numberOfAccessoriesConnected = (int)[accessoryManager.connectedAccessories count]; + + // Check to make sure there are accessories connected + if (numberOfAccessoriesConnected > 0) { + // Set up a string for all the accessory names + NSString *allAccessoryNames = @""; + // Set up a string for the accessory names + NSString *accessoryName; + // Get the accessories + NSArray *accessoryArray = accessoryManager.connectedAccessories; + // Run through all the accessories + for (int x = 0; x < numberOfAccessoriesConnected; x++) { + // Get the accessory at that index + accessory = [accessoryArray objectAtIndex:x]; + // Get the name of it + accessoryName = [accessory name]; + // Make sure there is a name + if (accessoryName == nil || accessoryName.length == 0) { + // If there isn't, try and get the manufacturer name + accessoryName = [accessory manufacturer]; + } + // Make sure there is a manufacturer name + if (accessoryName == nil || accessoryName.length == 0) { + // If there isn't a manufacturer name still + accessoryName = @"Unknown"; + } + // Format that name + allAccessoryNames = [allAccessoryNames stringByAppendingFormat:@"%@", accessoryName]; + if (x < numberOfAccessoriesConnected - 1) { + allAccessoryNames = [allAccessoryNames stringByAppendingFormat:@", "]; + } + } + // Return the name/s of the connected accessories + return allAccessoryNames; + } else { + // No accessories connected + return nil; + } + } + @catch (NSException *exception) { + // Error, return false + return nil; + } +} + +@end diff --git a/iDevices/Tweak/IDEVICES/SystemInfo/SystemServices.h b/iDevices/Tweak/IDEVICES/SystemInfo/SystemServices.h new file mode 100755 index 0000000..06d0c69 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/SystemInfo/SystemServices.h @@ -0,0 +1,61 @@ +#import +#import +#import "SSNetworkInfo.h" +#import "SSProcessorInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface SystemServices : NSObject + ++ (nonnull instancetype)sharedServices; +- (NSString *)systemsUptime; +- (NSString *)deviceModel; +- (NSString *)deviceName; +- (NSString *)systemName; +- (NSString *)systemsVersion; +- (NSString *)systemDeviceTypeNotFormatted; +- (NSString *)systemDeviceTypeFormatted; +- (NSInteger)screenWidth; +- (NSInteger)screenHeight; +- (float)screenBrightness; +- (BOOL)multitaskingEnabled; +- (BOOL)proximitySensorEnabled; +- (BOOL)debuggerAttached; +- (BOOL)pluggedIn; +- (BOOL)stepCountingAvailable; +- (BOOL)distanceAvailable; +- (BOOL)floorCountingAvailable; +- (NSInteger)numberProcessors; +- (NSInteger)numberActiveProcessors; +- (BOOL)accessoriesAttached; +- (BOOL)headphonesAttached; +- (NSInteger)numberAttachedAccessories; +- (NSString *)nameAttachedAccessories; +- (NSString *)carrierName; +- (NSString *)carrierCountry; +- (NSString *)carrierMobileCountryCode; +- (NSString *)carrierISOCountryCode; +- (NSString *)carrierMobileNetworkCode; +- (BOOL)carrierAllowsVOIP; +- (float)batteryLevel; +- (BOOL)charging; +- (BOOL)fullyCharged; +- (nullable NSString *)currentIPAddress; +- (nullable NSString *)externalIPAddress; +- (nullable NSString *)cellIPAddress; +- (nullable NSString *)cellNetmaskAddress; +- (nullable NSString *)cellBroadcastAddress; +- (nullable NSString *)wiFiIPAddress; +- (nullable NSString *)wiFiNetmaskAddress; +- (nullable NSString *)wiFiBroadcastAddress; +- (nullable NSString *)wiFiRouterAddress; +- (BOOL)connectedToWiFi; +- (BOOL)connectedToCellNetwork; +- (nullable NSString *)country; +- (nullable NSString *)language; +- (nullable NSString *)timeZoneSS; +- (nullable NSString *)currency; +- (nullable NSString *)clipboardContent; + +@end +NS_ASSUME_NONNULL_END diff --git a/iDevices/Tweak/IDEVICES/SystemInfo/SystemServices.m b/iDevices/Tweak/IDEVICES/SystemInfo/SystemServices.m new file mode 100755 index 0000000..c8c9bbc --- /dev/null +++ b/iDevices/Tweak/IDEVICES/SystemInfo/SystemServices.m @@ -0,0 +1,207 @@ +#import "SystemServices.h" + +@implementation SystemServices + ++ (nonnull instancetype)sharedServices { + static SystemServices *sharedSystemServices = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedSystemServices = [[self alloc] init]; + }); + return sharedSystemServices; +} + + +- (NSString *)systemsUptime { + return [SSProcessorInfo systemUptime]; +} + +- (NSString *)deviceModel { + return [SSProcessorInfo deviceModel]; +} + +- (NSString *)deviceName { + return [SSProcessorInfo deviceName]; +} + +- (NSString *)systemName { + return [SSProcessorInfo systemName]; +} + +- (NSString *)systemsVersion { + return [SSProcessorInfo systemVersion]; +} + +- (NSString *)systemDeviceTypeNotFormatted { + return [SSProcessorInfo systemDeviceTypeFormatted:NO]; +} + +- (NSString *)systemDeviceTypeFormatted { + return [SSProcessorInfo systemDeviceTypeFormatted:YES]; +} + +- (NSInteger)screenWidth { + return [SSProcessorInfo screenWidth]; +} + +- (NSInteger)screenHeight { + return [SSProcessorInfo screenHeight]; +} + +- (float)screenBrightness { + return [SSProcessorInfo screenBrightness]; +} + +- (BOOL)multitaskingEnabled { + return [SSProcessorInfo multitaskingEnabled]; +} + +- (BOOL)proximitySensorEnabled { + return [SSProcessorInfo proximitySensorEnabled]; +} + +- (BOOL)debuggerAttached { + return [SSProcessorInfo debuggerAttached]; +} + +- (BOOL)pluggedIn { + return [SSProcessorInfo pluggedIn]; +} + +- (BOOL)stepCountingAvailable { + return [SSProcessorInfo stepCountingAvailable]; +} + +- (BOOL)distanceAvailable { + return [SSProcessorInfo distanceAvailable]; +} + +- (BOOL)floorCountingAvailable { + return [SSProcessorInfo floorCountingAvailable]; +} + +- (NSInteger)numberProcessors { + return [SSProcessorInfo numberProcessors]; +} + +- (NSInteger)numberActiveProcessors { + return [SSProcessorInfo numberActiveProcessors]; +} + +- (BOOL)accessoriesAttached { + return [SSProcessorInfo accessoriesAttached]; +} + +- (BOOL)headphonesAttached { + return [SSProcessorInfo headphonesAttached]; +} + +- (NSInteger)numberAttachedAccessories { + return [SSProcessorInfo numberAttachedAccessories]; +} + +- (NSString *)nameAttachedAccessories { + return [SSProcessorInfo nameAttachedAccessories]; +} + +- (NSString *)carrierName { + return [SSProcessorInfo carrierName]; +} + +- (NSString *)carrierCountry { + return [SSProcessorInfo carrierCountry]; +} + +- (NSString *)carrierMobileCountryCode { + return [SSProcessorInfo carrierMobileCountryCode]; +} + +- (NSString *)carrierISOCountryCode { + return [SSProcessorInfo carrierISOCountryCode]; +} + +- (NSString *)carrierMobileNetworkCode { + return [SSProcessorInfo carrierMobileNetworkCode]; +} + +- (BOOL)carrierAllowsVOIP { + return [SSProcessorInfo carrierAllowsVOIP]; +} + +- (float)batteryLevel { + return [SSProcessorInfo batteryLevel]; +} + +- (BOOL)charging { + return [SSProcessorInfo charging]; +} + +- (BOOL)fullyCharged { + return [SSProcessorInfo fullyCharged]; +} + +- (nullable NSString *)currentIPAddress { + return [SSNetworkInfo currentIPAddress]; +} + +- (nullable NSString *)externalIPAddress { + return [SSNetworkInfo externalIPAddress]; +} + +- (nullable NSString *)cellIPAddress { + return [SSNetworkInfo cellIPAddress]; +} + +- (nullable NSString *)cellNetmaskAddress { + return [SSNetworkInfo cellNetmaskAddress]; +} + +- (nullable NSString *)cellBroadcastAddress { + return [SSNetworkInfo cellBroadcastAddress]; +} + +- (nullable NSString *)wiFiIPAddress { + return [SSNetworkInfo wiFiIPAddress]; +} + +- (nullable NSString *)wiFiNetmaskAddress { + return [SSNetworkInfo wiFiNetmaskAddress]; +} + +- (nullable NSString *)wiFiBroadcastAddress { + return [SSNetworkInfo wiFiBroadcastAddress]; +} + +- (nullable NSString *)wiFiRouterAddress { + return [SSNetworkInfo wiFiRouterAddress]; +} + +- (BOOL)connectedToWiFi { + return [SSNetworkInfo connectedToWiFi]; +} + +- (BOOL)connectedToCellNetwork { + return [SSNetworkInfo connectedToCellNetwork]; +} + +- (NSString *)country { + return [SSProcessorInfo country]; +} + +- (NSString *)language { + return [SSProcessorInfo language]; +} + +- (NSString *)timeZoneSS { + return [SSProcessorInfo timeZone]; +} + +- (NSString *)currency { + return [SSProcessorInfo currency]; +} + +- (NSString *)clipboardContent { + return [SSProcessorInfo clipboardContent]; +} + +@end diff --git a/iDevices/Tweak/IDEVICES/SystemInfo/route.h b/iDevices/Tweak/IDEVICES/SystemInfo/route.h new file mode 100644 index 0000000..eff8b1d --- /dev/null +++ b/iDevices/Tweak/IDEVICES/SystemInfo/route.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2000-2016 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1980, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)route.h 8.3 (Berkeley) 4/19/94 + * $FreeBSD: src/sys/net/route.h,v 1.36.2.1 2000/08/16 06:14:23 jayanth Exp $ + */ + +#ifndef _NET_ROUTE_H_ +#define _NET_ROUTE_H_ +#include +#include +#include +#include + +/* + * These numbers are used by reliable protocols for determining + * retransmission behavior and are included in the routing structure. + */ +struct rt_metrics { + u_int32_t rmx_locks; /* Kernel leaves these values alone */ + u_int32_t rmx_mtu; /* MTU for this path */ + u_int32_t rmx_hopcount; /* max hops expected */ + int32_t rmx_expire; /* lifetime for route, e.g. redirect */ + u_int32_t rmx_recvpipe; /* inbound delay-bandwidth product */ + u_int32_t rmx_sendpipe; /* outbound delay-bandwidth product */ + u_int32_t rmx_ssthresh; /* outbound gateway buffer limit */ + u_int32_t rmx_rtt; /* estimated round trip time */ + u_int32_t rmx_rttvar; /* estimated rtt variance */ + u_int32_t rmx_pksent; /* packets sent using this route */ + u_int32_t rmx_filler[4]; /* will be used for T/TCP later */ +}; + +/* + * rmx_rtt and rmx_rttvar are stored as microseconds; + */ +#define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */ + + + +#define RTF_UP 0x1 /* route usable */ +#define RTF_GATEWAY 0x2 /* destination is a gateway */ +#define RTF_HOST 0x4 /* host entry (net otherwise) */ +#define RTF_REJECT 0x8 /* host or net unreachable */ +#define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */ +#define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ +#define RTF_DONE 0x40 /* message confirmed */ +#define RTF_DELCLONE 0x80 /* delete cloned route */ +#define RTF_CLONING 0x100 /* generate new routes on use */ +#define RTF_XRESOLVE 0x200 /* external daemon resolves name */ +#define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */ +#define RTF_STATIC 0x800 /* manually added */ +#define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */ +#define RTF_NOIFREF 0x2000 /* not eligible for RTF_IFREF */ +#define RTF_PROTO2 0x4000 /* protocol specific routing flag */ +#define RTF_PROTO1 0x8000 /* protocol specific routing flag */ + +#define RTF_PRCLONING 0x10000 /* protocol requires cloning */ +#define RTF_WASCLONED 0x20000 /* route generated through cloning */ +#define RTF_PROTO3 0x40000 /* protocol specific routing flag */ + /* 0x80000 unused */ +#define RTF_PINNED 0x100000 /* future use */ +#define RTF_LOCAL 0x200000 /* route represents a local address */ +#define RTF_BROADCAST 0x400000 /* route represents a bcast address */ +#define RTF_MULTICAST 0x800000 /* route represents a mcast address */ +#define RTF_IFSCOPE 0x1000000 /* has valid interface scope */ +#define RTF_CONDEMNED 0x2000000 /* defunct; no longer modifiable */ +#define RTF_IFREF 0x4000000 /* route holds a ref to interface */ +#define RTF_PROXY 0x8000000 /* proxying, no interface scope */ +#define RTF_ROUTER 0x10000000 /* host is a router */ + /* 0x20000000 and up unassigned */ + +#define RTF_BITS \ + "\020\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" \ + "\10DELCLONE\11CLONING\12XRESOLVE\13LLINFO\14STATIC\15BLACKHOLE" \ + "\16NOIFREF\17PROTO2\20PROTO1\21PRCLONING\22WASCLONED\23PROTO3" \ + "\25PINNED\26LOCAL\27BROADCAST\30MULTICAST\31IFSCOPE\32CONDEMNED" \ + "\33IFREF\34PROXY\35ROUTER" + +/* + * Routing statistics. + */ +struct rtstat { + short rts_badredirect; /* bogus redirect calls */ + short rts_dynamic; /* routes created by redirects */ + short rts_newgateway; /* routes modified by redirects */ + short rts_unreach; /* lookups which failed */ + short rts_wildcard; /* lookups satisfied by a wildcard */ +}; + +/* + * Structures for routing messages. + */ +struct rt_msghdr { + u_short rtm_msglen; /* to skip over non-understood messages */ + u_char rtm_version; /* future binary compatibility */ + u_char rtm_type; /* message type */ + u_short rtm_index; /* index for associated ifp */ + int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ + int rtm_addrs; /* bitmask identifying sockaddrs in msg */ + pid_t rtm_pid; /* identify sender */ + int rtm_seq; /* for sender to identify action */ + int rtm_errno; /* why failed */ + int rtm_use; /* from rtentry */ + u_int32_t rtm_inits; /* which metrics we are initializing */ + struct rt_metrics rtm_rmx; /* metrics themselves */ +}; + +struct rt_msghdr2 { + u_short rtm_msglen; /* to skip over non-understood messages */ + u_char rtm_version; /* future binary compatibility */ + u_char rtm_type; /* message type */ + u_short rtm_index; /* index for associated ifp */ + int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ + int rtm_addrs; /* bitmask identifying sockaddrs in msg */ + int32_t rtm_refcnt; /* reference count */ + int rtm_parentflags; /* flags of the parent route */ + int rtm_reserved; /* reserved field set to 0 */ + int rtm_use; /* from rtentry */ + u_int32_t rtm_inits; /* which metrics we are initializing */ + struct rt_metrics rtm_rmx; /* metrics themselves */ +}; + + +#define RTM_VERSION 5 /* Up the ante and ignore older versions */ + +/* + * Message types. + */ +#define RTM_ADD 0x1 /* Add Route */ +#define RTM_DELETE 0x2 /* Delete Route */ +#define RTM_CHANGE 0x3 /* Change Metrics or flags */ +#define RTM_GET 0x4 /* Report Metrics */ +#define RTM_LOSING 0x5 /* RTM_LOSING is no longer generated by xnu + and is deprecated */ +#define RTM_REDIRECT 0x6 /* Told to use different route */ +#define RTM_MISS 0x7 /* Lookup failed on this address */ +#define RTM_LOCK 0x8 /* fix specified metrics */ +#define RTM_OLDADD 0x9 /* caused by SIOCADDRT */ +#define RTM_OLDDEL 0xa /* caused by SIOCDELRT */ +#define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */ +#define RTM_NEWADDR 0xc /* address being added to iface */ +#define RTM_DELADDR 0xd /* address being removed from iface */ +#define RTM_IFINFO 0xe /* iface going up/down etc. */ +#define RTM_NEWMADDR 0xf /* mcast group membership being added to if */ +#define RTM_DELMADDR 0x10 /* mcast group membership being deleted */ +#define RTM_IFINFO2 0x12 /* */ +#define RTM_NEWMADDR2 0x13 /* */ +#define RTM_GET2 0x14 /* */ + +/* + * Bitmask values for rtm_inits and rmx_locks. + */ +#define RTV_MTU 0x1 /* init or lock _mtu */ +#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */ +#define RTV_EXPIRE 0x4 /* init or lock _expire */ +#define RTV_RPIPE 0x8 /* init or lock _recvpipe */ +#define RTV_SPIPE 0x10 /* init or lock _sendpipe */ +#define RTV_SSTHRESH 0x20 /* init or lock _ssthresh */ +#define RTV_RTT 0x40 /* init or lock _rtt */ +#define RTV_RTTVAR 0x80 /* init or lock _rttvar */ + +/* + * Bitmask values for rtm_addrs. + */ +#define RTA_DST 0x1 /* destination sockaddr present */ +#define RTA_GATEWAY 0x2 /* gateway sockaddr present */ +#define RTA_NETMASK 0x4 /* netmask sockaddr present */ +#define RTA_GENMASK 0x8 /* cloning mask sockaddr present */ +#define RTA_IFP 0x10 /* interface name sockaddr present */ +#define RTA_IFA 0x20 /* interface addr sockaddr present */ +#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */ +#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */ + +/* + * Index offsets for sockaddr array for alternate internal encoding. + */ +#define RTAX_DST 0 /* destination sockaddr present */ +#define RTAX_GATEWAY 1 /* gateway sockaddr present */ +#define RTAX_NETMASK 2 /* netmask sockaddr present */ +#define RTAX_GENMASK 3 /* cloning mask sockaddr present */ +#define RTAX_IFP 4 /* interface name sockaddr present */ +#define RTAX_IFA 5 /* interface addr sockaddr present */ +#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */ +#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */ +#define RTAX_MAX 8 /* size of array to allocate */ + +struct rt_addrinfo { + int rti_addrs; + struct sockaddr *rti_info[RTAX_MAX]; +}; + + +#endif /* _NET_ROUTE_H_ */ diff --git a/iDevices/Tweak/IDEVICES/Tweaks/TweaksViewController.h b/iDevices/Tweak/IDEVICES/Tweaks/TweaksViewController.h new file mode 100644 index 0000000..b17a913 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Tweaks/TweaksViewController.h @@ -0,0 +1,22 @@ +#import +#import "Colour-Scheme.h" +#import "DataManager.h" +#import "CDHeaderView.h" +#import "TweakCell.h" + +@interface TweakModel : NSObject +-(id)initWithTitle:(NSString *)title subtitle:(NSString *)subtitle; +@property (nonatomic, retain) NSString *title; +@property (nonatomic, retain) NSString *subtitle; +@end + +@interface TweaksViewController : UIViewController +@property (nonatomic, retain) CDHeaderView *headerView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property(nonatomic, retain) NSMutableDictionary *packageInfo; +@property(nonatomic, retain) NSArray *tweakArray; +@property (nonatomic, retain) UIView *containerView; +@property (nonatomic, retain) UIImageView *headerIcon; +@property (nonatomic, retain) UILabel *headerTitle; +@end + diff --git a/iDevices/Tweak/IDEVICES/Tweaks/TweaksViewController.m b/iDevices/Tweak/IDEVICES/Tweaks/TweaksViewController.m new file mode 100644 index 0000000..f69aac7 --- /dev/null +++ b/iDevices/Tweak/IDEVICES/Tweaks/TweaksViewController.m @@ -0,0 +1,218 @@ +#import "TweaksViewController.h" + +@implementation TweakModel +-(id)initWithTitle:(NSString *)title subtitle:(NSString *)subtitle { + self = [super init]; + if(self) { + self.title = title; + self.subtitle = subtitle; + } + return self; +} +@end + + +@implementation TweaksViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + loadPrefs(); + + self.view.backgroundColor = [UIColor backgroundColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [UIColor accentColour]; + self.view.tintColor = [UIColor accentColour]; + + [self getTweakData]; + [self layoutHeaderView]; + [self layoutCollectionView]; +} + + +-(void)getTweakData { + + if(!self.packageInfo) { + self.packageInfo = [[NSMutableDictionary alloc] init]; + + NSString *dpkgStatus = [NSString stringWithContentsOfFile:@"Library/dpkg/status" encoding:NSUTF8StringEncoding error:nil]; + NSArray *packages = [dpkgStatus componentsSeparatedByString:@"\n\n"]; + for(NSString *p in packages) { + [p enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) { + if([line hasPrefix:@"Section: "]) { + *stop = YES; + + NSString *section = [line stringByReplacingOccurrencesOfString:@"Section: " withString:@""]; + section = [section stringByReplacingOccurrencesOfString:@"_" withString:@" "]; + if(self.packageInfo[section]) { + self.packageInfo[section] = @([self.packageInfo[section] intValue] + 1); + } else { + [self.packageInfo setObject:@1 forKey:section]; + } + } + }]; + } + } + + + + self.tweakArray = [[NSArray alloc] init]; + + NSMutableArray *packageBreakdownBySection = [[NSMutableArray alloc] init]; + + for(NSString *type in self.packageInfo) { + + NSString *packageCount = [NSString stringWithFormat:@"%i", [self.packageInfo[type] intValue]]; + [packageBreakdownBySection addObject:[[TweakModel alloc] initWithTitle:type subtitle:packageCount]]; + + NSArray *sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES]]; + NSArray *sortedArray = [packageBreakdownBySection sortedArrayUsingDescriptors:sortDescriptors]; + + self.tweakArray = sortedArray; + } + + +} + + +-(void)layoutHeaderView { + + self.containerView = [[UIView alloc] init]; + self.containerView.layer.cornerRadius = 25; + self.containerView.layer.cornerCurve = kCACornerCurveContinuous; + self.containerView.layer.maskedCorners = 12; + self.containerView.clipsToBounds = YES; + [self.view addSubview:self.containerView]; + + [self.containerView size:CGSizeMake(self.view.frame.size.width, 200)]; + [self.containerView x:self.view.centerXAnchor]; + [self.containerView top:self.view.topAnchor padding:0]; + + + UIImageView *wallpaper = [[UIImageView alloc] init]; + if (toggleCustomCoverImage) { + wallpaper.image = [UIImage imageWithData:customCoverImage]; + } else { + wallpaper.image = [UIImage imageWithContentsOfFile:@"/Library/Application Support/iDevices.bundle/Assets/Default/cover-image.png"]; + } + wallpaper.contentMode = UIViewContentModeScaleAspectFill; + [self.containerView addSubview:wallpaper]; + + [wallpaper fill]; + + + self.headerView = [[CDHeaderView alloc] initWithTitle:@"" accent:[UIColor accentColour] leftIcon:@"chevron.left" leftAction:@selector(pushBackVC)]; + self.headerView.leftButton.backgroundColor = [UIColor.navBarButtonColour colorWithAlphaComponent:0.5]; + [self.containerView addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.containerView.centerXAnchor]; + [self.headerView top:self.containerView.topAnchor padding:0]; + + + self.headerIcon = [[UIImageView alloc] init]; + self.headerIcon.contentMode = UIViewContentModeScaleAspectFit; + self.headerIcon.image = [UIImage systemImageNamed:@"hammer.fill"]; + self.headerIcon.tintColor = UIColor.coverIconColour; + [self.containerView addSubview:self.headerIcon]; + + [self.headerIcon size:CGSizeMake(75, 75)]; + [self.headerIcon x:self.containerView.centerXAnchor]; + [self.headerIcon top:self.headerView.bottomAnchor padding:-10]; + + + self.headerTitle = [[UILabel alloc] init]; + self.headerTitle.textAlignment = NSTextAlignmentCenter; + self.headerTitle.font = [UIFont systemFontOfSize:18 weight:UIFontWeightBold]; + self.headerTitle.textColor = UIColor.coverTitleColour; + self.headerTitle.text = @"Tweaks"; + [self.containerView addSubview:self.headerTitle]; + + [self.headerTitle x:self.containerView.centerXAnchor]; + [self.headerTitle top:self.headerIcon.bottomAnchor padding:10]; + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[TweakCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.view addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + + [self.collectionView top:self.containerView.bottomAnchor padding:5]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + [self.collectionView bottom:self.view.bottomAnchor padding:-5]; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.tweakArray.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + TweakCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + + TweakModel *data = self.tweakArray[indexPath.row]; + + cell.titleLabel.text = data.title; + cell.subtitleLabel.text = data.subtitle; + cell.iconImage.image = [UIImage systemImageNamed:@"hammer.fill"]; + cell.iconView.backgroundColor = [UIColor.accentColour colorWithAlphaComponent:0.4]; + cell.iconImage.tintColor = UIColor.accentColour; + + return cell; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + CGFloat width = self.view.frame.size.width-40; + return CGSizeMake(width, 65); +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { + return 20.0; +} + + +- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { + return 10.0; +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +-(void)pushBackVC { + [self.navigationController popToRootViewControllerAnimated:YES]; +} + + +@end diff --git a/iDevices/Tweak/Icloud.xm b/iDevices/Tweak/Icloud.xm new file mode 100644 index 0000000..0274fa5 --- /dev/null +++ b/iDevices/Tweak/Icloud.xm @@ -0,0 +1,135 @@ +#import + +NSString *plistStorage = @"/tmp/EMPStorageUsageInfo.plist"; +NSString *plistDevices = @"/tmp/EMPGetDevices.plist"; + + +@interface ACAccount +@end + +@interface AAURLSession : NSObject ++(id)sharedSigningSession; ++(id)sharedSession; +-(void)URLSession:(id)arg1 dataTask:(id)arg2 didReceiveData:(id)arg3; +-(void)URLSession:(id)arg1 didBecomeInvalidWithError:(id)arg2; +@end + +@interface AAQuotaInfoRequest ++(Class)responseClass; +-(id)urlString; +-(id)urlRequest; +-(id)account; +-(id)initWithAccount:(id)arg1 ; +-(id)initDetailedRequestWithAccount:(id)arg1 ; +@end + +@interface AAResponse +@property (nonatomic,readonly) long long statusCode; +@property (nonatomic,readonly) NSData * data; +@end + +@interface AARequester : NSObject{ + AAResponse* _response; +} +-(void)start; +-(void)_callHandler; +-(id)initWithRequest:(id)arg1 handler:(id)arg2 ; +@end + +@interface PLAccountStore : NSObject ++(id)pl_sharedAccountStore; +-(ACAccount *)cachedPrimaryAppleAccount; +@end + + +@interface MBStateInfo : NSObject +@property (assign,nonatomic) int state; +@property (assign,nonatomic) BOOL isBackground; +@property (assign,nonatomic) BOOL isCloud; +@property (assign,nonatomic) float progress; +@property (assign,nonatomic) unsigned long long estimatedTimeRemaining; +@property (nonatomic,retain) NSDate * date; +@property (nonatomic,retain) NSError * error; +@property (nonatomic,retain) NSMutableArray * errors; +@end + + +static ACAccount *acc; + + +%hook AARequester + +-(void)connection:(NSURLConnection*)arg1 didReceiveData:(id)arg2{ + %orig; + NSLog(@"DDDDDDD isKindOfClass:-%d, didReceiveData:-%@", [arg1 isKindOfClass:[NSURLConnection class]], arg1); + + if([arg1 isKindOfClass:[NSURLConnection class]]){ + NSMutableURLRequest *currentRequest = (NSMutableURLRequest*)arg1.currentRequest; + NSString *last = [currentRequest.URL lastPathComponent]; + NSLog(@"DDDDDDD last:-%@", last); + + if([last isEqual:@"storageUsageInfo"]) + [arg2 writeToFile:plistStorage atomically:YES]; + if([last isEqual:@"getDevices"]) + [arg2 writeToFile:plistDevices atomically:YES]; + } +} +%end + + +//This will load listDevice and iCloudStorage when user will open Settings app +%hook PSUIPrefsListController +-(void)viewWillAppear:(BOOL)arg1{ + + // [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.TitanD3v.Empire/refreshiCloudStorage" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { + // dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + // acc = [[%c(PLAccountStore) pl_sharedAccountStore] cachedPrimaryAppleAccount]; + // AAQuotaInfoRequest *aqReq = [[%c(AAQuotaInfoRequest) alloc] initDetailedRequestWithAccount:acc]; + // AARequester *aaReq = [[%c(AARequester) alloc] initWithRequest:aqReq handler:^{}]; + // [aaReq start]; + // }); + // }]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + acc = [[%c(PLAccountStore) pl_sharedAccountStore] cachedPrimaryAppleAccount]; + AAQuotaInfoRequest *aqReq = [[%c(AAQuotaInfoRequest) alloc] initDetailedRequestWithAccount:acc]; + AARequester *aaReq = [[%c(AARequester) alloc] initWithRequest:aqReq handler:^{}]; + [aaReq start]; + + AADeviceListRequest *myPic = [[%c(AADeviceListRequest) alloc] initWithAccount:acc]; + aaReq = [[%c(AARequester) alloc] initWithRequest:myPic handler:^{}]; + + [aaReq start]; + + }); + + %orig; +} +%end + + +//Save last scuessful backup date to plist +%hook MBStateInfo +-(int)state { + int state = %orig; + + NSLog(@"DDDDDDD state:-%ld, lastBackUpDate:-%@", (long)state, [self date]); + + if(state == 4){ + //[[TDTweakManager sharedInstance] setObject:[self date] forKey:@"lastBackUpDate" ID:@"com.TitanD3v.iDevicesPrefs"]; + NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"d MMM yy HH:mm"]; + [[TDTweakManager sharedInstance] setObject:[dateFormatter stringFromDate:[NSDate date]] forKey:@"lastiCloudBackUpDate" ID:@"com.TitanD3v.iDevicesPrefs"]; + } + + return state; +} +%end + +%ctor{ + NSBundle *appleAccountBundle = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/AppleAccount.framework/"]; + [appleAccountBundle load]; + + NSBundle *AccountSettingsBundle = [NSBundle bundleWithPath:@"/System/Library/PreferenceBundles/AccountSettings/AppleAccountSettings.bundle/"]; + [AccountSettingsBundle load]; +} diff --git a/iDevices/Tweak/Info.xm b/iDevices/Tweak/Info.xm new file mode 100644 index 0000000..be98603 --- /dev/null +++ b/iDevices/Tweak/Info.xm @@ -0,0 +1,102 @@ +#import + +static NSString *BID = @"com.TitanD3v.iDevicesPrefs"; + + +@interface SBApplication: NSObject +- (NSString*)bundleIdentifier; +@end + + +@interface SpringBoard: UIApplication +- (id)_accessibilityFrontMostApplication; +- (void)frontDisplayDidChange: (id)arg1; +-(void)launchTestView; +@end + + +@interface SBLockScreenManager : NSObject ++ (id)sharedInstance; +- (BOOL)isLockScreenVisible; +- (BOOL)_isPasscodeVisible; +- (BOOL)isUILocked; +- (BOOL)unlockUIFromSource:(int)arg1 withOptions:(id)arg2; +- (void)attemptUnlockWithPasscode:(id)arg1 finishUIUnlock:(BOOL)arg2 completion:(id)arg3; +@end + + +@interface SBBacklightController : NSObject +@property (nonatomic,readonly) BOOL screenIsOn; +@property (nonatomic,readonly) BOOL screenIsDim; +@end + + + + +%hook SpringBoard + +- (void)frontDisplayDidChange: (id)arg1 { + + %orig; + + NSString *currentApp = [(SBApplication*)[self _accessibilityFrontMostApplication] bundleIdentifier]; + + if (currentApp != nil) { + + NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"d MMM yy HH:mm"]; + [[TDTweakManager sharedInstance] setObject:[dateFormatter stringFromDate:[NSDate date]] forKey:currentApp ID:BID]; + + [[TDTweakManager sharedInstance] setObject:currentApp forKey:@"lastOpenedApp" ID:BID]; + + } + +} + + +- (void)applicationDidFinishLaunching: (id)application { + %orig; + + NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"d MMM yy HH:mm"]; + [[TDTweakManager sharedInstance] setObject:[dateFormatter stringFromDate:[NSDate date]] forKey:@"lastTimeRespring" ID:BID]; + +} + +%end + + +%hook SBBacklightController +-(void)_animateBacklightToFactor:(float)arg1 duration:(double)arg2 source:(long long)arg3 silently:(BOOL)arg4 completion:(id)arg5 { + if((arg1==0 && [self screenIsOn])) { + + if (![[%c(SBLockScreenManager) sharedInstance] isLockScreenVisible]) { + + NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"d MMM yy HH:mm"]; + + [[TDTweakManager sharedInstance] setObject:[dateFormatter stringFromDate:[NSDate date]] forKey:@"lastTimeLocked" ID:BID]; + + } + + } + %orig(arg1, arg2, arg3, arg4, arg5); +} + + +- (void)turnOnScreenFullyWithBacklightSource:(long long)arg1 { + + %orig; + + if ([[%c(SBLockScreenManager) sharedInstance] isLockScreenVisible]) { + + NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"d MMM yy HH:mm"]; + + [[TDTweakManager sharedInstance] setObject:[dateFormatter stringFromDate:[NSDate date]] forKey:@"lastTimeUnlocked" ID:BID]; + + } + +} + +%end diff --git a/iDevices/Tweak/Makefile b/iDevices/Tweak/Makefile new file mode 100644 index 0000000..830d10c --- /dev/null +++ b/iDevices/Tweak/Makefile @@ -0,0 +1,23 @@ +TWEAK_NAME = iDevices + +SOURCES = $(shell find . -name '*.m') +SOURCES += $(shell find . -name '*.x') +SOURCES += $(shell find . -name '*.xm') + +dtoim = $(foreach d,$(1),-I$(d)) +_IMPORTS = $(shell /bin/ls -d ./*/) +_IMPORTS = $(shell /bin/ls -d ./IDEVICES/) +_IMPORTS = $(shell /bin/ls -d ./IDEVICES/*/) +_IMPORTS += $(shell /bin/ls -d ./IDEVICES/*/*/) +_IMPORTS += $(shell /bin/ls -d ./IDEVICES/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./IDEVICES/*/*/*/*/) +_IMPORTS += $(shell /bin/ls -d ./) +IMPORTS = -I$./IDEVICES $(call dtoim, $(_IMPORTS)) + +$(TWEAK_NAME)_FILES = $(SOURCES) +$(TWEAK_NAME)_CFLAGS = -fobjc-arc -Wno-deprecated-declarations -Wno-unused-variable -Wno-error -Wno-unused-function -Wall $(IMPORTS) +$(TWEAK_NAME)_LIBRARIES = TitanD3vUniversal MobileGestalt +$(TWEAK_NAME)_PRIVATE_FRAMEWORKS = OnBoardingKit AppSupport + +include $(THEOS)/makefiles/common.mk +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/iDevices/Tweak/Profile.xm b/iDevices/Tweak/Profile.xm new file mode 100644 index 0000000..c5e3f36 --- /dev/null +++ b/iDevices/Tweak/Profile.xm @@ -0,0 +1,57 @@ +#import + +@interface AAAccount : NSObject +@property (nonatomic,readonly) NSString * lastName; +@property (nonatomic,readonly) NSString * firstName; +@property (nonatomic,readonly) NSString * primaryEmail; +@property (nonatomic,readonly) BOOL primaryEmailVerified; +@end + +@interface AAAccountManager : NSObject ++(id)sharedManager; +-(id)primaryAccount; +@end + +static NSString *fullName = @"Username"; +static UIImage *appleIdAvatar = nil; + + +%hook PSUIPrefsListController + +-(void)viewDidLoad { + %orig; + + static dispatch_once_t dataToken; + + dispatch_once(&dataToken, ^{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + appleIdAvatar = MSHookIvar(self, "_appleAccountSpecifierCachedIcon"); + NSData *imageData; + if (appleIdAvatar != nil) { + imageData = UIImagePNGRepresentation(appleIdAvatar); + } else { + UIImage *defaultImage = [UIImage imageWithContentsOfFile:@"/Library/Application Support/iDevices.bundle/Assets/Default/default-avatar.png"]; + imageData = UIImagePNGRepresentation(defaultImage); + } + [[TDTweakManager sharedInstance] setObject:imageData forKey:@"icloudAvatar" ID:@"com.TitanD3v.iDevicesPrefs"]; + + + AAAccount *account = [[%c(AAAccountManager) sharedManager] primaryAccount]; + if (account.firstName != nil) { + fullName = [NSString stringWithFormat:@"%@ %@", account.firstName, account.lastName]; + } else { + fullName = @"Username"; + } + [[TDTweakManager sharedInstance] setObject:fullName forKey:@"icloudName" ID:@"com.TitanD3v.iDevicesPrefs"]; + }); + }); + +} +%end + + +%ctor{ + NSBundle *appleAccountBundle = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/AppleAccount.framework/"]; + [appleAccountBundle load]; +} diff --git a/iDevices/Tweak/iDevices.plist b/iDevices/Tweak/iDevices.plist new file mode 100644 index 0000000..33535f1 --- /dev/null +++ b/iDevices/Tweak/iDevices.plist @@ -0,0 +1 @@ +{ Filter = { Bundles = ( "com.apple.springboard", "com.apple.Preferences" ); }; } diff --git a/iDevices/Tweak/iDevices.xm b/iDevices/Tweak/iDevices.xm new file mode 100644 index 0000000..8cbf9aa --- /dev/null +++ b/iDevices/Tweak/iDevices.xm @@ -0,0 +1,241 @@ +#import +#import "HomeViewController.h" +#import "HomeNavigationViewController.h" + +static BOOL toggleiDevices; +static BOOL toggleStatusbarLongPressGesture; +static BOOL toggleStatusbarDoubleTapGesture; +static BOOL toggleStatusbarTripleTapGesture; +static BOOL toggleDockGesture; +static BOOL toggleVolumeUpGesture; +static BOOL toggleVolumeDownGesture; +static BOOL toggleShakeGesture; + + +@interface _UIStatusBar : UIView +@end + +@interface SpringBoard : NSObject +@property (nonatomic, assign) BOOL didPressed; +@end + +@interface SBDockView : UIView +@end + + +%group IdeviceVC +%hook SpringBoard + +- (void)applicationDidFinishLaunching: (id)application { + %orig; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivePresentNotification:) name:@"iDevicesPresentVCNotification" object:nil]; +} + + +%new +- (void)receivePresentNotification:(NSNotification *) notification { + + if ([[notification name] isEqualToString:@"iDevicesPresentVCNotification"]) { + UIViewController *controller = [[UIApplication sharedApplication] keyWindow].rootViewController; + HomeViewController *vc = [[HomeViewController alloc] init]; + HomeNavigationViewController *nvc = [[HomeNavigationViewController alloc] initWithRootViewController:vc]; + [controller presentViewController:nvc animated:YES completion:nil]; + } +} + +%end +%end + + +%group IdeviceStatusbar +%hook _UIStatusBar + +-(void)willMoveToSuperview:(UIView *)newSuperview { + %orig(newSuperview); + + if (toggleStatusbarLongPressGesture) { + [self addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(presentVC)]]; + } + + if (toggleStatusbarDoubleTapGesture) { + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(presentVC)]; + tapGesture.numberOfTapsRequired = 2; + [self addGestureRecognizer:tapGesture]; + } + + if (toggleStatusbarTripleTapGesture) { + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(presentVC)]; + tapGesture.numberOfTapsRequired = 2; + [self addGestureRecognizer:tapGesture]; + } + +} + + +%new +-(void)presentVC { + [[NSNotificationCenter defaultCenter] postNotificationName:@"iDevicesPresentVCNotification" object:self]; +} + +%end +%end + + +%group IdeviceShake +%hook UIWindow + +- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { + %orig; + if(event.type == UIEventSubtypeMotionShake && self == [[UIApplication sharedApplication] keyWindow]) { + [[NSNotificationCenter defaultCenter] postNotificationName:@"iDevicesPresentVCNotification" object:self]; + } +} + +%end +%end + + +%group IdeviceDock +%hook SBDockView +-(void)layoutSubviews { + %orig; + + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(presentVC)]; + tapGesture.numberOfTapsRequired = 2; + [self addGestureRecognizer:tapGesture]; + +} + +%new +-(void)presentVC { + [[NSNotificationCenter defaultCenter] postNotificationName:@"iDevicesPresentVCNotification" object:self]; +} + +%end +%end + + +%group IdeviceVolumeUp +%hook SpringBoard +%property (nonatomic, assign) BOOL didPressed; + +-(BOOL)_handlePhysicalButtonEvent:(UIPressesEvent *)arg1 { + + UIPress *touch = [arg1.allPresses anyObject]; + + if (touch.type == 102) { // 102 up, 103 down + + if (touch.force == 1) { + + self.didPressed = YES; + [self performSelector:@selector(monitorGesturePressed) withObject:nil afterDelay:0.25f]; + + } else { + + self.didPressed = NO; + } + } + + return %orig; +} + +%new +-(void)monitorGesturePressed { + + if (self.didPressed) + [self performSelector:@selector(presentVC)]; +} + +%new +-(void)presentVC { + [[NSNotificationCenter defaultCenter] postNotificationName:@"iDevicesPresentVCNotification" object:self]; +} + +%end +%end + + +%group IdeviceVolumeDown +%hook SpringBoard +%property (nonatomic, assign) BOOL didPressed; + +-(BOOL)_handlePhysicalButtonEvent:(UIPressesEvent *)arg1 { + + UIPress *touch = [arg1.allPresses anyObject]; + + if (touch.type == 103) { // 102 up, 103 down + + if (touch.force == 1) { + + self.didPressed = YES; + [self performSelector:@selector(monitorGesturePressed) withObject:nil afterDelay:0.25f]; + + } else { + + self.didPressed = NO; + } + } + + return %orig; +} + +%new +-(void)monitorGesturePressed { + + if (self.didPressed) + [self performSelector:@selector(presentVC)]; +} + +%new +-(void)presentVC { + [[NSNotificationCenter defaultCenter] postNotificationName:@"iDevicesPresentVCNotification" object:self]; +} + +%end +%end + + +void SettingsChanged() { + + toggleiDevices = [[TDTweakManager sharedInstance] boolForKey:@"toggleiDevices" defaultValue:NO ID:@"com.TitanD3v.iDevicesPrefs"]; + toggleStatusbarLongPressGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleStatusbarLongPressGesture" defaultValue:YES ID:@"com.TitanD3v.iDevicesPrefs"]; + toggleStatusbarDoubleTapGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleStatusbarDoubleTapGesture" defaultValue:NO ID:@"com.TitanD3v.iDevicesPrefs"]; + toggleStatusbarTripleTapGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleStatusbarTripleTapGesture" defaultValue:NO ID:@"com.TitanD3v.iDevicesPrefs"]; + toggleDockGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleDockGesture" defaultValue:NO ID:@"com.TitanD3v.iDevicesPrefs"]; + toggleVolumeUpGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleVolumeUpGesture" defaultValue:NO ID:@"com.TitanD3v.iDevicesPrefs"]; + toggleVolumeDownGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleVolumeDownGesture" defaultValue:NO ID:@"com.TitanD3v.iDevicesPrefs"]; + toggleShakeGesture = [[TDTweakManager sharedInstance] boolForKey:@"toggleShakeGesture" defaultValue:NO ID:@"com.TitanD3v.iDevicesPrefs"]; + +} + +%ctor { + + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)SettingsChanged, CFSTR("com.TitanD3v.iDevicesPrefs.settingschanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); + SettingsChanged(); + + if (toggleiDevices) { + %init(IdeviceVC); + + if (toggleStatusbarLongPressGesture || toggleStatusbarDoubleTapGesture || toggleStatusbarTripleTapGesture) { + %init(IdeviceStatusbar); + } + + if (toggleDockGesture) { + %init(IdeviceDock); + } + + if (toggleShakeGesture) { + %init(IdeviceShake); + } + + if (toggleVolumeDownGesture) { + %init(IdeviceVolumeDown); + } + + if (toggleVolumeUpGesture) { + %init(IdeviceVolumeUp); + } + + } +} diff --git a/iDevices/control b/iDevices/control new file mode 100644 index 0000000..02f892e --- /dev/null +++ b/iDevices/control @@ -0,0 +1,11 @@ +Package: com.titand3v.idevices +Name: iDevices +Architecture: iphoneos-arm +Depends: mobilesubstrate, applist, com.titand3v.libtitand3vuniversal (>= 1.9) +Version: 1.0 +Section: Tweaks +Description: TitanD3v Tweaks +Maintainer: TitanD3v +Author: TitanD3v +Depiction: https://titand3v.github.io/depictions/idevices/index.html +Icon: https://titand3v.github.io/depictions/idevices/assets/icon.png diff --git a/iDevices/layout/.DS_Store b/iDevices/layout/.DS_Store new file mode 100644 index 0000000..f9287ba Binary files /dev/null and b/iDevices/layout/.DS_Store differ diff --git a/iDevices/layout/DEBIAN/postinst b/iDevices/layout/DEBIAN/postinst new file mode 100755 index 0000000..d54a73c --- /dev/null +++ b/iDevices/layout/DEBIAN/postinst @@ -0,0 +1,8 @@ +echo "" +echo "" +echo "Thank you for installing iDevices 😉" +echo "" +echo "Coded with 🤍" +echo "TitanD3v" +echo "" +echo "" diff --git a/iDevices/layout/Library/Application Support/iDevices.bundle/Assets/Default/cover-image.png b/iDevices/layout/Library/Application Support/iDevices.bundle/Assets/Default/cover-image.png new file mode 100644 index 0000000..8935054 Binary files /dev/null and b/iDevices/layout/Library/Application Support/iDevices.bundle/Assets/Default/cover-image.png differ diff --git a/iDevices/layout/Library/Application Support/iDevices.bundle/Assets/Default/default-avatar.png b/iDevices/layout/Library/Application Support/iDevices.bundle/Assets/Default/default-avatar.png new file mode 100644 index 0000000..8cc3aa9 Binary files /dev/null and b/iDevices/layout/Library/Application Support/iDevices.bundle/Assets/Default/default-avatar.png differ diff --git a/libTitanD3vUniversal/.DS_Store b/libTitanD3vUniversal/.DS_Store new file mode 100644 index 0000000..acf466d Binary files /dev/null and b/libTitanD3vUniversal/.DS_Store differ diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertAction+Private.h b/libTitanD3vUniversal/Alert/Private/TDAlertAction+Private.h new file mode 100644 index 0000000..9ed17bd --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertAction+Private.h @@ -0,0 +1,5 @@ +#import "TDAlertAction.h" + +@interface TDAlertAction () +@property (weak, nonatomic, nullable) UIButton *actionButton; +@end diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertTextView.h b/libTitanD3vUniversal/Alert/Private/TDAlertTextView.h new file mode 100644 index 0000000..3f2d899 --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertTextView.h @@ -0,0 +1,5 @@ +#import + +@interface TDAlertTextView : UITextView +@end + diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertTextView.m b/libTitanD3vUniversal/Alert/Private/TDAlertTextView.m new file mode 100644 index 0000000..f5a6e9e --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertTextView.m @@ -0,0 +1,43 @@ +#import "TDAlertTextView.h" + +@interface TDAlertTextView () +@property (strong, nonatomic) NSLayoutConstraint *heightConstraint; +@end + +@implementation TDAlertTextView + +- (instancetype)initWithFrame:(CGRect)frame textContainer:(NSTextContainer *)textContainer { + self = [super initWithFrame:frame textContainer:textContainer]; + + if (self) { + self.heightConstraint = [self.heightAnchor constraintEqualToConstant:0.0f]; + self.heightConstraint.priority = UILayoutPriorityDefaultHigh; + self.heightConstraint.active = YES; + + self.textContainerInset = UIEdgeInsetsZero; + } + + return self; +} + +- (void)setText:(NSString *)text { + [super setText:text]; + + [self updateHeightConstraint]; +} + +- (void)updateHeightConstraint { + self.heightConstraint.constant = [self sizeThatFits:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)].height; +} + +- (void)setBounds:(CGRect)bounds { + CGRect oldBounds = self.bounds; + + [super setBounds:bounds]; + + if (!CGSizeEqualToSize(oldBounds.size, bounds.size)) { + [self updateHeightConstraint]; + } +} + +@end diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertView.h b/libTitanD3vUniversal/Alert/Private/TDAlertView.h new file mode 100644 index 0000000..82cb9a4 --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertView.h @@ -0,0 +1,18 @@ +#import +#import "TDAlertViewControllerConfiguration.h" + +@interface TDAlertView : UIView +@property (nonatomic, readonly) UILabel *titleLabel; +@property (nonatomic, readonly) UITextView *messageTextView; +@property (nonatomic) UIView *contentView; +@property (nonatomic) CGFloat maximumWidth; +@property (nonatomic, readonly) NSLayoutConstraint *backgroundViewVerticalCenteringConstraint; +@property (nonatomic) NSArray *actionButtons; +@property (nonatomic) NSArray *textFields; + +- (instancetype)initWithConfiguration:(TDAlertViewControllerConfiguration *)configuration; ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; +- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE; +@end diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertView.m b/libTitanD3vUniversal/Alert/Private/TDAlertView.m new file mode 100644 index 0000000..e3c48c9 --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertView.m @@ -0,0 +1,277 @@ +#import "TDAlertView.h" +#import "TDAlertTextView.h" +#import "TDAlertAction.h" +#import "TDAlertViewController.h" +#import "UIView+Additions.h" + +@interface TDAlertView () + +@property (nonatomic) TDAlertViewControllerConfiguration *configuration; +@property (nonatomic) NSLayoutConstraint *alertBackgroundWidthConstraint; +@property (nonatomic, readonly) UIView *alertBackgroundView; +@property (nonatomic) UIView *contentViewContainerView; +@property (nonatomic) UIView *textFieldContainerView; +@property (nonatomic) UIView *actionButtonContainerView; +@property (nonatomic) UIStackView *actionButtonStackView; + +@end + +@implementation TDAlertView + +- (instancetype)initWithConfiguration:(TDAlertViewControllerConfiguration *)configuration { + self = [super init]; + + if (self) { + self.maximumWidth = 480.0f; + + _configuration = configuration; + + _alertBackgroundView = [[UIView alloc] initWithFrame:CGRectZero]; + self.alertBackgroundView.clipsToBounds = YES; + self.alertBackgroundView.layer.cornerRadius = configuration.alertViewCornerRadius; + self.alertBackgroundView.backgroundColor = configuration.alertViewBackgroundColor; + self.alertBackgroundView.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:_alertBackgroundView]; + + _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + [self.titleLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; + self.titleLabel.numberOfLines = 2; + self.titleLabel.font = configuration.titleFont; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = configuration.titleTextColor; + self.titleLabel.text = NSLocalizedString(@"Title Label", nil); + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.alertBackgroundView addSubview:self.titleLabel]; + + _messageTextView = [[TDAlertTextView alloc] initWithFrame:CGRectZero]; + self.messageTextView.backgroundColor = [UIColor clearColor]; + [self.messageTextView setContentHuggingPriority:0 forAxis:UILayoutConstraintAxisVertical]; + [self.messageTextView setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical]; + self.messageTextView.editable = NO; + self.messageTextView.textAlignment = NSTextAlignmentCenter; + self.messageTextView.textColor = configuration.messageTextColor; + self.messageTextView.font = configuration.messageFont; + self.messageTextView.text = NSLocalizedString(@"Message Text View", nil); + self.messageTextView.translatesAutoresizingMaskIntoConstraints = NO; + [self.alertBackgroundView addSubview:self.messageTextView]; + + _contentViewContainerView = [[UIView alloc] initWithFrame:CGRectZero]; + self.contentViewContainerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.alertBackgroundView addSubview:self.contentViewContainerView]; + + _textFieldContainerView = [[UIView alloc] initWithFrame:CGRectZero]; + [self.textFieldContainerView setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; + self.textFieldContainerView .translatesAutoresizingMaskIntoConstraints = NO; + [self.alertBackgroundView addSubview:self.textFieldContainerView]; + + _actionButtonContainerView = [[UIView alloc] initWithFrame:CGRectZero]; + [self.actionButtonContainerView setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; + self.actionButtonContainerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.alertBackgroundView addSubview:self.actionButtonContainerView]; + + _actionButtonStackView = [[UIStackView alloc] init]; + [self.actionButtonStackView setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; + [self.actionButtonContainerView addSubview:self.actionButtonStackView]; + [self.actionButtonStackView ny_pinEdgesToSuperviewEdges]; + + if (self.configuration.showsSeparators) { + UIView *separatorView = [[UIView alloc] init]; + separatorView.backgroundColor = self.configuration.separatorColor; + separatorView.translatesAutoresizingMaskIntoConstraints = NO; + [self.alertBackgroundView addSubview:separatorView]; + [separatorView.heightAnchor constraintEqualToConstant:1.0f / [UIScreen mainScreen].scale].active = YES; + [separatorView.leadingAnchor constraintEqualToAnchor:separatorView.superview.leadingAnchor].active = YES; + [separatorView.trailingAnchor constraintEqualToAnchor:separatorView.superview.trailingAnchor].active = YES; + [separatorView.bottomAnchor constraintEqualToAnchor:self.actionButtonStackView.topAnchor].active = YES; + } + + [self addConstraint:[NSLayoutConstraint constraintWithItem:self.alertBackgroundView + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeCenterX + multiplier:1.0f + constant:0.0f]]; + + CGFloat alertBackgroundViewWidth = MIN(CGRectGetWidth([UIApplication sharedApplication].keyWindow.bounds), + CGRectGetHeight([UIApplication sharedApplication].keyWindow.bounds)) * 0.8f; + + if (alertBackgroundViewWidth > self.maximumWidth) { + alertBackgroundViewWidth = self.maximumWidth; + } + + _alertBackgroundWidthConstraint = [NSLayoutConstraint constraintWithItem:self.alertBackgroundView + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:0.0f + constant:alertBackgroundViewWidth]; + + [self addConstraint:self.alertBackgroundWidthConstraint]; + + _backgroundViewVerticalCenteringConstraint = [NSLayoutConstraint constraintWithItem:self.alertBackgroundView + attribute:NSLayoutAttributeCenterY + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeCenterY + multiplier:1.0f + constant:0.0f]; + + [self addConstraint:self.backgroundViewVerticalCenteringConstraint]; + + [self addConstraint:[NSLayoutConstraint constraintWithItem:self.alertBackgroundView + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationLessThanOrEqual + toItem:self + attribute:NSLayoutAttributeHeight + multiplier:0.9f + constant:0.0f]]; + + [self.alertBackgroundView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_titleLabel]-|" + options:0 + metrics:nil + views:NSDictionaryOfVariableBindings(_titleLabel)]]; + + [self.alertBackgroundView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_messageTextView]-|" + options:0 + metrics:nil + views:NSDictionaryOfVariableBindings(_messageTextView)]]; + + [self.alertBackgroundView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_contentViewContainerView]|" + options:0 + metrics:nil + views:NSDictionaryOfVariableBindings(_contentViewContainerView)]]; + + [self.alertBackgroundView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_textFieldContainerView]|" + options:0 + metrics:nil + views:NSDictionaryOfVariableBindings(_textFieldContainerView)]]; + + [self.alertBackgroundView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_actionButtonContainerView]|" + options:0 + metrics:nil + views:NSDictionaryOfVariableBindings(_actionButtonContainerView)]]; + + [self.alertBackgroundView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_contentViewContainerView(0@250)]-[_titleLabel]-2-[_messageTextView][_textFieldContainerView(0@250)]-8-[_actionButtonContainerView]|" + options:0 + metrics:nil + views:NSDictionaryOfVariableBindings(_titleLabel, + _messageTextView, + _contentViewContainerView, + _textFieldContainerView, + _actionButtonContainerView)]]; + } + + return self; + } + + + - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { + for (UIView *subview in self.subviews) { + if ([subview hitTest:[self convertPoint:point toView:subview] withEvent:event]) { + return YES; + } + } + + return NO; + } + + - (void)setMaximumWidth:(CGFloat)maximumWidth { + _maximumWidth = maximumWidth; + self.alertBackgroundWidthConstraint.constant = maximumWidth; + } + + - (void)setContentView:(UIView *)contentView { + [self.contentView removeFromSuperview]; + + _contentView = contentView; + + if (contentView) { + self.contentViewContainerView.layoutMargins = self.configuration.contentViewInset; + [self.contentViewContainerView addSubview:self.contentView]; + [self.contentView ny_pinEdgesToSuperviewMargins]; + } + } + + - (void)setTextFields:(NSArray *)textFields { + for (UITextField *textField in self.textFields) { + [textField removeFromSuperview]; + } + + _textFields = textFields; + + for (int i = 0; i < [textFields count]; i++) { + UITextField *textField = textFields[i]; + textField.translatesAutoresizingMaskIntoConstraints = NO; + [self.textFieldContainerView addSubview:textField]; + + [self.textFieldContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[textField]-|" + options:0 + metrics:nil + views:NSDictionaryOfVariableBindings(textField)]]; + + + if (i == 0) { + [textField.topAnchor constraintEqualToAnchor:self.textFieldContainerView.layoutMarginsGuide.topAnchor].active = YES; + } else { + UITextField *previousTextField = textFields[i - 1]; + + [self.textFieldContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[previousTextField]-[textField]" + options:0 + metrics:nil + views:NSDictionaryOfVariableBindings(previousTextField, textField)]]; + } + + + if (i == ([textFields count] - 1)) { + [self.textFieldContainerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[textField]|" + options:0 + metrics:nil + views:NSDictionaryOfVariableBindings(textField)]]; + } + } + } + + - (void)setActionButtons:(NSArray *)actionButtons { + for (UIView *view in self.actionButtonStackView.arrangedSubviews) { + [view removeFromSuperview]; + } + + _actionButtons = actionButtons; + + + if (actionButtons.count == 2 && !self.configuration.alwaysArrangesActionButtonsVertically) { + self.actionButtonStackView.axis = UILayoutConstraintAxisHorizontal; + } else { + self.actionButtonStackView.axis = UILayoutConstraintAxisVertical; + } + + [actionButtons enumerateObjectsUsingBlock:^(UIButton * _Nonnull button, NSUInteger idx, BOOL * _Nonnull stop) { + if (self.configuration.showsSeparators && idx > 0) { + + UIView *separatorView = [[UIView alloc] init]; + separatorView.backgroundColor = self.configuration.separatorColor; + separatorView.translatesAutoresizingMaskIntoConstraints = NO; + + if (self.actionButtonStackView.axis == UILayoutConstraintAxisVertical) { + [separatorView.heightAnchor constraintEqualToConstant:1.0f / [UIScreen mainScreen].scale].active = YES; + } else { + [separatorView.widthAnchor constraintEqualToConstant:1.0f / [UIScreen mainScreen].scale].active = YES; + } + + [self.actionButtonStackView addArrangedSubview:separatorView]; + } + + [button setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; + [self.actionButtonStackView addArrangedSubview:button]; + + if (idx > 0) { + UIButton *previousButton = actionButtons[idx - 1]; + [button.widthAnchor constraintEqualToAnchor:previousButton.widthAnchor multiplier:1.0f].active = YES; + [button.heightAnchor constraintEqualToAnchor:previousButton.heightAnchor multiplier:1.0f].active = YES; + } + }]; + } + + @end diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertViewButton.h b/libTitanD3vUniversal/Alert/Private/TDAlertViewButton.h new file mode 100644 index 0000000..bf01f06 --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertViewButton.h @@ -0,0 +1,14 @@ +#import + +typedef NS_ENUM(NSInteger, TDAlertViewButtonType) { + TDAlertViewButtonTypeDefault, + TDAlertViewButtonTypeRoundRect, + TDAlertViewButtonTypeBordered +}; + +@interface TDAlertViewButton : UIButton + +@property (nonatomic) TDAlertViewButtonType type; +@property (nonatomic) CGFloat cornerRadius; + +@end diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertViewButton.m b/libTitanD3vUniversal/Alert/Private/TDAlertViewButton.m new file mode 100644 index 0000000..a65d6de --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertViewButton.m @@ -0,0 +1,105 @@ +#import "TDAlertViewButton.h" + +@implementation TDAlertViewButton + ++ (id)buttonWithType:(UIButtonType)buttonType { + return [super buttonWithType:UIButtonTypeCustom]; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [super initWithCoder:aDecoder]; + + if (self) { + [self commonInit]; + } + + return self; +} + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + + if (self) { + [self commonInit]; + } + + return self; +} + +- (void)commonInit { + self.layer.rasterizationScale = [[UIScreen mainScreen] scale]; + self.layer.shouldRasterize = YES; + + self.layer.borderWidth = 1.0f; + + self.cornerRadius = 4.0f; + self.clipsToBounds = YES; + + [self tintColorDidChange]; +} + +- (void)setHidden:(BOOL)hidden { + [super setHidden:hidden]; + [self invalidateIntrinsicContentSize]; +} + +- (void)setEnabled:(BOOL)enabled { + [super setEnabled:enabled]; + +} + +- (CGFloat)cornerRadius { + return self.layer.cornerRadius; +} + +- (void)setCornerRadius:(CGFloat)cornerRadius { + self.layer.cornerRadius = cornerRadius; +} + +- (CGSize)intrinsicContentSize { + if (self.hidden) { + return CGSizeZero; + } + + return CGSizeMake([super intrinsicContentSize].width + 12.0f, 44.0f); +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesBegan:touches withEvent:event]; + [self setNeedsDisplay]; +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesMoved:touches withEvent:event]; + [self setNeedsDisplay]; +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesEnded:touches withEvent:event]; + [self setNeedsDisplay]; +} + +- (void)drawRect:(CGRect)rect { + [super drawRect:rect]; + + self.layer.borderColor = self.tintColor.CGColor; + + if (self.type == TDAlertViewButtonTypeBordered) { + self.layer.borderWidth = 1.0f; + } else { + self.layer.borderWidth = 0.0f; + } + + if (self.state == UIControlStateHighlighted) { + + } else { + if (self.type == TDAlertViewButtonTypeBordered) { + self.layer.backgroundColor = nil; + [self setTitleColor:self.tintColor forState:UIControlStateNormal]; + } else { + + } + } +} + +@end diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertViewDismissalAnimationController.h b/libTitanD3vUniversal/Alert/Private/TDAlertViewDismissalAnimationController.h new file mode 100644 index 0000000..3805423 --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertViewDismissalAnimationController.h @@ -0,0 +1,9 @@ +#import +#import "TDAlertViewControllerTransitionStyle.h" + +@interface TDAlertViewDismissalAnimationController : NSObject + +@property TDAlertViewControllerTransitionStyle transitionStyle; +@property CGFloat duration; + +@end diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertViewDismissalAnimationController.m b/libTitanD3vUniversal/Alert/Private/TDAlertViewDismissalAnimationController.m new file mode 100644 index 0000000..909029a --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertViewDismissalAnimationController.m @@ -0,0 +1,59 @@ +#import "TDAlertViewDismissalAnimationController.h" + +static CGFloat const kDefaultDismissalAnimationDuration = 0.6f; + +@implementation TDAlertViewDismissalAnimationController + +- (instancetype)init { + self = [super init]; + + if (self) { + self.duration = kDefaultDismissalAnimationDuration; + } + + return self; +} + +- (void)animateTransition:(id)transitionContext { + if (self.transitionStyle == TDAlertViewControllerTransitionStyleSlideFromTop || self.transitionStyle == TDAlertViewControllerTransitionStyleSlideFromBottom) { + UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; + + CGRect finalFrame = [transitionContext finalFrameForViewController:fromViewController]; + finalFrame.origin.y = 1.2f * CGRectGetHeight([transitionContext containerView].frame); + + [UIView animateWithDuration:[self transitionDuration:transitionContext] + delay:0.0f + usingSpringWithDamping:0.8f + initialSpringVelocity:0.1f + options:0 + animations:^{ + fromViewController.view.frame = finalFrame; + } + completion:^(BOOL finished) { + [transitionContext completeTransition:YES]; + }]; + } else { + UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; + + [UIView animateWithDuration:[self transitionDuration:transitionContext] + animations:^{ + fromViewController.view.layer.opacity = 0.0f; + } + completion:^(BOOL finished) { + [transitionContext completeTransition:YES]; + }]; + } +} + +- (NSTimeInterval)transitionDuration:(id)transitionContext { + switch (self.transitionStyle) { + case TDAlertViewControllerTransitionStyleFade: + return 0.3f; + break; + + case TDAlertViewControllerTransitionStyleSlideFromTop: + case TDAlertViewControllerTransitionStyleSlideFromBottom: + return 0.6f; + }} + + @end diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationAnimationController.h b/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationAnimationController.h new file mode 100644 index 0000000..6c69080 --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationAnimationController.h @@ -0,0 +1,9 @@ +#import +#import "TDAlertViewControllerTransitionStyle.h" + +@interface TDAlertViewPresentationAnimationController : NSObject + +@property TDAlertViewControllerTransitionStyle transitionStyle; +@property CGFloat duration; + +@end diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationAnimationController.m b/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationAnimationController.m new file mode 100644 index 0000000..e231ee3 --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationAnimationController.m @@ -0,0 +1,82 @@ +#import "TDAlertViewPresentationAnimationController.h" + +static CGFloat const kDefaultPresentationAnimationDuration = 0.7f; + +@implementation TDAlertViewPresentationAnimationController + +- (instancetype)init { + self = [super init]; + + if (self) { + self.duration = kDefaultPresentationAnimationDuration; + } + + return self; +} + +- (void)animateTransition:(id)transitionContext { + if (self.transitionStyle == TDAlertViewControllerTransitionStyleSlideFromTop || self.transitionStyle == TDAlertViewControllerTransitionStyleSlideFromBottom) { + UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; + + CGRect initialFrame = [transitionContext finalFrameForViewController:toViewController]; + + initialFrame.origin.y = self.transitionStyle == TDAlertViewControllerTransitionStyleSlideFromTop ? -(initialFrame.size.height + initialFrame.origin.y) : (initialFrame.size.height + initialFrame.origin.y); + toViewController.view.frame = initialFrame; + + [[transitionContext containerView] addSubview:toViewController.view]; + + if (self.transitionStyle == TDAlertViewControllerTransitionStyleSlideFromTop) { + CATransform3D transform = CATransform3DIdentity; + transform.m34 = -1.0f / 600.0f; + transform = CATransform3DRotate(transform, M_PI_4 * 1.3f, 1.0f, 0.0f, 0.0f); + + toViewController.view.layer.zPosition = 100.0f; + toViewController.view.layer.transform = transform; + } + + [UIView animateWithDuration:[self transitionDuration:transitionContext] + delay:0.0f + usingSpringWithDamping:0.76f + initialSpringVelocity:0.2f + options:0 + animations:^{ + toViewController.view.layer.transform = CATransform3DIdentity; + toViewController.view.layer.opacity = 1.0f; + toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController]; + } + completion:^(BOOL finished) { + [transitionContext completeTransition:YES]; + }]; + } else { + UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; + + toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController]; + [[transitionContext containerView] addSubview:toViewController.view]; + + toViewController.view.layer.transform = CATransform3DMakeScale(1.2f, 1.2f, 1.2f); + toViewController.view.layer.opacity = 0.0f; + + [UIView animateWithDuration:[self transitionDuration:transitionContext] + animations:^{ + toViewController.view.layer.transform = CATransform3DIdentity; + toViewController.view.layer.opacity = 1.0f; + } + completion:^(BOOL finished) { + [transitionContext completeTransition:YES]; + }]; + } +} + +- (NSTimeInterval)transitionDuration:(id)transitionContext { + switch (self.transitionStyle) { + case TDAlertViewControllerTransitionStyleFade: + return 0.3f; + break; + + case TDAlertViewControllerTransitionStyleSlideFromTop: + case TDAlertViewControllerTransitionStyleSlideFromBottom: + return 0.6f; + } +} + +@end diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationController.h b/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationController.h new file mode 100644 index 0000000..ce2c810 --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationController.h @@ -0,0 +1,8 @@ +#import + +@interface TDAlertViewPresentationController : UIPresentationController + +@property (nonatomic) BOOL backgroundTapDismissalGestureEnabled; +@property UIView *backgroundDimmingView; + +@end diff --git a/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationController.m b/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationController.m new file mode 100644 index 0000000..92c6182 --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/TDAlertViewPresentationController.m @@ -0,0 +1,81 @@ +#import "TDAlertViewPresentationController.h" +#import "UIView+Additions.h" + +@interface TDAlertViewPresentationController () + +- (void)tapGestureRecognized:(UITapGestureRecognizer *)gestureRecognizer; + +@end + +@implementation TDAlertViewPresentationController + +- (void)presentationTransitionWillBegin { + self.presentedViewController.view.layer.cornerRadius = 6.0f; + self.presentedViewController.view.layer.masksToBounds = YES; + + self.backgroundDimmingView = [[UIView alloc] initWithFrame:CGRectZero]; + self.backgroundDimmingView.alpha = 0.0f; + self.backgroundDimmingView.backgroundColor = [UIColor blackColor]; + [self.containerView addSubview:self.backgroundDimmingView]; + + [self.backgroundDimmingView ny_pinEdgesToSuperviewEdges]; + + UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureRecognized:)]; + [self.backgroundDimmingView addGestureRecognizer:tapGestureRecognizer]; + + + id transitionCoordinator = [self.presentingViewController transitionCoordinator]; + [transitionCoordinator animateAlongsideTransition:^(id context) { + self.backgroundDimmingView.alpha = 0.7f; + } completion:nil]; +} + +- (BOOL)shouldPresentInFullscreen { + return NO; +} + +- (BOOL)shouldRemovePresentersView { + return NO; +} + +- (void)presentationTransitionDidEnd:(BOOL)completed { + [super presentationTransitionDidEnd:completed]; + + if (!completed) { + [self.backgroundDimmingView removeFromSuperview]; + } +} + +- (void)dismissalTransitionWillBegin { + [super dismissalTransitionWillBegin]; + + id transitionCoordinator = [self.presentingViewController transitionCoordinator]; + [transitionCoordinator animateAlongsideTransition:^(id context) { + self.backgroundDimmingView.alpha = 0.0f; + + self.presentingViewController.view.transform = CGAffineTransformIdentity; + } completion:nil]; +} + +- (void)containerViewWillLayoutSubviews { + [super containerViewWillLayoutSubviews]; + + [self presentedView].frame = [self frameOfPresentedViewInContainerView]; + self.backgroundDimmingView.frame = self.containerView.bounds; +} + +- (void)dismissalTransitionDidEnd:(BOOL)completed { + [super dismissalTransitionDidEnd:completed]; + + if (completed) { + [self.backgroundDimmingView removeFromSuperview]; + } +} + +- (void)tapGestureRecognized:(UITapGestureRecognizer *)gestureRecognizer { + if (self.backgroundTapDismissalGestureEnabled) { + [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; + } +} + +@end diff --git a/libTitanD3vUniversal/Alert/Private/UIView+Additions.h b/libTitanD3vUniversal/Alert/Private/UIView+Additions.h new file mode 100644 index 0000000..bea2452 --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/UIView+Additions.h @@ -0,0 +1,9 @@ +#import + +@interface UIView (Additions) + +- (void)ny_pinEdgesToSuperviewEdges; +- (void)ny_pinEdgesToSuperviewMargins; + +@end + diff --git a/libTitanD3vUniversal/Alert/Private/UIView+Additions.m b/libTitanD3vUniversal/Alert/Private/UIView+Additions.m new file mode 100644 index 0000000..a63779c --- /dev/null +++ b/libTitanD3vUniversal/Alert/Private/UIView+Additions.m @@ -0,0 +1,25 @@ +#import "UIView+Additions.h" + +@implementation UIView (Additions) + +- (void)ny_pinEdgesToSuperviewEdges { + NSAssert(self.superview, @"Superview must be nonnull"); + self.translatesAutoresizingMaskIntoConstraints = NO; + + [self.leadingAnchor constraintEqualToAnchor:self.superview.leadingAnchor].active = YES; + [self.trailingAnchor constraintEqualToAnchor:self.superview.trailingAnchor].active = YES; + [self.topAnchor constraintEqualToAnchor:self.superview.topAnchor].active = YES; + [self.bottomAnchor constraintEqualToAnchor:self.superview.bottomAnchor].active = YES; +} + +- (void)ny_pinEdgesToSuperviewMargins { + NSAssert(self.superview, @"Superview must be nonnull"); + self.translatesAutoresizingMaskIntoConstraints = NO; + + [self.leadingAnchor constraintEqualToAnchor:self.superview.layoutMarginsGuide.leadingAnchor].active = YES; + [self.trailingAnchor constraintEqualToAnchor:self.superview.layoutMarginsGuide.trailingAnchor].active = YES; + [self.topAnchor constraintEqualToAnchor:self.superview.layoutMarginsGuide.topAnchor].active = YES; + [self.bottomAnchor constraintEqualToAnchor:self.superview.layoutMarginsGuide.bottomAnchor].active = YES; +} + +@end diff --git a/libTitanD3vUniversal/Alert/TDAlertAction.h b/libTitanD3vUniversal/Alert/TDAlertAction.h new file mode 100644 index 0000000..6d83670 --- /dev/null +++ b/libTitanD3vUniversal/Alert/TDAlertAction.h @@ -0,0 +1,19 @@ +#import +#import "TDAlertActionConfiguration.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" + +@interface TDAlertAction : NSObject + +- (instancetype)initWithTitle:(NSString *)title style:(UIAlertActionStyle)style handler:(void (^__nullable)(TDAlertAction *action))handler; +- (instancetype)initWithTitle:(NSString *)title style:(UIAlertActionStyle)style handler:(void (^__nullable)(TDAlertAction *action))handler configuration:(nullable TDAlertActionConfiguration *)configuration; + +@property (nonatomic, strong, readonly) NSString *title; +@property (nonatomic, readonly) UIAlertActionStyle style; +@property (nonatomic, strong, readonly, nullable) void (^handler)(TDAlertAction *action); +@property (nonatomic, strong, readonly, nullable) TDAlertActionConfiguration *configuration; +@property (nonatomic) BOOL enabled; + +@end + diff --git a/libTitanD3vUniversal/Alert/TDAlertAction.m b/libTitanD3vUniversal/Alert/TDAlertAction.m new file mode 100644 index 0000000..14d4351 --- /dev/null +++ b/libTitanD3vUniversal/Alert/TDAlertAction.m @@ -0,0 +1,43 @@ +#import "TDAlertAction.h" +#import "TDAlertAction+Private.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" + +@implementation TDAlertAction + +- (instancetype)initWithTitle:(NSString *)title style:(UIAlertActionStyle)style handler:(void (^)(TDAlertAction * _Nonnull))handler { + return [self initWithTitle:title style:style handler:handler configuration:nil]; +} + +- (instancetype)initWithTitle:(NSString *)title style:(UIAlertActionStyle)style handler:(void (^__nullable)(TDAlertAction *action))handler configuration:(nullable TDAlertActionConfiguration *)configuration { + self = [super init]; + + if (self) { + _title = title; + _style= style; + _handler = handler; + _configuration = configuration; + _enabled = YES; + } + + return self; +} + +- (instancetype)init { + self = [super init]; + + if (self) { + _enabled = YES; + } + + return self; +} + +- (void)setEnabled:(BOOL)enabled { + _enabled = enabled; + + self.actionButton.enabled = enabled; +} + +@end diff --git a/libTitanD3vUniversal/Alert/TDAlertActionConfiguration.h b/libTitanD3vUniversal/Alert/TDAlertActionConfiguration.h new file mode 100644 index 0000000..1828d69 --- /dev/null +++ b/libTitanD3vUniversal/Alert/TDAlertActionConfiguration.h @@ -0,0 +1,10 @@ +#import + +@interface TDAlertActionConfiguration : NSObject + +@property (strong, nonatomic) UIFont *titleFont; +@property (strong, nonatomic) UIColor *titleColor; +@property (strong, nonatomic) UIColor *disabledTitleColor; + +@end + diff --git a/libTitanD3vUniversal/Alert/TDAlertActionConfiguration.m b/libTitanD3vUniversal/Alert/TDAlertActionConfiguration.m new file mode 100644 index 0000000..f496a98 --- /dev/null +++ b/libTitanD3vUniversal/Alert/TDAlertActionConfiguration.m @@ -0,0 +1,17 @@ +#import "TDAlertActionConfiguration.h" + +@implementation TDAlertActionConfiguration + +- (instancetype)init { + self = [super init]; + + if (self) { + _titleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + _titleColor = [UIColor darkGrayColor]; + _disabledTitleColor = [UIColor grayColor]; + } + + return self; +} + +@end diff --git a/libTitanD3vUniversal/Alert/TDAlertViewController.h b/libTitanD3vUniversal/Alert/TDAlertViewController.h new file mode 100644 index 0000000..50d5fe3 --- /dev/null +++ b/libTitanD3vUniversal/Alert/TDAlertViewController.h @@ -0,0 +1,24 @@ +#import +#import "TDAlertAction.h" +#import "TDAlertViewControllerConfiguration.h" +#import "TDUtilities.h" + +@interface TDAlertViewController : UIViewController + +- (instancetype)initWithOptions:(nullable TDAlertViewControllerConfiguration *)configuration title:(nullable NSString *)title message:(nullable NSString *)message actions:(NSArray *)actions; ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil NS_UNAVAILABLE; +- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE; + +@property (nonatomic, readonly) TDAlertViewControllerConfiguration *configuration; +@property (nonatomic, nullable) NSString *message; +@property (nonatomic, nullable) UIView *alertViewContentView; +@property (nonatomic) CGFloat maximumWidth; +@property (nonatomic, readonly) NSArray *actions; +@property (nonatomic, readonly) NSArray *textFields; + +- (void)addTextFieldWithConfigurationHandler:(void (^)(UITextField *textField))configurationHandler; + +@end + diff --git a/libTitanD3vUniversal/Alert/TDAlertViewController.m b/libTitanD3vUniversal/Alert/TDAlertViewController.m new file mode 100644 index 0000000..ce5a13b --- /dev/null +++ b/libTitanD3vUniversal/Alert/TDAlertViewController.m @@ -0,0 +1,250 @@ +#import "TDAlertViewController.h" + +#import "TDAlertView.h" +#import "TDAlertAction+Private.h" +#import "TDAlertViewButton.h" +#import "TDAlertViewDismissalAnimationController.h" +#import "TDAlertViewPresentationAnimationController.h" +#import "TDAlertViewPresentationController.h" + +@interface TDAlertViewController () + +@property TDAlertView *view; +@property UIPanGestureRecognizer *panGestureRecognizer; +@property (nonatomic, strong) id transitioningDelegate; + +- (void)panGestureRecognized:(UIPanGestureRecognizer *)gestureRecognizer; + +@end + + +@implementation TDAlertViewController + +@dynamic view; + +- (instancetype)initWithOptions:(TDAlertViewControllerConfiguration *)configuration title:(NSString *)title message:(NSString *)message actions:(NSArray *)actions { + self = [super initWithNibName:nil bundle:nil]; + + if (self) { + _configuration = [configuration copy] ?: [TDAlertViewControllerConfiguration new]; + _actions = actions; + _textFields = [NSArray array]; + + self.modalPresentationStyle = UIModalPresentationCustom; + self.transitioningDelegate = self; + + self.panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognized:)]; + self.panGestureRecognizer.delegate = self; + self.panGestureRecognizer.enabled = configuration.swipeDismissalGestureEnabled; + [self.view addGestureRecognizer:self.panGestureRecognizer]; + + [self setTitle:title]; + [self setMessage:message]; + } + + return self; +} + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; +} + +- (void)loadView { + self.view = [[TDAlertView alloc] initWithConfiguration:self.configuration]; +} + +- (BOOL)prefersStatusBarHidden { + return !self.configuration.showsStatusBar; +} + +- (CGFloat)maximumWidth { + return self.view.maximumWidth; +} + +- (void)setMaximumWidth:(CGFloat)maximumWidth { + self.view.maximumWidth = maximumWidth; +} + +- (UIView *)alertViewContentView { + return self.view.contentView; +} + +- (void)setAlertViewContentView:(UIView *)alertViewContentView { + self.view.contentView = alertViewContentView; +} + +- (void)panGestureRecognized:(UIPanGestureRecognizer *)gestureRecognizer { + self.view.backgroundViewVerticalCenteringConstraint.constant = [gestureRecognizer translationInView:self.view].y; + + TDAlertViewPresentationController *presentationController = (TDAlertViewPresentationController *)self.presentationController; + + CGFloat windowHeight = CGRectGetHeight([UIApplication sharedApplication].keyWindow.bounds); + presentationController.backgroundDimmingView.alpha = 0.7f - (fabs([gestureRecognizer translationInView:self.view].y) / windowHeight); + + if (gestureRecognizer.state == UIGestureRecognizerStateEnded) { + CGFloat verticalGestureVelocity = [gestureRecognizer velocityInView:self.view].y; + + + if (fabs(verticalGestureVelocity) > 500.0f) { + CGFloat backgroundViewYPosition; + + if (verticalGestureVelocity > 500.0f) { + backgroundViewYPosition = CGRectGetHeight(self.view.frame); + } else { + backgroundViewYPosition = -CGRectGetHeight(self.view.frame); + } + + CGFloat animationDuration = 500.0f / fabs(verticalGestureVelocity); + + self.view.backgroundViewVerticalCenteringConstraint.constant = backgroundViewYPosition; + [UIView animateWithDuration:animationDuration + delay:0.0f + usingSpringWithDamping:0.8f + initialSpringVelocity:0.2f + options:0 + animations:^{ + presentationController.backgroundDimmingView.alpha = 0.0f; + [self.view layoutIfNeeded]; + } + completion:^(BOOL finished) { + [self dismissViewControllerAnimated:YES completion:^{ + self.view.backgroundViewVerticalCenteringConstraint.constant = 0.0f; + }]; + }]; + } else { + self.view.backgroundViewVerticalCenteringConstraint.constant = 0.0f; + [UIView animateWithDuration:0.5f + delay:0.0f + usingSpringWithDamping:0.8f + initialSpringVelocity:0.4f + options:0 + animations:^{ + presentationController.backgroundDimmingView.alpha = 0.7f; + [self.view layoutIfNeeded]; + } + completion:nil]; + } + } +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + [self createActionButtons]; + self.view.textFields = self.textFields; +} + +- (void)createActionButtons { + NSMutableArray *buttons = [NSMutableArray array]; + + for (int i = 0; i < [self.actions count]; i++) { + TDAlertAction *action = self.actions[i]; + + TDAlertViewButton *button = [TDAlertViewButton buttonWithType:UIButtonTypeCustom]; + + button.tag = i; + [button addTarget:self action:@selector(actionButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; + + button.enabled = action.enabled; + + [button setTranslatesAutoresizingMaskIntoConstraints:NO]; + [button setTitle:action.title forState:UIControlStateNormal]; + + TDAlertActionConfiguration *buttonConfiguration; + if (action.configuration) { + buttonConfiguration = action.configuration; + } else { + switch (action.style) { + case UIAlertActionStyleDefault: + buttonConfiguration = self.configuration.buttonConfiguration; + break; + case UIAlertActionStyleCancel: + buttonConfiguration = self.configuration.cancelButtonConfiguration; + break; + case UIAlertActionStyleDestructive: + buttonConfiguration = self.configuration.destructiveButtonConfiguration; + break; + } + } + + [button setTitleColor:buttonConfiguration.disabledTitleColor forState:UIControlStateDisabled]; + [button setTitleColor:buttonConfiguration.titleColor forState:UIControlStateNormal]; + [button setTitleColor:buttonConfiguration.titleColor forState:UIControlStateHighlighted]; + button.titleLabel.font = buttonConfiguration.titleFont; + + [buttons addObject:button]; + action.actionButton = button; + } + + self.view.actionButtons = buttons; +} + +- (void)actionButtonPressed:(UIButton *)button { + [[TDUtilities sharedInstance] haptic:0]; + TDAlertAction *action = self.actions[button.tag]; + + if (action.handler) { + action.handler(action); + } + + [self dismissViewControllerAnimated:YES completion:nil]; +} + +#pragma mark - Getters/Setters + +- (void)setTitle:(NSString *)title { + [super setTitle:title]; + + self.view.titleLabel.text = title; +} + +- (void)setMessage:(NSString *)message { + _message = message; + self.view.messageTextView.text = message; +} + +- (void)addTextFieldWithConfigurationHandler:(void (^)(UITextField *textField))configurationHandler { + UITextField *textField = [[UITextField alloc] initWithFrame:CGRectZero]; + textField.borderStyle = UITextBorderStyleRoundedRect; + + if (configurationHandler) { + configurationHandler(textField); + } + + _textFields = [self.textFields arrayByAddingObject:textField]; +} + +#pragma mark - UIViewControllerTransitioningDelegate + +- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source { + TDAlertViewPresentationController *presentationController = [[TDAlertViewPresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting]; + presentationController.backgroundTapDismissalGestureEnabled = self.configuration.backgroundTapDismissalGestureEnabled; + return presentationController; +} + +- (id )animationControllerForPresentedController:(UIViewController *)presented +presentingController:(UIViewController *)presenting +sourceController:(UIViewController *)source { + TDAlertViewPresentationAnimationController *presentationAnimationController = [[TDAlertViewPresentationAnimationController alloc] init]; + presentationAnimationController.transitionStyle = self.configuration.transitionStyle; + return presentationAnimationController; +} + +- (id )animationControllerForDismissedController:(UIViewController *)dismissed { + TDAlertViewDismissalAnimationController *dismissalAnimationController = [[TDAlertViewDismissalAnimationController alloc] init]; + dismissalAnimationController.transitionStyle = self.configuration.transitionStyle; + return dismissalAnimationController; +} + +#pragma mark - UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { + + if (([touch.view isKindOfClass:[UIButton class]])) { + return NO; + } + + return YES; +} + +@end diff --git a/libTitanD3vUniversal/Alert/TDAlertViewControllerConfiguration.h b/libTitanD3vUniversal/Alert/TDAlertViewControllerConfiguration.h new file mode 100644 index 0000000..f4f3c66 --- /dev/null +++ b/libTitanD3vUniversal/Alert/TDAlertViewControllerConfiguration.h @@ -0,0 +1,27 @@ +#import +#import "TDAlertActionConfiguration.h" +#import "TDAlertViewControllerTransitionStyle.h" + + +@interface TDAlertViewControllerConfiguration : NSObject + +@property (nonatomic) BOOL showsStatusBar; +@property (nonatomic) TDAlertViewControllerTransitionStyle transitionStyle; +@property (nonatomic) BOOL backgroundTapDismissalGestureEnabled; +@property (nonatomic) BOOL swipeDismissalGestureEnabled; +@property (nonatomic) BOOL alwaysArrangesActionButtonsVertically; +@property (nonatomic) UIColor *alertViewBackgroundColor; +@property (nonatomic) CGFloat alertViewCornerRadius; +@property (nonatomic) UIColor *titleTextColor; +@property (nonatomic) UIColor *messageTextColor; +@property (nonatomic) BOOL showsSeparators; +@property (nonatomic) UIColor *separatorColor; +@property (nonatomic) UIEdgeInsets contentViewInset; +@property (nonatomic) UIFont *titleFont; +@property (nonatomic) UIFont *messageFont; +@property (nonatomic, strong) TDAlertActionConfiguration *buttonConfiguration; +@property (nonatomic, strong) TDAlertActionConfiguration *destructiveButtonConfiguration; +@property (nonatomic, strong) TDAlertActionConfiguration *cancelButtonConfiguration; + +@end + diff --git a/libTitanD3vUniversal/Alert/TDAlertViewControllerConfiguration.m b/libTitanD3vUniversal/Alert/TDAlertViewControllerConfiguration.m new file mode 100644 index 0000000..3c3e0dd --- /dev/null +++ b/libTitanD3vUniversal/Alert/TDAlertViewControllerConfiguration.m @@ -0,0 +1,48 @@ +#import "TDAlertViewControllerConfiguration.h" + +@implementation TDAlertViewControllerConfiguration + +- (instancetype)init { + self = [super init]; + + if (self) { + _showsStatusBar = YES; + _transitionStyle = TDAlertViewControllerTransitionStyleSlideFromTop; + + _backgroundTapDismissalGestureEnabled = NO; + _swipeDismissalGestureEnabled = NO; + _alwaysArrangesActionButtonsVertically = NO; + + _titleTextColor = [UIColor darkGrayColor]; + _messageTextColor = [UIColor darkGrayColor]; + + _alertViewBackgroundColor = [UIColor whiteColor]; + _alertViewCornerRadius = 6.0f; + + _showsSeparators = YES; + _separatorColor = [UIColor lightGrayColor]; + + _contentViewInset = UIEdgeInsetsZero; + + _titleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + _messageFont = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline]; + + _buttonConfiguration = [TDAlertActionConfiguration new]; + + _destructiveButtonConfiguration = [TDAlertActionConfiguration new]; + _destructiveButtonConfiguration.titleColor = [UIColor colorWithRed:1.0f green:0.23f blue:0.21f alpha:1.0f]; + + _cancelButtonConfiguration = [TDAlertActionConfiguration new]; + _cancelButtonConfiguration.titleFont = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; + } + + return self; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(nullable NSZone *)zone { + return self; +} + +@end diff --git a/libTitanD3vUniversal/Alert/TDAlertViewControllerTransitionStyle.h b/libTitanD3vUniversal/Alert/TDAlertViewControllerTransitionStyle.h new file mode 100644 index 0000000..62dc335 --- /dev/null +++ b/libTitanD3vUniversal/Alert/TDAlertViewControllerTransitionStyle.h @@ -0,0 +1,7 @@ +typedef NS_ENUM(NSInteger, TDAlertViewControllerTransitionStyle) { + + TDAlertViewControllerTransitionStyleFade, + TDAlertViewControllerTransitionStyleSlideFromTop, + TDAlertViewControllerTransitionStyleSlideFromBottom + +}; diff --git a/libTitanD3vUniversal/AppList/TDAppList.h b/libTitanD3vUniversal/AppList/TDAppList.h new file mode 100644 index 0000000..28ce077 --- /dev/null +++ b/libTitanD3vUniversal/AppList/TDAppList.h @@ -0,0 +1,9 @@ +#import + +@interface TDAppList : NSObject ++ (NSMutableArray *)allApps; ++ (NSMutableArray *)userApps; ++ (NSMutableArray *)systemApps; ++ (NSMutableArray *)audioApps; ++(NSMutableArray*)sortArray:(NSMutableArray*)arrayToSort; +@end \ No newline at end of file diff --git a/libTitanD3vUniversal/AppList/TDAppList.m b/libTitanD3vUniversal/AppList/TDAppList.m new file mode 100644 index 0000000..632ffae --- /dev/null +++ b/libTitanD3vUniversal/AppList/TDAppList.m @@ -0,0 +1,213 @@ +#import "TDAppList.h" + +@interface _LSLazyPropertyList : NSObject +@property(readonly) NSDictionary *propertyList; +@end + +@interface LSApplicationProxy : NSObject +@property(setter=_setLocalizedName:, nonatomic, copy) NSString *localizedName; +@property(nonatomic, readonly) NSString *bundleIdentifier; +@property(nonatomic, readonly) NSString *primaryIconName; +@property(nonatomic, readonly) NSDictionary *iconsDictionary; +@property(nonatomic, readonly) NSArray *appTags; +@property(setter=_setInfoDictionary:, nonatomic, copy) +_LSLazyPropertyList *_infoDictionary; +- (NSArray *)_boundIconFileNames; +- (NSArray *)boundIconFileNames; +@end + +@interface LSApplicationWorkspace ++ (id)defaultWorkspace; +- (id)allInstalledApplications; +- (id)allApplications; +- (id)applicationsOfType:(unsigned long long)arg1; +- (id)applicationsWithUIBackgroundModes; +@end + +@interface TDAppList () ++ (NSString *)nameForApp:(LSApplicationProxy *)app; +@end + +@interface UIImage (Private) ++(id)_applicationIconImageForBundleIdentifier:(NSString*)displayIdentifier format:(int)form scale:(CGFloat)scale; +@end + +@implementation TDAppList + +int iOSVersion; ++ (NSMutableArray *)userApps { + + NSMutableArray *userApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + applicationsOfType:0]; + + for (LSApplicationProxy *app in defaultWorkspaceApps) { + [userApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + return [self sortArray:userApps]; +} + ++ (NSMutableArray *)audioApps { + + NSMutableArray *audioApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + applicationsWithUIBackgroundModes]; + + for (LSApplicationProxy *app in defaultWorkspaceApps) { + NSDictionary *info = app._infoDictionary.propertyList; + NSArray *background = info[@"UIBackgroundModes"]; + if (background && [background containsObject:@"audio"]) { + if ([self hasIconAndVisible:app.bundleIdentifier]) { + [audioApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + } + } + return [self sortArray:audioApps]; +} + ++ (NSMutableArray *)systemApps { + + NSMutableArray *systemApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + applicationsOfType:1]; + + for (LSApplicationProxy *app in defaultWorkspaceApps) { + if ([self hasIconAndVisible:app.bundleIdentifier]) { + [systemApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + } + + return [self sortArray:systemApps]; +} + ++ (NSMutableArray *)allApps { + + NSMutableArray *allApps = [NSMutableArray new]; + NSMutableArray *defaultWorkspaceApps = + [[NSClassFromString(@"LSApplicationWorkspace") defaultWorkspace] + allApplications]; + for (LSApplicationProxy *app in defaultWorkspaceApps) { + if ([self hasIconAndVisible:app.bundleIdentifier]) { + [allApps addObject:@{ + @"bundleID" : app.bundleIdentifier, + @"name" : [self nameForApp:app] + }]; + } + } + return [self sortArray:allApps]; +} + ++ (BOOL)hasIconAndVisible:(NSString *)bundleIdentifier { + NSArray *blacklist = [NSArray arrayWithObjects:@"com.apple.Magnifier", + @"com.apple.InCallService", + @"com.apple.RemoteiCloudQuotaUI", + @"com.apple.PublicHealthRemoteUI", + @"com.apple.CarPlaySplashScreen", + @"com.apple.iMessageAppsViewService", + @"com.apple.BarcodeScanner", + @"com.apple.HealthENLauncher", + @"com.apple.AXUIViewService", + @"com.apple.AppSSOUIService", + @"com.apple.CarPlaySettings", + @"com.apple.mobilesms.compose", + @"com.apple.BusinessChatViewService", + @"com.apple.DiagnosticsService", + @"com.apple.CTNotifyUIService", + @"com.apple.HealthPrivacyService", + @"com.apple.WebContentFilter.remoteUI.WebContentAnalysisUI", + @"com.apple.ScreenshotServicesService", + @"com.apple.FTMInternal", + @"com.apple.carkit.DNDBuddy", + @"com.apple.PreBoard", + @"com.apple.datadetectors.DDActionsService", + @"com.apple.DemoApp", + @"com.apple.CoreAuthUI", + @"com.apple.SubcredentialUIService", + @"com.apple.MailCompositionService", + @"com.apple.Diagnostics", + @"com.apple.AuthKitUIService", + @"com.apple.TVRemote", + @"com.apple.gamecenter.GameCenterUIService", + @"com.apple.PrintKit.Print-Center", + @"com.apple.sidecar", + @"com.apple.AccountAuthenticationDialog", + @"com.apple.PassbookUIService", + @"com.apple.siri", + @"com.apple.CloudKit.ShareBear", + @"com.apple.HealthENBuddy", + @"com.apple.SafariViewService", + @"com.apple.SIMSetupUIService", + @"com.apple.CompassCalibrationViewService", + @"com.apple.PhotosViewService", + @"com.apple.MusicUIService", + @"com.apple.TrustMe", + @"com.apple.Home.HomeUIService", + @"com.apple.CTCarrierSpaceAuth", + @"com.apple.StoreDemoViewService", + @"com.apple.susuiservice", + @"com.apple.social.SLYahooAuth", + @"com.apple.Spotlight", + @"com.apple.fieldtest", + @"com.apple.WebSheet", + @"com.apple.iad.iAdOptOut", + @"com.apple.dt.XcodePreviews", + @"com.apple.appleseed.FeedbackAssistant", + @"com.apple.FontInstallViewService", + @"com.apple.ScreenSharingViewService", + @"com.apple.SharedWebCredentialViewService", + @"com.apple.CheckerBoard", + @"com.apple.DataActivation", + @"com.apple.TVAccessViewService", + @"com.apple.VSViewService", + @"com.apple.TVRemoteUIService", + @"com.apple.SharingViewService", + @"com.apple.ios.StoreKitUIService", + @"com.apple.purplebuddy", + @"com.apple.ScreenTimeUnlock", + @"com.apple.webapp", + @"com.apple.ActivityMessagesApp", + @"com.apple.icloud.apps.messages.business", + @"com.apple.ClipViewService", + @"com.apple.CredentialSharingService", + @"com.apple.ctkui", + @"com.apple.FunCamera.EmojiStickers", + @"com.apple.siri.parsec.HashtagImagesApp", + @"com.apple.icq", + @"com.apple.Jellyfish", + @"com.apple.Animoji.StickersApp", + @"com.apple.PassbookSecureUIService", + @"com.apple.Photos.PhotosUIService", + @"com.apple.shortcuts.runtime", + @"com.apple.SleepLockScreen", + @"com.apple.FunCamera.TextPicker", + @"com.apple.FunCamera.ShapesPicker", + @"com.apple.smsFilter", + @"com.apple.AskPermissionUI", nil]; + UIImage *image = [UIImage _applicationIconImageForBundleIdentifier:bundleIdentifier format:2 scale:[UIScreen mainScreen].scale]; + NSData *imageData = UIImagePNGRepresentation(image); + if(imageData.length == 9762 || [blacklist containsObject:bundleIdentifier]) + return NO; + return YES; +} + ++ (NSString *)nameForApp:(LSApplicationProxy *)app { + return (app.localizedName ? app.localizedName : app.bundleIdentifier); +} + ++(NSMutableArray*)sortArray:(NSMutableArray*)arrayToSort{ + NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)]; + return [[arrayToSort sortedArrayUsingDescriptors:@[sort]] mutableCopy]; +} +@end diff --git a/libTitanD3vUniversal/AppList/TDAppListController.h b/libTitanD3vUniversal/AppList/TDAppListController.h new file mode 100644 index 0000000..7bba9d4 --- /dev/null +++ b/libTitanD3vUniversal/AppList/TDAppListController.h @@ -0,0 +1,30 @@ +#import +#import +#import "TDResultsTableController.h" +#import +#import "TDAppearance.h" +#import "TDUtilities.h" + +@interface TDAppListController : PSViewController +@property (nonatomic, retain) UISearchController *searchController; +@property (nonatomic, retain) UITableView *tableView; +@property(nonatomic, strong) NSArray *fullAppList; +@property(nonatomic, strong) NSArray *appList; +@property (nonatomic, retain) NSArray *preferencesAppList; +@property(nonatomic, strong) NSMutableArray *selectedApps; +@property(nonatomic, strong) NSMutableArray *unselectedApps; +@property(nonatomic, assign) NSString *postNotification; +@property(nonatomic, assign) NSString *preferencesSuiteName; +@property(nonatomic, assign) NSString *preferencesKey; +@property(nonatomic, assign) BOOL isLimitApps; +@property(nonatomic, assign) int appsCapacity; +@property (nonatomic, retain) UIColor *navigationBarColour; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *backgroundColour; +@property (nonatomic, retain) UIColor *cellsColour; +@property (nonatomic, retain) UIColor *labelColour; +@end + +@interface UIImage (Private) ++(id)_applicationIconImageForBundleIdentifier:(NSString*)displayIdentifier format:(int)form scale:(CGFloat)scale; +@end diff --git a/libTitanD3vUniversal/AppList/TDAppListController.m b/libTitanD3vUniversal/AppList/TDAppListController.m new file mode 100644 index 0000000..b11e512 --- /dev/null +++ b/libTitanD3vUniversal/AppList/TDAppListController.m @@ -0,0 +1,444 @@ +#include "TDAppsCell.h" +#include "TDAppList.h" +#include "TDAppListController.h" + +@interface TDAppListController () +@property(nonatomic, retain) TDResultsTableController *resultsTableController; +@end + +static UIView *selectionView; +static NSString *headerTitle; +static NSString *prefPath; + + +@implementation TDAppListController + +- (void)viewWillAppear:(BOOL)arg1 { + [super viewWillAppear:arg1]; + + self.navigationBarColour = [[TDAppearance sharedInstance] navigationBarColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.backgroundColour = [[TDAppearance sharedInstance] backgroundColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = self.tintColour; + + + UINavigationBar *bar = self.navigationController.navigationController.navigationBar; + bar.barTintColor = self.navigationBarColour; + bar.tintColor = self.tintColour; + [[UIButton appearance]setTintColor:self.tintColour]; + self.view.tintColor = self.tintColour; + + + self.view.backgroundColor = self.backgroundColour; + + + self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.backgroundColor = self.backgroundColour; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + NSDictionary *properties = self.specifier.properties; + self.preferencesSuiteName = properties[@"defaults"]; + self.preferencesKey = properties[@"key"]; + self.postNotification = properties[@"postNotification"]; + self.isLimitApps = [properties[@"limitApps"] boolValue]; + self.appsCapacity = [properties[@"appsCapacity"] intValue]; + + NSString *appList = [properties[@"appList"] lowercaseString]; + if ([appList isEqualToString:@"allapps"]) { + headerTitle = @"All Applications"; + self.fullAppList = [TDAppList.allApps copy]; + } else if ([appList isEqualToString:@"userapps"]) { + headerTitle = @"All User Apps"; + self.fullAppList = [TDAppList.userApps copy]; + } else if ([appList isEqualToString:@"systemapps"]) { + headerTitle = @"All System Apps"; + self.fullAppList = [TDAppList.systemApps copy]; + } else if ([appList isEqualToString:@"audioapps"]) { + headerTitle = @"All Audio Apps"; + self.fullAppList = [TDAppList.audioApps copy]; + } + + self.appList = self.fullAppList; + + // if (!([self.preferencesSuiteName length] == 0 || [self.preferencesKey length] == 0)) { + // NSUserDefaults *preferences = [[NSUserDefaults alloc] + // initWithSuiteName:self.preferencesSuiteName]; + // self.selectedApps = + // [[preferences objectForKey:self.preferencesKey] mutableCopy]; + // } else { + // [self errorAlert]; + // } + + prefPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", self.preferencesSuiteName]; + NSMutableDictionary *prefs = [NSMutableDictionary dictionaryWithContentsOfFile:prefPath]; + NSArray *apps; + + if ([[NSFileManager defaultManager] fileExistsAtPath:prefPath]) { + apps = prefs[self.preferencesKey]; + } else { + apps = @[]; + } + + self.preferencesAppList = apps; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.resultsTableController = [TDResultsTableController new]; + self.searchController = [[UISearchController alloc] initWithSearchResultsController:self.resultsTableController]; + self.searchController.searchResultsUpdater = self; + self.searchController.delegate = self; + self.searchController.searchBar.delegate = self; + self.searchController.hidesNavigationBarDuringPresentation = false; + self.searchController.searchBar.searchBarStyle = UISearchBarStyleProminent; + self.searchController.searchBar.placeholder = @"App"; + self.searchController.searchBar.tintColor = UIColor.whiteColor; + self.searchController.searchBar.barTintColor =[UIColor colorWithRed:53.0 / 255.0 green:59.0 / 255.0 blue:68.0 / 255.0 alpha:1.0]; + self.searchController.hidesNavigationBarDuringPresentation = true; + self.searchController.searchBar.keyboardAppearance = UIKeyboardAppearanceDark; + + [[UITextField appearanceWhenContainedInInstancesOfClasses:@ [[UISearchBar class]]] setTintColor:UIColor.blackColor]; + self.searchController.view.backgroundColor = [UIColor colorWithRed:53 / 255.0 green:59 / 255.0 blue:68.0 / 255.0 alpha:0.75]; + self.definesPresentationContext = YES; + + self.resultsTableController.searchResult = [[NSMutableArray alloc] init]; + + // UIBarButtonItem *searchButton = [[UIBarButtonItem alloc] + // initWithBarButtonSystemItem:UIBarButtonSystemItemSearch + // target:self + // action:@selector(toggleSearch)]; + + UIBarButtonItem *actionButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(toggleAll)]; + + self.navigationItem.rightBarButtonItems = @[actionButton]; +} + + +-(int)getDisAppCnt{ + NSMutableDictionary *prefs = [NSMutableDictionary dictionaryWithContentsOfFile:prefPath]; + return [prefs[self.preferencesKey] count]; +} + + +-(void)toggleAll{ + + [[TDUtilities sharedInstance] haptic:0]; + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"App List" message:@"Enable or disable all apps" preferredStyle:UIAlertControllerStyleAlert]; + + [alert addAction:[UIAlertAction actionWithTitle:@"Select All" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + [[TDUtilities sharedInstance] haptic:0]; + NSMutableArray *list = [[NSMutableArray alloc] init]; + //int i = [self getDisAppCnt]; + int i = 0; + NSLog(@"aaaaaa iiiiiiiiiiii:-%d,", i); + for(; i < self.fullAppList.count; i++){ + // int maxApps = i + [self getDisAppCnt]; + NSLog(@"aaaaaa isLimitApps:-%d, appsCapacity:-%ld", self.isLimitApps, (long)self.appsCapacity); + + if(self.isLimitApps && i > self.appsCapacity-1){ + NSString *msg = [NSString stringWithFormat:@"You can't enable more than %ld apps", (long)self.appsCapacity]; + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Sorry" message:msg preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){ + }]; + + [alert addAction:okAction]; + [self presentViewController:alert animated:YES completion:nil]; + + NSLog(@"aaaaaa [list count]:-%ld,", [list count]); + if([list count] ==0) + return; + self.preferencesAppList = [list copy]; + [self updatePreferencesAppList]; + [self.tableView reloadData]; + return; + } + [list addObject:self.fullAppList[i][@"bundleID"]]; + } + self.preferencesAppList = [list copy]; + [self updatePreferencesAppList]; + [self.tableView reloadData]; + }]]; + + + [alert addAction:[UIAlertAction actionWithTitle:@"Unselect All" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + self.preferencesAppList = @[]; + [self updatePreferencesAppList]; + [self.tableView reloadData]; + [[TDUtilities sharedInstance] haptic:0]; + }]]; + + + [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [alert dismissViewControllerAnimated:YES completion:nil]; + }]]; + + [self presentViewController:alert animated:YES completion:nil]; +} + + +- (void)toggleSearch { + if (self.searchController.active) { + self.searchController.active = NO; + } else { + self.searchController.active = YES; + } +} + + +- (void)errorAlert { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Error loading prefs" message:@"Oh no! Something went wrong!" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){ + }]; + + [alert addAction:okAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + + +static void writeToPlist(NSString *key, NSArray *value){ + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + NSLog(@"aaaaaa writeToPlist value:-%@", value); + + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; + if (![settings objectForKey:key]) { + [settings setObject:[NSMutableDictionary new] forKey:key]; + } + [settings setObject:value forKey:key]; + [settings writeToFile:prefPath atomically:YES]; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [self.fullAppList count]; +} + + +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + return 35.0f; +} + + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { + + UIView *sectionHeaderView = [[UIView alloc] initWithFrame:CGRectMake(10, 0, tableView.frame.size.width -10, 120.0)]; + sectionHeaderView.backgroundColor = UIColor.clearColor; + sectionHeaderView.clipsToBounds = true; + + UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + headerLabel.backgroundColor = [UIColor clearColor]; + headerLabel.textColor = self.labelColour; + + headerLabel.textAlignment = NSTextAlignmentLeft; + headerLabel.font = [UIFont boldSystemFontOfSize:26]; + [sectionHeaderView addSubview:headerLabel]; + + headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[headerLabel centerYAnchor] constraintEqualToAnchor:sectionHeaderView.centerYAnchor].active = true; + [headerLabel.leadingAnchor constraintEqualToAnchor:sectionHeaderView.leadingAnchor constant:15].active = YES; + + switch (section) { + case 0: + headerLabel.text = headerTitle; + return sectionHeaderView; + break; + default: + break; + } + + return sectionHeaderView; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + TDAppsCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[TDAppsCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"Cell"]; + } + + selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + + UISwitch *appSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; + appSwitch.onTintColor = self.tintColour; + appSwitch.tag = [[NSString stringWithFormat:@"%ld%ld", (long)indexPath.section + 1, (long)indexPath.row] intValue]; + [appSwitch addTarget:self action:@selector(updateSwitch:) forControlEvents:UIControlEventPrimaryActionTriggered]; + [cell setAccessoryView:appSwitch]; + + if ([self.preferencesAppList containsObject:[[self.fullAppList objectAtIndex:indexPath.row] objectForKey:@"bundleID"]]) { + [appSwitch setOn:YES animated:NO]; + } + + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + cell.backgroundColor = UIColor.clearColor; + cell.appImage.image = [UIImage _applicationIconImageForBundleIdentifier:[[self.fullAppList objectAtIndex:indexPath.row] objectForKey:@"bundleID"] format:2 scale:[UIScreen mainScreen].scale]; + cell.appnameLabel.text = [[self.fullAppList objectAtIndex:indexPath.row] objectForKey:@"name"]; + cell.appBIDLabel.text = [[self.fullAppList objectAtIndex:indexPath.row] objectForKey:@"bundleID"]; + return cell; +} + + +- (void)updatePreferencesAppList { + writeToPlist(self.preferencesKey, self.preferencesAppList); + if (self.postNotification) { + CFNotificationCenterRef r = CFNotificationCenterGetDarwinNotifyCenter(); + CFNotificationCenterPostNotification( + r, (CFStringRef)self.postNotification, NULL, NULL, true); + } + } + + - (void)updateSwitch:(UISwitch *)appSwitch { + NSString *tag = [NSString stringWithFormat:@"%ld", (long)appSwitch.tag]; + NSInteger section = [[tag substringToIndex:1] intValue] - 1; + NSInteger row = [[tag substringFromIndex:1] intValue]; + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section]; + UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; + BOOL on = [(UISwitch *)cell.accessoryView isOn]; + int maxApps = [self getDisAppCnt]; + + // [(UISwitch *)cell.accessoryView setOn:NO animated:NO]; + + NSLog(@"aaaaaa isLimitApps:-%d, maxApps:-%ld appsCapacity:-%ld", self.isLimitApps, (long)maxApps, (long)self.appsCapacity); + NSLog(@"aaaaaaaa maxApps:-%ld, on:-%d", (long)maxApps, on); + if(self.isLimitApps && maxApps >= self.appsCapacity && on){ + NSString *msg = [NSString stringWithFormat:@"You can't disable more than %ld apps", (long)self.appsCapacity]; + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Can't Enable" message:msg preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){ + [(UISwitch *)cell.accessoryView setOn:NO animated:NO]; + }]; + + [alert addAction:okAction]; + [self presentViewController:alert animated:YES completion:nil]; + + } else{ + + NSString *bundleIdentifier = [[self.fullAppList objectAtIndex:indexPath.row] objectForKey:@"bundleID"]; + + NSMutableArray *list = [[NSMutableArray alloc] init]; + + if(self.preferencesAppList) + list = [self.preferencesAppList mutableCopy]; + + if (!on) { + [list removeObject:bundleIdentifier]; + } else { + [list addObject:bundleIdentifier]; + } + + NSLog(@"aaaaaa updateSwitch bundleIdentifier:-%@, list:-%@", bundleIdentifier, list); + + self.preferencesAppList = [list mutableCopy]; + NSLog(@"aaaaaa updateSwitch preferencesAppList:-%@", self.preferencesAppList); + + [self updatePreferencesAppList]; + } + } + + + - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; + } + + + -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + } + + + -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 90; + } + + + - (void)searchWithText:(NSString *)text { + + if (text.length == 0) { + self.fullAppList = self.appList; + [self.resultsTableController.searchTable reloadData]; + + } else { + NSMutableArray *mutableList = [[NSMutableArray alloc] init]; + int count = 0; + for(NSDictionary *data in self.appList){ + NSString *appName = data[@"name"]; + if ([appName.lowercaseString rangeOfString:text.lowercaseString].location != NSNotFound) { + [mutableList addObject:data]; + count++; + } + } + self.fullAppList = [mutableList copy]; + self.resultsTableController.searchResult = [mutableList copy]; + } + + [self.resultsTableController.searchTable reloadData]; + } + + + - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)text { + [self searchWithText:text]; + } + + + - (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar { + [searchBar setShowsCancelButton:YES animated:YES]; + } + + + - (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar { + [self searchWithText:searchBar.text]; + } + + + - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { + [searchBar resignFirstResponder]; + [searchBar setShowsCancelButton:NO animated:YES]; + [searchBar setText:@""]; + self.resultsTableController.searchEnabled = NO; + [self.resultsTableController.searchTable reloadData]; + } + + + - (void)presentSearchController:(UISearchController *)searchController { + [self presentViewController:self.searchController animated:YES completion:nil]; + self.resultsTableController.searchTable.delegate = self; + self.resultsTableController.searchTable.dataSource = self; + self.resultsTableController.searchTable.tableFooterView = [UIView new]; + self.resultsTableController.searchTable.separatorInset = + UIEdgeInsetsMake(0, 10, 0, 10); + self.resultsTableController.searchTable.separatorColor = UIColor.whiteColor; + } + + + - (void)updateSearchResultsForSearchController: + (UISearchController *)searchController { + } + + @end diff --git a/libTitanD3vUniversal/AppList/TDAppsCell.h b/libTitanD3vUniversal/AppList/TDAppsCell.h new file mode 100644 index 0000000..05a6beb --- /dev/null +++ b/libTitanD3vUniversal/AppList/TDAppsCell.h @@ -0,0 +1,13 @@ +#import +#import "TDAppearance.h" + +@interface TDAppsCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *appImage; +@property (nonatomic, retain) UILabel *appnameLabel; +@property (nonatomic, retain) UILabel *appBIDLabel; +@property (nonatomic, retain) UIColor *cellsColour; +@property (nonatomic, retain) UIColor *labelColour; + +@end diff --git a/libTitanD3vUniversal/AppList/TDAppsCell.m b/libTitanD3vUniversal/AppList/TDAppsCell.m new file mode 100644 index 0000000..ad4d277 --- /dev/null +++ b/libTitanD3vUniversal/AppList/TDAppsCell.m @@ -0,0 +1,70 @@ +#import "TDAppsCell.h" + +@implementation TDAppsCell + + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.cellsColour = [[TDAppearance sharedInstance] cellColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + self.baseView = [[UIView alloc] initWithFrame:CGRectZero]; + self.baseView.layer.cornerRadius = 15; + self.baseView.clipsToBounds = true; + self.baseView.backgroundColor = self.cellsColour; + [self addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5].active = YES; + + + self.appImage = [[UIImageView alloc] initWithFrame:CGRectZero]; + self.appImage.layer.cornerRadius = 10; + self.appImage.clipsToBounds = true; + [self.baseView addSubview:self.appImage]; + + self.appImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.appImage.widthAnchor constraintEqualToConstant:50.0].active = YES; + [self.appImage.heightAnchor constraintEqualToConstant:50.0].active = YES; + [[self.appImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.appImage.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10].active = YES; + + + self.appnameLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.appnameLabel.textColor = self.labelColour; + self.appnameLabel.font = [UIFont boldSystemFontOfSize:16]; + self.appnameLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.appnameLabel]; + + self.appnameLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.appnameLabel.heightAnchor constraintEqualToConstant:16.0].active = YES; + [self.appnameLabel.widthAnchor constraintEqualToConstant:220.0].active = YES; + [[self.appnameLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor constant:-10].active = true; + [self.appnameLabel.leadingAnchor constraintEqualToAnchor:self.appImage.trailingAnchor constant:10.0].active = YES; + + + self.appBIDLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.appBIDLabel.textColor = self.labelColour;; + self.appBIDLabel.font = [UIFont systemFontOfSize:12]; + self.appBIDLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.appBIDLabel]; + + self.appBIDLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.appBIDLabel.heightAnchor constraintEqualToConstant:12.0].active = YES; + [self.appBIDLabel.widthAnchor constraintEqualToConstant:220.0].active = YES; + [self.appBIDLabel.topAnchor constraintEqualToAnchor:self.appnameLabel.bottomAnchor constant:5.0].active = YES; + [self.appBIDLabel.leadingAnchor constraintEqualToAnchor:self.appImage.trailingAnchor constant:10.0].active = YES; + + } + + return self; +} + +@end diff --git a/libTitanD3vUniversal/AppList/TDResultsTableController.h b/libTitanD3vUniversal/AppList/TDResultsTableController.h new file mode 100644 index 0000000..8dbf88d --- /dev/null +++ b/libTitanD3vUniversal/AppList/TDResultsTableController.h @@ -0,0 +1,7 @@ +#import + +@interface TDResultsTableController : UIViewController +@property(nonatomic, retain) UITableView *searchTable; +@property(nonatomic, strong) NSArray *searchResult; +@property(nonatomic, assign) BOOL searchEnabled; +@end \ No newline at end of file diff --git a/libTitanD3vUniversal/AppList/TDResultsTableController.m b/libTitanD3vUniversal/AppList/TDResultsTableController.m new file mode 100644 index 0000000..85fbb55 --- /dev/null +++ b/libTitanD3vUniversal/AppList/TDResultsTableController.m @@ -0,0 +1,14 @@ +#import "TDResultsTableController.h" + +@implementation TDResultsTableController +- (void)viewDidLoad { + [super viewDidLoad]; + + self.searchTable = + [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; + self.searchTable.backgroundColor = [UIColor clearColor]; + self.view.backgroundColor = [UIColor colorWithRed:53 / 255.0 green:59 / 255.0 blue:68.0 / 255.0 alpha:0.95]; + self.searchTable.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag; + [self.view addSubview:self.searchTable]; +} +@end diff --git a/libTitanD3vUniversal/Appearance/TDAppearance.h b/libTitanD3vUniversal/Appearance/TDAppearance.h new file mode 100644 index 0000000..c830e5c --- /dev/null +++ b/libTitanD3vUniversal/Appearance/TDAppearance.h @@ -0,0 +1,38 @@ +#import +#import "TDPrefsManager.h" +#import "HEXColour.h" + +@interface TDAppearance : NSObject { + + // NSString *navigationBarDefault; + // NSString *tintDefault; + // NSString *backgroundDefault; + // NSString *cellDefault; + // NSString *labelDefault; + // NSString *bannerDefault; + // NSString *containerDefault; + // NSString *borderDefault; +} + ++(instancetype)sharedInstance; +-(id)init; + +// -(void)defaultNavigationBarColour:(NSString *)defaultColour; +// -(void)defaultTintColour:(NSString *)defaultColour; +// -(void)defaultBackgroundColour:(NSString *)defaultColour; +// -(void)defaultCellColour:(NSString *)defaultColour; +// -(void)defaultLabelColour:(NSString *)defaultColour; +// -(void)defaultBannerColour:(NSString *)defaultColour; +// -(void)defaultContainerColour:(NSString *)defaultColour; +// -(void)defaultBorderColour:(NSString *)defaultColour; + +-(UIColor *)navigationBarColour; +-(UIColor *)tintColour; +-(UIColor *)backgroundColour; +-(UIColor *)cellColour; +-(UIColor *)labelColour; +-(UIColor *)bannerColour; +-(UIColor *)containerColour; +-(UIColor *)borderColour; + +@end diff --git a/libTitanD3vUniversal/Appearance/TDAppearance.m b/libTitanD3vUniversal/Appearance/TDAppearance.m new file mode 100644 index 0000000..7ced7a1 --- /dev/null +++ b/libTitanD3vUniversal/Appearance/TDAppearance.m @@ -0,0 +1,108 @@ +#import "TDAppearance.h" + +@implementation TDAppearance + ++(instancetype)sharedInstance { + static TDAppearance *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[TDAppearance alloc] init]; + }); + return sharedInstance; +} + +- (id)init { + return self; +} + + +// -(void)defaultNavigationBarColour:(NSString *)defaultColour { +// navigationBarDefault = defaultColour; +// } + +// -(void)defaultTintColour:(NSString *)defaultColour { +// tintDefault = defaultColour; +// } + +// -(void)defaultBackgroundColour:(NSString *)defaultColour { +// backgroundDefault = defaultColour; +// } + +// -(void)defaultCellColour:(NSString *)defaultColour { +// cellDefault = defaultColour; +// } + +// -(void)defaultLabelColour:(NSString *)defaultColour { +// labelDefault = defaultColour; +// } + +// -(void)defaultBannerColour:(NSString *)defaultColour { +// bannerDefault = defaultColour; +// } + +// -(void)defaultContainerColour:(NSString *)defaultColour { +// containerDefault = defaultColour; +// } + +// -(void)defaultBorderColour:(NSString *)defaultColour { +// borderDefault = defaultColour; +// } + + +-(UIColor *)navigationBarColour { + + NSString *colourString = @"161616"; + UIColor *color = colorFromHexString(colourString); + return color; +} + +-(UIColor *)tintColour { + + NSString *colourString = @"F1462C"; + UIColor *color = colorFromHexString(colourString); + return color; +} + +-(UIColor *)backgroundColour { + + NSString *colourString = @"161616"; + UIColor *color = colorFromHexString(colourString); + return color; +} + +-(UIColor *)cellColour { + + NSString *colourString = @"1B1B1B"; + UIColor *color = colorFromHexString(colourString); + return color; +} + +-(UIColor *)labelColour { + + NSString *colourString = @"FFFFFF"; + UIColor *color = colorFromHexString(colourString); + return color; +} + +-(UIColor *)bannerColour { + + NSString *colourString = @"1B1B1B"; + UIColor *color = colorFromHexString(colourString); + return color; +} + +-(UIColor *)containerColour { + + NSString *colourString = @"1B1B1B"; + UIColor *color = colorFromHexString(colourString); + return color; +} + +-(UIColor *)borderColour { + + NSString *colourString = @"F1462C"; + UIColor *color = colorFromHexString(colourString); + return color; +} + +@end diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityCellHeaderView.h b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityCellHeaderView.h new file mode 100644 index 0000000..1f31794 --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityCellHeaderView.h @@ -0,0 +1,8 @@ +#import + +@interface TDAvatarIdentityCellHeaderView : UICollectionReusableView +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *headerLabel; +@end + + diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityCellHeaderView.m b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityCellHeaderView.m new file mode 100644 index 0000000..f3af4c1 --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityCellHeaderView.m @@ -0,0 +1,28 @@ +#import "TDAvatarIdentityCellHeaderView.h" + +@implementation TDAvatarIdentityCellHeaderView + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] initWithFrame:self.bounds]; + self.baseView.clipsToBounds = YES; + [self addSubview:self.baseView]; + + + self.headerLabel = [[UILabel alloc] init]; + self.headerLabel.textColor = UIColor.tertiaryLabelColor; + self.headerLabel.font = [UIFont boldSystemFontOfSize:18]; + [self.baseView addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = YES; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:20].active = YES; + + } + return self; +} + +@end diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityEmojiCell.h b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityEmojiCell.h new file mode 100644 index 0000000..2f7caba --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityEmojiCell.h @@ -0,0 +1,7 @@ +#import +#import "ConstraintExtension.h" + +@interface TDAvatarIdentityEmojiCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *emojiLabel; +@end diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityEmojiCell.m b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityEmojiCell.m new file mode 100644 index 0000000..546c20f --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityEmojiCell.m @@ -0,0 +1,40 @@ +#import "TDAvatarIdentityEmojiCell.h" + +@implementation TDAvatarIdentityEmojiCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = self.frame.size.width/2; + self.clipsToBounds = true; + + + self.baseView = [[UIView alloc] initWithFrame:self.contentView.bounds]; + self.baseView.layer.cornerRadius = self.frame.size.width/2; + self.baseView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + + self.emojiLabel = [[UILabel alloc] init]; + self.emojiLabel.textAlignment = NSTextAlignmentCenter; + self.emojiLabel.font = [UIFont systemFontOfSize:45]; + [self.baseView addSubview:self.emojiLabel]; + + [self.emojiLabel x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.emojiLabel.text = nil; +} + + +@end diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerDataSource.h b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerDataSource.h new file mode 100644 index 0000000..0198b6d --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerDataSource.h @@ -0,0 +1,16 @@ +#import +#import + +@interface TDAvatarIdentityPickerEmojiDataModel : NSObject +-(id)initWithEmoji:(NSString *)emoji colour:(NSString *)colour; +@property (nonatomic, retain) NSString *emoji; +@property (nonatomic, retain) NSString *colour; +@end + +@interface TDAvatarIdentityPickerDataSource : NSObject ++(instancetype)sharedInstance; +-(id)init; + +-(NSMutableArray*)stickersData; +-(NSMutableArray*)emojiData; +@end diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerDataSource.m b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerDataSource.m new file mode 100644 index 0000000..f4a66f8 --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerDataSource.m @@ -0,0 +1,101 @@ +#import "TDAvatarIdentityPickerDataSource.h" + +@implementation TDAvatarIdentityPickerEmojiDataModel +-(id)initWithEmoji:(NSString *)emoji colour:(NSString *)colour { + self = [super init]; + if(self) { + self.emoji = emoji; + self.colour = colour; + } + return self; +} +@end + + +@implementation TDAvatarIdentityPickerDataSource + ++(instancetype)sharedInstance { + static TDAvatarIdentityPickerDataSource *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[TDAvatarIdentityPickerDataSource alloc] init]; + }); + return sharedInstance; +} + + +-(id)init { + return self; +} + + +-(NSMutableArray*)stickersData { + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + NSString *stickersPath = @"/var/mobile/Library/Avatar/Stickers"; + + NSMutableArray *folders = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:stickersPath error:nil] mutableCopy]; + + for (int i = 0; i < folders.count; i++) { + + NSString *path = [folders objectAtIndex:i]; + if ([path hasSuffix:@".png"]){ + [array addObject:path]; + } + } + + [array sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + + return array; +} + + +-(NSMutableArray*)emojiData { + + NSMutableArray *array = [[NSMutableArray alloc] init]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"😀" colour:@"a8e6cf"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🥶" colour:@"d0e1f9"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"😜" colour:@"a8e6cf"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"😍" colour:@"ffaaa5"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"😘" colour:@"eedbdb"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🥳" colour:@"dddddd"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"😻" colour:@"e4dcf1"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"💋" colour:@"eee3e7"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"💍" colour:@"e7d3d3"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🦄" colour:@"fec8c1"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🍻" colour:@"96ceb4"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🥂" colour:@"ff6f69"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🍿" colour:@"ffdbac"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"⚽️" colour:@"64a1f4"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🏈" colour:@"add6ff"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🏒" colour:@"ffefd7"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🚗" colour:@"a8e6cf"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🛴" colour:@"dcedc1"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"🚀" colour:@"ffcc5c"]]; + [array addObject:[[TDAvatarIdentityPickerEmojiDataModel alloc] initWithEmoji:@"💻" colour:@"b3cde0"]]; + return array; +} + +@end + + + + + + + + + + + + + + + + + + + + + diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerViewController.h b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerViewController.h new file mode 100644 index 0000000..5609c91 --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerViewController.h @@ -0,0 +1,33 @@ +#import +#import "ConstraintExtension.h" +#import "TDHeaderView.h" +#import "TDAvatarIdentityToolsCell.h" +#import "TDAvatarIdentityCellHeaderView.h" +#import "TDAvatarIdentityStickerCell.h" +#import "TDAvatarIdentityEmojiCell.h" +#import "TDAvatarIdentityPickerDataSource.h" +#import "TDEmojiPickerViewController.h" + +@protocol TDAvatarPickerProtocol +@required +-(void)didCreatedAvatar:(UIImage *)avatar; +-(void)didDismissedAvatarPicker; +@end + +@interface TDAvatarIdentityPickerViewController : UIViewController +-(instancetype)initWithTitle:(NSString *)title showDefaultAvatar:(BOOL)defaultAvatar avatarImage:(UIImage *)avatar accent:(UIColor *)accent; +@property (nonatomic, retain) TDHeaderView *headerView; +@property (nonatomic, retain) UIView *preview; +@property (nonatomic, retain) UIImageView *previewImage; +@property (nonatomic, retain) UIImageView *stickerImage; +@property (nonatomic, retain) UILabel *emojiLabel; +@property (nonatomic, retain) UITextField *textField; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *stickersArray; +@property (nonatomic, retain) NSMutableArray *emojisArray; +@property(nonatomic,assign)id delegate; +@property (nonatomic, retain) NSString *titleString; +@property (nonatomic) BOOL useDefaultAvatarImage; +@property (nonatomic, retain) UIImage *defaultAvatar; +@property (nonatomic, retain) UIColor *accentColour; +@end diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerViewController.m b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerViewController.m new file mode 100644 index 0000000..5ace16a --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityPickerViewController.m @@ -0,0 +1,453 @@ +#import "TDAvatarIdentityPickerViewController.h" + +@implementation TDAvatarIdentityPickerViewController + +-(instancetype)initWithTitle:(NSString *)title showDefaultAvatar:(BOOL)defaultAvatar avatarImage:(UIImage *)avatar accent:(UIColor *)accent { + + self = [super init]; + if (self) { + self.titleString = title; + self.useDefaultAvatarImage = defaultAvatar; + self.defaultAvatar = avatar; + self.accentColour = accent; + } + return self; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.systemBackgroundColor; + self.view.tintColor = self.accentColour; + + UIWindow *window = [UIApplication sharedApplication].windows.firstObject; + window.tintColor = self.accentColour; + + self.stickersArray = [[TDAvatarIdentityPickerDataSource sharedInstance] stickersData]; + self.emojisArray = [[TDAvatarIdentityPickerDataSource sharedInstance] emojiData]; + + [self layoutHeaderView]; + [self layoutCollectionView]; +} + + +-(void)layoutHeaderView { + + self.headerView = [[TDHeaderView alloc] initWithTitle:self.titleString accent:self.accentColour leftIcon:@"xmark" leftAction:@selector(dismissVC) rightIcon:@"checkmark" rightAction:@selector(applyAvatar)]; + self.headerView.rightButton.backgroundColor = self.accentColour; + self.headerView.rightButton.tintColor = UIColor.whiteColor; + self.headerView.rightButton.alpha = 0; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.topAnchor padding:0]; + + + self.preview = [[UIView alloc] init]; + self.preview.backgroundColor = [self colorWithHexString:@"64a1f4"]; + self.preview.layer.cornerRadius = 55; + self.preview.clipsToBounds = YES; + [self.view addSubview:self.preview]; + + [self.preview size:CGSizeMake(110, 110)]; + [self.preview x:self.view.centerXAnchor]; + [self.preview top:self.headerView.bottomAnchor padding:20]; + + + self.previewImage = [[UIImageView alloc] init]; + self.previewImage.contentMode = UIViewContentModeScaleAspectFill; + if (!self.useDefaultAvatarImage) { + self.previewImage.image = self.defaultAvatar; + } + [self.preview addSubview:self.previewImage]; + + [self.previewImage size:CGSizeMake(110, 110)]; + [self.previewImage x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; + + + self.stickerImage = [[UIImageView alloc] init]; + self.stickerImage.contentMode = UIViewContentModeScaleAspectFill; + self.stickerImage.alpha = 0; + [self.preview addSubview:self.stickerImage]; + + [self.stickerImage size:CGSizeMake(80, 80)]; + [self.stickerImage x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; + + + self.emojiLabel = [[UILabel alloc] init]; + self.emojiLabel.textAlignment = NSTextAlignmentCenter; + self.emojiLabel.font = [UIFont systemFontOfSize:67]; + if (self.useDefaultAvatarImage) { + self.emojiLabel.text = @"😀"; + } else { + self.emojiLabel.alpha = 0; + } + [self.preview addSubview:self.emojiLabel]; + + [self.emojiLabel x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; + + + self.textField = [[UITextField alloc] init]; + self.textField.backgroundColor = UIColor.clearColor; + self.textField.tintColor = self.accentColour; + self.textField.textAlignment = NSTextAlignmentCenter; + self.textField.font = [UIFont systemFontOfSize:47 weight:UIFontWeightBold]; + self.textField.autocapitalizationType = UITextAutocapitalizationTypeAllCharacters; + self.textField.delegate = self; + self.textField.returnKeyType = UIReturnKeyDone; + self.textField.alpha = 0; + [self.preview addSubview:self.textField]; + + [self.textField size:CGSizeMake(105, 105)]; + [self.textField x:self.preview.centerXAnchor y:self.preview.centerYAnchor]; + +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[TDAvatarIdentityToolsCell class] forCellWithReuseIdentifier:@"ToolsCell"]; + [self.collectionView registerClass:[TDAvatarIdentityStickerCell class] forCellWithReuseIdentifier:@"StickerCell"]; + [self.collectionView registerClass:[TDAvatarIdentityEmojiCell class] forCellWithReuseIdentifier:@"EmojiCell"]; + [self.collectionView registerClass:[TDAvatarIdentityCellHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; + [self.view addSubview:self.collectionView]; + + [self.collectionView top:self.preview.bottomAnchor padding:20]; + [self.collectionView bottom:self.view.bottomAnchor padding:-20]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView { + return 3; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { + return CGSizeMake(self.view.frame.size.width, 45); +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + + if (section == 0) { + return 4; + } else if (section == 1) { + return self.stickersArray.count; + } else { + return self.emojisArray.count; + } +} + + +-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + UICollectionReusableView *reusableview = nil; + + if (kind == UICollectionElementKindSectionHeader) { + + TDAvatarIdentityCellHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; + + NSArray *titleArray = [[NSArray alloc] initWithObjects:@"", @"Stickers", @"More", nil]; + + headerView.headerLabel.text = [titleArray objectAtIndex:indexPath.section]; + reusableview = headerView; + } + + return reusableview; + +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + if (indexPath.section == 0) { + + TDAvatarIdentityToolsCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ToolsCell" forIndexPath:indexPath]; + + cell.baseView.backgroundColor = [self.accentColour colorWithAlphaComponent:0.4]; + cell.baseView.layer.borderWidth = 0.8; + cell.baseView.layer.borderColor = [self.accentColour colorWithAlphaComponent:0.7].CGColor; + cell.iconImage.tintColor = self.accentColour; + + if (indexPath.row == 0) { + cell.iconImage.image = [UIImage systemImageNamed:@"photo.fill.on.rectangle.fill"]; + } else if (indexPath.row == 1) { + cell.iconImage.image = [UIImage systemImageNamed:@"paintpalette.fill"]; + } else if (indexPath.row == 2) { + cell.iconImage.image = [UIImage systemImageNamed:@"face.smiling.fill"]; + } else if (indexPath.row == 3) { + cell.iconImage.image = [UIImage systemImageNamed:@"textformat"]; + } + + return cell; + + } else if (indexPath.section == 1) { + + TDAvatarIdentityStickerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"StickerCell" forIndexPath:indexPath]; + + cell.iconImage.image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/var/mobile/Library/Avatar/Stickers/%@", [self.stickersArray objectAtIndex:indexPath.row]]]; + return cell; + + } else { + + TDAvatarIdentityEmojiCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"EmojiCell" forIndexPath:indexPath]; + + TDAvatarIdentityPickerEmojiDataModel *emojiData = [self.emojisArray objectAtIndex:indexPath.row]; + + cell.baseView.backgroundColor = [self colorWithHexString:emojiData.colour]; + cell.emojiLabel.text = emojiData.emoji; + + return cell; + } + +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ + return CGSizeMake(self.view.frame.size.width/4-20, self.view.frame.size.width/4-20); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + self.modalInPresentation = YES; + self.headerView.rightButton.alpha = 1; + + if (indexPath.section == 0) { + + if (indexPath.row == 0) { + [self presentPhotoPickerVC]; + } else if (indexPath.row == 1) { + [self presentColourPickerVC]; + } else if (indexPath.row == 2) { + [self presentEmojiPickerVC]; + } else if (indexPath.row == 3) { + [self presentKeyboardEditing]; + } + + } else if (indexPath.section == 1) { + + [self.textField resignFirstResponder]; + self.previewImage.alpha = 0; + self.emojiLabel.alpha = 0; + self.stickerImage.alpha = 1; + self.textField.alpha = 0; + self.stickerImage.image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"/var/mobile/Library/Avatar/Stickers/%@", [self.stickersArray objectAtIndex:indexPath.row]]]; + + } else if (indexPath.section == 2) { + + [self.textField resignFirstResponder]; + self.previewImage.alpha = 0; + self.emojiLabel.alpha = 1; + self.stickerImage.alpha = 0; + self.textField.alpha = 0; + + TDAvatarIdentityPickerEmojiDataModel *emojiData = [self.emojisArray objectAtIndex:indexPath.row]; + self.preview.backgroundColor = [self colorWithHexString:emojiData.colour]; + self.emojiLabel.text = emojiData.emoji; + } + + +} + + +-(void)presentPhotoPickerVC { + + UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init]; + imagePickerController.delegate = self; + imagePickerController.allowsEditing = false; + imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [self presentViewController:imagePickerController animated:YES completion:nil]; + +} + + +-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(nonnull NSDictionary *)info { + + [self.textField resignFirstResponder]; + self.previewImage.alpha = 1; + self.stickerImage.alpha = 0; + self.emojiLabel.alpha = 0; + self.textField.alpha = 0; + + self.previewImage.image = info[UIImagePickerControllerOriginalImage]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)presentColourPickerVC { + [self.textField resignFirstResponder]; + if (@available(iOS 14.0, *)) { + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + colourPickerVC.selectedColor = self.preview.backgroundColor; + colourPickerVC.supportsAlpha = NO; + [self presentViewController:colourPickerVC animated:YES completion:nil]; + } +} + + +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController API_AVAILABLE(ios(14.0)){ + self.previewImage.alpha = 0; + UIColor *cpSelectedColour = viewController.selectedColor; + self.preview.backgroundColor = cpSelectedColour; +} + + +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController API_AVAILABLE(ios(14.0)){ + self.previewImage.alpha = 0; + UIColor *cpSelectedColour = viewController.selectedColor; + self.preview.backgroundColor = cpSelectedColour; +} + + +-(void)presentEmojiPickerVC { + [self.textField resignFirstResponder]; + TDEmojiPickerViewController *vc = [[TDEmojiPickerViewController alloc] init]; + vc.delegate = self; + [self presentViewController:vc animated:YES completion:nil]; +} + + +-(void)presentKeyboardEditing { + + self.emojiLabel.alpha = 0; + self.previewImage.alpha = 0; + self.textField.alpha = 1; + self.stickerImage.alpha = 0; + self.emojiLabel.text = 0; + + [self.textField becomeFirstResponder]; + +} + + +-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { + + if (textField.text.length >= 2 && range.length == 0) { + return NO; + } else { + return YES; + + } +} + + +-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + textField.userInteractionEnabled = NO; + return YES; +} + + +-(void)textFieldDidEndEditing:(UITextField *)textField { + textField.userInteractionEnabled = YES; +} + + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + if (textField.text.length >= 1) { + [textField resignFirstResponder]; + return YES; + } else { + return NO; + } +} + + +-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ + [self.view endEditing:YES]; +} + + +-(void)didSelectEmoji:(NSString *)emoji { + self.emojiLabel.alpha = 1; + self.previewImage.alpha = 0; + self.textField.alpha = 0; + self.stickerImage.alpha = 0; + self.emojiLabel.text = emoji; +} + + +-(void)didDismissedEmojiPicker { + NSLog(@"Emoji picker dismissed"); +} + + +-(void)dismissVC { + [self.delegate didDismissedAvatarPicker]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)applyAvatar { + [self.textField resignFirstResponder]; + [self.delegate didCreatedAvatar:[self avatarSnapshot]]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(UIImage *)avatarSnapshot { + + UIGraphicsBeginImageContextWithOptions(self.preview.frame.size, NO, 0); + CGContextRef context = UIGraphicsGetCurrentContext(); + [self.preview.layer renderInContext:context]; + UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext(); + return snapshotImage; +} + + +-(UIColor*)colorWithHexString:(NSString*)hex { + + NSString *cString = [[hex stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; + + if ([cString length] < 6) return [UIColor grayColor]; + + if ([cString hasPrefix:@"0X"]) cString = [cString substringFromIndex:2]; + + if ([cString length] != 6) return [UIColor grayColor]; + + NSRange range; + range.location = 0; + range.length = 2; + NSString *rString = [cString substringWithRange:range]; + + range.location = 2; + NSString *gString = [cString substringWithRange:range]; + + range.location = 4; + NSString *bString = [cString substringWithRange:range]; + + unsigned int r, g, b; + [[NSScanner scannerWithString:rString] scanHexInt:&r]; + [[NSScanner scannerWithString:gString] scanHexInt:&g]; + [[NSScanner scannerWithString:bString] scanHexInt:&b]; + + return [UIColor colorWithRed:((float) r / 255.0f) green:((float) g / 255.0f) blue:((float) b / 255.0f) alpha:1.0f]; +} + +@end diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityStickerCell.h b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityStickerCell.h new file mode 100644 index 0000000..bb1ea84 --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityStickerCell.h @@ -0,0 +1,7 @@ +#import +#import "ConstraintExtension.h" + +@interface TDAvatarIdentityStickerCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@end diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityStickerCell.m b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityStickerCell.m new file mode 100644 index 0000000..6e71c20 --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityStickerCell.m @@ -0,0 +1,32 @@ +#import "TDAvatarIdentityStickerCell.h" + +@implementation TDAvatarIdentityStickerCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + + self.baseView = [[UIView alloc] initWithFrame:self.contentView.bounds]; + [self.contentView addSubview:self.baseView]; + + + self.iconImage = [[UIImageView alloc] init]; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(self.frame.size.width, self.frame.size.width)]; + [self.iconImage x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.iconImage.image = nil; +} + + +@end diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityToolsCell.h b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityToolsCell.h new file mode 100644 index 0000000..18d7dda --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityToolsCell.h @@ -0,0 +1,7 @@ +#import +#import "ConstraintExtension.h" + +@interface TDAvatarIdentityToolsCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@end diff --git a/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityToolsCell.m b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityToolsCell.m new file mode 100644 index 0000000..b5a1d78 --- /dev/null +++ b/libTitanD3vUniversal/AvatarPicker/TDAvatarIdentityToolsCell.m @@ -0,0 +1,39 @@ +#import "TDAvatarIdentityToolsCell.h" + +@implementation TDAvatarIdentityToolsCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.layer.cornerRadius = self.frame.size.width/2; + self.clipsToBounds = true; + + + self.baseView = [[UIView alloc] initWithFrame:self.contentView.bounds]; + self.baseView.layer.cornerRadius = self.frame.size.width/2; + self.baseView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(self.frame.size.width/2, self.frame.size.width/2)]; + [self.iconImage x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.iconImage.image = nil; +} + + +@end diff --git a/libTitanD3vUniversal/Banner/TDBannerView.h b/libTitanD3vUniversal/Banner/TDBannerView.h new file mode 100644 index 0000000..9720189 --- /dev/null +++ b/libTitanD3vUniversal/Banner/TDBannerView.h @@ -0,0 +1,17 @@ +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface TDBannerView : UIView + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *bannerImage; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UIColor *bannerColour; +@property (nonatomic, retain) UIColor *labelColour; +@property (nonatomic, retain) UIColor *tintColour; + +@end diff --git a/libTitanD3vUniversal/Banner/TDBannerView.m b/libTitanD3vUniversal/Banner/TDBannerView.m new file mode 100644 index 0000000..f8e451d --- /dev/null +++ b/libTitanD3vUniversal/Banner/TDBannerView.m @@ -0,0 +1,200 @@ +#import "TDBannerView.h" + +NSDate *todaysDate; +NSDateFormatter *todaysDateFormat; +NSString *todaysDateString; + +@implementation TDBannerView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + self.backgroundColor = UIColor.clearColor; + + self.bannerColour = [[TDAppearance sharedInstance] bannerColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *bannerCoverPath = [[TDPrefsManager sharedInstance] getBannerCoverPath]; + NSString *bannerCoverString = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, bannerCoverPath]; + NSString *bannerIconPath = [[TDPrefsManager sharedInstance] getBannerIconPath]; + NSString *bannerIconString = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, bannerIconPath]; + + BOOL useBanner = [[TDPrefsManager sharedInstance] bannerWithCoverImage]; + BOOL iconTint = [[TDPrefsManager sharedInstance] bannerWithIconTint]; + + + self.baseView = [[UIView alloc] init]; + self.baseView.layer.cornerRadius = 25; + if(@available(iOS 13.0, *)) { + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + } + if (useBanner) { + self.baseView.backgroundColor = UIColor.clearColor;; + } else { + self.baseView.backgroundColor = self.bannerColour; + } + self.baseView.clipsToBounds = true; + [self addSubview:self.baseView]; + + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.topAnchor constraintEqualToAnchor:self.topAnchor constant:10].active = YES; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-10].active = YES; + + + self.bannerImage = [[UIImageView alloc] init]; + self.bannerImage.contentMode = UIViewContentModeScaleAspectFill; + self.bannerImage.image = [[UIImage imageWithContentsOfFile:bannerCoverString]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + if (useBanner) { + self.bannerImage.alpha = 1; + } else { + self.bannerImage.alpha = 0; + } + [self.baseView addSubview:self.bannerImage]; + + self.bannerImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.bannerImage.topAnchor constraintEqualToAnchor:self.baseView.topAnchor].active = YES; + [self.bannerImage.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor].active = YES; + [self.bannerImage.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor].active = YES; + [self.bannerImage.bottomAnchor constraintEqualToAnchor:self.baseView.bottomAnchor].active = YES; + + + self.iconImage = [[UIImageView alloc] initWithFrame:CGRectZero]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFill; + self.iconImage.userInteractionEnabled = true; + self.iconImage.alpha = 0; + if (iconTint) { + self.iconImage.image = [[UIImage imageWithContentsOfFile:bannerIconString]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.iconImage.tintColor = self.tintColour; + } else { + self.iconImage.image = [[UIImage imageWithContentsOfFile:bannerIconString]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + } + [self.baseView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:90].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor constant:-35].active = true; + + + self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.titleLabel.text = [[TDPrefsManager sharedInstance] getBannerTitle]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.font = [UIFont boldSystemFontOfSize:30]; + self.titleLabel.textColor = self.labelColour; + self.titleLabel.alpha = 0; + [self.baseView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.titleLabel centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + [self.titleLabel.topAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant: 10].active = YES; + [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant: 10].active = YES; + [self.titleLabel.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant: -10].active = YES; + + + self.subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.subtitleLabel.text = [[TDPrefsManager sharedInstance] getBannerSubtitle]; + self.subtitleLabel.textAlignment = NSTextAlignmentCenter; + self.subtitleLabel.font = [UIFont systemFontOfSize:14]; + self.subtitleLabel.textColor = self.labelColour; + self.subtitleLabel.alpha = 0; + [self.baseView addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.subtitleLabel centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + [self.subtitleLabel.topAnchor constraintEqualToAnchor:self.titleLabel.bottomAnchor constant: 10].active = YES; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant: 10].active = YES; + [self.subtitleLabel.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant: -10].active = YES; + + + NSString *birthdayDate = [[TDPrefsManager sharedInstance] objectForKey:@"profileDOB" defaultValue:@"22/11"]; + NSString *devName = [[TDPrefsManager sharedInstance] getDeveloperName]; + NSString *developerString = [NSString stringWithFormat:@"From %@", devName]; + + todaysDate = [NSDate date]; + todaysDateFormat = [[NSDateFormatter alloc] init]; + [todaysDateFormat setDateFormat:@"dd/MM"]; + todaysDateString = [todaysDateFormat stringFromDate:todaysDate]; + + if ([todaysDateString isEqualToString:birthdayDate]) { + + self.titleLabel.text = @"Happy Birthday"; + self.subtitleLabel.text = developerString; + + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Events/birthday.png"]; + + } + + + NSDate * now = [NSDate date]; + NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; + NSDateComponents *monthComponents = [gregorian components:NSCalendarUnitMonth fromDate:now]; + NSDateComponents *dayComponents = [gregorian components:NSCalendarUnitDay fromDate:now]; + + + if ([dayComponents day] == 4 && [monthComponents month] == 7) { + + self.titleLabel.text = @"Happy 4th July"; + self.subtitleLabel.text = developerString; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Events/fourth-july.png"]; + + } else if ([dayComponents day] == 31 && [monthComponents month] == 10) { + + self.titleLabel.text = @"Happy Halloween"; + self.subtitleLabel.text = developerString; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Events/halloween.png"]; + + } else if ([dayComponents day] == 25 && [monthComponents month] == 12) { + + self.titleLabel.text = @"Merry Christmas"; + self.subtitleLabel.text = developerString; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Events/christmas.png"]; + self.iconImage.layer.borderColor = UIColor.clearColor.CGColor; + + } else if ([dayComponents day] == 31 && [monthComponents month] == 12) { + + self.titleLabel.text = @"Happy New Year Eve"; + self.subtitleLabel.text = developerString; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Events/nye.png"]; + + } else if ([dayComponents day] == 1 && [monthComponents month] == 1) { + + self.titleLabel.text = @"Happy New Year"; + self.subtitleLabel.text = developerString; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Events/nyd.png"]; + + } + + + } + + return self; +} + + +-(void)didMoveToSuperview { + [super didMoveToSuperview]; + [self fadeInBanner]; +} + + +-(void)fadeInBanner { + + [UIView animateWithDuration:1.0 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ + self.iconImage.alpha = 1; + self.titleLabel.alpha = 1; + self.subtitleLabel.alpha = 1; + } completion:nil]; + +} + + +@end diff --git a/libTitanD3vUniversal/BlurView/TDBlurView.h b/libTitanD3vUniversal/BlurView/TDBlurView.h new file mode 100644 index 0000000..8cf3864 --- /dev/null +++ b/libTitanD3vUniversal/BlurView/TDBlurView.h @@ -0,0 +1,12 @@ +#import + +typedef enum BlurStyle : NSUInteger { + Light, + Dark, + Dynamic +} BlurStyle; + +@interface TDBlurView : UIView +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +-(instancetype)initWithFrame:(CGRect)frame style:(BlurStyle)blurStyle; +@end diff --git a/libTitanD3vUniversal/BlurView/TDBlurView.m b/libTitanD3vUniversal/BlurView/TDBlurView.m new file mode 100644 index 0000000..50bcd79 --- /dev/null +++ b/libTitanD3vUniversal/BlurView/TDBlurView.m @@ -0,0 +1,35 @@ +#import "TDBlurView.h" + +@implementation TDBlurView + +-(instancetype)initWithFrame:(CGRect)frame style:(BlurStyle)blurStyle { + + self = [super initWithFrame:frame]; + if (self) { + + self.blurEffectView = [[UIVisualEffectView alloc] init]; + [self insertSubview:self.blurEffectView atIndex:0]; + + self.blurEffectView.translatesAutoresizingMaskIntoConstraints = false; + [self.blurEffectView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0].active = YES; + [self.blurEffectView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0].active = YES; + [self.blurEffectView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:0].active = YES; + [self.blurEffectView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0].active = YES; + + + if(blurStyle == Light) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; + } else if (blurStyle == Dark) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + }else if (blurStyle == Dynamic) { + + if (@available(iOS 13.0, *)) { + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemMaterial]; + } + } + + } + return self; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDAppLinkCell.h b/libTitanD3vUniversal/Cells/TDAppLinkCell.h new file mode 100644 index 0000000..21246e9 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDAppLinkCell.h @@ -0,0 +1,16 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface TDAppLinkCell: PSTableCell { + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UIColor *tintColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDAppLinkCell.m b/libTitanD3vUniversal/Cells/TDAppLinkCell.m new file mode 100644 index 0000000..a81bde6 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDAppLinkCell.m @@ -0,0 +1,63 @@ +#import "TDAppLinkCell.h" + +@implementation TDAppLinkCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + + self.iconImage = [[UIImageView alloc]init]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:-9].active = true; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + self.subtitleLabel = [[UILabel alloc]init]; + [self.subtitleLabel setText:specifier.properties[@"subtitle"]]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.subtitleLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:9].active = true; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + } + + return self; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDAppearanceCell.h b/libTitanD3vUniversal/Cells/TDAppearanceCell.h new file mode 100644 index 0000000..cccf5b0 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDAppearanceCell.h @@ -0,0 +1,12 @@ +#import +#import "TDAppearanceOptionView.h" + +@interface TDAppearanceCell : PSTableCell { + float inset; +} +@end + +@interface PSSpecifier (PrivateMethods) +-(void)performSetterWithValue:(id)value; +-(id)performGetter; +@end diff --git a/libTitanD3vUniversal/Cells/TDAppearanceCell.m b/libTitanD3vUniversal/Cells/TDAppearanceCell.m new file mode 100644 index 0000000..e76755a --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDAppearanceCell.m @@ -0,0 +1,76 @@ +#import "TDAppearanceCell.h" +//#import "../Global-Prefs.h" + +@implementation TDAppearanceCell { + UIStackView *_stackView; +} + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)identifier specifier:(PSSpecifier *)specifier { + self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier specifier:specifier]; + + if(self) { + + specifier.properties[@"height"] = [NSNumber numberWithInt:160]; + + NSMutableArray *optionViewArray = [[NSMutableArray alloc] init]; + NSDictionary *options = [specifier propertyForKey:@"options"]; + + for(NSString *key in options) { + NSDictionary *optionProperties = [options objectForKey:key]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/%@.png", [optionProperties objectForKey:@"imageName"]]; + + TDAppearanceOptionView *optionView = [[TDAppearanceOptionView alloc] initWithFrame:CGRectZero appearanceOption:[optionProperties objectForKey:@"appearanceOption"]]; + optionView.delegate = self; + optionView.label.text = [optionProperties objectForKey:@"title"]; + optionView.previewImage = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + optionView.tag = [[optionProperties objectForKey:@"arrangement"] integerValue]; + optionView.translatesAutoresizingMaskIntoConstraints = NO; + + [optionViewArray addObject:optionView]; + } + + + NSSortDescriptor *ascendingSort = [[NSSortDescriptor alloc] initWithKey:@"tag" ascending:YES]; + _stackView = [[UIStackView alloc] initWithArrangedSubviews:[optionViewArray sortedArrayUsingDescriptors:@[ascendingSort]]]; + _stackView.alignment = UIStackViewAlignmentCenter; + _stackView.axis = UILayoutConstraintAxisHorizontal; + _stackView.distribution = UIStackViewDistributionFillEqually; + _stackView.spacing = 0; + _stackView.translatesAutoresizingMaskIntoConstraints = NO; + [self.contentView addSubview:_stackView]; + + for(TDAppearanceOptionView *view in _stackView.arrangedSubviews) { + view.enabled = [view.appearanceOption isEqual:[specifier performGetter]]; + view.highlighted = [view.appearanceOption isEqual:[specifier performGetter]]; + } + + [NSLayoutConstraint activateConstraints:@[ + [_stackView.topAnchor constraintEqualToAnchor:self.topAnchor], + [_stackView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], + [_stackView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor], + [_stackView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor], + ]]; + } + + return self; +} + + +-(void)selectedOption:(TDAppearanceOptionView *)option { + [self.specifier performSetterWithValue:option.appearanceOption]; + + for(TDAppearanceOptionView *view in _stackView.arrangedSubviews) { + [view updateViewForAppearance:option.appearanceOption]; + } +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDAppearanceOptionView.h b/libTitanD3vUniversal/Cells/TDAppearanceOptionView.h new file mode 100644 index 0000000..7e2b5aa --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDAppearanceOptionView.h @@ -0,0 +1,21 @@ +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@class TDAppearanceOptionView; +@protocol TDAppearanceOptionViewDelegate +-(void)selectedOption:(TDAppearanceOptionView *)option; +@end + +@interface TDAppearanceOptionView : UIView +@property (nonatomic, weak) id delegate; +@property (nonatomic, retain) id appearanceOption; +@property (nonatomic, assign) BOOL enabled; +@property (nonatomic, assign) BOOL highlighted; +@property (nonatomic, retain) UIImageView *previewImageView; +@property (nonatomic, retain) UIImage *previewImage; +@property (nonatomic, retain) UILabel *label; +@property (nonatomic, retain) UIColor *tintColour; +-(id)initWithFrame:(CGRect)frame appearanceOption:(id)option; +-(void)updateViewForAppearance:(NSString *)style; +@end diff --git a/libTitanD3vUniversal/Cells/TDAppearanceOptionView.m b/libTitanD3vUniversal/Cells/TDAppearanceOptionView.m new file mode 100644 index 0000000..852a992 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDAppearanceOptionView.m @@ -0,0 +1,101 @@ +#import "TDAppearanceOptionView.h" + +@implementation TDAppearanceOptionView { + UIStackView *_stackView; + UITapGestureRecognizer *_tapGesture; + UIImpactFeedbackGenerator *appearanceHapticFeedback; +} + +-(id)initWithFrame:(CGRect)frame appearanceOption:(id)option { + self = [super initWithFrame:frame]; + + if(self) { + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + _appearanceOption = option; + + _previewImageView = [[UIImageView alloc] initWithFrame:CGRectZero]; + _previewImageView.clipsToBounds = YES; + _previewImageView.contentMode = UIViewContentModeScaleAspectFit; + _previewImageView.layer.cornerRadius = 8; + _previewImageView.layer.borderColor = self.tintColour.CGColor; + _previewImageView.translatesAutoresizingMaskIntoConstraints = NO; + + _label = [[UILabel alloc] initWithFrame:CGRectZero]; + _label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightLight]; + _label.textAlignment = NSTextAlignmentCenter; + _label.translatesAutoresizingMaskIntoConstraints = NO; + + _stackView = [[UIStackView alloc] initWithArrangedSubviews:@[_previewImageView, _label]]; + _stackView.alignment = UIStackViewAlignmentCenter; + _stackView.axis = UILayoutConstraintAxisVertical; + _stackView.distribution = UIStackViewDistributionEqualSpacing; + _stackView.spacing = 5; + _stackView.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:_stackView]; + + [NSLayoutConstraint activateConstraints:@[ + [_stackView.topAnchor constraintEqualToAnchor:self.topAnchor], + [_stackView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], + [_stackView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor], + [_stackView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor], + ]]; + + _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; + [self addGestureRecognizer:_tapGesture]; + } + + return self; +} + +-(void)setPreviewImage:(UIImage *)image { + _previewImage = image; + _previewImageView.image = _previewImage; +} + +-(void)setEnabled:(BOOL)enabled { + _enabled = enabled; +} + +-(void)setHighlighted:(BOOL)highlighted { + _highlighted = highlighted; + + if(_highlighted) { + CABasicAnimation *showBorder = [CABasicAnimation animationWithKeyPath:@"borderWidth"]; + showBorder.duration = 0.1; + showBorder.fromValue = @0; + showBorder.toValue = @3; + + _previewImageView.layer.borderWidth = 3; + [_previewImageView.layer addAnimation:showBorder forKey:@"Show Border"]; + } + + if(!_highlighted && _previewImageView.layer.borderWidth == 3) { + CABasicAnimation *hideBorder = [CABasicAnimation animationWithKeyPath:@"borderWidth"]; + hideBorder.duration = 0.1; + hideBorder.fromValue = @3; + hideBorder.toValue = @0; + + _previewImageView.layer.borderWidth = 0; + [_previewImageView.layer addAnimation:hideBorder forKey:@"Hide Border"]; + } +} + +-(void)updateViewForAppearance:(NSString *)style { + self.enabled = [style isEqualToString:_appearanceOption]; + self.highlighted = [style isEqualToString:_appearanceOption]; +} + +-(void)handleTap:(UIGestureRecognizer *)gesture { + if(gesture.state == UIGestureRecognizerStateRecognized) { + [self.delegate selectedOption:self]; + appearanceHapticFeedback = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; + [appearanceHapticFeedback impactOccurred]; + } +} + +-(BOOL)gestureRecognizer:(id)gesture shouldRecognizeSimultaneouslyWithGestureRecognizer:(id)otherGesture { + return YES; +} +@end diff --git a/libTitanD3vUniversal/Cells/TDButtonCell.h b/libTitanD3vUniversal/Cells/TDButtonCell.h new file mode 100644 index 0000000..b43c51a --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDButtonCell.h @@ -0,0 +1,17 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface TDButtonCell : PSTableCell { + float inset; + NSString *customIconPath; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UIColor *tintColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDButtonCell.m b/libTitanD3vUniversal/Cells/TDButtonCell.m new file mode 100644 index 0000000..5a0faba --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDButtonCell.m @@ -0,0 +1,62 @@ +#import "TDButtonCell.h" + +@implementation TDButtonCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + + self.iconImage = [[UIImageView alloc]init]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:-9].active = true; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + self.subtitleLabel = [[UILabel alloc]init]; + [self.subtitleLabel setText:specifier.properties[@"subtitle"]]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.subtitleLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:9].active = true; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + } + + return self; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDDatePickerCell.h b/libTitanD3vUniversal/Cells/TDDatePickerCell.h new file mode 100644 index 0000000..ec04687 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDDatePickerCell.h @@ -0,0 +1,29 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "TDDatePickerVC.h" +#import "TDUtilities.h" + +@interface TDDatePickerCell : PSTableCell { + TDDatePickerVC *datePickerVC; + NSDate *pickedDate; + NSDateFormatter *pickedDateFormat; + NSString *pickedDateString; + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UILabel *dateLabel; +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIDatePicker *datePicker; +@property (nonatomic, retain) UIButton *doneButton; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *containerColour; +@property (nonatomic, retain) UIColor *labelColour; +@property (nonatomic, retain) UIColor *borderColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDDatePickerCell.m b/libTitanD3vUniversal/Cells/TDDatePickerCell.m new file mode 100644 index 0000000..d437a1d --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDDatePickerCell.m @@ -0,0 +1,283 @@ +#import "TDDatePickerCell.h" + +@implementation TDDatePickerCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + if (self) { + + self.containerColour = [[TDAppearance sharedInstance] containerColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + self.borderColour = [[TDAppearance sharedInstance] borderColour]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + + self.iconImage = [[UIImageView alloc]init]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:-9].active = true; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + self.subtitleLabel = [[UILabel alloc]init]; + [self.subtitleLabel setText:specifier.properties[@"subtitle"]]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.subtitleLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:9].active = true; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + self.dateLabel = [[UILabel alloc]init]; + self.subtitleLabel.font = [UIFont boldSystemFontOfSize:12]; + [self addSubview:self.dateLabel]; + + self.dateLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.dateLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.dateLabel.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = YES; + + } + + return self; +} + + +- (id)target { + return self; +} + + +- (id)cellTarget { + return self; +} + + +- (SEL)action { + return @selector(openDatePicker); +} + + +- (SEL)cellAction { + return @selector(openDatePicker); +} + + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + [self.specifier setTarget:self]; + [self.specifier setButtonAction:@selector(openDatePicker)]; + + + UIView *blankView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 30, 30)]; + [blankView setClipsToBounds:YES]; + [self setAccessoryView:blankView]; + + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + NSString *keyString = self.specifier.properties[@"key"]; + NSString *formatString = self.specifier.properties[@"format"]; + + + if ([settings objectForKey:keyString] != nil) { + + NSDate *existingDate = [settings objectForKey:keyString]; + pickedDateFormat = [[NSDateFormatter alloc] init]; + [pickedDateFormat setDateFormat:formatString]; + pickedDateString = [pickedDateFormat stringFromDate:existingDate]; + + self.dateLabel.text = pickedDateString; + + } else { + self.dateLabel.text = @"No available date"; + } + +} + + +-(void)openDatePicker { + + + datePickerVC = [[TDDatePickerVC alloc] init]; + datePickerVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController presentViewController:datePickerVC animated:YES completion:nil]; + + // datePickerVC.view.backgroundColor = UIColor.clearColor; + + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = self.containerColour; + self.baseView.layer.cornerRadius = 20; + if (@available(iOS 13.0, *)) { + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.baseView.layer.borderWidth = 1; + self.baseView.layer.borderColor = self.borderColour.CGColor; + self.baseView.clipsToBounds = true; + [datePickerVC.view addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.heightAnchor constraintEqualToConstant:300.0].active = YES; + [self.baseView.leadingAnchor constraintEqualToAnchor:datePickerVC.view.leadingAnchor constant:20].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:datePickerVC.view.trailingAnchor constant:-20].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:datePickerVC.view.bottomAnchor constant:-20].active = YES; + + + self.doneButton = [[UIButton alloc] init]; + self.doneButton.backgroundColor = self.tintColour; + [self.doneButton setTitle:@"Done" forState:UIControlStateNormal]; + [self.doneButton setTitleColor:self.labelColour forState:UIControlStateNormal]; + [self.doneButton addTarget:self action:@selector(dismissDatePicker) forControlEvents:UIControlEventTouchUpInside]; + self.doneButton.layer.cornerRadius = 10; + if (@available(iOS 13.0, *)) { + self.doneButton.layer.cornerCurve = kCACornerCurveContinuous; + } + [self.baseView addSubview:self.doneButton]; + + self.doneButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.doneButton.widthAnchor constraintEqualToConstant:200.0].active = YES; + [self.doneButton.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.doneButton centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + [self.doneButton.bottomAnchor constraintEqualToAnchor:self.baseView.bottomAnchor constant:-10].active = YES; + + + self.datePicker = [[UIDatePicker alloc] init]; + [self.datePicker setDatePickerMode:UIDatePickerModeDate]; + [self.datePicker setValue:self.labelColour forKey:@"textColor"]; + [self.datePicker addTarget:self action:@selector(datePickerChanged:) forControlEvents:UIControlEventValueChanged]; + [self.baseView addSubview:self.datePicker]; + + + self.datePicker.translatesAutoresizingMaskIntoConstraints = NO; + [self.datePicker.topAnchor constraintEqualToAnchor:self.baseView.topAnchor constant:10].active = YES; + [self.datePicker.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10].active = YES; + [self.datePicker.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + [self.datePicker.bottomAnchor constraintEqualToAnchor:self.doneButton.topAnchor constant:-10].active = YES; + + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + NSString *keyString = self.specifier.properties[@"key"]; + + if ([settings objectForKey:keyString] != nil) { + NSDate *existingDate = [settings objectForKey:keyString]; + [self.datePicker setDate:existingDate animated:NO]; + } + + +} + + +- (void)datePickerChanged:(UIDatePicker *)datePicker { + + pickedDate = [datePicker date]; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:pickedDate forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + + + NSString *keyString = self.specifier.properties[@"key"]; + NSString *formatString = self.specifier.properties[@"format"]; + + NSDate *existingDate = [settings objectForKey:keyString]; + pickedDateFormat = [[NSDateFormatter alloc] init]; + [pickedDateFormat setDateFormat:formatString]; + pickedDateString = [pickedDateFormat stringFromDate:existingDate]; + + self.dateLabel.text = pickedDateString; + +} + + +-(void)dismissDatePicker { + + [[TDUtilities sharedInstance] haptic:0]; + + [UIView animateWithDuration:0.2 animations:^ { + datePickerVC.blurEffectView.alpha = 0; + }]; + + pickedDate = [self.datePicker date]; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:pickedDate forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + + + NSString *keyString = self.specifier.properties[@"key"]; + NSString *formatString = self.specifier.properties[@"format"]; + + NSDate *existingDate = [settings objectForKey:keyString]; + pickedDateFormat = [[NSDateFormatter alloc] init]; + [pickedDateFormat setDateFormat:formatString]; + pickedDateString = [pickedDateFormat stringFromDate:existingDate]; + + self.dateLabel.text = pickedDateString; + + [self performSelector:@selector(dismissVC) withObject:nil afterDelay:0.1]; + +} + + +-(void)dismissVC { + [datePickerVC dismissViewControllerAnimated:YES completion:nil]; +} + + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { + if (touch.view != datePickerVC.view) { + return NO; + } + + return YES; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDDatePickerVC.h b/libTitanD3vUniversal/Cells/TDDatePickerVC.h new file mode 100644 index 0000000..761c7ca --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDDatePickerVC.h @@ -0,0 +1,6 @@ +#import +#import "TDUtilities.h" + +@interface TDDatePickerVC : UIViewController +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@end \ No newline at end of file diff --git a/libTitanD3vUniversal/Cells/TDDatePickerVC.m b/libTitanD3vUniversal/Cells/TDDatePickerVC.m new file mode 100644 index 0000000..ca22158 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDDatePickerVC.m @@ -0,0 +1,59 @@ +#import "TDDatePickerVC.h" + +@implementation TDDatePickerVC + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.clearColor; + + self.blurEffectView = [[UIVisualEffectView alloc] init]; + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + self.blurEffectView.alpha = 0; + self.blurEffectView.userInteractionEnabled = true; + [self.view insertSubview:self.blurEffectView atIndex:0]; + + self.blurEffectView.translatesAutoresizingMaskIntoConstraints = false; + [self.blurEffectView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.blurEffectView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.blurEffectView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.blurEffectView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; + + + UITapGestureRecognizer *dismissGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureFired)]; + dismissGesture.delegate = self; + [self.blurEffectView addGestureRecognizer:dismissGesture]; + + + [self performSelector:@selector(setDimming) withObject:nil afterDelay:0.3]; +} + + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + +} + + +-(void)setDimming { + [UIView animateWithDuration:0.4 animations:^ { + self.blurEffectView.alpha = 1; + }]; +} + + +-(void)tapGestureFired { + [[TDUtilities sharedInstance] haptic:0]; + + [UIView animateWithDuration:0.2 animations:^ { + self.blurEffectView.alpha = 0; + }]; + [self performSelector:@selector(dismissVC) withObject:nil afterDelay:0.1]; +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDDescriptionCell.h b/libTitanD3vUniversal/Cells/TDDescriptionCell.h new file mode 100644 index 0000000..eef8363 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDDescriptionCell.h @@ -0,0 +1,15 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface TDDescriptionCell : PSTableCell { + float inset; +} + +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UITextView *descriptionTextView; +@property (nonatomic, retain) UIColor *labelColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDDescriptionCell.m b/libTitanD3vUniversal/Cells/TDDescriptionCell.m new file mode 100644 index 0000000..6ef5386 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDDescriptionCell.m @@ -0,0 +1,58 @@ +#import "TDDescriptionCell.h" + +@implementation TDDescriptionCell +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + + self.headerLabel = [[UILabel alloc] init]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[UIFont boldSystemFontOfSize:19]]; + self.headerLabel.textAlignment = NSTextAlignmentLeft; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10].active = YES; + [self.headerLabel.topAnchor constraintEqualToAnchor:self.topAnchor constant:10].active = YES; + + + self.descriptionTextView = [[UITextView alloc] init]; + self.descriptionTextView.clipsToBounds = YES; + self.descriptionTextView.contentInset = UIEdgeInsetsZero; + self.descriptionTextView.delegate = self; + self.descriptionTextView.editable = NO; + self.descriptionTextView.font = [UIFont systemFontOfSize:16]; + self.descriptionTextView.backgroundColor = [UIColor clearColor]; + self.descriptionTextView.scrollEnabled = YES; + self.descriptionTextView.textAlignment = NSTextAlignmentLeft; + self.descriptionTextView.textContainerInset = UIEdgeInsetsMake(0, -5, 0, 0); + self.descriptionTextView.text = specifier.properties[@"description"]; + self.descriptionTextView.textColor = self.labelColour; + [self addSubview:self.descriptionTextView]; + + self.descriptionTextView.translatesAutoresizingMaskIntoConstraints = NO; + [self.descriptionTextView.topAnchor constraintEqualToAnchor:self.headerLabel.bottomAnchor constant:15].active = YES; + [self.descriptionTextView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10].active = YES; + [self.descriptionTextView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = YES; + [self.descriptionTextView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:10].active = YES; + + } + + + return self; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDEditCell.h b/libTitanD3vUniversal/Cells/TDEditCell.h new file mode 100644 index 0000000..95a6b3d --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDEditCell.h @@ -0,0 +1,21 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "TDUtilities.h" + +@interface TDEditCell : PSTableCell { + UIView *baseView; + BOOL customIcon; + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UITextField *textField; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *labelColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDEditCell.m b/libTitanD3vUniversal/Cells/TDEditCell.m new file mode 100644 index 0000000..3ef9e58 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDEditCell.m @@ -0,0 +1,191 @@ +#import "TDEditCell.h" + +@implementation TDEditCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + if (self) { + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + + baseView = [[UIView alloc] initWithFrame:self.bounds]; + baseView.backgroundColor = [[TDAppearance sharedInstance] cellColour]; + [self addSubview:baseView]; + + + customIcon = specifier.properties[@"customIcon"] && [specifier.properties[@"customIcon"] boolValue]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + self.iconImage = [[UIImageView alloc]init]; + if (customIcon) { + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + } else { + self.iconImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/edit.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + } + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:-9].active = true; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + self.subtitleLabel = [[UILabel alloc]init]; + [self.subtitleLabel setText:specifier.properties[@"subtitle"]]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.subtitleLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:9].active = true; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + NSString *bundleID = specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + self.textField = [[UITextField alloc] init]; + self.textField.font = [UIFont systemFontOfSize:15]; + self.textField.placeholder = specifier.properties[@"placeholderText"]; + self.textField.autocorrectionType = UITextAutocorrectionTypeNo; + self.textField.clearButtonMode = UITextFieldViewModeWhileEditing; + self.textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; + self.textField.delegate = self; + self.textField.backgroundColor = UIColor.clearColor; + self.textField.textColor = self.labelColour; + self.textField.text = [settings objectForKey:specifier.properties[@"objectKey"]] ?: specifier.properties[@"default"]; + [self addSubview:self.textField]; + + self.textField.translatesAutoresizingMaskIntoConstraints = NO; + [self.textField.leadingAnchor constraintEqualToAnchor:self.headerLabel.trailingAnchor constant:10].active = YES; + [self.textField.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = YES; + [self.textField.topAnchor constraintEqualToAnchor:self.topAnchor constant:10].active = YES; + [self.textField.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-10].active = YES; + + + if ([specifier.properties[@"keyboardType"] isEqualToString:@"keyboard"]) { + self.textField.keyboardType = UIKeyboardTypeDefault; + } else if ([specifier.properties[@"keyboardType"] isEqualToString:@"numberpad"]) { + self.textField.keyboardType = UIKeyboardTypeNumberPad; + } + + + } + + return self; +} + + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + UIView *blankView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 30, 30)]; + [blankView setClipsToBounds:YES]; + [self setAccessoryView:blankView]; +} + + +- (void)textFieldDidEndEditing:(UITextField *)textField { + + NSString *textString = self.textField.text; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:textString forKey:self.specifier.properties[@"objectKey"]]; + [settings writeToFile:prefsPath atomically:YES]; + +} + + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + [textField resignFirstResponder]; + return YES; +} + + +- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + + UIToolbar *textToolbar = [[UIToolbar alloc] init]; + [textToolbar sizeToFit]; + textToolbar.barStyle = UIBarStyleDefault; + textToolbar.tintColor = self.tintColour; + textToolbar.items = [self textToolBarButtons]; + self.textField.inputAccessoryView = textToolbar; + + return YES; + +} + + +-(NSArray *)textToolBarButtons { + + NSMutableArray *textButtons = [[NSMutableArray alloc] init]; + + [textButtons addObject:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil]]; + + [textButtons addObject:[[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(dismissKeyboard)]]; + + return [textButtons copy]; + +} + + +-(void)dismissKeyboard { + + [[TDUtilities sharedInstance] haptic:0]; + + NSString *textString = self.textField.text; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:textString forKey:self.specifier.properties[@"objectKey"]]; + [settings writeToFile:prefsPath atomically:YES]; + + [self.textField resignFirstResponder]; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + + +- (void)layoutSubviews { + [super layoutSubviews]; + + baseView.frame = self.bounds; + +} + + +@end diff --git a/libTitanD3vUniversal/Cells/TDEnableCell.h b/libTitanD3vUniversal/Cells/TDEnableCell.h new file mode 100644 index 0000000..9d84966 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDEnableCell.h @@ -0,0 +1,28 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "HEXColour.h" + +@interface TDEnableCell : PSTableCell { + + BOOL isEnabled; + BOOL customIcon; + UIColor *disabledColour; + UIColor *enabledColour; + float inset; +} + +@property (nonatomic, retain) UIStackView *stackView; +@property (nonatomic, retain) UIView *disabledView; +@property (nonatomic, retain) UIImageView *disabledImage; +@property (nonatomic, retain) UILabel *disabledLabel; +@property (nonatomic, retain) UIView *disabledStateView; +@property (nonatomic, retain) UIView *enabledView; +@property (nonatomic, retain) UIImageView *enabledImage; +@property (nonatomic, retain) UILabel *enabledLabel; +@property (nonatomic, retain) UIView *enabledStateView; +@property (nonatomic, retain) UIColor *backgroundColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDEnableCell.m b/libTitanD3vUniversal/Cells/TDEnableCell.m new file mode 100644 index 0000000..e3956c8 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDEnableCell.m @@ -0,0 +1,258 @@ +#import "TDEnableCell.h" + +@implementation TDEnableCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + specifier.properties[@"height"] = [NSNumber numberWithInt:100]; + + if (self) { + + self.backgroundColour = [[TDAppearance sharedInstance] backgroundColour]; + + + NSString *disabledColourString = specifier.properties[@"disabledColour"]; + disabledColour = colorFromHexString(disabledColourString); + + NSString *enabledColourString = specifier.properties[@"enabledColour"]; + enabledColour = colorFromHexString(enabledColourString); + + + customIcon = specifier.properties[@"customIcon"] && [specifier.properties[@"customIcon"] boolValue]; + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *disabledIconPath = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, specifier.properties[@"disabledIconPath"]]; + NSString *enabledIconPath = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, specifier.properties[@"enabledIconPath"]]; + + + self.stackView = [[UIStackView alloc] init]; + self.stackView.axis = UILayoutConstraintAxisHorizontal; + self.stackView.alignment = UIStackViewAlignmentCenter; + self.stackView.distribution = UIStackViewDistributionFillEqually; + self.stackView.spacing = 10; + [self addSubview:self.stackView]; + + + self.disabledView = [[UIView alloc] init]; + self.disabledView.layer.cornerRadius = 10; + if (@available(iOS 13.0, *)) { + self.disabledView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.disabledView.clipsToBounds = true; + self.disabledView.backgroundColor = self.backgroundColour; + self.disabledView.layer.shadowOpacity = 0.5; + self.disabledView.layer.shadowOffset = CGSizeMake(0.0,0.0); + self.disabledView.layer.shadowRadius = 3.0; + self.disabledView.layer.masksToBounds = false; + + [self.disabledView.heightAnchor constraintEqualToConstant:80].active = true; + + + self.disabledImage = [[UIImageView alloc] init]; + if (customIcon) { + self.disabledImage.image = [[UIImage imageWithContentsOfFile:disabledIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } else { + self.disabledImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/disabled.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } + self.disabledImage.tintColor = disabledColour; + [self.disabledView addSubview:self.disabledImage]; + + self.disabledImage.translatesAutoresizingMaskIntoConstraints = false; + [self.disabledImage.heightAnchor constraintEqualToConstant:30].active = true; + [self.disabledImage.widthAnchor constraintEqualToConstant:30].active = true; + [self.disabledImage.topAnchor constraintEqualToAnchor:self.disabledView.topAnchor constant:10].active = true; + [self.disabledImage.centerXAnchor constraintEqualToAnchor:self.disabledView.centerXAnchor].active = true; + + + self.disabledLabel = [[UILabel alloc] init]; + self.disabledLabel.textAlignment = NSTextAlignmentCenter; + self.disabledLabel.font = [UIFont boldSystemFontOfSize:12]; + self.disabledLabel.text = specifier.properties[@"disabledTitle"]; + self.disabledLabel.textColor = disabledColour; + [self.disabledView addSubview:self.disabledLabel]; + + self.disabledLabel.translatesAutoresizingMaskIntoConstraints = false; + [self.disabledLabel.topAnchor constraintEqualToAnchor:self.disabledImage.bottomAnchor constant:5].active = true; + [self.disabledLabel.centerXAnchor constraintEqualToAnchor:self.disabledView.centerXAnchor].active = true; + + + self.disabledStateView = [[UIView alloc] init]; + self.disabledStateView.backgroundColor = disabledColour; + self.disabledStateView.layer.cornerRadius = 3; + [self.disabledView addSubview:self.disabledStateView]; + + self.disabledStateView.translatesAutoresizingMaskIntoConstraints = false; + [self.disabledStateView.heightAnchor constraintEqualToConstant:6].active = true; + [self.disabledStateView.widthAnchor constraintEqualToConstant:50].active = true; + [self.disabledStateView.bottomAnchor constraintEqualToAnchor:self.disabledView.bottomAnchor constant:-5].active = true; + [self.disabledStateView.centerXAnchor constraintEqualToAnchor:self.disabledView.centerXAnchor].active = true; + + + self.enabledView = [[UIView alloc] init]; + self.enabledView.layer.cornerRadius = 10; + if (@available(iOS 13.0, *)) { + self.enabledView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.enabledView.clipsToBounds = true; + self.enabledView.backgroundColor = self.backgroundColour; + self.enabledView.layer.shadowOpacity = 0.5; + self.enabledView.layer.shadowOffset = CGSizeMake(0.0,0.0); + self.enabledView.layer.shadowRadius = 3.0; + self.enabledView.layer.masksToBounds = false; + + [self.enabledView.heightAnchor constraintEqualToConstant:80].active = true; + + + self.enabledImage = [[UIImageView alloc] init]; + if (customIcon) { + self.enabledImage.image = [[UIImage imageWithContentsOfFile:enabledIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } else { + self.enabledImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/enabled.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } + self.enabledImage.tintColor = enabledColour; + [self.enabledView addSubview:self.enabledImage]; + + self.enabledImage.translatesAutoresizingMaskIntoConstraints = false; + [self.enabledImage.heightAnchor constraintEqualToConstant:30].active = true; + [self.enabledImage.widthAnchor constraintEqualToConstant:30].active = true; + [self.enabledImage.topAnchor constraintEqualToAnchor:self.enabledView.topAnchor constant:10].active = true; + [self.enabledImage.centerXAnchor constraintEqualToAnchor:self.enabledView.centerXAnchor].active = true; + + + self.enabledLabel = [[UILabel alloc] init]; + self.enabledLabel.textAlignment = NSTextAlignmentCenter; + self.enabledLabel.font = [UIFont boldSystemFontOfSize:12]; + self.enabledLabel.text = specifier.properties[@"enabledTitle"]; + self.enabledLabel.textColor = enabledColour; + [self.enabledView addSubview:self.enabledLabel]; + + self.enabledLabel.translatesAutoresizingMaskIntoConstraints = false; + [self.enabledLabel.topAnchor constraintEqualToAnchor:self.enabledImage.bottomAnchor constant:5].active = true; + [self.enabledLabel.centerXAnchor constraintEqualToAnchor:self.enabledView.centerXAnchor].active = true; + + + self.enabledStateView = [[UIView alloc] init]; + self.enabledStateView.backgroundColor = enabledColour; + self.enabledStateView.layer.cornerRadius = 3; + [self.enabledView addSubview:self.enabledStateView]; + + self.enabledStateView.translatesAutoresizingMaskIntoConstraints = false; + [self.enabledStateView.heightAnchor constraintEqualToConstant:6].active = true; + [self.enabledStateView.widthAnchor constraintEqualToConstant:50].active = true; + [self.enabledStateView.bottomAnchor constraintEqualToAnchor:self.enabledView.bottomAnchor constant:-5].active = true; + [self.enabledStateView.centerXAnchor constraintEqualToAnchor:self.enabledView.centerXAnchor].active = true; + + + [self.stackView addArrangedSubview:self.disabledView]; + [self.stackView addArrangedSubview:self.enabledView]; + + self.stackView.translatesAutoresizingMaskIntoConstraints = false; + [self.stackView.topAnchor constraintEqualToAnchor:self.topAnchor constant:10].active = true; + [self.stackView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10].active = true; + [self.stackView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = true; + [self.stackView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-10].active = true; + [self.stackView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor].active = true; + [self.stackView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor].active = true; + + + [self.disabledView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(disableAction)]]; + [self.enabledView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(enableAction)]]; + + + } + + return self; +} + + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + [self updatingValue]; + +} + + +-(void)updatingValue { + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + + isEnabled = [[settings objectForKey:self.specifier.properties[@"key"]]boolValue] ?: [self.specifier.properties[@"default"]boolValue]; + + if (isEnabled) { + + self.disabledView.layer.shadowColor = UIColor.clearColor.CGColor; + self.enabledView.layer.shadowColor = enabledColour.CGColor; + + self.disabledImage.alpha = 0.4; + self.disabledLabel.alpha = 0.4; + self.disabledStateView.alpha = 0.4; + self.enabledImage.alpha = 1.0; + self.enabledLabel.alpha = 1.0; + self.enabledStateView.alpha = 1.0; + + } else { + + self.disabledView.layer.shadowColor = disabledColour.CGColor; + self.enabledView.layer.shadowColor = UIColor.clearColor.CGColor; + + self.disabledImage.alpha = 1.0; + self.disabledLabel.alpha = 1.0; + self.disabledStateView.alpha = 1.0; + self.enabledImage.alpha = 0.4; + self.enabledLabel.alpha = 0.4; + self.enabledStateView.alpha = 0.4; + + } + +} + + +-(void)disableAction { + + invokeHapticFeedback(); + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:[NSNumber numberWithBool:NO] forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + + [self updatingValue]; + +} + + +-(void)enableAction { + + invokeHapticFeedback(); + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:[NSNumber numberWithBool:YES] forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + + [self updatingValue]; + +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDFontPickerCell.h b/libTitanD3vUniversal/Cells/TDFontPickerCell.h new file mode 100644 index 0000000..820cfa6 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDFontPickerCell.h @@ -0,0 +1,19 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface TDFontPickerCell : PSTableCell { + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UILabel *fontLabel; + + +@property (nonatomic, retain) UIColor *tintColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDFontPickerCell.m b/libTitanD3vUniversal/Cells/TDFontPickerCell.m new file mode 100644 index 0000000..2da4e81 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDFontPickerCell.m @@ -0,0 +1,163 @@ +#import "TDFontPickerCell.h" + +@implementation TDFontPickerCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + if (self) { + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + self.iconImage = [[UIImageView alloc]init]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:-9].active = true; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + self.subtitleLabel = [[UILabel alloc]init]; + [self.subtitleLabel setText:specifier.properties[@"subtitle"]]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.subtitleLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:9].active = true; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + self.fontLabel = [[UILabel alloc]init]; + self.fontLabel.text = @"Font"; + [self addSubview:self.fontLabel]; + + self.fontLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.fontLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.fontLabel.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = YES; + + } + + return self; +} + + +- (id)target { + return self; +} + + +- (id)cellTarget { + return self; +} + + +- (SEL)action { + return @selector(openFontPicker); +} + + +- (SEL)cellAction { + return @selector(openFontPicker); +} + + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + [self.specifier setTarget:self]; + [self.specifier setButtonAction:@selector(openFontPicker)]; + + + UIView *blankView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 30, 30)]; + [blankView setClipsToBounds:YES]; + [self setAccessoryView:blankView]; + + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + NSString *keyString = self.specifier.properties[@"key"]; + + NSData *data = [settings objectForKey:keyString]; + NSError *error = nil; + UIFontDescriptor *descriptor = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:data error:&error]; + + self.fontLabel.font = [UIFont fontWithDescriptor:descriptor size:12]; + +} + + +-(void)openFontPicker { + + if (@available(iOS 13.0, *)) { + UIFontPickerViewControllerConfiguration *config = [[UIFontPickerViewControllerConfiguration alloc] init]; + config.includeFaces = YES; + config.displayUsingSystemFont = YES; + + UIFontPickerViewController *fontPicker = [[UIFontPickerViewController alloc] initWithConfiguration:config]; + fontPicker.delegate = self; + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController presentViewController:fontPicker animated:YES completion:nil]; + } + +} + + +-(void)fontPickerViewControllerDidPickFont:(UIFontPickerViewController *)fontPicker API_AVAILABLE(ios(13.0)) { + + if (@available(iOS 13.0, *)) { + UIFontDescriptor *descriptor = fontPicker.selectedFontDescriptor; + NSError *error = nil; + NSData *encodedDescriptor = [NSKeyedArchiver archivedDataWithRootObject:descriptor requiringSecureCoding:NO error:&error]; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:encodedDescriptor forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + + + NSString *keyString = self.specifier.properties[@"key"]; + + NSData *data = [settings objectForKey:keyString]; + UIFontDescriptor *descriptorFont = [NSKeyedUnarchiver unarchivedObjectOfClass:[UIFontDescriptor class] fromData:data error:&error]; + + self.fontLabel.font = [UIFont fontWithDescriptor:descriptorFont size:12]; + + [fontPicker dismissViewControllerAnimated:YES completion:nil]; + } + +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDGridCell.h b/libTitanD3vUniversal/Cells/TDGridCell.h new file mode 100644 index 0000000..130e596 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDGridCell.h @@ -0,0 +1,27 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface GridButton : UIButton +@property (nonatomic, retain) NSString *identifier; +@end + +@protocol GridTableView +- (id)initWithSpecifier:(PSSpecifier *)specifier; +- (CGFloat)preferredHeightForWidth:(CGFloat)width; +@end + +@interface TDGridCell : PSTableCell { + UIImage *leftIconImage; + UIImage *middleIconImage; + UIImage *rightIconImage; + NSString *leftIconPathString; + NSString *middleIconPathString; + NSString *rightIconPathString; + float inset; +} + +@property (nonatomic, retain) UIColor *tintColour; +@end diff --git a/libTitanD3vUniversal/Cells/TDGridCell.m b/libTitanD3vUniversal/Cells/TDGridCell.m new file mode 100644 index 0000000..5fc9c5d --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDGridCell.m @@ -0,0 +1,195 @@ +#import "TDGridCell.h" +#import "TDPrimraryController.h" +#import "TDSecondaryController.h" +#import "TDExternalController.h" + +@implementation GridButton +@end + + +@implementation TDGridCell + +- (id)initWithSpecifier:(PSSpecifier *)specifier { + self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell" specifier:specifier]; + specifier.properties[@"height"] = [NSNumber numberWithInt:150]; + return self; +} + + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + leftIconPathString = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", self.specifier.properties[@"leftIconName"]]; + middleIconPathString = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", self.specifier.properties[@"middleIconName"]]; + rightIconPathString = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", self.specifier.properties[@"rightIconName"]]; + + leftIconImage = [[UIImage imageNamed:leftIconPathString]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + middleIconImage = [[UIImage imageNamed:middleIconPathString]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + rightIconImage = [[UIImage imageNamed:rightIconPathString]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + + + UIStackView *stack = [[UIStackView alloc] initWithFrame:self.bounds]; + stack.axis = UILayoutConstraintAxisHorizontal; + stack.alignment = UIStackViewAlignmentCenter; + stack.distribution = UIStackViewDistributionEqualSpacing; + stack.spacing = 20; + stack.translatesAutoresizingMaskIntoConstraints = false; + + + UIStackView *leftStack = [[UIStackView alloc] initWithFrame:CGRectMake(20, 20, 80, 120)]; + leftStack.axis = UILayoutConstraintAxisVertical; + leftStack.alignment = UIStackViewAlignmentCenter; + leftStack.distribution = UIStackViewDistributionEqualSpacing; + leftStack.spacing = 15; + leftStack.translatesAutoresizingMaskIntoConstraints = false; + + + GridButton *leftButton = [[GridButton alloc] initWithFrame:CGRectMake(20, 20, 60, 60)]; + leftButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill; + leftButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill; + [leftButton setImage:leftIconImage forState:UIControlStateNormal]; + leftButton.tag = 1; + leftButton.clipsToBounds = YES; + [leftButton.imageView setContentMode:UIViewContentModeScaleAspectFit]; + leftButton.imageView.clipsToBounds = true; + leftButton.imageView.layer.cornerRadius = 10; + if (@available(iOS 13.0, *)) { + leftButton.imageView.layer.cornerCurve = kCACornerCurveContinuous; + } + leftButton.layer.masksToBounds = NO; + leftButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10); + leftButton.identifier = self.specifier.properties[@"leftClass"]; + if ([self.specifier.properties[@"classID"] isEqualToString:@"primrary"]) { + [leftButton addTarget:[[TDPrimraryController alloc] init] action:@selector(openController:) forControlEvents:UIControlEventTouchUpInside]; + } else if ([self.specifier.properties[@"classID"] isEqualToString:@"secondary"]) { + [leftButton addTarget:[[TDSecondaryController alloc] init] action:@selector(openController:) forControlEvents:UIControlEventTouchUpInside]; + } else if ([self.specifier.properties[@"classID"] isEqualToString:@"external"]) { + [leftButton addTarget:[[TDExternalController alloc] init] action:@selector(openController:) forControlEvents:UIControlEventTouchUpInside]; + } + [leftStack addArrangedSubview:leftButton]; + [leftButton.widthAnchor constraintEqualToConstant:80].active = true; + [leftButton.heightAnchor constraintEqualToConstant:80].active = true; + + + UILabel *leftLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 40)]; + leftLabel.text = self.specifier.properties[@"leftTitle"]; + leftLabel.font = [UIFont boldSystemFontOfSize:12]; + leftLabel.textAlignment = NSTextAlignmentCenter; + [leftStack addArrangedSubview:leftLabel]; + [stack addArrangedSubview:leftStack]; + + + UIStackView *middleStack = [[UIStackView alloc] initWithFrame:CGRectMake(0, 0, 80, 120)]; + middleStack.axis = UILayoutConstraintAxisVertical; + middleStack.alignment = UIStackViewAlignmentCenter; + middleStack.distribution = UIStackViewDistributionEqualSpacing; + middleStack.spacing = 15; + middleStack.translatesAutoresizingMaskIntoConstraints = YES; + + + GridButton *middleButton = [[GridButton alloc] initWithFrame:CGRectMake(0, 0, 60, 60)]; + middleButton.center = CGPointMake(CGRectGetMidX(self.bounds), middleButton.center.y); + middleButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill; + middleButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill; + [middleButton setImage:middleIconImage forState:UIControlStateNormal]; + middleButton.imageView.clipsToBounds = true; + middleButton.imageView.layer.cornerRadius = 10; + if (@available(iOS 13.0, *)) { + middleButton.imageView.layer.cornerCurve = kCACornerCurveContinuous; + } + middleButton.tag = 3; + middleButton.clipsToBounds = YES; + [middleButton.imageView setContentMode:UIViewContentModeScaleAspectFit]; + middleButton.layer.masksToBounds = NO; + middleButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10); + middleButton.identifier = self.specifier.properties[@"middleClass"]; + if ([self.specifier.properties[@"classID"] isEqualToString:@"primrary"]) { + [middleButton addTarget:[[TDPrimraryController alloc] init] action:@selector(openController:) forControlEvents:UIControlEventTouchUpInside]; + } else if ([self.specifier.properties[@"classID"] isEqualToString:@"secondary"]) { + [middleButton addTarget:[[TDSecondaryController alloc] init] action:@selector(openController:) forControlEvents:UIControlEventTouchUpInside]; + } else if ([self.specifier.properties[@"classID"] isEqualToString:@"external"]) { + [middleButton addTarget:[[TDExternalController alloc] init] action:@selector(openController:) forControlEvents:UIControlEventTouchUpInside]; + } + [middleStack addArrangedSubview:middleButton]; + [middleButton.widthAnchor constraintEqualToConstant:80].active = true; + [middleButton.heightAnchor constraintEqualToConstant:80].active = true; + + + UILabel *middleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 40)]; + middleLabel.text = self.specifier.properties[@"middleTitle"]; + middleLabel.font = [UIFont boldSystemFontOfSize:12]; + middleLabel.textAlignment = NSTextAlignmentCenter; + [middleStack addArrangedSubview:middleLabel]; + [stack addArrangedSubview:middleStack]; + + + UIStackView *rightStack = [[UIStackView alloc] initWithFrame:CGRectMake(0, 0, 80, 120)]; + rightStack.axis = UILayoutConstraintAxisVertical; + rightStack.alignment = UIStackViewAlignmentCenter; + rightStack.distribution = UIStackViewDistributionEqualSpacing; + rightStack.spacing = 15; + rightStack.translatesAutoresizingMaskIntoConstraints = false; + + + GridButton *rightButton = [[GridButton alloc] initWithFrame:CGRectMake(0, 0, 60, 60)]; + rightButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill; + rightButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill; + [rightButton setImage:rightIconImage forState:UIControlStateNormal]; + rightButton.imageView.clipsToBounds = true; + rightButton.imageView.layer.cornerRadius = 10; + if (@available(iOS 13.0, *)) { + rightButton.imageView.layer.cornerCurve = kCACornerCurveContinuous; + } + rightButton.tag = 2; + rightButton.clipsToBounds = YES; + [rightButton.imageView setContentMode:UIViewContentModeScaleAspectFit]; + rightButton.layer.masksToBounds = NO; + rightButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10); + rightButton.identifier = self.specifier.properties[@"rightClass"]; + if ([self.specifier.properties[@"classID"] isEqualToString:@"primrary"]) { + [rightButton addTarget:[[TDPrimraryController alloc] init] action:@selector(openController:) forControlEvents:UIControlEventTouchUpInside]; + } else if ([self.specifier.properties[@"classID"] isEqualToString:@"secondary"]) { + [rightButton addTarget:[[TDSecondaryController alloc] init] action:@selector(openController:) forControlEvents:UIControlEventTouchUpInside]; + } else if ([self.specifier.properties[@"classID"] isEqualToString:@"external"]) { + [rightButton addTarget:[[TDExternalController alloc] init] action:@selector(openController:) forControlEvents:UIControlEventTouchUpInside]; + } + [rightStack addArrangedSubview:rightButton]; + [rightButton.widthAnchor constraintEqualToConstant:80].active = true; + [rightButton.heightAnchor constraintEqualToConstant:80].active = true; + [stack addArrangedSubview:rightStack]; + + + UILabel *rightLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 40)]; + rightLabel.text = self.specifier.properties[@"rightTitle"]; + rightLabel.font = [UIFont boldSystemFontOfSize:12]; + rightLabel.textAlignment = NSTextAlignmentCenter; + [rightStack addArrangedSubview:rightLabel]; + [stack addArrangedSubview:rightStack]; + + + [self addSubview:stack]; + [stack.topAnchor constraintEqualToAnchor:self.topAnchor constant:20].active = true; + [stack.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-40].active = true; + [stack.heightAnchor constraintEqualToAnchor:self.heightAnchor constant:-40].active = true; + [stack.widthAnchor constraintEqualToAnchor:self.widthAnchor constant:-40].active = true; + [stack.centerXAnchor constraintEqualToAnchor:self.centerXAnchor].active = true; + [stack.centerYAnchor constraintEqualToAnchor:self.centerYAnchor].active = true; + +} + + +- (CGFloat)preferredHeightForWidth:(CGFloat)width { + return 100.0; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDHeaderCell.h b/libTitanD3vUniversal/Cells/TDHeaderCell.h new file mode 100644 index 0000000..5c1faa2 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDHeaderCell.h @@ -0,0 +1,14 @@ +#import +#import +#import "TDPrefsManager.h" + +@protocol PreferencesTableCustomView +- (id)initWithSpecifier:(PSSpecifier *)specifier; +- (CGFloat)preferredHeightForWidth:(CGFloat)width; +@end + +@interface TDHeaderCell : PSTableCell { + float inset; +} +@property (nonatomic, retain) UILabel *headerLabel; +@end diff --git a/libTitanD3vUniversal/Cells/TDHeaderCell.m b/libTitanD3vUniversal/Cells/TDHeaderCell.m new file mode 100644 index 0000000..ec12c8b --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDHeaderCell.m @@ -0,0 +1,48 @@ +#import "TDHeaderCell.h" + +@implementation TDHeaderCell + +- (id)initWithSpecifier:(PSSpecifier *)specifier { + self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell" specifier:specifier]; + if (self) { + + self.headerLabel = [[UILabel alloc] initWithFrame:[self frame]]; + [self.headerLabel setNumberOfLines:0]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setBackgroundColor:[UIColor clearColor]]; + self.headerLabel.textAlignment = NSTextAlignmentLeft; + [self.headerLabel setFont:[UIFont boldSystemFontOfSize:22]]; + [self addSubview:self.headerLabel]; + + } + return self; +} + +- (CGFloat)preferredHeightForWidth:(CGFloat)width { + return 40.f; +} + +- (void)setFrame:(CGRect)frame { + if (![[NSFileManager defaultManager] fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/shuffle.dylib"]) { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; + } else { + inset = 0; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; + } + + BOOL cellInset = [[TDPrefsManager sharedInstance] externalCellInset]; + + if (cellInset) { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; + } +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDImageCell.h b/libTitanD3vUniversal/Cells/TDImageCell.h new file mode 100644 index 0000000..0fc3ec4 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDImageCell.h @@ -0,0 +1,12 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface TDImageCell : PSTableCell { + float inset; +} + +@property (nonatomic, retain) UIImageView *bannerImage; +@end diff --git a/libTitanD3vUniversal/Cells/TDImageCell.m b/libTitanD3vUniversal/Cells/TDImageCell.m new file mode 100644 index 0000000..e2a4d00 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDImageCell.m @@ -0,0 +1,41 @@ +#import "TDImageCell.h" + +@implementation TDImageCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *imagePath = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, specifier.properties[@"imagePath"]]; + + self.bannerImage = [[UIImageView alloc] initWithFrame:self.bounds]; + self.bannerImage.clipsToBounds = YES; + self.bannerImage.contentMode = UIViewContentModeScaleAspectFill; + self.bannerImage.image = [[UIImage imageWithContentsOfFile:imagePath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + [self addSubview:self.bannerImage]; + + } + + return self; +} + + +- (void)layoutSubviews { + [super layoutSubviews]; + + self.bannerImage.frame = self.bounds; + +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDLinkCell.h b/libTitanD3vUniversal/Cells/TDLinkCell.h new file mode 100644 index 0000000..7de3ffa --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDLinkCell.h @@ -0,0 +1,16 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface TDLinkCell: PSTableCell { + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UIColor *tintColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDLinkCell.m b/libTitanD3vUniversal/Cells/TDLinkCell.m new file mode 100644 index 0000000..3fe84a1 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDLinkCell.m @@ -0,0 +1,62 @@ +#import "TDLinkCell.h" + +@implementation TDLinkCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + self.iconImage = [[UIImageView alloc]init]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:-9].active = true; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + self.subtitleLabel = [[UILabel alloc]init]; + [self.subtitleLabel setText:specifier.properties[@"subtitle"]]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.subtitleLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:9].active = true; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + } + + return self; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDListCell.h b/libTitanD3vUniversal/Cells/TDListCell.h new file mode 100644 index 0000000..37ab81e --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDListCell.h @@ -0,0 +1,16 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface TDListCell : PSTableCell { + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UIColor *tintColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDListCell.m b/libTitanD3vUniversal/Cells/TDListCell.m new file mode 100644 index 0000000..79c5e47 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDListCell.m @@ -0,0 +1,63 @@ +#import "TDListCell.h" + + +@implementation TDListCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + self.iconImage = [[UIImageView alloc]init]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:-9].active = true; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + self.subtitleLabel = [[UILabel alloc]init]; + [self.subtitleLabel setText:specifier.properties[@"subtitle"]]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.subtitleLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:9].active = true; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + } + + return self; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDReviewCell.h b/libTitanD3vUniversal/Cells/TDReviewCell.h new file mode 100644 index 0000000..1c44d91 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDReviewCell.h @@ -0,0 +1,23 @@ +#import +#import +#import "TDAppearance.h" +#import "TDReviewViewController.h" +#import "ConstraintExtension.h" +#import "TDUtilities.h" + +@interface TDReviewCell : PSTableCell { + TDReviewViewController *vc; + UIViewController *reviewVC; + NSString *ratingString; + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (nonatomic, retain) UITextField *reviewTextField; +@property (nonatomic, retain) UITextView *reviewTextView; +@property (nonatomic, retain) UILabel *placeholderLabel; + +@end diff --git a/libTitanD3vUniversal/Cells/TDReviewCell.m b/libTitanD3vUniversal/Cells/TDReviewCell.m new file mode 100644 index 0000000..6a6ea5b --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDReviewCell.m @@ -0,0 +1,389 @@ +#import "TDReviewCell.h" + +@implementation TDReviewCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + if (self) { + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + + self.iconImage = [[UIImageView alloc]init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/review.png"]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + self.headerLabel.text = @"Write a Review"; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:17]]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + } + + return self; +} + + +- (id)target { + return self; +} + + +- (id)cellTarget { + return self; +} + + +- (SEL)action { + return @selector(openReviewVC); +} + + +- (SEL)cellAction { + return @selector(openReviewVC); +} + + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + [self.specifier setTarget:self]; + [self.specifier setButtonAction:@selector(openReviewVC)]; + + + UIView *blankView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 30, 30)]; + [blankView setClipsToBounds:YES]; + [self setAccessoryView:blankView]; + +} + + +-(void)openReviewVC { + + UIViewController *prefsController = [self _viewControllerForAncestor]; + vc = [[TDReviewViewController alloc] init]; + vc.modalPresentationStyle = UIModalPresentationOverCurrentContext; + vc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + vc.rateTitle = @"How was your experience?"; + vc.confirmTitle = @"Review"; + vc.rateTitleColor = UIColor.whiteColor; + [vc onConfirmHandler:^(TDRate rate) { + switch (rate) { + case TDRateBad: + ratingString = @"BAD"; + break; + case TDRateUgh: + ratingString = @"UGH"; + break; + case TDRateOk: + ratingString = @"OK"; + break; + case TDRateGood: + ratingString = @"GOOD"; + break; + } + [self composeReview]; + [[TDUtilities sharedInstance] haptic:0]; + }]; + + [vc onCancelHandler:^{ + [prefsController dismissViewControllerAnimated:YES completion:nil]; + [[TDUtilities sharedInstance] haptic:0]; + }]; + + [prefsController presentViewController:vc animated:YES completion:nil]; + +} + + +-(void)composeReview { + + reviewVC = [[UIViewController alloc] init]; + + UINavigationBar* navbar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, reviewVC.view.frame.size.width, 50)]; + navbar.barTintColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + navbar.tintColor = self.tintColor; + [navbar setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6], NSForegroundColorAttributeName, nil]]; + + UINavigationItem* navItem = [[UINavigationItem alloc] initWithTitle:@"Write a Review"]; + + UIBarButtonItem* cancelBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelReview:)]; + navItem.leftBarButtonItem = cancelBtn; + + UIBarButtonItem* submitBtn = [[UIBarButtonItem alloc] initWithTitle:@"Submit" style:UIBarButtonItemStylePlain target:self action:@selector(submitReview:)]; + navItem.rightBarButtonItem = submitBtn; + + [navbar setItems:@[navItem]]; + [reviewVC.view addSubview:navbar]; + + if (@available(iOS 13.0, *)) { + reviewVC.modalInPresentation = true; + } + + [vc presentViewController:reviewVC animated:YES completion:nil]; + + + reviewVC.view.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + + + self.reviewTextField = [[UITextField alloc] init]; + self.reviewTextField.font = [UIFont systemFontOfSize:15]; + self.reviewTextField.placeholder = @"Your Name"; + self.reviewTextField.autocorrectionType = UITextAutocorrectionTypeNo; + self.reviewTextField.keyboardType = UIKeyboardTypeDefault; + self.reviewTextField.clearButtonMode = UITextFieldViewModeWhileEditing; + self.reviewTextField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; + self.reviewTextField.delegate = self; + self.reviewTextField.textColor = UIColor.whiteColor; + self.reviewTextField.tintColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + self.reviewTextField.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.reviewTextField.layer.cornerRadius = 10; + self.reviewTextField.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + self.reviewTextField.layer.borderWidth = 0.5; + [reviewVC.view addSubview:self.reviewTextField]; + + [self.reviewTextField top:navbar.bottomAnchor padding:15]; + [self.reviewTextField leading:reviewVC.view.leadingAnchor padding:10]; + [self.reviewTextField trailing:reviewVC.view.trailingAnchor padding:-10]; + [self.reviewTextField height:44]; + + [self.reviewTextField becomeFirstResponder]; + + + UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 44)]; + self.reviewTextField.leftView = paddingView; + self.reviewTextField.leftViewMode = UITextFieldViewModeAlways; + + + self.reviewTextView = [[UITextView alloc] init]; + self.reviewTextView.editable = YES; + self.reviewTextView.userInteractionEnabled = YES; + self.reviewTextView.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.reviewTextView.scrollEnabled = YES; + self.reviewTextView.delegate = self; + self.reviewTextView.tintColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + self.reviewTextView.font = [UIFont systemFontOfSize:17]; + self.reviewTextView.textContainerInset = UIEdgeInsetsMake(10, 10, 10, 10); + self.reviewTextView.textColor = UIColor.whiteColor; + self.reviewTextView.layer.cornerRadius = 10; + self.reviewTextView.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + self.reviewTextView.layer.borderWidth = 0.5; + [reviewVC.view addSubview:self.reviewTextView]; + + [self.reviewTextView top:self.reviewTextField.bottomAnchor padding:10]; + [self.reviewTextView leading:reviewVC.view.leadingAnchor padding:10]; + [self.reviewTextView trailing:reviewVC.view.trailingAnchor padding:-10]; + [self.reviewTextView height:230]; + + + self.placeholderLabel = [[UILabel alloc] init]; + self.placeholderLabel.text = @"Description"; + self.placeholderLabel.alpha = 1; + self.placeholderLabel.textAlignment = NSTextAlignmentLeft; + self.placeholderLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha:0.4]; + [self.reviewTextView addSubview:self.placeholderLabel]; + + [self.placeholderLabel top:self.reviewTextView.bottomAnchor padding:10]; + [self.placeholderLabel leading:self.reviewTextView.leadingAnchor padding:14]; + + if (@available(iOS 13.0, *)) { + self.reviewTextField.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; + self.reviewTextView.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; + } + +} + + +-(void)sendReview:(NSString*)subject msg:(NSString*)msg tweak:(NSString*)tweak name:(NSString*)name { + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; + NSString *url = @"https://payments.titand3v.com/review-mail.php?send=YES"; + NSString *finalsubject = [subject stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]; + NSString *finalmsg = [msg stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]; + NSString *finaltweak = [tweak stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]; + NSString *finalname = [name stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]; + NSString *finalURL = [NSString stringWithFormat:@"%@&subject=%@&msg=%@&tweak=%@&name=%@", url, finalsubject, finalmsg, finaltweak, finalname]; + [request setURL:[NSURL URLWithString:finalURL]]; + [request setHTTPMethod:@"GET"]; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; + [[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + }] resume]; +} + + +-(void)submitReview:(UIBarButtonItem*)item{ + + [[TDUtilities sharedInstance] haptic:0]; + + if (self.reviewTextView.text && self.reviewTextView.text.length && self.reviewTextField.text && self.reviewTextField.text.length > 0) { + + NSString *rating = [NSString stringWithFormat:@"%@", ratingString]; + NSString *messageString = self.reviewTextView.text; + NSString *tweakString = self.specifier.properties[@"tweakName"]; + NSString *nameString = self.reviewTextField.text; + + [self sendReview:rating msg:messageString tweak:tweakString name:nameString]; + + [reviewVC dismissViewControllerAnimated:YES completion:nil]; + [vc dismissViewControllerAnimated:YES completion:nil]; + [self performSelector:@selector(showFeedbackAlert) withObject:nil afterDelay:1.0]; + + } else { + [self showEmptyFieldAlert]; + + } + +} + + +-(void)showEmptyFieldAlert { + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Sorry!" message:@"The review or name is blank and you will need to add your name or nickname, write a review before you can submit your review" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + + }]; + [alertController addAction:okAction]; + alertController.view.tintColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + [reviewVC presentViewController:alertController animated:YES completion:nil]; +} + + +-(void)showFeedbackAlert { + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Thank you for your feedback 😀" message:@"" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + + }]; + [alertController addAction:okAction]; + alertController.view.tintColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController presentViewController:alertController animated:YES completion:nil]; + +} + + +- (void)textViewDidBeginEditing:(UITextView *)textView { + + if ([textView.text isEqualToString:@""]) { + self.placeholderLabel.alpha = 1; + } else { + self.placeholderLabel.alpha = 0; + } +} + + +- (void)textViewDidChange:(UITextView *)textView{ + + if ([textView.text isEqualToString:@""]) { + self.placeholderLabel.alpha = 1; + } else { + self.placeholderLabel.alpha = 0; + } +} + + +- (void)textViewDidEndEditing:(UITextView *)textView { + + if ([textView.text isEqualToString:@""]) { + self.placeholderLabel.alpha = 1; + } else { + self.placeholderLabel.alpha = 0; + } +} + + +- (BOOL)textViewShouldBeginEditing:(UITextView *)textView { + + UIToolbar *textToolbar = [[UIToolbar alloc] init]; + [textToolbar sizeToFit]; + if (@available(iOS 13.0, *)) { + textToolbar.barStyle = UIStatusBarStyleDarkContent; + } + textToolbar.tintColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + textToolbar.items = [self textToolBarButtons]; + self.reviewTextView.inputAccessoryView = textToolbar; + + if (@available(iOS 13.0, *)) { + self.reviewTextView.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; + } + + return YES; + +} + + +- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { + + UIToolbar *textToolbar = [[UIToolbar alloc] init]; + [textToolbar sizeToFit]; + if (@available(iOS 13.0, *)) { + textToolbar.barStyle = UIStatusBarStyleDarkContent; + } + textToolbar.tintColor = [UIColor colorWithRed: 0.98 green: 0.41 blue: 0.17 alpha: 1.00]; + textToolbar.items = [self textToolBarButtons]; + self.reviewTextField.inputAccessoryView = textToolbar; + + if (@available(iOS 13.0, *)) { + self.reviewTextField.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; + } + + return YES; + +} + + +-(NSArray *)textToolBarButtons { + + NSMutableArray *textButtons = [[NSMutableArray alloc] init]; + + [textButtons addObject:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil]]; + + [textButtons addObject:[[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(dismissKeyboard)]]; + + return [textButtons copy]; + +} + + +-(void)dismissKeyboard { + [[TDUtilities sharedInstance] haptic:0]; + [self.reviewTextField resignFirstResponder]; + [self.reviewTextView resignFirstResponder]; +} + + +-(void)cancelReview:(UIBarButtonItem*)item { + [[TDUtilities sharedInstance] haptic:0]; + [reviewVC dismissViewControllerAnimated:YES completion:nil]; + [vc dismissViewControllerAnimated:YES completion:nil]; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDSegmentCell.h b/libTitanD3vUniversal/Cells/TDSegmentCell.h new file mode 100644 index 0000000..d8c6e3d --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDSegmentCell.h @@ -0,0 +1,24 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "TDAlertViewController.h" +#import "TDUtilities.h" + +@interface PSSegmentTableCell : PSControlTableCell +@end + +@interface TDSegmentCell : PSSegmentTableCell { + BOOL showTips; + NSInteger tipsImageStyle; + float inset; +} + +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UIButton *tipsButton; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *containerColour; +@property (nonatomic, retain) UIColor *labelColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDSegmentCell.m b/libTitanD3vUniversal/Cells/TDSegmentCell.m new file mode 100644 index 0000000..28c032a --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDSegmentCell.m @@ -0,0 +1,134 @@ +#import "TDSegmentCell.h" + +@implementation TDSegmentCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + self.containerColour = [[TDAppearance sharedInstance] containerColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + + if (@available(iOS 13.0, *)) { + ((UISegmentedControl *)self.control).selectedSegmentTintColor = self.tintColour; + } + + + self.headerLabel = [[UILabel alloc] init]; + self.headerLabel.text = specifier.properties[@"title"]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.headerLabel.topAnchor constraintEqualToAnchor:self.topAnchor constant:10].active = YES; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:15].active = YES; + + + showTips = specifier.properties[@"showTips"] && [specifier.properties[@"showTips"] boolValue]; + + + if (showTips) { + + self.tipsButton = [[UIButton alloc] init]; + self.tipsButton.backgroundColor = self.tintColour; + UIImage *tipsImage = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Tips/tips.png"]; + [self.tipsButton setImage:tipsImage forState:UIControlStateNormal]; + self.tipsButton.imageEdgeInsets = UIEdgeInsetsMake(3, 3, 3, 3); + [self.tipsButton addTarget:self action:@selector(showTipsTapped:) forControlEvents:UIControlEventTouchUpInside]; + self.tipsButton.layer.cornerRadius = 10; + [self.contentView addSubview:self.tipsButton]; + + self.tipsButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.tipsButton.widthAnchor constraintEqualToConstant:20.0].active = YES; + [self.tipsButton.heightAnchor constraintEqualToConstant:20.0].active = YES; + [[self.tipsButton centerYAnchor] constraintEqualToAnchor:self.headerLabel.centerYAnchor].active = true; + [self.tipsButton.leadingAnchor constraintEqualToAnchor:self.headerLabel.trailingAnchor constant:5].active = YES; + + } + + } + return self; +} + + +-(void)showTipsTapped:(UIButton *)sender { + + [[TDUtilities sharedInstance] haptic:0]; + + NSString *titleString = self.specifier.properties[@"tipsTitle"]; + NSString *messageString = self.specifier.properties[@"tipsMessage"]; + NSString *tipsImagePath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Tips/%@.png", self.specifier.properties[@"tipsImage"]]; + UIImage *tipsImage = [UIImage imageWithContentsOfFile:tipsImagePath]; + + tipsImageStyle = [self.specifier.properties[@"tipsImageStyle"]integerValue]; + + + TDAlertViewControllerConfiguration *configuration = [TDAlertViewControllerConfiguration new]; + configuration.alertViewBackgroundColor = self.containerColour; + configuration.titleTextColor = self.labelColour; + configuration.messageTextColor = self.labelColour; + configuration.transitionStyle = TDAlertViewControllerTransitionStyleSlideFromTop; + configuration.backgroundTapDismissalGestureEnabled = YES; + configuration.swipeDismissalGestureEnabled = YES; + configuration.alwaysArrangesActionButtonsVertically = YES; + configuration.buttonConfiguration.titleColor = self.tintColour; + configuration.cancelButtonConfiguration.titleColor = self.tintColour; + configuration.cancelButtonConfiguration.titleFont = [UIFont systemFontOfSize:16]; + configuration.alertViewCornerRadius = 20; + configuration.showsSeparators = NO; + + + TDAlertAction *okAction = [[TDAlertAction alloc] initWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]; + + TDAlertViewController *alertViewController = [[TDAlertViewController alloc] initWithOptions:configuration title:titleString message:messageString actions:@[okAction]]; + + + if (tipsImageStyle == 0) { + + UIImageView *iconImageView = [[UIImageView alloc] initWithImage:tipsImage]; + iconImageView.contentMode = UIViewContentModeScaleAspectFit; + [iconImageView.heightAnchor constraintEqualToConstant:80.0f].active = YES; + alertViewController.alertViewContentView = iconImageView; + + } else { + + UIImageView *bannerImageView = [[UIImageView alloc] initWithImage:tipsImage]; + bannerImageView.clipsToBounds = YES; + bannerImageView.contentMode = UIViewContentModeScaleAspectFill; + [bannerImageView.heightAnchor constraintEqualToConstant:120.0f].active = YES; + alertViewController.alertViewContentView = bannerImageView; + + } + + + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController presentViewController:alertViewController animated:YES completion:nil]; + +} + + + +- (void)layoutSubviews { + [super layoutSubviews]; + + CGRect newHeight = self.control.frame; + newHeight.size.height = 30; + self.control.frame = newHeight; + + [self.control setFrame:CGRectOffset(self.control.frame, 0, 28)]; + +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDSliderCell.h b/libTitanD3vUniversal/Cells/TDSliderCell.h new file mode 100644 index 0000000..1d3b368 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDSliderCell.h @@ -0,0 +1,20 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "TDAlertViewController.h" +#import "TDUtilities.h" + +@interface TDSliderCell : PSSliderTableCell { + BOOL showTips; + NSInteger tipsImageStyle; + float inset; +} + +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UIButton *tipsButton; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *containerColour; +@property (nonatomic, retain) UIColor *labelColour; +@end diff --git a/libTitanD3vUniversal/Cells/TDSliderCell.m b/libTitanD3vUniversal/Cells/TDSliderCell.m new file mode 100644 index 0000000..9bc0bfe --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDSliderCell.m @@ -0,0 +1,128 @@ +#import "TDSliderCell.h" + + +@implementation TDSliderCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + self.containerColour = [[TDAppearance sharedInstance] containerColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + + self.headerLabel = [[UILabel alloc] init]; + self.headerLabel.text = specifier.properties[@"title"]; + [self.contentView addSubview:self.headerLabel]; + [self.control setFrame:CGRectOffset(self.control.frame, 0, 15)]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.headerLabel.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:10].active = YES; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:15].active = YES; + + + showTips = specifier.properties[@"showTips"] && [specifier.properties[@"showTips"] boolValue]; + + + if (showTips) { + + self.tipsButton = [[UIButton alloc] init]; + self.tipsButton.backgroundColor = self.tintColour; + UIImage *tipsImage = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Tips/tips.png"]; + [self.tipsButton setImage:tipsImage forState:UIControlStateNormal]; + self.tipsButton.imageEdgeInsets = UIEdgeInsetsMake(3, 3, 3, 3); + [self.tipsButton addTarget:self action:@selector(showTipsTapped:) forControlEvents:UIControlEventTouchUpInside]; + self.tipsButton.layer.cornerRadius = 10; + [self.contentView addSubview:self.tipsButton]; + + self.tipsButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.tipsButton.widthAnchor constraintEqualToConstant:20.0].active = YES; + [self.tipsButton.heightAnchor constraintEqualToConstant:20.0].active = YES; + [[self.tipsButton centerYAnchor] constraintEqualToAnchor:self.headerLabel.centerYAnchor].active = true; + [self.tipsButton.leadingAnchor constraintEqualToAnchor:self.headerLabel.trailingAnchor constant:5].active = YES; + + } + + } + + return self; +} + + +-(void)showTipsTapped:(UIButton *)sender { + + [[TDUtilities sharedInstance] haptic:0]; + + NSString *titleString = self.specifier.properties[@"tipsTitle"]; + NSString *messageString = self.specifier.properties[@"tipsMessage"]; + NSString *tipsImagePath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Tips/%@.png", self.specifier.properties[@"tipsImage"]]; + UIImage *tipsImage = [UIImage imageWithContentsOfFile:tipsImagePath]; + + tipsImageStyle = [self.specifier.properties[@"tipsImageStyle"]integerValue]; + + + TDAlertViewControllerConfiguration *configuration = [TDAlertViewControllerConfiguration new]; + configuration.alertViewBackgroundColor = self.containerColour; + configuration.titleTextColor = self.labelColour; + configuration.messageTextColor = self.labelColour; + configuration.transitionStyle = TDAlertViewControllerTransitionStyleSlideFromTop; + configuration.backgroundTapDismissalGestureEnabled = YES; + configuration.swipeDismissalGestureEnabled = YES; + configuration.alwaysArrangesActionButtonsVertically = YES; + configuration.buttonConfiguration.titleColor = self.tintColour; + configuration.cancelButtonConfiguration.titleColor = self.tintColour; + configuration.cancelButtonConfiguration.titleFont = [UIFont systemFontOfSize:16]; + configuration.alertViewCornerRadius = 20; + configuration.showsSeparators = NO; + + + TDAlertAction *okAction = [[TDAlertAction alloc] initWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]; + + TDAlertViewController *alertViewController = [[TDAlertViewController alloc] initWithOptions:configuration title:titleString message:messageString actions:@[okAction]]; + + + if (tipsImageStyle == 0) { + + UIImageView *iconImageView = [[UIImageView alloc] initWithImage:tipsImage]; + iconImageView.contentMode = UIViewContentModeScaleAspectFit; + [iconImageView.heightAnchor constraintEqualToConstant:80.0f].active = YES; + alertViewController.alertViewContentView = iconImageView; + + } else { + + UIImageView *bannerImageView = [[UIImageView alloc] initWithImage:tipsImage]; + bannerImageView.clipsToBounds = YES; + bannerImageView.contentMode = UIViewContentModeScaleAspectFill; + [bannerImageView.heightAnchor constraintEqualToConstant:120.0f].active = YES; + alertViewController.alertViewContentView = bannerImageView; + + } + + + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController presentViewController:alertViewController animated:YES completion:nil]; + +} + + +- (void)layoutSubviews { + [super layoutSubviews]; + + [self.control setFrame:CGRectOffset(self.control.frame, 0, 15)]; + +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDStepperCell.h b/libTitanD3vUniversal/Cells/TDStepperCell.h new file mode 100644 index 0000000..ad8ef90 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDStepperCell.h @@ -0,0 +1,27 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "TDAlertViewController.h" +#import "TDUtilities.h" + +@interface TDStepperCell : PSControlTableCell { + NSString *title; + BOOL showTips; + NSInteger tipsImageStyle; + float inset; +} + +@property (nonatomic, assign) BOOL showPercentage; +@property (nonatomic, retain) UIStepper *control; +@property (nonatomic, retain) UILabel *valueLabel; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UIButton *tipsButton; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *containerColour; +@property (nonatomic, retain) UIColor *labelColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDStepperCell.m b/libTitanD3vUniversal/Cells/TDStepperCell.m new file mode 100644 index 0000000..c0645b1 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDStepperCell.m @@ -0,0 +1,222 @@ +#import "TDStepperCell.h" + + +@implementation TDStepperCell +@dynamic control; + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]) { + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + self.titleLabel.hidden = YES; + + self.containerColour = [[TDAppearance sharedInstance] containerColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + self.iconImage = [[UIImageView alloc]init]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:-9].active = true; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + self.subtitleLabel = [[UILabel alloc]init]; + [self.subtitleLabel setText:specifier.properties[@"subtitle"]]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.subtitleLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:9].active = true; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + showTips = specifier.properties[@"showTips"] && [specifier.properties[@"showTips"] boolValue]; + + + if (showTips) { + + self.tipsButton = [[UIButton alloc] init]; + self.tipsButton.backgroundColor = self.tintColour; + UIImage *tipsImage = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Tips/tips.png"]; + [self.tipsButton setImage:tipsImage forState:UIControlStateNormal]; + self.tipsButton.imageEdgeInsets = UIEdgeInsetsMake(3, 3, 3, 3); + [self.tipsButton addTarget:self action:@selector(showTipsTapped:) forControlEvents:UIControlEventTouchUpInside]; + self.tipsButton.layer.cornerRadius = 10; + [self.contentView addSubview:self.tipsButton]; + + self.tipsButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.tipsButton.widthAnchor constraintEqualToConstant:20.0].active = YES; + [self.tipsButton.heightAnchor constraintEqualToConstant:20.0].active = YES; + [[self.tipsButton centerYAnchor] constraintEqualToAnchor:self.headerLabel.centerYAnchor].active = true; + [self.tipsButton.leadingAnchor constraintEqualToAnchor:self.headerLabel.trailingAnchor constant:5].active = YES; + + } + + + self.accessoryView = self.control; + UIStepper *stepper = (UIStepper*)self.control; + + + self.showPercentage = [[specifier propertyForKey:@"self.showPercentage"]boolValue]; + stepper.maximumValue = [[specifier propertyForKey:@"maximumValue"]doubleValue]; + stepper.value = [[specifier propertyForKey:@"default"]doubleValue]; + stepper.minimumValue = [[specifier propertyForKey:@"minimumValue"]doubleValue]; + stepper.stepValue = [[specifier propertyForKey:@"stepValue"]doubleValue]; + + + self.valueLabel=[UILabel new]; + self.valueLabel.font = [UIFont systemFontOfSize:10]; + [self addSubview:self.valueLabel]; + + } + return self; + +} + + +-(void)showTipsTapped:(UIButton *)sender { + + [[TDUtilities sharedInstance] haptic:0]; + + NSString *titleString = self.specifier.properties[@"tipsTitle"]; + NSString *messageString = self.specifier.properties[@"tipsMessage"]; + NSString *tipsImagePath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Tips/%@.png", self.specifier.properties[@"tipsImage"]]; + UIImage *tipsImage = [UIImage imageWithContentsOfFile:tipsImagePath]; + + tipsImageStyle = [self.specifier.properties[@"tipsImageStyle"]integerValue]; + + + TDAlertViewControllerConfiguration *configuration = [TDAlertViewControllerConfiguration new]; + configuration.alertViewBackgroundColor = self.containerColour; + configuration.titleTextColor = self.labelColour; + configuration.messageTextColor = self.labelColour; + configuration.transitionStyle = TDAlertViewControllerTransitionStyleSlideFromTop; + configuration.backgroundTapDismissalGestureEnabled = YES; + configuration.swipeDismissalGestureEnabled = YES; + configuration.alwaysArrangesActionButtonsVertically = YES; + configuration.buttonConfiguration.titleColor = self.tintColour; + configuration.cancelButtonConfiguration.titleColor = self.tintColour; + configuration.cancelButtonConfiguration.titleFont = [UIFont systemFontOfSize:16]; + configuration.alertViewCornerRadius = 20; + configuration.showsSeparators = NO; + + + TDAlertAction *okAction = [[TDAlertAction alloc] initWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]; + + TDAlertViewController *alertViewController = [[TDAlertViewController alloc] initWithOptions:configuration title:titleString message:messageString actions:@[okAction]]; + + + if (tipsImageStyle == 0) { + + UIImageView *iconImageView = [[UIImageView alloc] initWithImage:tipsImage]; + iconImageView.contentMode = UIViewContentModeScaleAspectFit; + [iconImageView.heightAnchor constraintEqualToConstant:80.0f].active = YES; + alertViewController.alertViewContentView = iconImageView; + + } else { + + UIImageView *bannerImageView = [[UIImageView alloc] initWithImage:tipsImage]; + bannerImageView.clipsToBounds = YES; + bannerImageView.contentMode = UIViewContentModeScaleAspectFill; + [bannerImageView.heightAnchor constraintEqualToConstant:120.0f].active = YES; + alertViewController.alertViewContentView = bannerImageView; + + } + + + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController presentViewController:alertViewController animated:YES completion:nil]; + +} + + +-(void)layoutSubviews{ + [super layoutSubviews]; + + float spacing = 15; + + CGRect accessoryViewFrame = self.accessoryView.frame; + accessoryViewFrame.origin.x = self.frame.size.width-self.accessoryView.frame.size.width-spacing; + accessoryViewFrame.size.height = self.frame.size.height; + self.accessoryView.frame = accessoryViewFrame; + + + self.valueLabel.frame = CGRectMake(accessoryViewFrame.origin.x-spacing-50, 0, 55, self.frame.size.height); + self.valueLabel.textAlignment = NSTextAlignmentRight; + + self.textLabel.textColor = self.labelColour; + self.textLabel.frame = CGRectMake(spacing, 0, self.valueLabel.frame.origin.x-spacing, self.frame.size.height); + +} + + +- (void)refreshCellContentsWithSpecifier:(PSSpecifier *)specifier { + [super refreshCellContentsWithSpecifier:specifier]; + self.showPercentage = [[specifier propertyForKey:@"showPercentage"]boolValue]; + [self _updateLabel]; +} + + +- (UIStepper *)newControl { + UIStepper *stepper = [[UIStepper alloc] initWithFrame:CGRectZero]; + + stepper.continuous = YES; + return stepper; +} + + +- (NSNumber *)controlValue { + return @(self.control.value); +} + + +- (void)setValue:(NSNumber *)value { + [super setValue:value]; + self.control.value = value.doubleValue; +} + + +- (void)controlChanged:(UIStepper *)stepper { + [super controlChanged:stepper]; + [self _updateLabel]; +} + + +- (void)_updateLabel { + if (!self.control) { + return; + } + + float value =self.control.value; + self.valueLabel.text = self.showPercentage ? [NSString stringWithFormat:@"%.0f%%", value] : [NSString stringWithFormat:@"%.2f",value]; + [self setNeedsLayout]; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDSwitchCell.h b/libTitanD3vUniversal/Cells/TDSwitchCell.h new file mode 100644 index 0000000..79b7e69 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDSwitchCell.h @@ -0,0 +1,23 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "TDAlertViewController.h" +#import "TDUtilities.h" + +@interface TDSwitchCell : PSSwitchTableCell { + BOOL showTips; + NSInteger tipsImageStyle; + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UIButton *tipsButton; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *containerColour; +@property (nonatomic, retain) UIColor *labelColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDSwitchCell.m b/libTitanD3vUniversal/Cells/TDSwitchCell.m new file mode 100644 index 0000000..a1ec9b3 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDSwitchCell.m @@ -0,0 +1,153 @@ +#import "TDSwitchCell.h" + +@implementation TDSwitchCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + self.containerColour = [[TDAppearance sharedInstance] containerColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + ((UISwitch *)self.control).onTintColor = self.tintColour; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + + self.iconImage = [[UIImageView alloc]init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:customIconPath]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:-9].active = true; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + self.subtitleLabel = [[UILabel alloc]init]; + [self.subtitleLabel setText:specifier.properties[@"subtitle"]]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.subtitleLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor constant:9].active = true; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + showTips = specifier.properties[@"showTips"] && [specifier.properties[@"showTips"] boolValue]; + + + if (showTips) { + + self.tipsButton = [[UIButton alloc] init]; + self.tipsButton.backgroundColor = self.tintColour; + UIImage *tipsImage = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Tips/tips.png"]; + [self.tipsButton setImage:tipsImage forState:UIControlStateNormal]; + self.tipsButton.imageEdgeInsets = UIEdgeInsetsMake(3, 3, 3, 3); + [self.tipsButton addTarget:self action:@selector(showTipsTapped:) forControlEvents:UIControlEventTouchUpInside]; + self.tipsButton.layer.cornerRadius = 10; + [self.contentView addSubview:self.tipsButton]; + + self.tipsButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.tipsButton.widthAnchor constraintEqualToConstant:20.0].active = YES; + [self.tipsButton.heightAnchor constraintEqualToConstant:20.0].active = YES; + [[self.tipsButton centerYAnchor] constraintEqualToAnchor:self.headerLabel.centerYAnchor].active = true; + [self.tipsButton.leadingAnchor constraintEqualToAnchor:self.headerLabel.trailingAnchor constant:5].active = YES; + + } + + } + + return self; +} + + +-(void)showTipsTapped:(UIButton *)sender { + + [[TDUtilities sharedInstance] haptic:0]; + + NSString *titleString = self.specifier.properties[@"tipsTitle"]; + NSString *messageString = self.specifier.properties[@"tipsMessage"]; + NSString *tipsImagePath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Tips/%@.png", self.specifier.properties[@"tipsImage"]]; + UIImage *tipsImage = [UIImage imageWithContentsOfFile:tipsImagePath]; + + tipsImageStyle = [self.specifier.properties[@"tipsImageStyle"]integerValue]; + + + TDAlertViewControllerConfiguration *configuration = [TDAlertViewControllerConfiguration new]; + configuration.alertViewBackgroundColor = self.containerColour; + configuration.titleTextColor = self.labelColour; + configuration.messageTextColor = self.labelColour; + configuration.transitionStyle = TDAlertViewControllerTransitionStyleSlideFromTop; + configuration.backgroundTapDismissalGestureEnabled = YES; + configuration.swipeDismissalGestureEnabled = YES; + configuration.alwaysArrangesActionButtonsVertically = YES; + configuration.buttonConfiguration.titleColor = self.tintColour; + configuration.cancelButtonConfiguration.titleColor = self.tintColour; + configuration.cancelButtonConfiguration.titleFont = [UIFont systemFontOfSize:16]; + configuration.alertViewCornerRadius = 20; + configuration.showsSeparators = NO; + + + TDAlertAction *okAction = [[TDAlertAction alloc] initWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]; + + TDAlertViewController *alertViewController = [[TDAlertViewController alloc] initWithOptions:configuration title:titleString message:messageString actions:@[okAction]]; + + + if (tipsImageStyle == 0) { + + UIImageView *iconImageView = [[UIImageView alloc] initWithImage:tipsImage]; + iconImageView.contentMode = UIViewContentModeScaleAspectFit; + [iconImageView.heightAnchor constraintEqualToConstant:80.0f].active = YES; + alertViewController.alertViewContentView = iconImageView; + + } else { + + UIImageView *bannerImageView = [[UIImageView alloc] initWithImage:tipsImage]; + bannerImageView.clipsToBounds = YES; + bannerImageView.contentMode = UIViewContentModeScaleAspectFill; + [bannerImageView.heightAnchor constraintEqualToConstant:120.0f].active = YES; + alertViewController.alertViewContentView = bannerImageView; + + } + + + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController presentViewController:alertViewController animated:YES completion:nil]; + +} + + +// - (void)layoutSubviews { +// [super layoutSubviews]; + +// [self.control setFrame:CGRectOffset(self.control.frame, -10, 0)]; + +// } + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDSystemColourPickerCell.h b/libTitanD3vUniversal/Cells/TDSystemColourPickerCell.h new file mode 100644 index 0000000..9463781 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDSystemColourPickerCell.h @@ -0,0 +1,20 @@ +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface PSTableCell (PrivateColourPicker) +- (UIViewController *)_viewControllerForAncestor; +@end + +@interface TDSystemColourPickerCell : PSTableCell { + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UIColor *borderColour; +@property (nonatomic, retain) UIColor *tintColour; + +@end diff --git a/libTitanD3vUniversal/Cells/TDSystemColourPickerCell.m b/libTitanD3vUniversal/Cells/TDSystemColourPickerCell.m new file mode 100644 index 0000000..32a9001 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDSystemColourPickerCell.m @@ -0,0 +1,174 @@ +#import "TDSystemColourPickerCell.h" + +static UIView *colorPreview; + +@implementation TDSystemColourPickerCell + + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.borderColour = [[TDAppearance sharedInstance] borderColour]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + + self.iconImage = [[UIImageView alloc]initWithFrame:CGRectMake(13,15,40,40)]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + + self.headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(65,17.5,200,20)]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.subtitleLabel = [[UILabel alloc]initWithFrame:CGRectMake(65,35,200,20)]; + [self.subtitleLabel setText:specifier.properties[@"subtitle"]]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + } + + return self; +} + + +- (id)target { + return self; +} + + +- (id)cellTarget { + return self; +} + + +- (SEL)action { + return @selector(openColorPicker); +} + + +- (SEL)cellAction { + return @selector(openColorPicker); +} + + +- (void)openColorPicker { + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + NSData *decodedData = [settings objectForKey:self.specifier.properties[@"key"]]; + UIColor *currentColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + + UIViewController *prefsController = [self _viewControllerForAncestor]; + + if (@available(iOS 14.0, *)) { + UIColorPickerViewController *colourPickerVC = [[UIColorPickerViewController alloc] init]; + colourPickerVC.delegate = self; + colourPickerVC.selectedColor = currentColour; + [prefsController presentViewController:colourPickerVC animated:YES completion:nil]; + } + +} + + +- (void)updatePreview { + + + colorPreview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 29)]; + colorPreview.layer.cornerRadius = 14.5; + colorPreview.layer.borderWidth = 1.5; + colorPreview.layer.borderColor = self.borderColour.CGColor; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + NSData *decodedData = [settings objectForKey:self.specifier.properties[@"key"]]; + UIColor *currentColour = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]; + + if (decodedData != nil ) { + colorPreview.backgroundColor = currentColour; + } else { + colorPreview.backgroundColor = UIColor.whiteColor; + } + + [self setAccessoryView:colorPreview]; +} + + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + [self updatePreview]; + + [self.specifier setTarget:self]; + [self.specifier setButtonAction:@selector(openColorPicker)]; + +} + + +- (void)colorPickerViewControllerDidSelectColor:(UIColorPickerViewController *)viewController API_AVAILABLE(ios(14.0)){ + + UIColor *selectedColour = viewController.selectedColor; + NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:selectedColour]; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:encodedData forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + + [self updatePreview]; + +} + + +- (void)colorPickerViewControllerDidFinish:(UIColorPickerViewController *)viewController API_AVAILABLE(ios(14.0)){ + + UIColor *selectedColour = viewController.selectedColor; + NSData *encodedData = [NSKeyedArchiver archivedDataWithRootObject:selectedColour]; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:encodedData forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + + [self updatePreview]; + +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + + +// - (void)layoutSubviews { +// [super layoutSubviews]; + +// [self.accessoryView setFrame:CGRectOffset(self.accessoryView.frame, -10, 0)]; + +// } + + +@end diff --git a/libTitanD3vUniversal/Cells/TDTermsAndConditionsCell.h b/libTitanD3vUniversal/Cells/TDTermsAndConditionsCell.h new file mode 100644 index 0000000..811b4df --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDTermsAndConditionsCell.h @@ -0,0 +1,20 @@ +#import +#import +#import "TDAppearance.h" +#import "ConstraintExtension.h" +#import "TDUtilities.h" +#import "./TermsandConditions/TDTermsAndConditionsVC.h" + +@interface TDTermsAndConditionsCell : PSTableCell { + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (nonatomic, retain) UITextField *reviewTextField; +@property (nonatomic, retain) UITextView *reviewTextView; +@property (nonatomic, retain) UILabel *placeholderLabel; + +@end diff --git a/libTitanD3vUniversal/Cells/TDTermsAndConditionsCell.m b/libTitanD3vUniversal/Cells/TDTermsAndConditionsCell.m new file mode 100644 index 0000000..98cef32 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDTermsAndConditionsCell.m @@ -0,0 +1,93 @@ +#import "TDTermsAndConditionsCell.h" + +@implementation TDTermsAndConditionsCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + if (self) { + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + + self.iconImage = [[UIImageView alloc]init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Terms&Conditions/terms-and-conditions.png"]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + self.headerLabel.text = @"Terms & Conditions"; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:17]]; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:12].active = YES; + + + } + + return self; +} + + +- (id)target { + return self; +} + + +- (id)cellTarget { + return self; +} + + +- (SEL)action { + return @selector(openTermsConditionsVC); +} + + +- (SEL)cellAction { + return @selector(openTermsConditionsVC); +} + + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + [self.specifier setTarget:self]; + [self.specifier setButtonAction:@selector(openTermsConditionsVC)]; + + + UIView *blankView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 30, 30)]; + [blankView setClipsToBounds:YES]; + [self setAccessoryView:blankView]; + +} + + +-(void)openTermsConditionsVC { + TDTermsAndConditionsVC *tvc = [[TDTermsAndConditionsVC alloc] init]; + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController presentViewController:tvc animated:YES completion:nil]; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/Cells/TDTextViewCell.h b/libTitanD3vUniversal/Cells/TDTextViewCell.h new file mode 100644 index 0000000..bdaae8a --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDTextViewCell.h @@ -0,0 +1,19 @@ +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "TDUtilities.h" + +@interface TDTextViewCell : PSTableCell { + UIView *baseView; + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UITextView *descriptionTextView; +@property (nonatomic, retain) UIColor *labelColour; + +@property (nonatomic, retain) UIColor *tintColour; +@end diff --git a/libTitanD3vUniversal/Cells/TDTextViewCell.m b/libTitanD3vUniversal/Cells/TDTextViewCell.m new file mode 100644 index 0000000..4670d25 --- /dev/null +++ b/libTitanD3vUniversal/Cells/TDTextViewCell.m @@ -0,0 +1,167 @@ +#import "TDTextViewCell.h" + +@implementation TDTextViewCell +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + + baseView = [[UIView alloc] initWithFrame:self.bounds]; + baseView.backgroundColor = [[TDAppearance sharedInstance] cellColour]; + [self addSubview:baseView]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + + self.iconImage = [[UIImageView alloc]init]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:40.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:40.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:13].active = YES; + + + self.headerLabel = [[UILabel alloc] init]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[UIFont boldSystemFontOfSize:14]]; + self.headerLabel.textAlignment = NSTextAlignmentLeft; + [self addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:10].active = YES; + [self.headerLabel.topAnchor constraintEqualToAnchor:self.topAnchor constant:10].active = YES; + + + NSString *bundleID = specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + + self.descriptionTextView = [[UITextView alloc] init]; + self.descriptionTextView.clipsToBounds = YES; + self.descriptionTextView.contentInset = UIEdgeInsetsZero; + self.descriptionTextView.delegate = self; + self.descriptionTextView.editable = YES; + self.descriptionTextView.font = [UIFont systemFontOfSize:16]; + self.descriptionTextView.backgroundColor = [UIColor clearColor]; + self.descriptionTextView.scrollEnabled = YES; + self.descriptionTextView.textAlignment = NSTextAlignmentLeft; + self.descriptionTextView.textContainerInset = UIEdgeInsetsMake(0, -5, 0, 0); + self.descriptionTextView.text = [settings objectForKey:specifier.properties[@"key"]] ?: specifier.properties[@"default"]; + self.descriptionTextView.textColor = self.labelColour; + [self addSubview:self.descriptionTextView]; + + self.descriptionTextView.translatesAutoresizingMaskIntoConstraints = NO; + [self.descriptionTextView.topAnchor constraintEqualToAnchor:self.headerLabel.bottomAnchor constant:10].active = YES; + [self.descriptionTextView.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:10].active = YES; + [self.descriptionTextView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = YES; + [self.descriptionTextView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:10].active = YES; + + } + + + return self; +} + + +- (BOOL)textViewShouldBeginEditing:(UITextView *)textView { + + UIToolbar *textToolbar = [[UIToolbar alloc] init]; + [textToolbar sizeToFit]; + textToolbar.barStyle = UIBarStyleDefault; + textToolbar.tintColor = self.tintColour; + textToolbar.items = [self textToolBarButtons]; + self.descriptionTextView.inputAccessoryView = textToolbar; + + return YES; + +} + + +-(NSArray *)textToolBarButtons { + + NSMutableArray *textButtons = [[NSMutableArray alloc] init]; + + [textButtons addObject:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil]]; + + [textButtons addObject:[[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(dismissKeyboard)]]; + + return [textButtons copy]; + +} + + +-(void)textViewDidChange:(UITextView *)textView { + + NSString *textString = self.descriptionTextView.text; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:textString forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; +} + + +- (void)textViewDidEndEditing:(UITextView *) textView { + + NSString *textString = self.descriptionTextView.text; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:textString forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + +} + + +-(void)dismissKeyboard { + + [[TDUtilities sharedInstance] haptic:0]; + + NSString *textString = self.descriptionTextView.text; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:textString forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + + [self.descriptionTextView resignFirstResponder]; +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + + +- (void)layoutSubviews { + [super layoutSubviews]; + + baseView.frame = self.bounds; + +} + +@end diff --git a/libTitanD3vUniversal/CollectionView/TDCyclePagerTransformLayout.h b/libTitanD3vUniversal/CollectionView/TDCyclePagerTransformLayout.h new file mode 100644 index 0000000..0e570e2 --- /dev/null +++ b/libTitanD3vUniversal/CollectionView/TDCyclePagerTransformLayout.h @@ -0,0 +1,45 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, TDCyclePagerTransformLayoutType) { + TDCyclePagerTransformLayoutNormal, + TDCyclePagerTransformLayoutLinear, + TDCyclePagerTransformLayoutCoverflow, +}; + +@class TDCyclePagerTransformLayout; +@protocol TDCyclePagerTransformLayoutDelegate +- (void)pagerViewTransformLayout:(TDCyclePagerTransformLayout *)pagerViewTransformLayout initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes; +- (void)pagerViewTransformLayout:(TDCyclePagerTransformLayout *)pagerViewTransformLayout applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes; +@end + + +@interface TDCyclePagerViewLayout : NSObject + +@property (nonatomic, assign) CGSize itemSize; +@property (nonatomic, assign) CGFloat itemSpacing; +@property (nonatomic, assign) UIEdgeInsets sectionInset; +@property (nonatomic, assign) TDCyclePagerTransformLayoutType layoutType; +@property (nonatomic, assign) CGFloat minimumScale; // sacle default 0.8 +@property (nonatomic, assign) CGFloat minimumAlpha; // alpha default 1.0 +@property (nonatomic, assign) CGFloat maximumAngle; // angle is % default 0.2 +@property (nonatomic, assign) BOOL isInfiniteLoop; // infinte scroll +@property (nonatomic, assign) CGFloat rateOfChange; // scale and angle change rate +@property (nonatomic, assign) BOOL adjustSpacingWhenScroling; +@property (nonatomic, assign) BOOL itemVerticalCenter; +@property (nonatomic, assign) BOOL itemHorizontalCenter; +@property (nonatomic, assign, readonly) UIEdgeInsets onlyOneSectionInset; +@property (nonatomic, assign, readonly) UIEdgeInsets firstSectionInset; +@property (nonatomic, assign, readonly) UIEdgeInsets lastSectionInset; +@property (nonatomic, assign, readonly) UIEdgeInsets middleSectionInset; + +@end + + +@interface TDCyclePagerTransformLayout : UICollectionViewFlowLayout +@property (nonatomic, strong) TDCyclePagerViewLayout *layout; +@property (nonatomic, weak, nullable) id delegate; +@end + +NS_ASSUME_NONNULL_END diff --git a/libTitanD3vUniversal/CollectionView/TDCyclePagerTransformLayout.m b/libTitanD3vUniversal/CollectionView/TDCyclePagerTransformLayout.m new file mode 100644 index 0000000..7440cb2 --- /dev/null +++ b/libTitanD3vUniversal/CollectionView/TDCyclePagerTransformLayout.m @@ -0,0 +1,292 @@ +#import "TDCyclePagerTransformLayout.h" + +typedef NS_ENUM(NSUInteger, TDTransformLayoutItemDirection) { + TDTransformLayoutItemLeft, + TDTransformLayoutItemCenter, + TDTransformLayoutItemRight, +}; + + +@interface TDCyclePagerTransformLayout () { + struct { + unsigned int applyTransformToAttributes :1; + unsigned int initializeTransformAttributes :1; + }_delegateFlags; +} + +@property (nonatomic, assign) BOOL applyTransformToAttributesDelegate; + +@end + + +@interface TDCyclePagerViewLayout () + +@property (nonatomic, weak) UIView *pageView; + +@end + + +@implementation TDCyclePagerTransformLayout + +- (instancetype)init { + if (self = [super init]) { + self.scrollDirection = UICollectionViewScrollDirectionHorizontal; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + if (self = [super initWithCoder:aDecoder]) { + self.scrollDirection = UICollectionViewScrollDirectionHorizontal; + } + return self; +} + +#pragma mark - getter setter + +- (void)setDelegate:(id)delegate { + _delegate = delegate; + _delegateFlags.initializeTransformAttributes = [delegate respondsToSelector:@selector(pagerViewTransformLayout:initializeTransformAttributes:)]; + _delegateFlags.applyTransformToAttributes = [delegate respondsToSelector:@selector(pagerViewTransformLayout:applyTransformToAttributes:)]; +} + +- (void)setLayout:(TDCyclePagerViewLayout *)layout { + _layout = layout; + _layout.pageView = self.collectionView; + self.itemSize = _layout.itemSize; + self.minimumInteritemSpacing = _layout.itemSpacing; + self.minimumLineSpacing = _layout.itemSpacing; +} + +- (CGSize)itemSize { + if (!_layout) { + return [super itemSize]; + } + return _layout.itemSize; +} + +- (CGFloat)minimumLineSpacing { + if (!_layout) { + return [super minimumLineSpacing]; + } + return _layout.itemSpacing; +} + +- (CGFloat)minimumInteritemSpacing { + if (!_layout) { + return [super minimumInteritemSpacing]; + } + return _layout.itemSpacing; +} + +- (TDTransformLayoutItemDirection)directionWithCenterX:(CGFloat)centerX { + TDTransformLayoutItemDirection direction= TDTransformLayoutItemRight; + CGFloat contentCenterX = self.collectionView.contentOffset.x + CGRectGetWidth(self.collectionView.frame)/2; + if (ABS(centerX - contentCenterX) < 0.5) { + direction = TDTransformLayoutItemCenter; + }else if (centerX - contentCenterX < 0) { + direction = TDTransformLayoutItemLeft; + } + return direction; +} + +#pragma mark - layout + +-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds +{ + return _layout.layoutType == TDCyclePagerTransformLayoutNormal ? [super shouldInvalidateLayoutForBoundsChange:newBounds] : YES; +} + +- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { + if (_delegateFlags.applyTransformToAttributes || _layout.layoutType != TDCyclePagerTransformLayoutNormal) { + NSArray *attributesArray = [[NSArray alloc] initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES]; + CGRect visibleRect = {self.collectionView.contentOffset,self.collectionView.bounds.size}; + for (UICollectionViewLayoutAttributes *attributes in attributesArray) { + if (!CGRectIntersectsRect(visibleRect, attributes.frame)) { + continue; + } + if (_delegateFlags.applyTransformToAttributes) { + [_delegate pagerViewTransformLayout:self applyTransformToAttributes:attributes]; + }else { + [self applyTransformToAttributes:attributes layoutType:_layout.layoutType]; + } + } + return attributesArray; + } + return [super layoutAttributesForElementsInRect:rect]; +} + +- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { + UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath]; + if (_delegateFlags.initializeTransformAttributes) { + [_delegate pagerViewTransformLayout:self initializeTransformAttributes:attributes]; + }else if(_layout.layoutType != TDCyclePagerTransformLayoutNormal){ + [self initializeTransformAttributes:attributes layoutType:_layout.layoutType]; + } + return attributes; +} + +#pragma mark - transform + +- (void)initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes layoutType:(TDCyclePagerTransformLayoutType)layoutType { + switch (layoutType) { + case TDCyclePagerTransformLayoutLinear: + [self applyLinearTransformToAttributes:attributes scale:_layout.minimumScale alpha:_layout.minimumAlpha]; + break; + case TDCyclePagerTransformLayoutCoverflow: + { + [self applyCoverflowTransformToAttributes:attributes angle:_layout.maximumAngle alpha:_layout.minimumAlpha]; + break; + } + default: + break; + } +} + +- (void)applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes layoutType:(TDCyclePagerTransformLayoutType)layoutType { + switch (layoutType) { + case TDCyclePagerTransformLayoutLinear: + [self applyLinearTransformToAttributes:attributes]; + break; + case TDCyclePagerTransformLayoutCoverflow: + [self applyCoverflowTransformToAttributes:attributes]; + break; + default: + break; + } +} + +#pragma mark - LinearTransform + +- (void)applyLinearTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes { + CGFloat collectionViewWidth = self.collectionView.frame.size.width; + if (collectionViewWidth <= 0) { + return; + } + CGFloat centetX = self.collectionView.contentOffset.x + collectionViewWidth/2; + CGFloat delta = ABS(attributes.center.x - centetX); + CGFloat scale = MAX(1 - delta/collectionViewWidth*_layout.rateOfChange, _layout.minimumScale); + CGFloat alpha = MAX(1 - delta/collectionViewWidth, _layout.minimumAlpha); + [self applyLinearTransformToAttributes:attributes scale:scale alpha:alpha]; +} + +- (void)applyLinearTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes scale:(CGFloat)scale alpha:(CGFloat)alpha { + CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale); + if (_layout.adjustSpacingWhenScroling) { + TDTransformLayoutItemDirection direction = [self directionWithCenterX:attributes.center.x]; + CGFloat translate = 0; + switch (direction) { + case TDTransformLayoutItemLeft: + translate = 1.15 * attributes.size.width*(1-scale)/2; + break; + case TDTransformLayoutItemRight: + translate = -1.15 * attributes.size.width*(1-scale)/2; + break; + default: + // center + scale = 1.0; + alpha = 1.0; + break; + } + transform = CGAffineTransformTranslate(transform,translate, 0); + } + attributes.transform = transform; + attributes.alpha = alpha; +} + +#pragma mark - CoverflowTransform + +- (void)applyCoverflowTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes{ + CGFloat collectionViewWidth = self.collectionView.frame.size.width; + if (collectionViewWidth <= 0) { + return; + } + CGFloat centetX = self.collectionView.contentOffset.x + collectionViewWidth/2; + CGFloat delta = ABS(attributes.center.x - centetX); + CGFloat angle = MIN(delta/collectionViewWidth*(1-_layout.rateOfChange), _layout.maximumAngle); + CGFloat alpha = MAX(1 - delta/collectionViewWidth, _layout.minimumAlpha); + [self applyCoverflowTransformToAttributes:attributes angle:angle alpha:alpha]; +} + +- (void)applyCoverflowTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes angle:(CGFloat)angle alpha:(CGFloat)alpha { + TDTransformLayoutItemDirection direction = [self directionWithCenterX:attributes.center.x]; + CATransform3D transform3D = CATransform3DIdentity; + transform3D.m34 = -0.002; + CGFloat translate = 0; + switch (direction) { + case TDTransformLayoutItemLeft: + translate = (1-cos(angle*1.2*M_PI))*attributes.size.width; + break; + case TDTransformLayoutItemRight: + translate = -(1-cos(angle*1.2*M_PI))*attributes.size.width; + angle = -angle; + break; + default: + // center + angle = 0; + alpha = 1; + break; + } + + transform3D = CATransform3DRotate(transform3D, M_PI*angle, 0, 1, 0); + if (_layout.adjustSpacingWhenScroling) { + transform3D = CATransform3DTranslate(transform3D, translate, 0, 0); + } + attributes.transform3D = transform3D; + attributes.alpha = alpha; + +} +@end + + +@implementation TDCyclePagerViewLayout + +- (instancetype)init { + if (self = [super init]) { + _itemVerticalCenter = YES; + _minimumScale = 0.8; + _minimumAlpha = 1.0; + _maximumAngle = 0.2; + _rateOfChange = 0.4; + _adjustSpacingWhenScroling = YES; + } + return self; +} + +#pragma mark - getter + +- (UIEdgeInsets)onlyOneSectionInset { + CGFloat leftSpace = _pageView && !_isInfiniteLoop && _itemHorizontalCenter ? (CGRectGetWidth(_pageView.frame) - _itemSize.width)/2 : _sectionInset.left; + CGFloat rightSpace = _pageView && !_isInfiniteLoop && _itemHorizontalCenter ? (CGRectGetWidth(_pageView.frame) - _itemSize.width)/2 : _sectionInset.right; + if (_itemVerticalCenter) { + CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2; + return UIEdgeInsetsMake(verticalSpace, leftSpace, verticalSpace, rightSpace); + } + return UIEdgeInsetsMake(_sectionInset.top, leftSpace, _sectionInset.bottom, rightSpace); +} + +- (UIEdgeInsets)firstSectionInset { + if (_itemVerticalCenter) { + CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2; + return UIEdgeInsetsMake(verticalSpace, _sectionInset.left, verticalSpace, _itemSpacing); + } + return UIEdgeInsetsMake(_sectionInset.top, _sectionInset.left, _sectionInset.bottom, _itemSpacing); +} + +- (UIEdgeInsets)lastSectionInset { + if (_itemVerticalCenter) { + CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2; + return UIEdgeInsetsMake(verticalSpace, 0, verticalSpace, _sectionInset.right); + } + return UIEdgeInsetsMake(_sectionInset.top, 0, _sectionInset.bottom, _sectionInset.right); +} + +- (UIEdgeInsets)middleSectionInset { + if (_itemVerticalCenter) { + CGFloat verticalSpace = (CGRectGetHeight(_pageView.frame) - _itemSize.height)/2; + return UIEdgeInsetsMake(verticalSpace, 0, verticalSpace, _itemSpacing); + } + return _sectionInset; +} + +@end diff --git a/libTitanD3vUniversal/CollectionView/TDCyclePagerView.h b/libTitanD3vUniversal/CollectionView/TDCyclePagerView.h new file mode 100644 index 0000000..beea3a0 --- /dev/null +++ b/libTitanD3vUniversal/CollectionView/TDCyclePagerView.h @@ -0,0 +1,75 @@ +#import +#import "TDCyclePagerTransformLayout.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef struct { + NSInteger index; + NSInteger section; +}TDIndexSection; + + +typedef NS_ENUM(NSUInteger, TDPagerScrollDirection) { + TDPagerScrollDirectionLeft, + TDPagerScrollDirectionRight, +}; + +@class TDCyclePagerView; +@protocol TDCyclePagerViewDataSource +- (NSInteger)numberOfItemsInPagerView:(TDCyclePagerView *)pageView; +- (__kindof UICollectionViewCell *)pagerView:(TDCyclePagerView *)pagerView cellForItemAtIndex:(NSInteger)index; +- (TDCyclePagerViewLayout *)layoutForPagerView:(TDCyclePagerView *)pageView; + +@end + +@protocol TDCyclePagerViewDelegate +@optional + +- (void)pagerView:(TDCyclePagerView *)pageView didScrollFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex; +- (void)pagerView:(TDCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndex:(NSInteger)index; +- (void)pagerView:(TDCyclePagerView *)pageView didSelectedItemCell:(__kindof UICollectionViewCell *)cell atIndexSection:(TDIndexSection)indexSection; +- (void)pagerView:(TDCyclePagerView *)pageView initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes; +- (void)pagerView:(TDCyclePagerView *)pageView applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes; +- (void)pagerViewDidScroll:(TDCyclePagerView *)pageView; +- (void)pagerViewWillBeginDragging:(TDCyclePagerView *)pageView; +- (void)pagerViewDidEndDragging:(TDCyclePagerView *)pageView willDecelerate:(BOOL)decelerate; +- (void)pagerViewWillBeginDecelerating:(TDCyclePagerView *)pageView; +- (void)pagerViewDidEndDecelerating:(TDCyclePagerView *)pageView; +- (void)pagerViewWillBeginScrollingAnimation:(TDCyclePagerView *)pageView; +- (void)pagerViewDidEndScrollingAnimation:(TDCyclePagerView *)pageView; + +@end + + +@interface TDCyclePagerView : UIView + +@property (nonatomic, strong, nullable) UIView *backgroundView; +@property (nonatomic, weak, nullable) id dataSource; +@property (nonatomic, weak, nullable) id delegate; +@property (nonatomic, weak, readonly) UICollectionView *collectionView; +@property (nonatomic, strong, readonly) TDCyclePagerViewLayout *layout; +@property (nonatomic, assign) BOOL isInfiniteLoop; +@property (nonatomic, assign) CGFloat autoScrollInterval; +@property (nonatomic, assign) BOOL reloadDataNeedResetIndex; +@property (nonatomic, assign, readonly) NSInteger curIndex; +@property (nonatomic, assign, readonly) TDIndexSection indexSection; +@property (nonatomic, assign, readonly) CGPoint contentOffset; +@property (nonatomic, assign, readonly) BOOL tracking; +@property (nonatomic, assign, readonly) BOOL dragging; +@property (nonatomic, assign, readonly) BOOL decelerating; +- (void)reloadData; +- (void)updateData; +- (void)setNeedUpdateLayout; +- (void)setNeedClearLayout; +- (__kindof UICollectionViewCell * _Nullable)curIndexCell; +- (NSArray<__kindof UICollectionViewCell *> *_Nullable)visibleCells; +- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate; +- (void)scrollToItemAtIndexSection:(TDIndexSection)indexSection animate:(BOOL)animate; +- (void)scrollToNearlyIndexAtDirection:(TDPagerScrollDirection)direction animate:(BOOL)animate; +- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier; +- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier; +- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; + +@end + +NS_ASSUME_NONNULL_END diff --git a/libTitanD3vUniversal/CollectionView/TDCyclePagerView.m b/libTitanD3vUniversal/CollectionView/TDCyclePagerView.m new file mode 100644 index 0000000..03b39d9 --- /dev/null +++ b/libTitanD3vUniversal/CollectionView/TDCyclePagerView.m @@ -0,0 +1,599 @@ +#import "TDCyclePagerView.h" + +NS_INLINE BOOL TDEqualIndexSection(TDIndexSection indexSection1,TDIndexSection indexSection2) { + return indexSection1.index == indexSection2.index && indexSection1.section == indexSection2.section; +} + +NS_INLINE TDIndexSection TDMakeIndexSection(NSInteger index, NSInteger section) { + TDIndexSection indexSection; + indexSection.index = index; + indexSection.section = section; + return indexSection; +} + +@interface TDCyclePagerView () { + struct { + unsigned int pagerViewDidScroll :1; + unsigned int didScrollFromIndexToNewIndex :1; + unsigned int initializeTransformAttributes :1; + unsigned int applyTransformToAttributes :1; + }_delegateFlags; + struct { + unsigned int cellForItemAtIndex :1; + unsigned int layoutForPagerView :1; + }_dataSourceFlags; +} + +// UI +@property (nonatomic, weak) UICollectionView *collectionView; +@property (nonatomic, strong) TDCyclePagerViewLayout *layout; +@property (nonatomic, strong) NSTimer *timer; + +// Data +@property (nonatomic, assign) NSInteger numberOfItems; + +@property (nonatomic, assign) NSInteger dequeueSection; +@property (nonatomic, assign) TDIndexSection beginDragIndexSection; +@property (nonatomic, assign) NSInteger firstScrollIndex; + +@property (nonatomic, assign) BOOL needClearLayout; +@property (nonatomic, assign) BOOL didReloadData; +@property (nonatomic, assign) BOOL didLayout; +@property (nonatomic, assign) BOOL needResetIndex; + +@end + +#define kPagerViewMaxSectionCount 200 +#define kPagerViewMinSectionCount 18 + +@implementation TDCyclePagerView + +#pragma mark - life Cycle + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + [self configureProperty]; + + [self addCollectionView]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + if (self = [super initWithCoder:aDecoder]) { + [self configureProperty]; + + [self addCollectionView]; + } + return self; +} + +- (void)configureProperty { + _needResetIndex = NO; + _didReloadData = NO; + _didLayout = NO; + _autoScrollInterval = 0; + _isInfiniteLoop = YES; + _beginDragIndexSection.index = 0; + _beginDragIndexSection.section = 0; + _indexSection.index = -1; + _indexSection.section = -1; + _firstScrollIndex = -1; +} + +- (void)addCollectionView { + TDCyclePagerTransformLayout *layout = [[TDCyclePagerTransformLayout alloc]init]; + UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:layout]; + layout.delegate = _delegateFlags.applyTransformToAttributes ? self : nil;; + collectionView.backgroundColor = [UIColor clearColor]; + collectionView.dataSource = self; + collectionView.delegate = self; + collectionView.pagingEnabled = NO; + collectionView.decelerationRate = 1-0.0076; + if ([collectionView respondsToSelector:@selector(setPrefetchingEnabled:)]) { + collectionView.prefetchingEnabled = NO; + } + collectionView.showsHorizontalScrollIndicator = NO; + collectionView.showsVerticalScrollIndicator = NO; + [self addSubview:collectionView]; + _collectionView = collectionView; +} + +- (void)willMoveToSuperview:(UIView *)newSuperview { + if (!newSuperview) { + [self removeTimer]; + }else { + [self removeTimer]; + if (_autoScrollInterval > 0) { + [self addTimer]; + } + } +} + + +#pragma mark - timer + +- (void)addTimer { + if (_timer || _autoScrollInterval <= 0) { + return; + } + _timer = [NSTimer timerWithTimeInterval:_autoScrollInterval target:self selector:@selector(timerFired:) userInfo:nil repeats:YES]; + [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; +} + +- (void)removeTimer { + if (!_timer) { + return; + } + [_timer invalidate]; + _timer = nil; +} + +- (void)timerFired:(NSTimer *)timer { + if (!self.superview || !self.window || _numberOfItems == 0 || self.tracking) { + return; + } + + [self scrollToNearlyIndexAtDirection:TDPagerScrollDirectionRight animate:YES]; +} + +#pragma mark - getter + +- (TDCyclePagerViewLayout *)layout { + if (!_layout) { + if (_dataSourceFlags.layoutForPagerView) { + _layout = [_dataSource layoutForPagerView:self]; + _layout.isInfiniteLoop = _isInfiniteLoop; + } + if (_layout.itemSize.width <= 0 || _layout.itemSize.height <= 0) { + _layout = nil; + } + } + return _layout; +} + +- (NSInteger)curIndex { + return _indexSection.index; +} + +- (CGPoint)contentOffset { + return _collectionView.contentOffset; +} + +- (BOOL)tracking { + return _collectionView.tracking; +} + +- (BOOL)dragging { + return _collectionView.dragging; +} + +- (BOOL)decelerating { + return _collectionView.decelerating; +} + +- (UIView *)backgroundView { + return _collectionView.backgroundView; +} + +- (__kindof UICollectionViewCell *)curIndexCell { + return [_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:_indexSection.index inSection:_indexSection.section]]; +} + +- (NSArray<__kindof UICollectionViewCell *> *)visibleCells { + return _collectionView.visibleCells; +} + +- (NSArray *)visibleIndexs { + NSMutableArray *indexs = [NSMutableArray array]; + for (NSIndexPath *indexPath in _collectionView.indexPathsForVisibleItems) { + [indexs addObject:@(indexPath.item)]; + } + return [indexs copy]; +} + +#pragma mark - setter + +- (void)setBackgroundView:(UIView *)backgroundView { + [_collectionView setBackgroundView:backgroundView]; +} + +- (void)setAutoScrollInterval:(CGFloat)autoScrollInterval { + _autoScrollInterval = autoScrollInterval; + [self removeTimer]; + if (autoScrollInterval > 0 && self.superview) { + [self addTimer]; + } +} + +- (void)setDelegate:(id)delegate { + _delegate = delegate; + _delegateFlags.pagerViewDidScroll = [delegate respondsToSelector:@selector(pagerViewDidScroll:)]; + _delegateFlags.didScrollFromIndexToNewIndex = [delegate respondsToSelector:@selector(pagerView:didScrollFromIndex:toIndex:)]; + _delegateFlags.initializeTransformAttributes = [delegate respondsToSelector:@selector(pagerView:initializeTransformAttributes:)]; + _delegateFlags.applyTransformToAttributes = [delegate respondsToSelector:@selector(pagerView:applyTransformToAttributes:)]; + if (self.collectionView && self.collectionView.collectionViewLayout) { + ((TDCyclePagerTransformLayout *)self.collectionView.collectionViewLayout).delegate = _delegateFlags.applyTransformToAttributes ? self : nil; + } +} + +- (void)setDataSource:(id)dataSource { + _dataSource = dataSource; + _dataSourceFlags.cellForItemAtIndex = [dataSource respondsToSelector:@selector(pagerView:cellForItemAtIndex:)]; + _dataSourceFlags.layoutForPagerView = [dataSource respondsToSelector:@selector(layoutForPagerView:)]; +} + +#pragma mark - public + +- (void)reloadData { + _didReloadData = YES; + _needResetIndex = YES; + [self setNeedClearLayout]; + [self clearLayout]; + [self updateData]; +} + +// not clear layout +- (void)updateData { + [self updateLayout]; + _numberOfItems = [_dataSource numberOfItemsInPagerView:self]; + [_collectionView reloadData]; + if (!_didLayout && !CGRectIsEmpty(self.collectionView.frame) && _indexSection.index < 0) { + _didLayout = YES; + } + BOOL needResetIndex = _needResetIndex && _reloadDataNeedResetIndex; + _needResetIndex = NO; + if (needResetIndex) { + [self removeTimer]; + } + [self resetPagerViewAtIndex:(_indexSection.index < 0 && !CGRectIsEmpty(self.collectionView.frame)) || needResetIndex ? 0 :_indexSection.index]; + if (needResetIndex) { + [self addTimer]; + } +} + +- (void)scrollToNearlyIndexAtDirection:(TDPagerScrollDirection)direction animate:(BOOL)animate { + TDIndexSection indexSection = [self nearlyIndexPathAtDirection:direction]; + [self scrollToItemAtIndexSection:indexSection animate:animate]; +} + +- (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate { + if (!_didLayout && _didReloadData) { + _firstScrollIndex = index; + }else { + _firstScrollIndex = -1; + } + if (!_isInfiniteLoop) { + [self scrollToItemAtIndexSection:TDMakeIndexSection(index, 0) animate:animate]; + return; + } + + [self scrollToItemAtIndexSection:TDMakeIndexSection(index, index >= self.curIndex ? _indexSection.section : _indexSection.section+1) animate:animate]; +} + +- (void)scrollToItemAtIndexSection:(TDIndexSection)indexSection animate:(BOOL)animate { + if (_numberOfItems <= 0 || ![self isValidIndexSection:indexSection]) { + //NSLog(@"scrollToItemAtIndex: item indexSection is invalid!"); + return; + } + + if (animate && [_delegate respondsToSelector:@selector(pagerViewWillBeginScrollingAnimation:)]) { + [_delegate pagerViewWillBeginScrollingAnimation:self]; + } + CGFloat offset = [self caculateOffsetXAtIndexSection:indexSection]; + [_collectionView setContentOffset:CGPointMake(offset, _collectionView.contentOffset.y) animated:animate]; +} + +- (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier { + [_collectionView registerClass:Class forCellWithReuseIdentifier:identifier]; +} + +- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier { + [_collectionView registerNib:nib forCellWithReuseIdentifier:identifier]; +} + +- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index { + UICollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:[NSIndexPath indexPathForItem:index inSection:_dequeueSection]]; + return cell; +} + +#pragma mark - configure layout + +- (void)updateLayout { + if (!self.layout) { + return; + } + self.layout.isInfiniteLoop = _isInfiniteLoop; + ((TDCyclePagerTransformLayout *)_collectionView.collectionViewLayout).layout = self.layout; +} + +- (void)clearLayout { + if (_needClearLayout) { + _layout = nil; + _needClearLayout = NO; + } +} + +- (void)setNeedClearLayout { + _needClearLayout = YES; +} + +- (void)setNeedUpdateLayout { + if (!self.layout) { + return; + } + [self clearLayout]; + [self updateLayout]; + [_collectionView.collectionViewLayout invalidateLayout]; + [self resetPagerViewAtIndex:_indexSection.index < 0 ? 0 :_indexSection.index]; +} + +#pragma mark - pager index + +- (BOOL)isValidIndexSection:(TDIndexSection)indexSection { + return indexSection.index >= 0 && indexSection.index < _numberOfItems && indexSection.section >= 0 && indexSection.section < kPagerViewMaxSectionCount; +} + +- (TDIndexSection)nearlyIndexPathAtDirection:(TDPagerScrollDirection)direction{ + return [self nearlyIndexPathForIndexSection:_indexSection direction:direction]; +} + +- (TDIndexSection)nearlyIndexPathForIndexSection:(TDIndexSection)indexSection direction:(TDPagerScrollDirection)direction { + if (indexSection.index < 0 || indexSection.index >= _numberOfItems) { + return indexSection; + } + + if (!_isInfiniteLoop) { + if (direction == TDPagerScrollDirectionRight && indexSection.index == _numberOfItems - 1) { + return _autoScrollInterval > 0 ? TDMakeIndexSection(0, 0) : indexSection; + } else if (direction == TDPagerScrollDirectionRight) { + return TDMakeIndexSection(indexSection.index+1, 0); + } + + if (indexSection.index == 0) { + return _autoScrollInterval > 0 ? TDMakeIndexSection(_numberOfItems - 1, 0) : indexSection; + } + return TDMakeIndexSection(indexSection.index-1, 0); + } + + if (direction == TDPagerScrollDirectionRight) { + if (indexSection.index < _numberOfItems-1) { + return TDMakeIndexSection(indexSection.index+1, indexSection.section); + } + if (indexSection.section >= kPagerViewMaxSectionCount-1) { + return TDMakeIndexSection(indexSection.index, kPagerViewMaxSectionCount-1); + } + return TDMakeIndexSection(0, indexSection.section+1); + } + + if (indexSection.index > 0) { + return TDMakeIndexSection(indexSection.index-1, indexSection.section); + } + if (indexSection.section <= 0) { + return TDMakeIndexSection(indexSection.index, 0); + } + return TDMakeIndexSection(_numberOfItems-1, indexSection.section-1); +} + +- (TDIndexSection)caculateIndexSectionWithOffsetX:(CGFloat)offsetX { + if (_numberOfItems <= 0) { + return TDMakeIndexSection(0, 0); + } + UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)_collectionView.collectionViewLayout; + CGFloat leftEdge = _isInfiniteLoop ? _layout.sectionInset.left : _layout.onlyOneSectionInset.left; + CGFloat width = CGRectGetWidth(_collectionView.frame); + CGFloat middleOffset = offsetX + width/2; + CGFloat itemWidth = layout.itemSize.width + layout.minimumInteritemSpacing; + NSInteger curIndex = 0; + NSInteger curSection = 0; + if (middleOffset - leftEdge >= 0) { + NSInteger itemIndex = (middleOffset - leftEdge+layout.minimumInteritemSpacing/2)/itemWidth; + if (itemIndex < 0) { + itemIndex = 0; + }else if (itemIndex >= _numberOfItems*kPagerViewMaxSectionCount) { + itemIndex = _numberOfItems*kPagerViewMaxSectionCount-1; + } + curIndex = itemIndex%_numberOfItems; + curSection = itemIndex/_numberOfItems; + } + return TDMakeIndexSection(curIndex, curSection); +} + +- (CGFloat)caculateOffsetXAtIndexSection:(TDIndexSection)indexSection{ + if (_numberOfItems == 0) { + return 0; + } + UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)_collectionView.collectionViewLayout; + UIEdgeInsets edge = _isInfiniteLoop ? _layout.sectionInset : _layout.onlyOneSectionInset; + CGFloat leftEdge = edge.left; + CGFloat rightEdge = edge.right; + CGFloat width = CGRectGetWidth(_collectionView.frame); + CGFloat itemWidth = layout.itemSize.width + layout.minimumInteritemSpacing; + CGFloat offsetX = 0; + if (!_isInfiniteLoop && !_layout.itemHorizontalCenter && indexSection.index == _numberOfItems - 1) { + offsetX = leftEdge + itemWidth*(indexSection.index + indexSection.section*_numberOfItems) - (width - itemWidth) - layout.minimumInteritemSpacing + rightEdge; + }else { + offsetX = leftEdge + itemWidth*(indexSection.index + indexSection.section*_numberOfItems) - layout.minimumInteritemSpacing/2 - (width - itemWidth)/2; + } + return MAX(offsetX, 0); +} + +- (void)resetPagerViewAtIndex:(NSInteger)index { + if (_didLayout && _firstScrollIndex >= 0) { + index = _firstScrollIndex; + _firstScrollIndex = -1; + } + if (index < 0) { + return; + } + if (index >= _numberOfItems) { + index = 0; + } + [self scrollToItemAtIndexSection:TDMakeIndexSection(index, _isInfiniteLoop ? kPagerViewMaxSectionCount/3 : 0) animate:NO]; + if (!_isInfiniteLoop && _indexSection.index < 0) { + [self scrollViewDidScroll:_collectionView]; + } +} + +- (void)recyclePagerViewIfNeed { + if (!_isInfiniteLoop) { + return; + } + if (_indexSection.section > kPagerViewMaxSectionCount - kPagerViewMinSectionCount || _indexSection.section < kPagerViewMinSectionCount) { + [self resetPagerViewAtIndex:_indexSection.index]; + } +} + +#pragma mark - UICollectionViewDataSource + +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { + return _isInfiniteLoop ? kPagerViewMaxSectionCount : 1; +} + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + _numberOfItems = [_dataSource numberOfItemsInPagerView:self]; + return _numberOfItems; +} + +- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + _dequeueSection = indexPath.section; + if (_dataSourceFlags.cellForItemAtIndex) { + return [_dataSource pagerView:self cellForItemAtIndex:indexPath.row]; + } + NSAssert(NO, @"pagerView cellForItemAtIndex: is nil!"); + return nil; +} + +#pragma mark - UICollectionViewDelegateFlowLayout + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + if (!_isInfiniteLoop) { + return _layout.onlyOneSectionInset; + } + if (section == 0 ) { + return _layout.firstSectionInset; + }else if (section == kPagerViewMaxSectionCount -1) { + return _layout.lastSectionInset; + } + return _layout.middleSectionInset; +} + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; + if ([_delegate respondsToSelector:@selector(pagerView:didSelectedItemCell:atIndex:)]) { + [_delegate pagerView:self didSelectedItemCell:cell atIndex:indexPath.item]; + } + if ([_delegate respondsToSelector:@selector(pagerView:didSelectedItemCell:atIndexSection:)]) { + [_delegate pagerView:self didSelectedItemCell:cell atIndexSection:TDMakeIndexSection(indexPath.item, indexPath.section)]; + } +} + +#pragma mark - UIScrollViewDelegate + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + if (!_didLayout) { + return; + } + TDIndexSection newIndexSection = [self caculateIndexSectionWithOffsetX:scrollView.contentOffset.x]; + if (_numberOfItems <= 0 || ![self isValidIndexSection:newIndexSection]) { + NSLog(@"inVlaidIndexSection:(%ld,%ld)!",(long)newIndexSection.index,(long)newIndexSection.section); + return; + } + TDIndexSection indexSection = _indexSection; + _indexSection = newIndexSection; + + if (_delegateFlags.pagerViewDidScroll) { + [_delegate pagerViewDidScroll:self]; + } + + if (_delegateFlags.didScrollFromIndexToNewIndex && !TDEqualIndexSection(_indexSection, indexSection)) { + //NSLog(@"curIndex %ld",(long)_indexSection.index); + [_delegate pagerView:self didScrollFromIndex:MAX(indexSection.index, 0) toIndex:_indexSection.index]; + } +} + +- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { + if (_autoScrollInterval > 0) { + [self removeTimer]; + } + _beginDragIndexSection = [self caculateIndexSectionWithOffsetX:scrollView.contentOffset.x]; + if ([_delegate respondsToSelector:@selector(pagerViewWillBeginDragging:)]) { + [_delegate pagerViewWillBeginDragging:self]; + } +} + +- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { + if (fabs(velocity.x) < 0.35 || !TDEqualIndexSection(_beginDragIndexSection, _indexSection)) { + targetContentOffset->x = [self caculateOffsetXAtIndexSection:_indexSection]; + return; + } + TDPagerScrollDirection direction = TDPagerScrollDirectionRight; + if ((scrollView.contentOffset.x < 0 && targetContentOffset->x <= 0) || (targetContentOffset->x < scrollView.contentOffset.x && scrollView.contentOffset.x < scrollView.contentSize.width - scrollView.frame.size.width)) { + direction = TDPagerScrollDirectionLeft; + } + TDIndexSection indexSection = [self nearlyIndexPathForIndexSection:_indexSection direction:direction]; + targetContentOffset->x = [self caculateOffsetXAtIndexSection:indexSection]; +} + +- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { + if (_autoScrollInterval > 0) { + [self addTimer]; + } + if ([_delegate respondsToSelector:@selector(pagerViewDidEndDragging:willDecelerate:)]) { + [_delegate pagerViewDidEndDragging:self willDecelerate:decelerate]; + } +} + +- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { + if ([_delegate respondsToSelector:@selector(pagerViewWillBeginDecelerating:)]) { + [_delegate pagerViewWillBeginDecelerating:self]; + } +} + +- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { + [self recyclePagerViewIfNeed]; + if ([_delegate respondsToSelector:@selector(pagerViewDidEndDecelerating:)]) { + [_delegate pagerViewDidEndDecelerating:self]; + } +} + +- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { + [self recyclePagerViewIfNeed]; + if ([_delegate respondsToSelector:@selector(pagerViewDidEndScrollingAnimation:)]) { + [_delegate pagerViewDidEndScrollingAnimation:self]; + } +} + +#pragma mark - TDCyclePagerTransformLayoutDelegate + +- (void)pagerViewTransformLayout:(TDCyclePagerTransformLayout *)pagerViewTransformLayout initializeTransformAttributes:(UICollectionViewLayoutAttributes *)attributes { + if (_delegateFlags.initializeTransformAttributes) { + [_delegate pagerView:self initializeTransformAttributes:attributes]; + } +} + +- (void)pagerViewTransformLayout:(TDCyclePagerTransformLayout *)pagerViewTransformLayout applyTransformToAttributes:(UICollectionViewLayoutAttributes *)attributes { + if (_delegateFlags.applyTransformToAttributes) { + [_delegate pagerView:self applyTransformToAttributes:attributes]; + } +} + +- (void)layoutSubviews { + [super layoutSubviews]; + BOOL needUpdateLayout = !CGRectEqualToRect(_collectionView.frame, self.bounds); + _collectionView.frame = self.bounds; + if ((_indexSection.section < 0 || needUpdateLayout) && (_numberOfItems > 0 || _didReloadData)) { + _didLayout = YES; + [self setNeedUpdateLayout]; + } +} + +- (void)dealloc { + ((TDCyclePagerTransformLayout *)_collectionView.collectionViewLayout).delegate = nil; + _collectionView.delegate = nil; + _collectionView.dataSource = nil; +} + +@end + + diff --git a/libTitanD3vUniversal/ColourPicker/.DS_Store b/libTitanD3vUniversal/ColourPicker/.DS_Store new file mode 100644 index 0000000..283c4d1 Binary files /dev/null and b/libTitanD3vUniversal/ColourPicker/.DS_Store differ diff --git a/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker.h b/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker.h new file mode 100644 index 0000000..addf413 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker.h @@ -0,0 +1,67 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// Hexadecimal string representation formats +typedef enum : NSUInteger { + TDHexFormatAuto = 0, + TDHexFormatRGB = 3, + TDHexFormatRGBA = 4, + TDHexFormatRRGGBB = 6, + TDHexFormatRRGGBBAA = 8 +} TDHexFormat; + +@interface UIColor (ChromaPicker) + +// +// General +// + +- (BOOL)isDarkColor; + +- (NSArray *)HSBAValues; +- (NSArray *)RGBAValues; +- (NSArray *)CMYKAValues; + +// +// Hex Support +// + +/// Creates a color object using the specified hexadecimal string representation +/// @param hexString a hex string in one of the following formats (RGB, #RGB, 0xRGB, RGBA, #RGBA, 0xRGBA RRGGBB, #RRGGBB, 0xRRGGBB RRGGBBAA, #RRGGBBAA, 0xRRGGBBAA) ++ (UIColor *)colorByEvaluatingHexString:(NSString *)hexString; + + +/// Creates a hexadecimal string representation of the color in the specified format. output examples (#RGB, #RGBA, #RRGGBB, #RRGGBBAA) +/// @param color an instance of a UIColor object +/// @param format the desired output format ++ (NSString *)hexStringWithColor:(UIColor *)color format:(TDHexFormat)format; + + +/// Creates a hexadecimal string representation of the color instance #RRGGBB, or #RRGGBBAA if the color uses the alpha channel +- (NSString *)hexStringValue; + +// +// CMYK Support +// + +/// Creates a color object using the specified CMYKA values +/// @param cyan cyan value +/// @param magenta magenta value +/// @param yellow yellow value +/// @param black black value +/// @param alpha alpha value ++ (instancetype)colorWithCyan:(CGFloat)cyan magenta:(CGFloat)magenta yellow:(CGFloat)yellow black:(CGFloat)black alpha:(CGFloat)alpha; + + +/// Returns the components that make up the color in the CMYK color space. +/// @param cyan on return, the cyan component of the color object +/// @param magenta on return, the magents component of the color object +/// @param yellow on return, the yellow component of the color object +/// @param black on return, the black component of the color object +/// @param alpha on return, the alpha component of the color object +- (BOOL)getCyan:(nullable CGFloat *)cyan magenta:(nullable CGFloat *)magenta yellow:(nullable CGFloat *)yellow black:(nullable CGFloat *)black alpha:(nullable CGFloat *)alpha; + +@end + +NS_ASSUME_NONNULL_END diff --git a/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker.m b/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker.m new file mode 100644 index 0000000..0ee65f0 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker.m @@ -0,0 +1,138 @@ +#import "UIColor+ChromaPicker.h" + +@implementation UIColor (ChromaPicker) + +#pragma mark - General + +- (BOOL)isDarkColor { + NSArray *components = self.RGBAValues; + return (0.2126 * [components[0] doubleValue] + 0.7152 * [components[1] doubleValue] + 0.0722 * [components[2] doubleValue]) < 0.50; +} + +- (NSArray *)HSBAValues { + CGFloat h, s, b, a; + [self getHue:&h saturation:&s brightness:&b alpha:&a]; + return @[@(h), @(s), @(b), @(a)]; +} + +- (NSArray *)RGBAValues { + CGFloat r, g, b, a; + [self getRed:&r green:&g blue:&b alpha:&a]; + return @[@(r), @(g), @(b), @(a)]; +} + +- (NSArray *)CMYKAValues { + CGFloat c, m, y, k, a; + [self getCyan:&c magenta:&m yellow:&y black:&k alpha:&a]; + return @[@(c), @(m), @(y), @(k), @(a)]; +} + +#pragma mark - Hex Support + ++ (UIColor *)colorByEvaluatingHexString:(NSString *)hexString { + + NSString *evalutationString = [[hexString stringByReplacingOccurrencesOfString:@"#" withString:@""] + stringByReplacingOccurrencesOfString:@"0x" withString:@""]; + + CGFloat a, r, b, g; + unsigned hexadecimalValue; + [[NSScanner scannerWithString:evalutationString] scanHexInt:&hexadecimalValue]; + + CGFloat(^componentValue)(unsigned, unsigned, float) = ^(unsigned dec, unsigned shift, float devisor) { + return (CGFloat)((hexadecimalValue & dec) >> shift) / devisor; + }; + + switch (evalutationString.length) { + case TDHexFormatRGB: + r = componentValue(0xF00, 8, 15); + g = componentValue(0x0F0, 4, 15); + b = componentValue(0x00F, 0, 15); + a = 1.0f; + break; + case TDHexFormatRGBA: + r = componentValue(0xF000, 12, 15); + g = componentValue(0x0F00, 8, 15); + b = componentValue(0x00F0, 4, 15); + a = componentValue(0x000F, 0, 15); + break; + case TDHexFormatRRGGBB: + r = componentValue(0xFF0000, 16, 255); + g = componentValue(0x00FF00, 8, 255); + b = componentValue(0x0000FF, 0, 255); + a = 1.0f; + break; + case TDHexFormatRRGGBBAA: + r = componentValue(0xFF000000, 24, 255); + g = componentValue(0x00FF0000, 16, 255); + b = componentValue(0x0000FF00, 8, 255); + a = componentValue(0x000000FF, 0, 255); + break; + default: + r = g = b = a = 1.0f; + break; + } + + return [UIColor colorWithRed:r green:g blue:b alpha:a]; +} + ++ (NSString *)hexStringWithColor:(UIColor *)color format:(TDHexFormat)format { + + CGFloat r, g, b, a; + [color getRed:&r green:&g blue:&b alpha:&a]; + + switch (format) { + case TDHexFormatRGB: + return [[NSString stringWithFormat:@"#%03x", (unsigned)(r*15)<<8 | (unsigned)(g*15)<<4 | (unsigned)(b*15)<<0] uppercaseString]; + case TDHexFormatRGBA: + return [[NSString stringWithFormat:@"#%08x", (unsigned)(r*15)<<12 | (unsigned)(g*15)<<8 | (unsigned)(b*15)<<4 | (unsigned)(a*15)<<0] uppercaseString]; + case TDHexFormatRRGGBB: + return [[NSString stringWithFormat:@"#%06x", (unsigned)(r*255)<<16 | (unsigned)(g*255)<<8 | (unsigned)(b*255)<<0] uppercaseString]; + case TDHexFormatRRGGBBAA: + return [[NSString stringWithFormat:@"#%08x", (unsigned)(r*255)<<24 | (unsigned)(g*255)<<16 | (unsigned)(b*255)<<8 | (unsigned)(a*255)<<0] uppercaseString]; + default: { + return (a >= 1) + ? [[NSString stringWithFormat:@"#%06x", (unsigned)(r*255)<<16 | (unsigned)(g*255)<<8 | (unsigned)(b*255)<<0] uppercaseString] + : [[NSString stringWithFormat:@"#%08x", (unsigned)(r*255)<<24 | (unsigned)(g*255)<<16 | (unsigned)(b*255)<<8 | (unsigned)(a*255)<<0] uppercaseString]; + } + } +} + +- (NSString *)hexStringValue { + return [UIColor hexStringWithColor:self format:TDHexFormatAuto]; +} + +#pragma mark - CMYK Support + ++ (instancetype)colorWithCyan:(CGFloat)cyan magenta:(CGFloat)magenta yellow:(CGFloat)yellow black:(CGFloat)black alpha:(CGFloat)alpha { + CGFloat red = (1 - cyan) * (1 - black); + CGFloat green = (1 - magenta) * (1 - black); + CGFloat blue = (1 - yellow) * (1 - black); + return [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; +} + +- (BOOL)getCyan:(CGFloat *)cyan magenta:(CGFloat *)magenta yellow:(CGFloat *)yellow black:(CGFloat *)black alpha:(CGFloat *)alpha { + CGFloat r, g, b, a; + if (![self getRed:&r green:&g blue:&b alpha:&a]) { + return NO; + } + + CGFloat k = 1 - MAX(MAX(r, g), b); + if (k == 1) { + if (cyan) *cyan = 0; + if (magenta) *magenta = 0; + if (yellow) *yellow = 0; + if (black) *black = 1; + } else { + if (cyan) *cyan = (1 - r - k) / (1 - k); + if (magenta) *magenta = (1 - g - k) / (1 - k); + if (yellow) *yellow = (1 - b - k) / (1 - k); + if (black) *black = k; + } + + if (alpha) *alpha = a; + + return YES; +} + + +@end diff --git a/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker_Internal.h b/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker_Internal.h new file mode 100644 index 0000000..ab561a9 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker_Internal.h @@ -0,0 +1,21 @@ +#import +#import "TDSliderType.h" +#import "UIColor+ChromaPicker.h" + +#define rgba(r,g,b,a) [UIColor colorWithRed:r green:g blue:b alpha:a] +#define hsba(h,s,b,a) [UIColor colorWithHue:h saturation:s brightness:b alpha:a] +#define cmyka(c,m,y,k,a) [UIColor colorWithCyan:c magenta:m yellow:y black:k alpha:a] + +NS_ASSUME_NONNULL_BEGIN + +@interface UIColor (ChromaPicker_Internal) + ++ (NSArray *)hueColors; ++ (NSArray *)someColors; +- (UIImage *)imageWithSize:(CGSize)size; +- (CGFloat)valueForType:(TDSliderType)sliderType; +- (UIColor *)colorByApplyingValue:(CGFloat)value sliderType:(TDSliderType)slidetType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker_Internal.m b/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker_Internal.m new file mode 100644 index 0000000..96e7407 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Categories/UIColor+ChromaPicker_Internal.m @@ -0,0 +1,102 @@ +#import "UIColor+ChromaPicker_Internal.h" +#import "UIColor+ChromaPicker.h" + +@implementation UIColor (ChromaPicker_Internal) + +- (UIImage *)imageWithSize:(CGSize)size { + return [[[UIGraphicsImageRenderer alloc] initWithSize:size] imageWithActions:^(UIGraphicsImageRendererContext *rendererContext) { + [self setFill]; + [rendererContext fillRect:CGRectMake(0, 0, size.width, size.height)]; + }]; +} + ++ (NSArray *)hueColors { + NSMutableArray *colors = [NSMutableArray new]; + for (NSInteger deg = 0; deg <= 360; deg += 5) { + [colors addObject:(__bridge id)[UIColor colorWithHue:1.0f * deg / 360.0f saturation:1.0f brightness:1.0f alpha:1.0f].CGColor]; + } + return colors.copy; +} + ++ (NSArray *)someColors { + NSMutableArray *colors = [NSMutableArray new]; + for (NSInteger deg = 0; deg <= 360; deg += 1) { + [colors addObject:[UIColor colorWithHue:1.0f * deg / 360.0f saturation:1.0f brightness:1.0f alpha:1.0f]]; + } + return colors.copy; +} + +- (CGFloat)valueForType:(TDSliderType)sliderType { + CGFloat value = 0; + + switch (sliderType) { + case TDSliderTypeAlpha: { [self getHue:nil saturation:nil brightness:nil alpha: &value]; } break; + case TDSliderTypeHue: { [self getHue:&value saturation:nil brightness:nil alpha:nil]; } break; + case TDSliderTypeSaturation: { [self getHue:nil saturation:&value brightness:nil alpha:nil]; } break; + case TDSliderTypeBrightness: { [self getHue:nil saturation:nil brightness:&value alpha:nil]; } break; + case TDSliderTypeRed: { [self getRed:&value green:nil blue:nil alpha:nil]; } break; + case TDSliderTypeGreen: { [self getRed:nil green:&value blue:nil alpha:nil]; } break; + case TDSliderTypeBlue: { [self getRed:nil green:nil blue:&value alpha:nil]; } break; + case TDSliderTypeCyan: { value = [self.CMYKAValues[0] doubleValue]; } break; + case TDSliderTypeMagenta: { value = [self.CMYKAValues[1] doubleValue]; } break; + case TDSliderTypeYellow: { value = [self.CMYKAValues[2] doubleValue]; } break; + case TDSliderTypeBlack: { value = [self.CMYKAValues[3] doubleValue]; } break; + } + + return value; +} + +- (UIColor *)colorByApplyingValue:(CGFloat)value sliderType:(TDSliderType)sliderType { + UIColor *color; + + switch (sliderType) { + case TDSliderTypeHue: { + NSArray *components = self.HSBAValues; + color = hsba(value, [components[1] doubleValue], [components[2] doubleValue], [components[3] doubleValue]); + } break; + case TDSliderTypeAlpha: { + NSArray *components = self.HSBAValues; + color = hsba([components[0] doubleValue], [components[1] doubleValue], [components[2] doubleValue], value); + } break; + case TDSliderTypeSaturation: { + NSArray *components = self.HSBAValues; + color = hsba([components[0] doubleValue], value, [components[2] doubleValue], [components[3] doubleValue]); + } break; + case TDSliderTypeBrightness: { + NSArray *components = self.HSBAValues; + color = hsba([components[0] doubleValue], [components[1] doubleValue], value, [components[3] doubleValue]); + } break; + case TDSliderTypeRed: { + NSArray *components = self.RGBAValues; + color = rgba(value, [components[1] doubleValue], [components[2] doubleValue], [components[3] doubleValue]); + } break; + case TDSliderTypeGreen: { + NSArray *components = self.RGBAValues; + color = rgba([components[0] doubleValue], value, [components[2] doubleValue], [components[3] doubleValue]); + } break; + case TDSliderTypeBlue: { + NSArray *components = self.RGBAValues; + color = rgba([components[0] doubleValue], [components[1] doubleValue], value, [components[3] doubleValue]); + } break; + case TDSliderTypeCyan: { + NSArray *components = self.CMYKAValues; + color = cmyka(value, [components[1] doubleValue], [components[2] doubleValue], [components[3] doubleValue], [components[4] doubleValue]); + } break; + case TDSliderTypeMagenta: { + NSArray *components = self.CMYKAValues; + color = cmyka([components[0] doubleValue], value, [components[2] doubleValue], [components[3] doubleValue], [components[4] doubleValue]); + } break; + case TDSliderTypeYellow: { + NSArray *components = self.CMYKAValues; + color = cmyka([components[0] doubleValue], [components[1] doubleValue], value, [components[3] doubleValue], [components[4] doubleValue]); + } break; + case TDSliderTypeBlack: { + NSArray *components = self.CMYKAValues; + color = cmyka([components[0] doubleValue], [components[1] doubleValue], [components[2] doubleValue], value, [components[4] doubleValue]); + } break; + } + + return color; +} + +@end diff --git a/libTitanD3vUniversal/ColourPicker/ChromaPicker.h b/libTitanD3vUniversal/ColourPicker/ChromaPicker.h new file mode 100644 index 0000000..4f4e2ce --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/ChromaPicker.h @@ -0,0 +1,11 @@ +#import +#import "Controllers/TDColorPickerViewController.h" +#import "Delegates/TDColorPickerDelegate.h" +#import "Types/TDColorSpaceType.h" +#import "Categories/UIColor+ChromaPicker.h" + + +FOUNDATION_EXPORT double ChromaPickerVersionNumber; + +FOUNDATION_EXPORT const unsigned char ChromaPickerVersionString[]; + diff --git a/libTitanD3vUniversal/ColourPicker/Controllers/TDColorPickerViewController.h b/libTitanD3vUniversal/ColourPicker/Controllers/TDColorPickerViewController.h new file mode 100644 index 0000000..881c657 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Controllers/TDColorPickerViewController.h @@ -0,0 +1,28 @@ +#import +#import "TDColorPickerDelegate.h" +#import "TDColorSpaceType.h" +#import "TDColorCollection.h" +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "TDUtilities.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" + +CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void); + +@interface TDColorPickerViewController : UIViewController + +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (nonatomic, strong) UIColor *currentColor; +@property (nonatomic, strong, nullable) TDColorCollection *colorCollection; +@property (nonatomic, weak) id delegate; +@property (nonatomic, retain) NSDictionary *properties; +@property (nonatomic, retain) UIColor *containerColour; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *borderColour; +-(instancetype)initWithColor:(UIColor *)color stackType:(TDColorSpaceType)stackType delegate:(id)delegate; + +@end + diff --git a/libTitanD3vUniversal/ColourPicker/Controllers/TDColorPickerViewController.m b/libTitanD3vUniversal/ColourPicker/Controllers/TDColorPickerViewController.m new file mode 100644 index 0000000..06c6c3a --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Controllers/TDColorPickerViewController.m @@ -0,0 +1,364 @@ +#import "TDColorPickerViewController.h" +#import "TDColorSliderStackView.h" +#import "UIColor+ChromaPicker_Internal.h" +#import "TDColorDisplayView.h" + + +@interface TDColorPickerViewController () +@property (nonatomic, strong) UIStackView *viewStack; +@property (nonatomic, strong) TDColorDisplayView *colorDisplayView; +@property (nonatomic, strong) TDColorSliderStackView *sliderStackView; +@property (nonatomic, strong) UISegmentedControl *typeSelectionView; +@property (nonatomic, strong) UICollectionView *colorCollectionView; +@property (nonatomic, strong) UIView *backgroundView; +@property (nonatomic, strong) UIView *grabberView; +@property (nonatomic, strong) NSArray *colorDataSource; +@end + + +@implementation TDColorPickerViewController + +- (instancetype)initWithColor:(UIColor *)color stackType:(TDColorSpaceType)stackType delegate:(id)delegate { + + if (self == [super init]) { + self.delegate = delegate; + self.currentColor = color; + + _sliderStackView = [[TDColorSliderStackView alloc] initWithColor:color stackType:stackType delegate:self]; + _colorDisplayView = [[TDColorDisplayView alloc] initWithColor:color]; + } + + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + + self.blurEffectView = [[UIVisualEffectView alloc] init]; + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + self.blurEffectView.alpha = 0; + self.blurEffectView.userInteractionEnabled = true; + [self.view insertSubview:self.blurEffectView atIndex:0]; + + self.blurEffectView.translatesAutoresizingMaskIntoConstraints = false; + [self.blurEffectView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.blurEffectView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.blurEffectView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.blurEffectView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; + + + UITapGestureRecognizer *dismissGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureFired)]; + dismissGesture.delegate = self; + [self.blurEffectView addGestureRecognizer:dismissGesture]; + + + [self performSelector:@selector(setDimming) withObject:nil afterDelay:0.3]; + + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.containerColour = [[TDAppearance sharedInstance] containerColour]; + self.borderColour = [[TDAppearance sharedInstance] borderColour]; + + + UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new]; + layout.itemSize = CGSizeMake(30, 30); + layout.headerReferenceSize = CGSizeMake(40, 30); + layout.minimumInteritemSpacing = 8; + layout.minimumLineSpacing = 8; + layout.scrollDirection = UICollectionViewScrollDirectionVertical; + + _colorCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + _colorCollectionView.backgroundColor = nil; + _colorCollectionView.dataSource = self; + _colorCollectionView.delegate = self; + _colorCollectionView.translatesAutoresizingMaskIntoConstraints = NO; + [_colorCollectionView registerClass:UICollectionViewCell.class forCellWithReuseIdentifier:@"CELL"]; + [_colorCollectionView registerClass:UICollectionReusableView.class forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HEADER"]; + + [self setColorCollection:_colorCollection]; + + _backgroundView = [UIView new]; + _backgroundView.layer.cornerRadius = 16; + _backgroundView.layer.masksToBounds = YES; + if (@available(iOS 13.0, *)) { + _backgroundView.layer.cornerCurve = kCACornerCurveContinuous; + } + _backgroundView.layer.borderWidth = 1; + _backgroundView.layer.borderColor = self.borderColour.CGColor; + _backgroundView.backgroundColor = self.containerColour; + [self.view addSubview:_backgroundView]; + + _grabberView = [UIView new]; + _grabberView.layer.cornerRadius = 3; + _grabberView.layer.masksToBounds = YES; + _grabberView.backgroundColor = self.tintColour; + [self.view addSubview:_grabberView]; + + _typeSelectionView = [UISegmentedControl new]; + [_typeSelectionView addTarget:self action:@selector(setStackType:) forControlEvents:UIControlEventValueChanged]; + [_typeSelectionView insertSegmentWithTitle:@"HSB" atIndex:0 animated:NO]; + [_typeSelectionView insertSegmentWithTitle:@"RGB" atIndex:1 animated:NO]; + [_typeSelectionView insertSegmentWithTitle:@"CMYK" atIndex:2 animated:NO]; + [_typeSelectionView insertSegmentWithTitle:@"Picker" atIndex:3 animated:NO]; + _typeSelectionView.selectedSegmentIndex = 0; + if (@available(iOS 13.0, *)) { + _typeSelectionView.selectedSegmentTintColor = self.tintColour; + } + [self.view addSubview:_typeSelectionView]; + + [self.view addSubview:_sliderStackView]; + + _viewStack = [UIStackView new]; + _viewStack.axis = UILayoutConstraintAxisVertical; + _viewStack.alignment = UIStackViewAlignmentFill; + _viewStack.distribution = UIStackViewDistributionFill; + _viewStack.spacing = 8; + [_backgroundView addSubview:_viewStack]; + + [_viewStack addArrangedSubview:_colorDisplayView]; + [_viewStack addArrangedSubview:_typeSelectionView]; + [_viewStack addArrangedSubview:_sliderStackView]; + + _viewStack.translatesAutoresizingMaskIntoConstraints = NO; + _grabberView.translatesAutoresizingMaskIntoConstraints = NO; + _sliderStackView.translatesAutoresizingMaskIntoConstraints = NO; + _typeSelectionView.translatesAutoresizingMaskIntoConstraints = NO; + _backgroundView.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [_grabberView.widthAnchor constraintEqualToConstant:75], + [_grabberView.heightAnchor constraintEqualToConstant:6], + [_grabberView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], + [_grabberView.topAnchor constraintEqualToAnchor:_backgroundView.topAnchor constant:12], + + [_backgroundView.heightAnchor constraintEqualToAnchor:_viewStack.heightAnchor constant:46], + [_backgroundView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-32], + [_backgroundView.leadingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor constant:16], + [_backgroundView.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor constant:-16], + + [_viewStack.leadingAnchor constraintEqualToAnchor:_backgroundView.leadingAnchor constant:16], + [_viewStack.trailingAnchor constraintEqualToAnchor:_backgroundView.trailingAnchor constant:-16], + [_viewStack.bottomAnchor constraintEqualToAnchor:_backgroundView.bottomAnchor constant:-16], + + [_colorDisplayView.heightAnchor constraintEqualToConstant: 40] + ]]; + + // if (@available(iOS 13, *)) { + // if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { + // _backgroundView.backgroundColor = [UIColor colorWithRed: 0.14 green: 0.14 blue: 0.14 alpha: 1.00]; + // _grabberView.backgroundColor = [UIColor colorWithRed: 0.20 green: 0.20 blue: 0.20 alpha: 1.00]; + // } else { + // _backgroundView.backgroundColor = [UIColor colorWithRed: 0.92 green: 0.92 blue: 0.92 alpha: 1.00]; + // _grabberView.backgroundColor = [UIColor colorWithRed: 0.88 green: 0.88 blue: 0.88 alpha: 1.00]; + // } + // } else { + // _backgroundView.backgroundColor = [UIColor colorWithRed: 0.92 green: 0.92 blue: 0.92 alpha: 1.00]; + // _grabberView.backgroundColor = [UIColor colorWithRed: 0.88 green: 0.88 blue: 0.88 alpha: 1.00]; + // } +} + + +-(void)setDimming { + [UIView animateWithDuration:0.4 animations:^ { + self.blurEffectView.alpha = 1; + }]; +} + + +-(void)tapGestureFired { + [[TDUtilities sharedInstance] haptic:0]; + + [UIView animateWithDuration:0.2 animations:^ { + self.blurEffectView.alpha = 0; + }]; + [self performSelector:@selector(dismissVC) withObject:nil afterDelay:0.1]; +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + if (self.delegate && [self.delegate respondsToSelector:@selector(colorPickerDismissedWithColor:)]) { + [self.delegate colorPickerDismissedWithColor:self.currentColor]; + } + + [UIView animateWithDuration:0.25 animations:^{ + self.view.frame = CGRectMake(0, UIScreen.mainScreen.bounds.size.height, self.view.bounds.size.width, self.view.bounds.size.height); + } completion:^(BOOL finished) { + + }]; +} + + +- (void)colorPickerDidUpdateColor:(UIColor *)color { + self.currentColor = color; + _colorDisplayView.color = color; + if (self.delegate && [self.delegate respondsToSelector:@selector(colorPickerDidUpdateColor:)]) { + [self.delegate colorPickerDidUpdateColor:self.currentColor]; + } + +} + + +- (void)colorPickerDidChangeColor:(UIColor *)color { + if (self.delegate && [self.delegate respondsToSelector:@selector(colorPickerDidChangeColor:)]) { + [self.delegate colorPickerDidChangeColor:self.currentColor]; + } + +} + + +- (UIModalPresentationStyle)modalPresentationStyle { + return UIModalPresentationOverCurrentContext; +} + + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesEnded:touches withEvent:event]; + if (touches.anyObject.view == self.view) { + //[self dismissViewControllerAnimated:YES completion:nil]; + } else if (touches.anyObject.view != _colorDisplayView) { + [_colorDisplayView resignFirstResponder]; + } +} + + +- (void)setStackType:(UISegmentedControl *)sender { + + if (sender.selectedSegmentIndex < 3) { + if (![_viewStack.arrangedSubviews containsObject:_sliderStackView]) { + [_colorCollectionView removeFromSuperview]; + [_viewStack addArrangedSubview:_sliderStackView]; + } + } else { + if (![_viewStack.arrangedSubviews containsObject:_colorCollectionView]) { + [_sliderStackView removeFromSuperview]; + [_colorCollectionView.heightAnchor constraintEqualToConstant:200].active = YES; + [_viewStack addArrangedSubview:_colorCollectionView]; + } + } + + switch (sender.selectedSegmentIndex) { + case 0: { [_sliderStackView configureForStackType:TDColorSpaceTypeHSBA color:self.currentColor]; } break; + case 1: { [_sliderStackView configureForStackType:TDColorSpaceTypeRGBA color:self.currentColor]; } break; + case 2: { [_sliderStackView configureForStackType:TDColorSpaceTypeCMYKA color:self.currentColor]; } break; + case 3: { } break; + default: { [_sliderStackView configureForStackType:TDColorSpaceTypeHSBA color:self.currentColor]; } break; + } +} + + +- (void)setColor:(UIColor *)color { + self.currentColor = color; + _colorDisplayView.color = color; + [_sliderStackView setColor:color]; +} + + +- (void)setColorCollection:(TDColorCollection *)colorCollection { + _colorCollection = colorCollection; + + NSArray *defaultColors = @[ + [TDColorCollection defaultSystemColorsCollection], + [TDColorCollection defaultPrimaryColorsCollection], + [TDColorCollection defaultHueColorsCollection] + ]; + + _colorDataSource = colorCollection ? [@[colorCollection] arrayByAddingObjectsFromArray:defaultColors] : defaultColors; + [_colorCollectionView reloadData]; +} + + +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { + return _colorDataSource.count; +} + + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return _colorDataSource[section].count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CELL" forIndexPath:indexPath]; + cell.backgroundColor = _colorDataSource[indexPath.section].colors[indexPath.row]; + cell.layer.cornerRadius = 15; + cell.layer.masksToBounds = YES; + cell.layer.borderWidth = 1; + if (@available(iOS 13.0, *)) { + cell.layer.borderColor = UIColor.tertiarySystemFillColor.CGColor; + } else { + cell.layer.borderColor = UIColor.whiteColor.CGColor; + } + return cell; +} + + +- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + UICollectionReusableView *headerView; + + if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { + headerView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"HEADER" forIndexPath:indexPath]; + + NSInteger labelTag = 0x2727272; + UILabel *label = [headerView viewWithTag:labelTag]; + + if (!label) { + label = [UILabel new]; + [headerView addSubview:label]; + [label setTag:labelTag]; + if (@available(iOS 13.0, *)) { + [label setTextColor:UIColor.secondaryLabelColor]; + } else { + [label setTextColor:UIColor.blackColor]; + } + [label setTranslatesAutoresizingMaskIntoConstraints:NO]; + [NSLayoutConstraint activateConstraints:@[ + [label.topAnchor constraintEqualToAnchor:headerView.topAnchor], + [label.bottomAnchor constraintEqualToAnchor:headerView.bottomAnchor], + [label.leadingAnchor constraintEqualToAnchor:headerView.leadingAnchor], + [label.trailingAnchor constraintEqualToAnchor:headerView.trailingAnchor] + ]]; + } + + label.text = _colorDataSource[indexPath.section].title.uppercaseString; + } + + return headerView; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { + return CGSizeMake(40, 40); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + [collectionView deselectItemAtIndexPath:indexPath animated:YES]; + [self colorPickerDidUpdateColor:_colorDataSource[indexPath.section].colors[indexPath.row]]; +} + +// - (void) traitCollectionDidChange: (UITraitCollection *) previousTraitCollection { + +// if (@available(iOS 13, *)) { +// if ([UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark) { +// _backgroundView.backgroundColor = [UIColor colorWithRed: 0.14 green: 0.14 blue: 0.14 alpha: 1.00]; +// _grabberView.backgroundColor = [UIColor colorWithRed: 0.20 green: 0.20 blue: 0.20 alpha: 1.00]; +// } else { +// _backgroundView.backgroundColor = [UIColor colorWithRed: 0.92 green: 0.92 blue: 0.92 alpha: 1.00]; +// _grabberView.backgroundColor = [UIColor colorWithRed: 0.88 green: 0.88 blue: 0.88 alpha: 1.00]; +// } +// } else { +// _backgroundView.backgroundColor = [UIColor colorWithRed: 0.92 green: 0.92 blue: 0.92 alpha: 1.00]; +// _grabberView.backgroundColor = [UIColor colorWithRed: 0.88 green: 0.88 blue: 0.88 alpha: 1.00]; +// } + +// } + +@end diff --git a/libTitanD3vUniversal/ColourPicker/Controls/TDColorSlider.h b/libTitanD3vUniversal/ColourPicker/Controls/TDColorSlider.h new file mode 100644 index 0000000..8df0c55 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Controls/TDColorSlider.h @@ -0,0 +1,19 @@ +#import +#import "TDSliderType.h" +#import "TDColorSliderDelegate.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface TDColorSlider : UISlider + +@property (nonatomic, weak) id delegate; +@property (nonatomic, readonly) TDSliderType type; +@property (nonatomic, readonly) UIColor *colorValue; + +- (instancetype)initWithSliderType:(TDSliderType)type color:(UIColor *)color; + +- (void)setColor:(UIColor *)color; + +@end + +NS_ASSUME_NONNULL_END diff --git a/libTitanD3vUniversal/ColourPicker/Controls/TDColorSlider.m b/libTitanD3vUniversal/ColourPicker/Controls/TDColorSlider.m new file mode 100644 index 0000000..7f87b42 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Controls/TDColorSlider.m @@ -0,0 +1,130 @@ +#import "TDColorSlider.h" +#import "TDGradientView.h" +#import "UIColor+ChromaPicker_Internal.h" + + +@implementation UILabel (Private) + ++ (instancetype)sliderLabel { + UILabel *label = [UILabel new]; + label.numberOfLines = 1; + label.font = [UIFont systemFontOfSize:16 weight: UIFontWeightLight]; + label.backgroundColor = UIColor.clearColor; + label.textAlignment = NSTextAlignmentCenter; + return label; +} +@end + +@implementation TDColorSlider { + UIVisualEffectView *_grabberEffectView; + TDGradientView *_trackGradientView; + UILabel *_leadingLabel; + UILabel *_trailingLabel; +} + +- (instancetype)initWithSliderType:(TDSliderType)type color:(UIColor *)color { + if (self == [super init]) { + [self configureWithType:type color:color]; + } + return self; +} + +- (void)configureWithType:(TDSliderType)type color:(UIColor *)color { + [self setMinimumTrackImage:UIImage.new forState:UIControlStateNormal]; + [self setMaximumTrackImage:UIImage.new forState:UIControlStateNormal]; + + self.minimumValueImage = [UIColor.clearColor imageWithSize:CGSizeMake(30, 1)]; + self.maximumValueImage = [UIColor.clearColor imageWithSize:CGSizeMake(30, 1)]; + + UIView *grabber = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 24, 24)]; + if (@available(iOS 13.0, *)) { + grabber.layer.cornerCurve = kCACornerCurveContinuous; + } + grabber.layer.cornerRadius = 12; + grabber.layer.borderWidth = 5; + + [self setThumbImage:[UIColor.clearColor imageWithSize:CGSizeMake(24, 24)] forState:UIControlStateNormal]; + _grabberEffectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]]; + _grabberEffectView.userInteractionEnabled = NO; + _grabberEffectView.maskView = grabber; + [self addSubview:_grabberEffectView]; + + _trackGradientView = [[TDGradientView alloc] initWithColors:@[]]; + [self.layer insertSublayer:_trackGradientView atIndex:0]; + + _leadingLabel = UILabel.sliderLabel; + [self addSubview:_leadingLabel]; + _leadingLabel.translatesAutoresizingMaskIntoConstraints = NO; + [_leadingLabel.widthAnchor constraintEqualToConstant: 30].active = YES; + [_leadingLabel.centerYAnchor constraintEqualToAnchor: self.centerYAnchor].active = YES; + [_leadingLabel.leadingAnchor constraintEqualToAnchor: self.leadingAnchor].active = YES; + + _trailingLabel = UILabel.sliderLabel; + [self addSubview:_trailingLabel]; + _trailingLabel.translatesAutoresizingMaskIntoConstraints = NO; + [_trailingLabel.widthAnchor constraintEqualToConstant: 30].active = YES; + [_trailingLabel.centerYAnchor constraintEqualToAnchor: self.centerYAnchor].active = YES; + [_trailingLabel.trailingAnchor constraintEqualToAnchor: self.trailingAnchor].active = YES; + + _leadingLabel.text = sliderTypeShortName(type); + self.maximumValue = sliderTypeMaxValue(type); + + _type = type; + [self setColor:color]; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + CGRect rect = [self trackRectForBounds:self.bounds]; + _trackGradientView.frame = CGRectMake(CGRectGetMinX(rect), CGRectGetMinY(rect) - 10, CGRectGetWidth(rect), 20); + _grabberEffectView.frame = [self thumbRectForBounds:self.bounds trackRect:rect value:self.value]; +} + +- (void)setColor:(UIColor *)color { + _colorValue = color; + if (_type != TDSliderTypeHue || _trackGradientView.colors.count < 2) { + [_trackGradientView setColorsForSliderType:_type primaryColor:color]; + } + self.value = [color valueForType:_type] * self.maximumValue; + _trailingLabel.text = [NSString stringWithFormat:@"%.f", self.value]; +} + +- (void)_updateSlider:(BOOL)finalized { + if (self.delegate && [self.delegate respondsToSelector:@selector(slider:valueChanged:)]) { + [self.delegate slider:self valueChanged:self.value]; + } + if (self.delegate && [self.delegate respondsToSelector:@selector(slider:valueFinishedChange:)]) { + [self.delegate slider:self valueFinishedChange:self.value]; + } + _trailingLabel.text = [NSString stringWithFormat:@"%.f", self.value]; +} + +- (CGSize)intrinsicContentSize { + return CGSizeMake(200, 40); +} + +#pragma mark - UISliderTracking +- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { + BOOL tracking = [super beginTrackingWithTouch:touch withEvent:event]; + [self _updateSlider:NO]; + return tracking; +} + +- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { + BOOL tracking = [super continueTrackingWithTouch:touch withEvent:event]; + [self _updateSlider:NO]; + return tracking; +} + +- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { + [super endTrackingWithTouch:touch withEvent:event]; + [self _updateSlider:YES]; +} + +- (void)cancelTrackingWithEvent:(UIEvent *)event { + [super cancelTrackingWithEvent:event]; + [self _updateSlider:YES]; +} + +@end diff --git a/libTitanD3vUniversal/ColourPicker/Delegates/TDColorPickerDelegate.h b/libTitanD3vUniversal/ColourPicker/Delegates/TDColorPickerDelegate.h new file mode 100644 index 0000000..85b82e6 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Delegates/TDColorPickerDelegate.h @@ -0,0 +1,13 @@ +#ifndef TDColorPickerDelegate_h +#define TDColorPickerDelegate_h + +@protocol TDColorPickerDelegate + +@optional +- (void)colorPickerDismissedWithColor:(UIColor *)color; +- (void)colorPickerDidUpdateColor:(UIColor *)color; +- (void)colorPickerDidChangeColor:(UIColor *)color; + +@end + +#endif /* TDColorPickerDelegate_h */ diff --git a/libTitanD3vUniversal/ColourPicker/Delegates/TDColorSliderDelegate.h b/libTitanD3vUniversal/ColourPicker/Delegates/TDColorSliderDelegate.h new file mode 100644 index 0000000..21d0960 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Delegates/TDColorSliderDelegate.h @@ -0,0 +1,8 @@ +@class TDColorSlider; +@protocol TDColorSliderDelegate + +- (void)slider:(TDColorSlider *)colorSlider valueChanged:(CGFloat)value; +- (void)slider:(TDColorSlider *)colorSlider valueFinishedChange:(CGFloat)value; +- (void)slider:(TDColorSlider *)colorSlider colorChanged:(UIColor *)color; + +@end diff --git a/libTitanD3vUniversal/ColourPicker/HEXColour.h b/libTitanD3vUniversal/ColourPicker/HEXColour.h new file mode 100644 index 0000000..dfa7916 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/HEXColour.h @@ -0,0 +1,69 @@ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" + +static CGFloat colorComponentFrom(NSString *string, NSInteger start, NSInteger length) { + NSString *substring = [string substringWithRange: NSMakeRange(start, length)]; + NSString *fullHex = length == 2 ? substring : [NSString stringWithFormat: @"%@%@", substring, substring]; + unsigned hexComponent; + [[NSScanner scannerWithString:fullHex] scanHexInt:&hexComponent]; + return hexComponent / 255.0; +} + +static UIColor *colorFromHexString(NSString *hexString) { + CGFloat red, green, blue, alpha; + switch(hexString.length) { + case 3: // #RGB + red = colorComponentFrom(hexString, 0, 1); + green = colorComponentFrom(hexString, 1, 1); + blue = colorComponentFrom(hexString, 2, 1); + alpha = 1; + break; + case 4: // #RGBA + red = colorComponentFrom(hexString, 0, 1); + green = colorComponentFrom(hexString, 1, 1); + blue = colorComponentFrom(hexString, 2, 1); + alpha = colorComponentFrom(hexString, 3, 1); + break; + case 6: // #RRGGBB + red = colorComponentFrom(hexString, 0, 2); + green = colorComponentFrom(hexString, 2, 2); + blue = colorComponentFrom(hexString, 4, 2); + alpha = 1; + break; + case 8: // #RRGGBBAA + red = colorComponentFrom(hexString, 0, 2); + green = colorComponentFrom(hexString, 2, 2); + blue = colorComponentFrom(hexString, 4, 2); + alpha = colorComponentFrom(hexString, 6, 2); + break; + default: // Invalid color + red = 0; + green = 0; + blue = 0; + alpha = 0; + break; + } + return [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; +} + + +static NSString *stringFromColor(UIColor *color) { + CGColorSpaceModel colorSpace = CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor)); + const CGFloat *components = CGColorGetComponents(color.CGColor); + + CGFloat r = 0, g = 0, b = 0, a = 0; + + if (colorSpace == kCGColorSpaceModelMonochrome) { + r = components[0]; + g = components[0]; + b = components[0]; + a = components[1]; + } else if (colorSpace == kCGColorSpaceModelRGB) { + r = components[0]; + g = components[1]; + b = components[2]; + a = components[3]; + } + + return [NSString stringWithFormat:@"%02lX%02lX%02lX%02lX", lroundf(r * 255), lroundf(g * 255), lroundf(b * 255), lroundf(a * 255)]; +} diff --git a/libTitanD3vUniversal/ColourPicker/TDColourPickerCell.h b/libTitanD3vUniversal/ColourPicker/TDColourPickerCell.h new file mode 100644 index 0000000..de267b4 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/TDColourPickerCell.h @@ -0,0 +1,21 @@ +#import +#import "ChromaPicker.h" +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface PSTableCell (PrivateColourPicker) +- (UIViewController *)_viewControllerForAncestor; +@end + +@interface TDColourPickerCell : PSTableCell { + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) UIColor *borderColour; +@property (nonatomic, retain) UIColor *tintColour; + +@end diff --git a/libTitanD3vUniversal/ColourPicker/TDColourPickerCell.m b/libTitanD3vUniversal/ColourPicker/TDColourPickerCell.m new file mode 100644 index 0000000..460ca3e --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/TDColourPickerCell.m @@ -0,0 +1,163 @@ +#import "TDColourPickerCell.h" +#import "HEXColour.h" + +static UIView *colorPreview; + +@implementation TDColourPickerCell + + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + if (self) { + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.borderColour = [[TDAppearance sharedInstance] borderColour]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", specifier.properties[@"iconName"]]; + + + self.iconImage = [[UIImageView alloc]initWithFrame:CGRectMake(13,15,40,40)]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + + self.headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(65,17.5,200,20)]; + [self.headerLabel setText:specifier.properties[@"title"]]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.subtitleLabel = [[UILabel alloc]initWithFrame:CGRectMake(65,35,200,20)]; + [self.subtitleLabel setText:specifier.properties[@"subtitle"]]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + } + + return self; +} + + +- (id)target { + return self; +} + + +- (id)cellTarget { + return self; +} + + +- (SEL)action { + return @selector(openColorPicker); +} + + +- (SEL)cellAction { + return @selector(openColorPicker); +} + + +- (void)openColorPicker { + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + NSString *hex = [settings objectForKey:self.specifier.properties[@"key"]] ?: self.specifier.properties[@"default"]; + UIColor *currentColor = colorFromHexString(hex); + + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController presentViewController:[[TDColorPickerViewController alloc] initWithColor:currentColor stackType:TDColorSpaceTypeHSBA delegate:self] animated:YES completion:nil]; + +} + + +- (void)updatePreview { + + + colorPreview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 29)]; + colorPreview.layer.cornerRadius = 14.5; + colorPreview.layer.borderWidth = 1.5; + colorPreview.layer.borderColor = self.borderColour.CGColor; + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + NSString *hex = [settings objectForKey:self.specifier.properties[@"key"]] ?: self.specifier.properties[@"default"]; + + UIColor *color = colorFromHexString(hex); + + colorPreview.backgroundColor = color; + + [self setAccessoryView:colorPreview]; +} + + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + [self updatePreview]; + + [self.specifier setTarget:self]; + [self.specifier setButtonAction:@selector(openColorPicker)]; + +} + + +- (void)colorPickerDidUpdateColor:(UIColor *)color { + + NSString *hex = stringFromColor(color); + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:hex forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + + [self updatePreview]; + +} + +- (void)colorPickerDidChangeColor:(UIColor *)color { + + NSString *hex = stringFromColor(color); + + NSString *bundleID = self.specifier.properties[@"defaults"]; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:hex forKey:self.specifier.properties[@"key"]]; + [settings writeToFile:prefsPath atomically:YES]; + + [self updatePreview]; + +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + + +// - (void)layoutSubviews { +// [super layoutSubviews]; + +// [self.accessoryView setFrame:CGRectOffset(self.accessoryView.frame, -10, 0)]; + +// } + + +@end diff --git a/libTitanD3vUniversal/ColourPicker/Types/TDColorCollection.h b/libTitanD3vUniversal/ColourPicker/Types/TDColorCollection.h new file mode 100644 index 0000000..ecc835a --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Types/TDColorCollection.h @@ -0,0 +1,20 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface TDColorCollection : NSObject +@property (nonatomic, strong, readonly) NSString *title; +@property (nonatomic, strong, readonly) NSArray *colors; + +@property (nonatomic, readonly) NSInteger count; + ++ (instancetype)collectionWithTitle:(NSString *)title colors:(NSArray *)colors; +- (instancetype)initWithTitle:(NSString *)title colors:(NSArray *)colors; + ++ (instancetype)defaultSystemColorsCollection; ++ (instancetype)defaultPrimaryColorsCollection; ++ (instancetype)defaultHueColorsCollection; + +@end + +NS_ASSUME_NONNULL_END diff --git a/libTitanD3vUniversal/ColourPicker/Types/TDColorCollection.m b/libTitanD3vUniversal/ColourPicker/Types/TDColorCollection.m new file mode 100644 index 0000000..daa7362 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Types/TDColorCollection.m @@ -0,0 +1,60 @@ +#import "TDColorCollection.h" + +@implementation TDColorCollection + ++ (instancetype)collectionWithTitle:(NSString *)title colors:(NSArray *)colors { + return [[TDColorCollection alloc] initWithTitle:title colors:colors]; +} + +- (instancetype)initWithTitle:(NSString *)title colors:(NSArray *)colors { + if (self = [super init]) { + _title = title; + _colors = colors; + } + + return self; +} + +- (NSInteger)count { + return _colors.count; +} + ++ (instancetype)defaultSystemColorsCollection { + return [TDColorCollection collectionWithTitle:@"SYSTEM COLORS" colors:@[ + UIColor.systemRedColor, + UIColor.systemOrangeColor, + UIColor.systemYellowColor, + UIColor.systemGreenColor, + UIColor.systemTealColor, + UIColor.systemBlueColor, + [UIColor colorWithRed: 0.35 green: 0.34 blue: 0.84 alpha: 1.00], + UIColor.systemPurpleColor, + UIColor.systemPinkColor, + UIColor.systemGrayColor, + [UIColor colorWithRed: 0.68 green: 0.68 blue: 0.70 alpha: 1.00], + [UIColor colorWithRed: 0.78 green: 0.78 blue: 0.84 alpha: 1.00], + [UIColor colorWithRed: 0.82 green: 0.82 blue: 0.84 alpha: 1.00], + [UIColor colorWithRed: 0.90 green: 0.90 blue: 0.92 alpha: 1.00], + [UIColor colorWithRed: 0.95 green: 0.95 blue: 0.97 alpha: 1.00], + UIColor.whiteColor, + UIColor.blackColor + ]]; +} + ++ (instancetype)defaultPrimaryColorsCollection { + NSMutableArray *colors = [NSMutableArray new]; + for (NSInteger deg = 0; deg <= 360; deg += 30) { + [colors addObject:[UIColor colorWithHue:1.0f * deg / 360.0f saturation:1.0f brightness:1.0f alpha:1.0f]]; + } + return [TDColorCollection collectionWithTitle:@"PRIMARY COLORS" colors:colors]; +} + ++ (instancetype)defaultHueColorsCollection { + NSMutableArray *colors = [NSMutableArray new]; + for (NSInteger deg = 0; deg <= 360; deg += 1) { + [colors addObject:[UIColor colorWithHue:1.0f * deg / 360.0f saturation:1.0f brightness:1.0f alpha:1.0f]]; + } + return [TDColorCollection collectionWithTitle:@"HUE COLORS" colors:colors]; +} + +@end diff --git a/libTitanD3vUniversal/ColourPicker/Types/TDColorSpaceType.h b/libTitanD3vUniversal/ColourPicker/Types/TDColorSpaceType.h new file mode 100644 index 0000000..fac6730 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Types/TDColorSpaceType.h @@ -0,0 +1,13 @@ +#ifndef TDColorSpaceType_h +#define TDColorSpaceType_h + +typedef enum : NSUInteger { + TDColorSpaceTypeRGB, + TDColorSpaceTypeRGBA, + TDColorSpaceTypeHSB, + TDColorSpaceTypeHSBA, + TDColorSpaceTypeCMYK, + TDColorSpaceTypeCMYKA +} TDColorSpaceType; + +#endif /* TDColorSpaceType_h */ diff --git a/libTitanD3vUniversal/ColourPicker/Types/TDSliderType.h b/libTitanD3vUniversal/ColourPicker/Types/TDSliderType.h new file mode 100644 index 0000000..a83926f --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Types/TDSliderType.h @@ -0,0 +1,50 @@ +#ifndef TDSliderType_h +#define TDSliderType_h + +typedef enum : NSUInteger { + TDSliderTypeAlpha, + TDSliderTypeHue, + TDSliderTypeSaturation, + TDSliderTypeBrightness, + TDSliderTypeRed, + TDSliderTypeGreen, + TDSliderTypeBlue, + TDSliderTypeCyan, + TDSliderTypeMagenta, + TDSliderTypeYellow, + TDSliderTypeBlack +} TDSliderType; + +NS_INLINE NSString *sliderTypeShortName(TDSliderType type) { + switch (type) { + case TDSliderTypeAlpha: return @"A"; + case TDSliderTypeHue: return @"H"; + case TDSliderTypeSaturation: return @"S"; + case TDSliderTypeBrightness: return @"B"; + case TDSliderTypeRed: return @"R"; + case TDSliderTypeGreen: return @"G"; + case TDSliderTypeBlue: return @"B"; + case TDSliderTypeCyan: return @"C"; + case TDSliderTypeMagenta: return @"M"; + case TDSliderTypeYellow: return @"Y"; + case TDSliderTypeBlack: return @"K"; + } +} + +NS_INLINE CGFloat sliderTypeMaxValue(TDSliderType type) { + switch (type) { + case TDSliderTypeHue: return (CGFloat)360.0f; + case TDSliderTypeRed: + case TDSliderTypeGreen: + case TDSliderTypeBlue: return (CGFloat)255.0f; + case TDSliderTypeAlpha: + case TDSliderTypeSaturation: + case TDSliderTypeBrightness: + case TDSliderTypeCyan: + case TDSliderTypeMagenta: + case TDSliderTypeYellow: + case TDSliderTypeBlack: return (CGFloat)100.0f; + } +} + +#endif /* TDSliderType_h */ diff --git a/libTitanD3vUniversal/ColourPicker/Views/TDColorDisplayView.h b/libTitanD3vUniversal/ColourPicker/Views/TDColorDisplayView.h new file mode 100644 index 0000000..700794c --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Views/TDColorDisplayView.h @@ -0,0 +1,13 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface TDColorDisplayView : UILabel + +@property (nonatomic, strong) UIColor *color; + +- (instancetype)initWithColor:(UIColor *)color; + +@end + +NS_ASSUME_NONNULL_END diff --git a/libTitanD3vUniversal/ColourPicker/Views/TDColorDisplayView.m b/libTitanD3vUniversal/ColourPicker/Views/TDColorDisplayView.m new file mode 100644 index 0000000..1881166 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Views/TDColorDisplayView.m @@ -0,0 +1,32 @@ +#import "TDColorDisplayView.h" +#import "UIColor+ChromaPicker_Internal.h" + +@implementation TDColorDisplayView + +- (instancetype)initWithColor:(UIColor *)color { + + if (self == [super init]) { + self.textAlignment = NSTextAlignmentCenter; + self.font = [UIFont systemFontOfSize: 30 weight:UIFontWeightBold]; + self.adjustsFontSizeToFitWidth = YES; + self.layer.cornerRadius = 12; + self.layer.masksToBounds = YES; + if (@available(iOS 13.0, *)) { + self.layer.cornerCurve = kCACornerCurveContinuous; + } + self.color = color; + + } + + return self; +} + +- (void)setColor:(UIColor *)color { + _color = color; + self.text = color.hexStringValue; + self.backgroundColor = color; + self.textColor = color.isDarkColor ? UIColor.lightTextColor : UIColor.darkTextColor; +} + + +@end diff --git a/libTitanD3vUniversal/ColourPicker/Views/TDColorSliderStackView.h b/libTitanD3vUniversal/ColourPicker/Views/TDColorSliderStackView.h new file mode 100644 index 0000000..415da41 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Views/TDColorSliderStackView.h @@ -0,0 +1,18 @@ +#import +#import "TDColorSliderDelegate.h" +#import "TDColorPickerDelegate.h" +#import "TDColorSpaceType.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface TDColorSliderStackView : UIStackView + +@property (nonatomic, weak) id delegate; + +- (instancetype)initWithColor:(UIColor *)color stackType:(TDColorSpaceType)type delegate:(id)delegate; +- (void)configureForStackType:(TDColorSpaceType)type color:(UIColor *)color; + +- (void)setColor:(UIColor *)color; +@end + +NS_ASSUME_NONNULL_END diff --git a/libTitanD3vUniversal/ColourPicker/Views/TDColorSliderStackView.m b/libTitanD3vUniversal/ColourPicker/Views/TDColorSliderStackView.m new file mode 100644 index 0000000..cbbb7a5 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Views/TDColorSliderStackView.m @@ -0,0 +1,126 @@ +#import "TDColorSliderStackView.h" +#import "TDColorSlider.h" +#import "TDColorDisplayView.h" +#import "UIColor+ChromaPicker_Internal.h" + +@implementation TDColorSliderStackView { + NSArray *_sliders; + UIColor *_color; + TDColorSpaceType _type; +} + +- (instancetype)initWithColor:(UIColor *)color stackType:(TDColorSpaceType)type delegate:(id)delegate { + if (self == [super init]) { + self.delegate = delegate; + [self configureForStackType:type color:color]; + } + return self; +} + +- (void)configureForStackType:(TDColorSpaceType)type color:(UIColor *)color { + self.axis = UILayoutConstraintAxisVertical; + self.alignment = UIStackViewAlignmentFill; + self.distribution = UIStackViewDistributionFillEqually; + self.spacing = 8; + + _type = type; + _color = color; + + switch (type) { + + case TDColorSpaceTypeRGB: + _sliders = @[ + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeRed color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeGreen color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeBlue color:color] + ]; + break; + case TDColorSpaceTypeRGBA: + _sliders = @[ + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeRed color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeGreen color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeBlue color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeAlpha color:color], + ]; + break; + case TDColorSpaceTypeHSB: + _sliders = @[ + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeHue color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeSaturation color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeBrightness color:color] + ]; + break; + case TDColorSpaceTypeHSBA: + _sliders = @[ + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeHue color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeSaturation color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeBrightness color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeAlpha color:color] + ]; + break; + case TDColorSpaceTypeCMYK: + _sliders = @[ + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeCyan color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeMagenta color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeYellow color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeBlack color:color] + ]; + break; + case TDColorSpaceTypeCMYKA: + _sliders = @[ + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeCyan color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeMagenta color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeYellow color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeBlack color:color], + [[TDColorSlider alloc] initWithSliderType:TDSliderTypeAlpha color:color] + ]; + break; + } + + [self.arrangedSubviews enumerateObjectsUsingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) { + [self removeArrangedSubview:obj]; + [obj removeConstraints:obj.constraints]; + [obj removeFromSuperview]; + }]; + + for (TDColorSlider *slider in _sliders) { + slider.delegate = self; + [self addArrangedSubview:slider]; + } +} + +- (void)applyColorExcludingSlider:(TDColorSlider *)excludingSlider { + if (self.delegate && [self.delegate respondsToSelector:@selector(colorPickerDidUpdateColor:)]) + [self.delegate colorPickerDidUpdateColor:_color]; + + for (TDColorSlider *slider in _sliders) { + if (slider != excludingSlider) { + [slider setColor:_color]; + } + } +} + +- (void)setColor:(UIColor *)color { + _color = color; + [self applyColorExcludingSlider:nil]; +} + +#pragma mark - TDColorSliderDelegate + +- (void)slider:(TDColorSlider *)colorSlider colorChanged:(UIColor *)color { + _color = color; + [self applyColorExcludingSlider:colorSlider]; +} + +- (void)slider:(TDColorSlider *)colorSlider valueChanged:(CGFloat)value { + _color = [_color colorByApplyingValue:value / colorSlider.maximumValue sliderType:colorSlider.type]; + [self applyColorExcludingSlider:colorSlider]; +} + +- (void)slider:(TDColorSlider *)colorSlider valueFinishedChange:(CGFloat)value { + if (self.delegate && [self.delegate respondsToSelector:@selector(colorPickerDidChangeColor:)]) + [self.delegate colorPickerDidChangeColor:_color]; +} + + +@end diff --git a/libTitanD3vUniversal/ColourPicker/Views/TDGradientView.h b/libTitanD3vUniversal/ColourPicker/Views/TDGradientView.h new file mode 100644 index 0000000..980d628 --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Views/TDGradientView.h @@ -0,0 +1,14 @@ +#import +#import "TDSliderType.h" + +NS_ASSUME_NONNULL_BEGIN + +@class UIColor; +@interface TDGradientView : CAGradientLayer + +- (instancetype)initWithColors:(NSArray *)colors; +- (void)setColorsForSliderType:(TDSliderType)type primaryColor:(UIColor *)primary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/libTitanD3vUniversal/ColourPicker/Views/TDGradientView.m b/libTitanD3vUniversal/ColourPicker/Views/TDGradientView.m new file mode 100644 index 0000000..7b2356c --- /dev/null +++ b/libTitanD3vUniversal/ColourPicker/Views/TDGradientView.m @@ -0,0 +1,86 @@ +#import "TDGradientView.h" +#import "UIColor+ChromaPicker_Internal.h" + +@implementation TDGradientView + +- (instancetype)initWithColors:(NSArray *)colors { + if (self == [super init]) { + self.startPoint = CGPointMake(0, 0.5); + self.endPoint = CGPointMake(1, 0.5); + if (@available(iOS 13.0, *)) { + self.cornerCurve = kCACornerCurveContinuous; + } + self.masksToBounds = YES; + self.cornerRadius = 10; + self.borderWidth = 1; + if (@available(iOS 13.0, *)) { + self.borderColor = UIColor.tertiarySystemFillColor.CGColor; + } else { + self.borderColor = UIColor.lightGrayColor.CGColor; + } + self.colors = colors; + } + + return self; +} + +- (void)setColorsForSliderType:(TDSliderType)type primaryColor:(UIColor *)primary { + switch (type) { + + case TDSliderTypeHue: { + self.colors = UIColor.hueColors; + } break; + case TDSliderTypeAlpha: { + NSArray *components = primary.HSBAValues; + self.colors = @[(__bridge id)hsba([components[0] doubleValue], [components[1] doubleValue], [components[2] doubleValue], 0).CGColor, + (__bridge id)hsba([components[0] doubleValue], [components[1] doubleValue], [components[2] doubleValue], 1).CGColor]; + } break; + case TDSliderTypeSaturation: { + NSArray *components = primary.HSBAValues; + self.colors = @[(__bridge id)hsba([components[0] doubleValue], 0, [components[2] doubleValue], [components[3] doubleValue]).CGColor, + (__bridge id)hsba([components[0] doubleValue], 1, [components[2] doubleValue], [components[3] doubleValue]).CGColor]; + } break; + case TDSliderTypeBrightness: { + NSArray *components = primary.HSBAValues; + self.colors = @[(__bridge id)hsba([components[0] doubleValue], [components[1] doubleValue], 0, [components[3] doubleValue]).CGColor, + (__bridge id)hsba([components[0] doubleValue], [components[1] doubleValue], 1, [components[3] doubleValue]).CGColor]; + } break; + case TDSliderTypeRed: { + NSArray *components = primary.RGBAValues; + self.colors = @[(__bridge id)rgba(0, [components[1] doubleValue], [components[2] doubleValue], [components[3] doubleValue]).CGColor, + (__bridge id)rgba(1, [components[1] doubleValue], [components[2] doubleValue], [components[3] doubleValue]).CGColor]; + } break; + case TDSliderTypeGreen: { + NSArray *components = primary.RGBAValues; + self.colors = @[(__bridge id)rgba([components[0] doubleValue], 0, [components[2] doubleValue], [components[3] doubleValue]).CGColor, + (__bridge id)rgba([components[0] doubleValue], 1, [components[2] doubleValue], [components[3] doubleValue]).CGColor]; + } break; + case TDSliderTypeBlue: { + NSArray *components = primary.RGBAValues; + self.colors = @[(__bridge id)rgba([components[0] doubleValue], [components[1] doubleValue], 0, [components[3] doubleValue]).CGColor, + (__bridge id)rgba([components[0] doubleValue], [components[1] doubleValue], 1, [components[3] doubleValue]).CGColor]; + } break; + case TDSliderTypeCyan: { + NSArray *components = primary.CMYKAValues; + self.colors = @[(__bridge id)cmyka(0, [components[1] doubleValue], [components[2] doubleValue], [components[3] doubleValue], [components[4] doubleValue]).CGColor, + (__bridge id)cmyka(1, [components[1] doubleValue], [components[2] doubleValue], [components[3] doubleValue], [components[4] doubleValue]).CGColor]; + } break; + case TDSliderTypeMagenta: { + NSArray *components = primary.CMYKAValues; + self.colors = @[(__bridge id)cmyka([components[0] doubleValue], 0, [components[2] doubleValue], [components[3] doubleValue], [components[4] doubleValue]).CGColor, + (__bridge id)cmyka([components[0] doubleValue], 1, [components[2] doubleValue], [components[3] doubleValue], [components[4] doubleValue]).CGColor]; + } break; + case TDSliderTypeYellow: { + NSArray *components = primary.CMYKAValues; + self.colors = @[(__bridge id)cmyka([components[0] doubleValue], [components[1] doubleValue], 0, [components[3] doubleValue], [components[4] doubleValue]).CGColor, + (__bridge id)cmyka([components[0] doubleValue], [components[1] doubleValue], 1, [components[3] doubleValue], [components[4] doubleValue]).CGColor]; + } break; + case TDSliderTypeBlack: { + NSArray *components = primary.CMYKAValues; + self.colors = @[(__bridge id)cmyka([components[0] doubleValue], [components[1] doubleValue], [components[2] doubleValue], 0, [components[4] doubleValue]).CGColor, + (__bridge id)cmyka([components[0] doubleValue], [components[1] doubleValue], [components[2] doubleValue], 1, [components[4] doubleValue]).CGColor]; + } break; + } +} + +@end diff --git a/libTitanD3vUniversal/Confetti/TDConfettiView.h b/libTitanD3vUniversal/Confetti/TDConfettiView.h new file mode 100644 index 0000000..605edc7 --- /dev/null +++ b/libTitanD3vUniversal/Confetti/TDConfettiView.h @@ -0,0 +1,22 @@ +#import + +typedef enum : NSUInteger { + TDConfettiTypeConfetti, + TDConfettiTypeTriangle, + TDConfettiTypeStar, + TDConfettiTypeDiamond, + TDConfettiTypeCustom +} TDConfettiType; + +@interface TDConfettiView : UIView + +@property (nonatomic, strong) NSArray *colors; +@property (nonatomic, assign) CGFloat intensity; +@property (nonatomic, assign) CGFloat birthRate; +@property (nonatomic, assign) TDConfettiType type; +@property (nonatomic, strong) UIImage *customImage; +@property (nonatomic, assign, readonly) BOOL isRaining; +-(void)startConfetti; +-(void)stopConfetti; + +@end \ No newline at end of file diff --git a/libTitanD3vUniversal/Confetti/TDConfettiView.m b/libTitanD3vUniversal/Confetti/TDConfettiView.m new file mode 100644 index 0000000..4e0c58c --- /dev/null +++ b/libTitanD3vUniversal/Confetti/TDConfettiView.m @@ -0,0 +1,118 @@ +#import "TDConfettiView.h" + +@interface TDConfettiView () + +@property (nonatomic, strong) CAEmitterLayer *emitter; +@property (nonatomic, assign) BOOL isRaining; + +@end + +@implementation TDConfettiView + +#pragma mark - Properties + +-(void)setBirthRate:(CGFloat)birthRate +{ + if(birthRate == _birthRate) + return; + + _birthRate = birthRate; + self.emitter.birthRate = _birthRate; +} + +#pragma mark - Lifecycle + +-(instancetype)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if(!self) + return nil; + + [self setupConfetti]; + + return self; +} + +-(instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if(!self) + return nil; + + [self setupConfetti]; + + return self; +} + +-(void)setupConfetti +{ + self.colors = @[[UIColor colorWithRed:0.95 green:0.40 blue:0.27 alpha:1.0], + [UIColor colorWithRed:1.00 green:0.78 blue:0.36 alpha:1.0], + [UIColor colorWithRed:0.48 green:0.78 blue:0.64 alpha:1.0], + [UIColor colorWithRed:0.30 green:0.76 blue:0.85 alpha:1.0], + [UIColor colorWithRed:0.58 green:0.39 blue:0.55 alpha:1.0]]; + + self.intensity = 1.5; + self.birthRate = 1; + self.type = TDConfettiTypeConfetti; +} + + +#pragma mark - Public + +-(void)startConfetti +{ + //* + if(self.emitter == nil) { + self.emitter = CAEmitterLayer.new; + self.emitter.emitterPosition = CGPointMake(self.center.x, 0); + self.emitter.emitterShape = kCAEmitterLayerLine; + self.emitter.emitterSize = CGSizeMake(self.bounds.size.width, 1); + + + NSMutableArray *cells = NSMutableArray.new; + for (UIColor *color in self.colors) { + [cells addObject:[self cellWithColor:color]]; + } + + self.emitter.emitterCells = cells; + [self.layer addSublayer:self.emitter]; + } + + self.emitter.birthRate = self.birthRate; + self.isRaining = YES; +} + +-(void)stopConfetti +{ + if(self.emitter) + self.emitter.birthRate = 0; + + self.isRaining = NO; +} + +#pragma mark - Private + +-(CAEmitterCell *)cellWithColor:(UIColor *)color +{ + CAEmitterCell *confetti = [CAEmitterCell new]; + + confetti.birthRate = 6.0 * self.intensity / 2; + confetti.lifetime = 14.0 * self.intensity * 2.2; + confetti.lifetimeRange = 0; + confetti.color = color.CGColor; + confetti.velocity = (CGFloat)350.0 * self.intensity / 2.3; + confetti.velocityRange = (CGFloat)80.0 * self.intensity; + confetti.emissionLongitude = (CGFloat)M_PI; + confetti.emissionRange = (CGFloat)M_PI_4; + confetti.spin = (CGFloat)3.5 * self.intensity; + confetti.spinRange = (CGFloat)4.0 * self.intensity; + confetti.scaleRange = (CGFloat)self.intensity; + confetti.scaleSpeed = (CGFloat)(-0.1 * self.intensity); + + confetti.contents = (id)[[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Confetti/diamond.png"] CGImage]; + + return confetti; +} + +@end diff --git a/libTitanD3vUniversal/Constraints/ConstraintExtension.h b/libTitanD3vUniversal/Constraints/ConstraintExtension.h new file mode 100644 index 0000000..e90ec61 --- /dev/null +++ b/libTitanD3vUniversal/Constraints/ConstraintExtension.h @@ -0,0 +1,20 @@ +#import + +@interface UIView (extension) + +-(void)top:(nullable NSLayoutAnchor *)top leading:(nullable NSLayoutAnchor *)leading bottom:(nullable NSLayoutAnchor *)bottom trailing:(nullable NSLayoutAnchor *)trailing padding:(UIEdgeInsets)insets; +-(void)top:(nullable NSLayoutAnchor *)top padding:(CGFloat)size; +-(void)leading:(nullable NSLayoutAnchor *)leading padding:(CGFloat)size; +-(void)trailing:(nullable NSLayoutAnchor *)trailing padding:(CGFloat)size; +-(void)bottom:(nullable NSLayoutAnchor *)bottom padding:(CGFloat)size; +-(void)size:(CGSize)size; +-(void)width:(CGFloat)size; +-(void)height:(CGFloat)size; +-(void)x:(nullable NSLayoutAnchor *)centerX; +-(void)y:(nullable NSLayoutAnchor *)centerY; +-(void)x:(nullable NSLayoutAnchor *)centerX padding:(CGFloat)size; +-(void)y:(nullable NSLayoutAnchor *)centerY padding:(CGFloat)size; +-(void)x:(nullable NSLayoutAnchor *)centerX y:(nullable NSLayoutAnchor *)centerY; +-(void)fill; + +@end diff --git a/libTitanD3vUniversal/Constraints/ConstraintExtension.m b/libTitanD3vUniversal/Constraints/ConstraintExtension.m new file mode 100644 index 0000000..cbdb804 --- /dev/null +++ b/libTitanD3vUniversal/Constraints/ConstraintExtension.m @@ -0,0 +1,128 @@ +#import "ConstraintExtension.h" + +@implementation UIView (extension) + +-(void)top:(nullable NSLayoutAnchor *)top leading:(nullable NSLayoutAnchor *)leading bottom:(nullable NSLayoutAnchor *)bottom trailing:(nullable NSLayoutAnchor *)trailing padding:(UIEdgeInsets)insets { + + self.translatesAutoresizingMaskIntoConstraints = NO; + + if (top) { + [self.topAnchor constraintEqualToAnchor:top constant:insets.top].active = YES; + } + + if (leading) { + [self.leadingAnchor constraintEqualToAnchor:leading constant:insets.left].active = YES; + } + + if (trailing) { + [self.trailingAnchor constraintEqualToAnchor:trailing constant:insets.right].active = YES; + } + + if (bottom) { + [self.bottomAnchor constraintEqualToAnchor:bottom constant:insets.bottom].active = YES; + } + +} + + +-(void)top:(nullable NSLayoutAnchor *)top padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (top) { + [self.topAnchor constraintEqualToAnchor:top constant:size].active = YES; + } +} + + +-(void)leading:(nullable NSLayoutAnchor *)leading padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (leading) { + [self.leadingAnchor constraintEqualToAnchor:leading constant:size].active = YES; + } +} + + +-(void)trailing:(nullable NSLayoutAnchor *)trailing padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (trailing) { + [self.trailingAnchor constraintEqualToAnchor:trailing constant:size].active = YES; + } +} + + +-(void)bottom:(nullable NSLayoutAnchor *)bottom padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + if (bottom) { + [self.bottomAnchor constraintEqualToAnchor:bottom constant:size].active = YES; + } +} + + +-(void)size:(CGSize)size { + + self.translatesAutoresizingMaskIntoConstraints = NO; + + if (size.width != 0) { + [self.widthAnchor constraintEqualToConstant:size.width].active = YES; + } + + if (size.height != 0) { + [self.heightAnchor constraintEqualToConstant:size.height].active = YES; + } + +} + + +-(void)width:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.widthAnchor constraintEqualToConstant:size].active = YES; +} + + +-(void)height:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.heightAnchor constraintEqualToConstant:size].active = YES; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX y:(nullable NSLayoutAnchor *)centerY { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX].active = true; + [[self centerYAnchor] constraintEqualToAnchor:centerY].active = true; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX].active = true; +} + + +-(void)y:(nullable NSLayoutAnchor *)centerY { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerYAnchor] constraintEqualToAnchor:centerY].active = true; +} + + +-(void)x:(nullable NSLayoutAnchor *)centerX padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerXAnchor] constraintEqualToAnchor:centerX constant:size].active = true; +} + + +-(void)y:(nullable NSLayoutAnchor *)centerY padding:(CGFloat)size { + self.translatesAutoresizingMaskIntoConstraints = NO; + [[self centerYAnchor] constraintEqualToAnchor:centerY constant:size].active = true; +} + + +-(void)fill { + + self.translatesAutoresizingMaskIntoConstraints = NO; + [self.topAnchor constraintEqualToAnchor:self.superview.topAnchor].active = YES; + [self.leadingAnchor constraintEqualToAnchor:self.superview.leadingAnchor].active = YES; + [self.trailingAnchor constraintEqualToAnchor:self.superview.trailingAnchor].active = YES; + [self.bottomAnchor constraintEqualToAnchor:self.superview.bottomAnchor].active = YES; + +} + +@end diff --git a/libTitanD3vUniversal/ContactPicker/TDContact.h b/libTitanD3vUniversal/ContactPicker/TDContact.h new file mode 100644 index 0000000..43f01f0 --- /dev/null +++ b/libTitanD3vUniversal/ContactPicker/TDContact.h @@ -0,0 +1,12 @@ +#import + +@interface TDContact : NSObject +@property (nonatomic, retain) NSString *fullName; +@property (nonatomic, retain) NSString *phoneNumber; +@property (nonatomic, retain) NSString *emailAddress; +@property (nonatomic, retain) NSString *identifier; +@property (nonatomic, retain) UIImage *avatarImage; +@property (nonatomic) BOOL isEmailAvailable; +@property (nonatomic) BOOL isAvatarAvailable; +@property (nonatomic) BOOL isPhoneNumberContainPrefix; +@end diff --git a/libTitanD3vUniversal/ContactPicker/TDContact.m b/libTitanD3vUniversal/ContactPicker/TDContact.m new file mode 100644 index 0000000..cedc2fe --- /dev/null +++ b/libTitanD3vUniversal/ContactPicker/TDContact.m @@ -0,0 +1,4 @@ +#import "TDContact.h" + +@implementation TDContact +@end diff --git a/libTitanD3vUniversal/ContactPicker/TDContactPickerCell.h b/libTitanD3vUniversal/ContactPicker/TDContactPickerCell.h new file mode 100644 index 0000000..9780192 --- /dev/null +++ b/libTitanD3vUniversal/ContactPicker/TDContactPickerCell.h @@ -0,0 +1,11 @@ +#import +#import "ConstraintExtension.h" + +@interface TDContactPickerCell : UITableViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *avatar; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UILabel *numberLabel; +@property (nonatomic, retain) UILabel *emailLabel; +@end + diff --git a/libTitanD3vUniversal/ContactPicker/TDContactPickerCell.m b/libTitanD3vUniversal/ContactPicker/TDContactPickerCell.m new file mode 100644 index 0000000..f9ac067 --- /dev/null +++ b/libTitanD3vUniversal/ContactPicker/TDContactPickerCell.m @@ -0,0 +1,83 @@ +#import "TDContactPickerCell.h" + +@implementation TDContactPickerCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.baseView.clipsToBounds = true; + self.baseView.layer.cornerRadius = 10; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + [self addSubview:self.baseView]; + + [self.baseView top:self.topAnchor padding:3]; + [self.baseView leading:self.leadingAnchor padding:2]; + [self.baseView trailing:self.trailingAnchor padding:-2]; + [self.baseView bottom:self.bottomAnchor padding:-3]; + + + self.avatar = [[UIImageView alloc] init]; + self.avatar.contentMode = UIViewContentModeScaleAspectFill; + self.avatar.layer.cornerRadius = 25; + self.avatar.clipsToBounds = YES; + [self.baseView addSubview:self.avatar]; + + [self.avatar size:CGSizeMake(50, 50)]; + [self.avatar leading:self.baseView.leadingAnchor padding:10]; + [self.avatar y:self.baseView.centerYAnchor]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.textAlignment = NSTextAlignmentLeft; + self.nameLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightBold]; + self.nameLabel.textColor = UIColor.labelColor; + [self.baseView addSubview:self.nameLabel]; + + [self.nameLabel top:self.avatar.topAnchor padding:-5]; + [self.nameLabel leading:self.avatar.trailingAnchor padding:10]; + [self.nameLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.numberLabel = [[UILabel alloc] init]; + self.numberLabel.textAlignment = NSTextAlignmentLeft; + self.numberLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightRegular]; + self.numberLabel.textColor = UIColor.tertiaryLabelColor; + [self.baseView addSubview:self.numberLabel]; + + [self.numberLabel y:self.baseView.centerYAnchor]; + [self.numberLabel leading:self.avatar.trailingAnchor padding:10]; + [self.numberLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + self.emailLabel = [[UILabel alloc] init]; + self.emailLabel.textAlignment = NSTextAlignmentLeft; + self.emailLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightRegular]; + self.emailLabel.textColor = UIColor.tertiaryLabelColor; + [self.baseView addSubview:self.emailLabel]; + + [self.emailLabel bottom:self.avatar.bottomAnchor padding:2]; + [self.emailLabel leading:self.avatar.trailingAnchor padding:10]; + [self.emailLabel trailing:self.baseView.trailingAnchor padding:-10]; + + + } + + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + + self.avatar.image = nil; + self.nameLabel.text = nil; + self.numberLabel.text = nil; + self.emailLabel.text = nil; +} + +@end diff --git a/libTitanD3vUniversal/ContactPicker/TDContactPickerViewController.h b/libTitanD3vUniversal/ContactPicker/TDContactPickerViewController.h new file mode 100644 index 0000000..d29df21 --- /dev/null +++ b/libTitanD3vUniversal/ContactPicker/TDContactPickerViewController.h @@ -0,0 +1,31 @@ +#import +#import "ConstraintExtension.h" +#import +#import "TDPeople.h" +#import "TDContactPickerCell.h" +#import "TDContact.h" +#import "TDHeaderView.h" + +@protocol TDContactPickerProtocol +@required +-(void)didPickAContact:(TDContact*)contact; +-(void)didCancelPickAContact; +@end + +@interface TDContactPickerViewController : UIViewController +-(instancetype)initWithTitle:(NSString *)title accentColour:(UIColor *)accent; +@property (nonatomic, retain) TDHeaderView *headerView; +@property (nonatomic, retain) UITableView *tableView; +@property (strong, nonatomic) NSArray * sectionIndexTitles; +@property (strong, nonatomic) NSMutableArray * contactPeople; +@property (strong, nonatomic) NSMutableArray * parsedContacts; +@property (nonatomic) NSInteger selectedSection; +@property (nonatomic) NSInteger selectedIndex; +@property (nonatomic) BOOL didSelectedContact; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) NSString *titleString; +@property (nonatomic, retain) UIColor *accentColour; +@property(nonatomic,assign)id delegate; +@property (nonatomic, retain) TDContact *tdcontact; +@end + diff --git a/libTitanD3vUniversal/ContactPicker/TDContactPickerViewController.m b/libTitanD3vUniversal/ContactPicker/TDContactPickerViewController.m new file mode 100644 index 0000000..97b50d0 --- /dev/null +++ b/libTitanD3vUniversal/ContactPicker/TDContactPickerViewController.m @@ -0,0 +1,333 @@ +#import "TDContactPickerViewController.h" + +@implementation TDContactPickerViewController + +-(instancetype)initWithTitle:(NSString *)title accentColour:(UIColor *)accent { + + self = [super init]; + if (self) { + self.titleString = title; + self.accentColour = accent; + + self.tdcontact = [[TDContact alloc] init]; + } + + + return self; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.systemBackgroundColor; + [self layoutHeaderView]; + [self getContacts]; + [self appendContacts]; + [self layoutTableView]; +} + + +-(void)layoutHeaderView { + + + self.headerView = [[TDHeaderView alloc] initWithTitle:self.titleString accent:self.accentColour leftIcon:@"xmark" leftAction:@selector(dismissVC) rightIcon:@"person.crop.circle.fill.badge.checkmark" rightAction:@selector(applyContact)]; + self.headerView.rightButton.tintColor = UIColor.whiteColor; + self.headerView.rightButton.backgroundColor = self.accentColour; + self.headerView.rightButton.alpha = 0; + [self.view addSubview:self.headerView]; + + [self.headerView size:CGSizeMake(self.view.frame.size.width, 75)]; + [self.headerView x:self.view.centerXAnchor]; + [self.headerView top:self.view.safeAreaLayoutGuide.topAnchor padding:0]; +} + + +-(void)getContacts { + + CNAuthorizationStatus authorizationStatus = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]; + if (authorizationStatus != CNAuthorizationStatusAuthorized) { + NSLog(@"No authorization..."); + return; + } + + self.contactPeople = [[NSMutableArray alloc] init]; + + NSArray *keysToFetch = @[CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey, CNContactEmailAddressesKey, CNContactImageDataKey, CNContactIdentifierKey]; + CNContactFetchRequest *fetchRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:keysToFetch]; + CNContactStore *contactStore = [[CNContactStore alloc] init]; + [contactStore enumerateContactsWithFetchRequest:fetchRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) { + + NSString *givenName = contact.givenName; + NSString *familyName = contact.familyName; + + TDPeople *tdpeople = [[TDPeople alloc] init]; + tdpeople.firstName = givenName; + tdpeople.lastName = familyName; + + NSArray *phoneNumbers = contact.phoneNumbers; + for (CNLabeledValue *labelValue in phoneNumbers) { + CNPhoneNumber *phoneNumber = labelValue.value; + NSString * onePhone = phoneNumber.stringValue; + + tdpeople.phone = [onePhone stringByReplacingOccurrencesOfString:@" " withString:@""]; + } + + + NSArray *emailArray = contact.emailAddresses; + for (CNLabeledValue *labelValue2 in emailArray) { + NSString *email = labelValue2.value; + tdpeople.email = email; + } + + + if (contact.imageData != nil ) { + UIImage *contactImage = [UIImage imageWithData:(NSData *)contact.imageData]; + tdpeople.avatar = contactImage; + } + + + NSString *ids = contact.identifier; + tdpeople.identifier = ids; + + + [self.contactPeople addObject:tdpeople]; + }]; +} + + +-(void)appendContacts { + + NSMutableArray * columns = [[NSMutableArray alloc] initWithCapacity:26]; + for(int i = 0; i < 26; i ++){ + NSMutableArray * group = [[NSMutableArray alloc] init]; + for(int j = 0; j < self.contactPeople.count ; j++){ + TDPeople *tdpeople = self.contactPeople [j]; + NSString * letter; + if(tdpeople.firstName.length != 0) { + letter = [tdpeople.firstName substringToIndex:1]; + } + else if(tdpeople.lastName.length != 0) { + letter = [tdpeople.lastName substringToIndex:1]; + } + if( letter == [NSString stringWithFormat: @"%c", i+'A'] ){ + [group addObject:tdpeople]; + } + } + if (group.count) { + [columns addObject:group]; + } + } + self.parsedContacts = columns; + + NSMutableArray* letters = [[NSMutableArray alloc] init]; + for(int i = 0; i < self.parsedContacts.count; i ++){ + NSString * item = [NSString stringWithFormat:@"%c", i+'A']; + [letters addObject:item]; + } + + self.sectionIndexTitles = [letters copy]; +} + + +-(void)layoutTableView { + + self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleInsetGrouped]; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor;; + self.tableView.sectionIndexColor = self.accentColour; + self.tableView.showsVerticalScrollIndicator = NO; + self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; + [self.view addSubview:self.tableView]; + + self.tableView.delegate = self; + self.tableView.dataSource = self; + + + [self.tableView top:self.headerView.bottomAnchor padding:0]; + [self.tableView leading:self.view.leadingAnchor padding:0]; + [self.tableView trailing:self.view.trailingAnchor padding:0]; + [self.tableView bottom:self.view.bottomAnchor padding:0]; +} + + +-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { + TDPeople *tdpeople = self.parsedContacts [section] [0]; + NSString * title; + if(tdpeople.firstName.length != 0) { + title = [tdpeople.firstName substringToIndex:1]; + } else { + title = [tdpeople.lastName substringToIndex:1]; + } + return title; +} + + +-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { + NSMutableArray * indices = [[NSMutableArray alloc] init]; + for (int i = 0; i < self.parsedContacts.count; ++i) { + TDPeople *tdpeople = self.parsedContacts[i][0]; + NSString *title; + if (tdpeople.firstName.length != 0) { + title = [tdpeople.firstName substringToIndex:1]; + } else { + title = [tdpeople.lastName substringToIndex:1]; + } + [indices addObject:title]; + } + return indices; +} + + +-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [self.parsedContacts[section] count]; +} + + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return self.parsedContacts.count; +} + + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + TDContactPickerCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + cell = [[TDContactPickerCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *bgColorView = [[UIView alloc] init]; + bgColorView.backgroundColor = UIColor.clearColor; + [cell setSelectedBackgroundView:bgColorView]; + + cell.backgroundColor = UIColor.clearColor; + + TDPeople *tdpeople = self.parsedContacts [indexPath.section] [indexPath.row]; + cell.nameLabel.text = [NSString stringWithFormat:@"%@ %@", tdpeople.firstName, tdpeople.lastName]; + + cell.emailLabel.text = tdpeople.email; + + + if (tdpeople.phone != nil) { + cell.numberLabel.text = tdpeople.phone; + } else { + cell.numberLabel.text = @"No phone number available"; + } + + + if (tdpeople.email != nil) { + cell.emailLabel.text = tdpeople.email; + } else { + cell.emailLabel.text = @"No email address available"; + } + + + if (tdpeople.avatar !=nil) { + cell.avatar.image = tdpeople.avatar; + } else { + cell.avatar.image = [UIImage systemImageNamed:@"person.crop.circle.fill"]; + cell.avatar.tintColor = self.accentColour; + } + + + if (self.didSelectedContact) { + if ((indexPath.section == self.selectedSection) && (indexPath.row == self.selectedIndex)) { + cell.baseView.backgroundColor = self.accentColour; + cell.nameLabel.textColor = UIColor.whiteColor; + cell.numberLabel.textColor = UIColor.whiteColor; + cell.emailLabel.textColor = UIColor.whiteColor; + UIImageView *checkmark = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"checkmark"]]; + checkmark.tintColor = UIColor.whiteColor; + cell.accessoryView = checkmark; + cell.avatar.tintColor = UIColor.whiteColor; + } else { + cell.baseView.backgroundColor = UIColor.secondarySystemBackgroundColor; + cell.nameLabel.textColor = UIColor.labelColor; + cell.numberLabel.textColor = UIColor.tertiaryLabelColor; + cell.emailLabel.textColor = UIColor.tertiaryLabelColor; + cell.accessoryView = nil; + cell.avatar.tintColor = self.accentColour; + } + } + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 75; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + + TDPeople *tdpeople = self.parsedContacts [indexPath.section] [indexPath.row]; + + self.tdcontact.fullName = [NSString stringWithFormat:@"%@ %@", tdpeople.firstName, tdpeople.lastName]; + self.tdcontact.phoneNumber = tdpeople.phone; + self.tdcontact.emailAddress = tdpeople.email; + self.tdcontact.identifier = tdpeople.identifier; + self.tdcontact.avatarImage = tdpeople.avatar; + + NSRange rangeValue = [self.tdcontact.phoneNumber rangeOfString:@"+" options:NSCaseInsensitiveSearch]; + + if (rangeValue.length > 0) { + self.tdcontact.isPhoneNumberContainPrefix = YES; + } else { + self.tdcontact.isPhoneNumberContainPrefix = NO; + } + + + if (self.tdcontact.emailAddress != nil) { + self.tdcontact.isEmailAvailable = YES; + } else { + self.tdcontact.isEmailAvailable = NO; + } + + if (self.tdcontact.avatarImage != nil) { + self.tdcontact.isAvatarAvailable = YES; + } else { + self.tdcontact.isAvatarAvailable = NO; + } + + self.headerView.rightButton.alpha = 1; + self.modalInPresentation = YES; + self.didSelectedContact = YES; + self.selectedSection = indexPath.section; + self.selectedIndex = indexPath.row; + [self.tableView reloadData]; +} + + +-(void)dismissVC { + [self.delegate didCancelPickAContact]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)applyContact { + [self.delegate didPickAContact:self.tdcontact]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(UIColor *)randomColor { + static NSArray *__colors = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + __colors = @[UIColor.systemRedColor, + UIColor.systemIndigoColor, + UIColor.systemTealColor, + UIColor.systemPinkColor, + UIColor.systemYellowColor, + UIColor.systemOrangeColor, + UIColor.systemGreenColor + ]; + }); + int index = arc4random_uniform((uint32_t)__colors.count); + return __colors[index]; +} + +@end diff --git a/libTitanD3vUniversal/ContactPicker/TDPeople.h b/libTitanD3vUniversal/ContactPicker/TDPeople.h new file mode 100644 index 0000000..f0e6f28 --- /dev/null +++ b/libTitanD3vUniversal/ContactPicker/TDPeople.h @@ -0,0 +1,11 @@ +#import + +@interface TDPeople : NSObject +@property (strong, nonatomic) NSString *firstName; +@property (strong, nonatomic) NSString *lastName; +@property (strong, nonatomic) NSString *phone; +@property (strong, nonatomic) NSString *email; +@property (strong, nonatomic) NSString *identifier; +@property (strong, nonatomic) UIImage *avatar; +@end + diff --git a/libTitanD3vUniversal/ContactPicker/TDPeople.m b/libTitanD3vUniversal/ContactPicker/TDPeople.m new file mode 100644 index 0000000..8212dda --- /dev/null +++ b/libTitanD3vUniversal/ContactPicker/TDPeople.m @@ -0,0 +1,4 @@ +#import "TDPeople.h" + +@implementation TDPeople +@end diff --git a/libTitanD3vUniversal/CustomViews/TDButton.h b/libTitanD3vUniversal/CustomViews/TDButton.h new file mode 100644 index 0000000..257cfd7 --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDButton.h @@ -0,0 +1,7 @@ +#import + +@interface TDButton : UIButton +-(instancetype)initWithTitle:(NSString *)title colour:(UIColor *)colour fontColour:(UIColor *)fontColour fontSize:(CGFloat)size corner:(CGFloat)corner; +-(instancetype)initWithImage:(UIImage *)image inset:(UIEdgeInsets)inset colour:(UIColor *)colour tint:(BOOL)tint tintColour:(UIColor *)tintColour corner:(CGFloat)corner; +@end + diff --git a/libTitanD3vUniversal/CustomViews/TDButton.m b/libTitanD3vUniversal/CustomViews/TDButton.m new file mode 100644 index 0000000..917e32c --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDButton.m @@ -0,0 +1,39 @@ +#import "TDButton.h" + +@implementation TDButton + +-(instancetype)initWithTitle:(NSString *)title colour:(UIColor *)colour fontColour:(UIColor *)fontColour fontSize:(CGFloat)size corner:(CGFloat)corner { + + self = [super init]; + if (self) { + + [self setTitle:title forState:UIControlStateNormal]; + self.backgroundColor = colour; + [self setTitleColor:fontColour forState:UIControlStateNormal]; + self.titleLabel.font = [UIFont systemFontOfSize:size]; + self.layer.cornerRadius = corner; + + } + return self; +} + + +-(instancetype)initWithImage:(UIImage *)image inset:(UIEdgeInsets)inset colour:(UIColor *)colour tint:(BOOL)tint tintColour:(UIColor *)tintColour corner:(CGFloat)corner { + + self = [super init]; + if (self) { + + if (tint) { + self.tintColor = tintColour; + } + + [self setImage:image forState:UIControlStateNormal]; + self.backgroundColor = colour; + self.layer.cornerRadius = corner; + self.imageEdgeInsets = inset; + + } + return self; +} + +@end diff --git a/libTitanD3vUniversal/CustomViews/TDHeaderView.h b/libTitanD3vUniversal/CustomViews/TDHeaderView.h new file mode 100644 index 0000000..e5fa6bf --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDHeaderView.h @@ -0,0 +1,14 @@ +#import +#import "ConstraintExtension.h" + +@interface TDHeaderView : UIView +@property (nonatomic, retain) UIView *grabberView; +@property (nonatomic, retain) UIView *headerView; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIButton *leftButton; +@property (nonatomic, retain) UIButton *rightButton; + +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction; +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction rightIcon:(NSString *)rightIconString rightAction:(SEL)rightAction; +@end + diff --git a/libTitanD3vUniversal/CustomViews/TDHeaderView.m b/libTitanD3vUniversal/CustomViews/TDHeaderView.m new file mode 100644 index 0000000..8635a04 --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDHeaderView.m @@ -0,0 +1,129 @@ +#import "TDHeaderView.h" + +@implementation TDHeaderView + + +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction { + + self = [super init]; + if (self) { + + self.clipsToBounds = YES; + + self.headerView = [[UIView alloc] init]; + [self addSubview:self.headerView]; + + [self.headerView fill]; + + + self.grabberView = [[UIView alloc] init]; + self.grabberView.backgroundColor = UIColor.tertiarySystemFillColor; + self.grabberView.layer.cornerRadius = 3; + [self.headerView addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.headerView.centerXAnchor]; + [self.grabberView top:self.headerView.topAnchor padding:10]; + + + self.leftButton = [[UIButton alloc] init]; + self.leftButton.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.leftButton.layer.cornerRadius = 12; + self.leftButton.layer.cornerCurve = kCACornerCurveContinuous; + UIImage *leftIcon = [UIImage systemImageNamed:leftIconString]; + [self.leftButton setImage:leftIcon forState:UIControlStateNormal]; + self.leftButton.tintColor = accent; + [self.leftButton addTarget:self.superview action:leftAction forControlEvents:UIControlEventTouchUpInside]; + [self.headerView addSubview:self.leftButton]; + + [self.leftButton size:CGSizeMake(40, 40)]; + [self.leftButton y:self.headerView.centerYAnchor padding:5]; + [self.leftButton leading:self.headerView.leadingAnchor padding:20]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold]; + self.titleLabel.text = title; + [self.headerView addSubview:self.titleLabel]; + + [self.titleLabel y:self.headerView.centerYAnchor padding:5]; + [self.titleLabel x:self.headerView.centerXAnchor]; + + } + + return self; +} + + +-(instancetype)initWithTitle:(NSString *)title accent:(UIColor *)accent leftIcon:(NSString *)leftIconString leftAction:(SEL)leftAction rightIcon:(NSString *)rightIconString rightAction:(SEL)rightAction { + + self = [super init]; + if (self) { + + self.clipsToBounds = YES; + + self.headerView = [[UIView alloc] init]; + [self addSubview:self.headerView]; + + [self.headerView fill]; + + + self.grabberView = [[UIView alloc] init]; + self.grabberView.backgroundColor = UIColor.tertiarySystemFillColor; + self.grabberView.layer.cornerRadius = 3; + [self.headerView addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.headerView.centerXAnchor]; + [self.grabberView top:self.headerView.topAnchor padding:10]; + + + self.leftButton = [[UIButton alloc] init]; + self.leftButton.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.leftButton.layer.cornerRadius = 12; + self.leftButton.layer.cornerCurve = kCACornerCurveContinuous; + UIImage *leftIcon = [UIImage systemImageNamed:leftIconString]; + [self.leftButton setImage:leftIcon forState:UIControlStateNormal]; + self.leftButton.tintColor = accent; + [self.leftButton addTarget:self.superview action:leftAction forControlEvents:UIControlEventTouchUpInside]; + [self.headerView addSubview:self.leftButton]; + + [self.leftButton size:CGSizeMake(40, 40)]; + [self.leftButton y:self.headerView.centerYAnchor padding:5]; + [self.leftButton leading:self.headerView.leadingAnchor padding:20]; + + + self.rightButton = [[UIButton alloc] init]; + self.rightButton.backgroundColor = UIColor.secondarySystemBackgroundColor; + self.rightButton.layer.cornerRadius = 12; + self.rightButton.layer.cornerCurve = kCACornerCurveContinuous; + UIImage *rightIcon = [UIImage systemImageNamed:rightIconString]; + [self.rightButton setImage:rightIcon forState:UIControlStateNormal]; + [self.rightButton addTarget:self.superview action:rightAction forControlEvents:UIControlEventTouchUpInside]; + self.rightButton.tintColor = accent; + [self.headerView addSubview:self.rightButton]; + + [self.rightButton size:CGSizeMake(40, 40)]; + [self.rightButton y:self.headerView.centerYAnchor padding:5]; + [self.rightButton trailing:self.headerView.trailingAnchor padding:-20]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = UIColor.labelColor; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold]; + self.titleLabel.text = title; + [self.headerView addSubview:self.titleLabel]; + + [self.titleLabel y:self.headerView.centerYAnchor padding:5]; + [self.titleLabel x:self.headerView.centerXAnchor]; + + } + + return self; +} + + +@end diff --git a/libTitanD3vUniversal/CustomViews/TDImage.h b/libTitanD3vUniversal/CustomViews/TDImage.h new file mode 100644 index 0000000..d5c5018 --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDImage.h @@ -0,0 +1,6 @@ +#import + +@interface TDImage : UIImageView +- (instancetype _Nullable )initWithImage:(nullable UIImage *)image tint:(BOOL)tint tintColour:(UIColor *_Nullable)tintColour corner:(CGFloat)corner; +@end + diff --git a/libTitanD3vUniversal/CustomViews/TDImage.m b/libTitanD3vUniversal/CustomViews/TDImage.m new file mode 100644 index 0000000..dd828c8 --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDImage.m @@ -0,0 +1,24 @@ +#import "TDImage.h" + +@implementation TDImage + +- (instancetype _Nullable )initWithImage:(nullable UIImage *)image tint:(BOOL)tint tintColour:(UIColor *_Nullable)tintColour corner:(CGFloat)corner { + + self = [super init]; + if (self) { + + if (tint) { + self.tintColor = tintColour; + } + + self.image = image; + self.layer.cornerRadius = corner; + self.userInteractionEnabled = true; + + } + return self; + + +} + +@end diff --git a/libTitanD3vUniversal/CustomViews/TDIndexBar.h b/libTitanD3vUniversal/CustomViews/TDIndexBar.h new file mode 100644 index 0000000..e08910f --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDIndexBar.h @@ -0,0 +1,31 @@ +#import + +@class TDIndexBar; +@protocol TDIndexBarDelegate +- (void)indexDidChanged:(TDIndexBar *)indexBar index:(NSInteger)index title:(NSString *)title; +@end + + +@interface TDIndexBar : UIView +@property (nonatomic, weak) id delegate; +@property (nonatomic, strong) UIColor *textColor; +@property (nonatomic, strong) UIColor *selectedTextColor; +@property (nonatomic, strong) UIColor *selectedBackgroundColor; +@property (nonatomic, strong) UIColor *detailViewDrawColor; +@property (nonatomic, strong) UIColor *detailViewTextColor; +@property (nonatomic, assign) BOOL onTouch; +@property (nonatomic, assign) BOOL hideDetailView; +@property (nonatomic, assign) CGFloat sectionHeight; +- (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_UNAVAILABLE; +- (void)setIndexes:(NSArray *)indexes; +- (void)setSelectedLabel:(NSInteger)index; +@end + + + + + + + diff --git a/libTitanD3vUniversal/CustomViews/TDIndexBar.m b/libTitanD3vUniversal/CustomViews/TDIndexBar.m new file mode 100644 index 0000000..885ad7f --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDIndexBar.m @@ -0,0 +1,246 @@ +#import "TDIndexBar.h" + + +@interface CustomView: UIView +@property (nonatomic, strong) UILabel *indexLabel; +@property (nonatomic, strong) UIColor *drawColor; +@property (nonatomic, strong) UIColor *textColor; +@end + + +@implementation CustomView + +- (instancetype)initWithFrame:(CGRect)frame { + + if (self = [super initWithFrame:frame]) { + + _drawColor = [UIColor lightGrayColor]; + _indexLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, frame.size.height, frame.size.height)]; + _indexLabel.textColor = [UIColor whiteColor]; + _indexLabel.textAlignment = NSTextAlignmentCenter; + _indexLabel.font = [UIFont boldSystemFontOfSize:18]; + [self addSubview:_indexLabel]; + + } + return self; +} + +- (void)setTextColor:(UIColor *)textColor { + + _textColor = textColor; + _indexLabel.textColor = textColor; +} + +- (void)drawRect:(CGRect)rect { + + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSetLineWidth(context, 2.0); + CGContextSetFillColorWithColor(context,_drawColor.CGColor); + [self getDrawPath:context]; + CGContextFillPath(context); +} + +- (void)getDrawPath:(CGContextRef)context { + + CGFloat width = self.bounds.size.width; + CGFloat height = self.bounds.size.height; + CGFloat xOffset = self.bounds.size.width * 1/4; + CGFloat yOffset = self.bounds.size.height * 1/4; + CGFloat radius = sqrt(pow(xOffset, 2) + pow(yOffset, 2)); + + CGContextMoveToPoint(context, width - xOffset, height * 0.5 - yOffset); + CGContextAddLineToPoint(context,width, height * 0.5); + CGContextAddLineToPoint(context,width - xOffset, height * 0.5 + yOffset); + + CGContextAddArcToPoint(context, width * 0.5, height, width * 0.5 - xOffset, height * 0.5 + yOffset, radius); + CGContextAddArcToPoint(context, 0, height * 0.5, width * 0.5 - xOffset, height * 0.5 - yOffset, radius); + CGContextAddArcToPoint(context, width * 0.5, 0, width * 0.5 + xOffset, height * 0.5 - yOffset, radius); + CGContextClosePath(context); +} + +@end + + +@interface TDIndexBar() + +@property (nonatomic, strong) UILabel *preLabel; +@property (nonatomic, assign) NSInteger preIndex; +@property (nonatomic, strong) NSMutableArray *labelArr; +@property (nonatomic, strong) CustomView *indexDetailView; +@property (nonatomic, strong) UIImpactFeedbackGenerator *gen API_AVAILABLE(ios(10.0)); + +@end + + +@implementation TDIndexBar + +- (instancetype)initWithFrame:(CGRect)frame { + + if (self = [super initWithFrame:frame]) { + [self initData]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + + if (self = [super initWithCoder:aDecoder]) { + [self initData]; + } + return self; +} + +- (UIImpactFeedbackGenerator *)gen { + if (_gen == nil) { + _gen = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; + [_gen prepare]; + } + return _gen; +} + + +- (void)initData { + _preIndex = -1; + _sectionHeight = 16; + _textColor = [UIColor colorWithRed:135/255.0 green:135/255.0 blue:135/255.0 alpha:1]; + _selectedTextColor = [UIColor whiteColor]; + _selectedBackgroundColor = [UIColor colorWithRed:54/255.0 green:129/255.0 blue:228/255.0 alpha:1]; + _detailViewDrawColor = [UIColor lightGrayColor]; + _detailViewTextColor = [UIColor whiteColor]; +} + + +- (void)setIndexes:(NSArray *)indexes { + + while (self.subviews.count) { + [self.subviews.lastObject removeFromSuperview]; + } + + [_labelArr removeAllObjects]; + _preIndex = -1; + + _indexDetailView = [[CustomView alloc] initWithFrame:CGRectMake(-80, 0, 50, 50)]; + _indexDetailView.backgroundColor = [UIColor clearColor]; + _indexDetailView.drawColor = _detailViewDrawColor; + _indexDetailView.textColor = _detailViewTextColor; + _indexDetailView.alpha = 0; + [self addSubview:_indexDetailView]; + + + CGRect rect = self.frame; + rect.size.height = indexes.count * _sectionHeight;; + rect.origin.y = (self.superview.bounds.size.height - rect.size.height) * 0.5; + [self setFrame:rect]; + + + CGFloat width = _sectionHeight; + CGFloat height = _sectionHeight; + CGFloat x = (self.bounds.size.width - width) * 0.5; + + _labelArr = [NSMutableArray new]; + for (int i = 0; i < indexes.count; i++) { + CGFloat y = (_sectionHeight * i); + + UILabel *alphaLabel = [[UILabel alloc] initWithFrame:CGRectMake(x, y, width, height)]; + alphaLabel.textAlignment = NSTextAlignmentCenter; + alphaLabel.text = [[indexes objectAtIndex:i] uppercaseString]; + alphaLabel.font = [UIFont boldSystemFontOfSize:10.0]; + alphaLabel.backgroundColor = [UIColor clearColor]; + alphaLabel.textColor = self.textColor; + alphaLabel.layer.cornerRadius = width * 0.5; + alphaLabel.clipsToBounds = YES; + [self addSubview:alphaLabel]; + [_labelArr addObject:alphaLabel]; + } + + + if (indexes.count > 0) { + [self setSelectedLabel:0]; + } +} + +- (void)setSelectedLabel:(NSInteger)index { + + _preLabel.backgroundColor = [UIColor clearColor]; + _preLabel.textColor = _textColor; + UILabel *label = _labelArr[index]; + label.textColor = _selectedTextColor; + label.backgroundColor = _selectedBackgroundColor; + _preLabel = label; +} + +- (void)toSelectTitle:(CGPoint)touchPoint { + + if(touchPoint.y <= 0 || touchPoint.y >= self.bounds.size.height) return; + + __block NSString *title; + __block NSInteger index = 0; + + [_labelArr enumerateObjectsUsingBlock:^(__kindof UILabel * _Nonnull subview, NSUInteger idx, BOOL * _Nonnull stop) { + if(touchPoint.y < CGRectGetMaxY(subview.frame)) { + _preLabel.backgroundColor = [UIColor clearColor]; + _preLabel.textColor = _textColor; + subview.backgroundColor = _selectedBackgroundColor; + subview.textColor = _selectedTextColor; + _preLabel = subview; + index = idx; + title = subview.text; + *stop = YES; + } + }]; + + if (_preIndex == index) return; + + _preIndex = index; + _indexDetailView.center = CGPointMake(_indexDetailView.center.x, _sectionHeight * 0.5 + index * _sectionHeight); + _indexDetailView.indexLabel.text = title; + + + if (@available(iOS 10.0, *)) { + [self.gen impactOccurred]; + } + + if (_delegate && [_delegate conformsToProtocol:@protocol(TDIndexBarDelegate)]) { + [_delegate indexDidChanged:self index:index title:title]; + } +} + + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + + [super touchesEnded:touches withEvent:event]; + + _onTouch = NO; + [UIView animateWithDuration:.3 animations:^{ + self.indexDetailView.alpha = 0; + }]; +} + + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + + [super touchesBegan:touches withEvent:event]; + + _onTouch = YES; + if (!_hideDetailView) { + _indexDetailView.alpha = 1; + } + CGPoint touchPoint = [[[event touchesForView:self] anyObject] locationInView:self]; + [self toSelectTitle:touchPoint]; +} + + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + + [super touchesMoved:touches withEvent:event]; + + CGPoint touchPoint = [[[event touchesForView:self] anyObject] locationInView:self]; + [self toSelectTitle:touchPoint]; +} + + +@end + + + + diff --git a/libTitanD3vUniversal/CustomViews/TDLabel.h.txt b/libTitanD3vUniversal/CustomViews/TDLabel.h.txt new file mode 100644 index 0000000..6c8ef36 --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDLabel.h.txt @@ -0,0 +1,11 @@ +// #import + +// typedef enum TextAlignment : NSUInteger { +// Left, +// Center, +// Right +// } TextAlignment; + +// @interface TDLabel : UILabel +// -(instancetype)initWithText:(NSString *)text colour:(UIColor *)colour alignment:(TextAlignment)alignment size:(CGFloat)size bold:(BOOL)bold; +// @end diff --git a/libTitanD3vUniversal/CustomViews/TDLabel.m.txt b/libTitanD3vUniversal/CustomViews/TDLabel.m.txt new file mode 100644 index 0000000..1d3cf72 --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDLabel.m.txt @@ -0,0 +1,30 @@ +// #import "TDLabel.h" + +// @implementation TDLabel + +// -(instancetype)initWithText:(NSString *)text colour:(UIColor *)colour alignment:(TextAlignment)alignment size:(CGFloat)size bold:(BOOL)bold { +// self = [super init]; + +// if (self) { +// self.text = text; +// self.textColor = colour; + +// if(alignment == Left) { +// self.textAlignment = NSTextAlignmentLeft; +// } else if (alignment == Center) { +// self.textAlignment = NSTextAlignmentCenter; +// } else if (alignment == Right) { +// self.textAlignment = NSTextAlignmentRight; +// } + +// if (bold) { +// self.font = [UIFont boldSystemFontOfSize:size]; +// } else { +// self.font = [UIFont systemFontOfSize:size]; +// } +// } + +// return self; +// } + +// @end diff --git a/libTitanD3vUniversal/CustomViews/TDView.h b/libTitanD3vUniversal/CustomViews/TDView.h new file mode 100644 index 0000000..b2974b4 --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDView.h @@ -0,0 +1,6 @@ +#import + +@interface TDView : UIView +-(instancetype)initWithColour:(UIColor *)colour corner:(CGFloat)corner curve:(BOOL)curve clip:(BOOL)clip; +@end + diff --git a/libTitanD3vUniversal/CustomViews/TDView.m b/libTitanD3vUniversal/CustomViews/TDView.m new file mode 100644 index 0000000..9cf8bb3 --- /dev/null +++ b/libTitanD3vUniversal/CustomViews/TDView.m @@ -0,0 +1,26 @@ +#import "TDView.h" + +@implementation TDView + +-(instancetype)initWithColour:(UIColor *)colour corner:(CGFloat)corner curve:(BOOL)curve clip:(BOOL)clip { + + self = [super init]; + if (self) { + + self.backgroundColor = colour; + self.layer.cornerRadius = corner; + if (curve) { + if (@available(iOS 13.0, *)) { + self.layer.cornerCurve = kCACornerCurveContinuous; + } + } + + if (clip) { + self.clipsToBounds = true; + } + + } + return self; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/.DS_Store b/libTitanD3vUniversal/Drawer/.DS_Store new file mode 100644 index 0000000..194ead1 Binary files /dev/null and b/libTitanD3vUniversal/Drawer/.DS_Store differ diff --git a/libTitanD3vUniversal/Drawer/Cells/CategoriesCell.h b/libTitanD3vUniversal/Drawer/Cells/CategoriesCell.h new file mode 100644 index 0000000..afa6b80 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/CategoriesCell.h @@ -0,0 +1,14 @@ +#import +#import "ConstraintExtension.h" + +@interface CategoriesCell : UICollectionViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *selectedView; +@property (nonatomic, retain) UIView *iconView; +@property (nonatomic, retain) UIView *gradientView; +@property (nonatomic, retain) CAGradientLayer *gradient; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; + +@end \ No newline at end of file diff --git a/libTitanD3vUniversal/Drawer/Cells/CategoriesCell.m b/libTitanD3vUniversal/Drawer/Cells/CategoriesCell.m new file mode 100644 index 0000000..0f98658 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/CategoriesCell.m @@ -0,0 +1,79 @@ +#import "CategoriesCell.h" + +@implementation CategoriesCell + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + UIColor *primraryColour = [UIColor colorWithRed: 0.07 green: 0.09 blue: 0.11 alpha: 1.00]; + UIColor *secondaryColour = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.11 alpha: 1.00]; + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = UIColor.clearColor; + self.baseView.clipsToBounds = true; + [self.contentView addSubview:self.baseView]; + + [self.baseView fill]; + + + self.selectedView = [[UIView alloc] init]; + self.selectedView.backgroundColor = [UIColor colorWithRed: 0.95 green: 0.27 blue: 0.17 alpha: 1.00]; + self.selectedView.layer.cornerRadius = 3; + self.selectedView.layer.maskedCorners = 3; + self.selectedView.clipsToBounds = true; + [self.baseView addSubview:self.selectedView]; + + [self.selectedView size:CGSizeMake(55, 5)]; + [self.selectedView x:self.baseView.centerXAnchor]; + [self.selectedView bottom:self.baseView.bottomAnchor padding:0]; + + + self.iconView = [[UIView alloc] init]; + self.iconView.backgroundColor = UIColor.clearColor; + self.iconView.layer.cornerRadius = 15; + self.iconView.layer.cornerCurve = kCACornerCurveContinuous; + self.iconView.clipsToBounds = true; + [self.baseView addSubview:self.iconView]; + + [self.iconView size:CGSizeMake(55, 55)]; + [self.iconView x:self.baseView.centerXAnchor]; + [self.iconView top:self.baseView.topAnchor padding:0]; + + + self.gradientView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 55, 55)]; + self.gradientView.backgroundColor = UIColor.clearColor; + [self.iconView addSubview:self.gradientView]; + + + self.gradient = [CAGradientLayer layer]; + self.gradient.frame = self.gradientView.bounds; + self.gradient.colors = @[(id)primraryColour.CGColor, (id)secondaryColour.CGColor]; + [self.gradientView.layer insertSublayer:self.gradient atIndex:0]; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.contentMode = UIViewContentModeScaleAspectFit; + [self.iconView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(40, 40)]; + [self.iconImage x:self.iconView.centerXAnchor y:self.iconView.centerYAnchor]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.font = [UIFont systemFontOfSize:10 weight:UIFontWeightSemibold]; + [self.baseView addSubview:self.titleLabel]; + + [self.titleLabel top:self.iconView.bottomAnchor padding:0]; + [self.titleLabel x:self.iconView.centerXAnchor]; + + + } + return self; +} + + +@end diff --git a/libTitanD3vUniversal/Drawer/Cells/ChangelogCell.h b/libTitanD3vUniversal/Drawer/Cells/ChangelogCell.h new file mode 100644 index 0000000..13c0f2b --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/ChangelogCell.h @@ -0,0 +1,16 @@ +#import +#import "ConstraintExtension.h" + +@interface ChangelogCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UIView *categoriesView; +@property (nonatomic, retain) UILabel *categoriesLabel; +@property (nonatomic, retain) UIView *versionView; +@property (nonatomic, retain) UILabel *versionLabel; +@property (nonatomic, retain) UIView *splitView; +@property (nonatomic, retain) UITextView *messageLabel; + +@end + diff --git a/libTitanD3vUniversal/Drawer/Cells/ChangelogCell.m b/libTitanD3vUniversal/Drawer/Cells/ChangelogCell.m new file mode 100644 index 0000000..4ab49be --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/ChangelogCell.m @@ -0,0 +1,117 @@ +#import "ChangelogCell.h" + +@implementation ChangelogCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.contentView.layer.cornerRadius = 30; + self.contentView.layer.cornerCurve = kCACornerCurveContinuous; + self.contentView.clipsToBounds = true; + + + self.baseView = [[UIView alloc] initWithFrame:CGRectZero]; + self.baseView.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.baseView.layer.cornerRadius = 30; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + self.baseView.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + self.baseView.layer.borderWidth = 0.5; + [self.contentView addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:10].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-10].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-5].active = YES; + + + self.iconImage = [[UIImageView alloc] initWithFrame:CGRectZero]; + self.iconImage.layer.cornerRadius = 27.5; + self.iconImage.clipsToBounds = true; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(55, 55)]; + [self.iconImage top:self.baseView.topAnchor padding:15]; + [self.iconImage leading:self.baseView.leadingAnchor padding:15]; + + + self.categoriesView = [[UIView alloc] init]; + self.categoriesView.backgroundColor = [UIColor colorWithRed: 0.94 green: 0.27 blue: 0.18 alpha: 0.5]; + self.categoriesView.layer.cornerRadius = 5; + self.categoriesView.layer.cornerCurve = kCACornerCurveContinuous; + [self.baseView addSubview:self.categoriesView]; + + [self.categoriesView height:25]; + [self.categoriesView width:100]; + [self.categoriesView top:self.iconImage.topAnchor padding:0]; + [self.categoriesView leading:self.iconImage.trailingAnchor padding:10]; + + + self.categoriesLabel = [[UILabel alloc] init]; + self.categoriesLabel.font = [UIFont boldSystemFontOfSize:14]; + self.categoriesLabel.textColor = UIColor.whiteColor; + [self.categoriesView addSubview:self.categoriesLabel]; + + [self.categoriesLabel x:self.categoriesView.centerXAnchor y:self.categoriesView.centerYAnchor]; + + + self.versionView = [[UIView alloc] init]; + self.versionView.backgroundColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 1.0]; + self.versionView.layer.cornerRadius = 5; + self.versionView.layer.cornerCurve = kCACornerCurveContinuous; + [self.baseView addSubview:self.versionView]; + + [self.versionView height:20]; + [self.versionView width:70]; + [self.versionView bottom:self.iconImage.bottomAnchor padding:0]; + [self.versionView leading:self.iconImage.trailingAnchor padding:10]; + + + self.versionLabel = [[UILabel alloc] init]; + self.versionLabel.text = @"v1.1"; + self.versionLabel.font = [UIFont systemFontOfSize:12]; + self.versionLabel.textColor = UIColor.whiteColor; + [self.versionView addSubview:self.versionLabel]; + + [self.versionLabel x:self.versionView.centerXAnchor y:self.versionView.centerYAnchor]; + + + self.splitView = [[UIView alloc] init]; + self.splitView.backgroundColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5]; + self.splitView.layer.cornerRadius = 1; + [self.baseView addSubview:self.splitView]; + + [self.splitView height:2]; + [self.splitView x:self.baseView.centerXAnchor]; + [self.splitView top:self.iconImage.bottomAnchor padding:15]; + [self.splitView leading:self.baseView.leadingAnchor padding:20]; + [self.splitView trailing:self.baseView.trailingAnchor padding:-20]; + + + self.messageLabel = [[UITextView alloc] init]; + self.messageLabel.font = [UIFont systemFontOfSize:18]; + self.messageLabel.textAlignment = NSTextAlignmentLeft; + self.messageLabel.delegate = self; + self.messageLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.8]; + self.messageLabel.scrollEnabled = NO; + self.messageLabel.editable = NO; + self.messageLabel.backgroundColor = UIColor.clearColor; + self.messageLabel.userInteractionEnabled = NO; + [self.baseView addSubview:self.messageLabel]; + + [self.messageLabel top:self.splitView.bottomAnchor padding:5];; + [self.messageLabel leading:self.baseView.leadingAnchor padding:15]; + [self.messageLabel trailing:self.baseView.trailingAnchor padding:-15]; + [self.messageLabel bottom:self.baseView.bottomAnchor padding:-10]; + + + } + + return self; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Cells/CrewCell.h b/libTitanD3vUniversal/Drawer/Cells/CrewCell.h new file mode 100644 index 0000000..3d09f2c --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/CrewCell.h @@ -0,0 +1,15 @@ +#import +#import +#import "TDAppearance.h" + +@interface CrewCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *bannerImage; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UILabel *roleLabel; +@property (nonatomic, retain) UILabel *followLabel; +@property (nonatomic, retain) UIColor *tintColour; +@end + diff --git a/libTitanD3vUniversal/Drawer/Cells/CrewCell.m b/libTitanD3vUniversal/Drawer/Cells/CrewCell.m new file mode 100644 index 0000000..252f1d7 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/CrewCell.m @@ -0,0 +1,108 @@ +#import "CrewCell.h" + +@implementation CrewCell + + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + + self.baseView = [[UIView alloc] initWithFrame:CGRectZero]; + self.baseView.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.baseView.layer.cornerRadius = 20; + if(@available(iOS 13.0, *)) { + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.baseView.clipsToBounds = true; + self.baseView.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + self.baseView.layer.borderWidth = 0.5; + [self.contentView addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:10].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-10].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-5].active = YES; + + + self.bannerImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 120)]; + [self.bannerImage setContentMode:UIViewContentModeScaleToFill]; + [self.baseView addSubview:self.bannerImage]; + + + self.iconImage = [[UIImageView alloc] initWithFrame:CGRectZero]; + self.iconImage.layer.cornerRadius = 50; + self.iconImage.clipsToBounds = true; + self.iconImage.layer.borderWidth = 1; + self.iconImage.layer.borderColor = self.tintColour.CGColor; + [self.baseView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:100.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:100.0].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + [self.iconImage.topAnchor constraintEqualToAnchor:self.bannerImage.bottomAnchor constant:-70].active = YES; + + + self.nameLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.nameLabel.textColor = UIColor.whiteColor; + self.nameLabel.font = [UIFont boldSystemFontOfSize:20]; + self.nameLabel.textAlignment = NSTextAlignmentCenter; + [self.baseView addSubview:self.nameLabel]; + + self.nameLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.nameLabel centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + [self.nameLabel.topAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant:20.0].active = YES; + + + self.roleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.roleLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.7]; + self.roleLabel.font = [UIFont systemFontOfSize:16]; + self.roleLabel.textAlignment = NSTextAlignmentCenter; + [self.baseView addSubview:self.roleLabel]; + + self.roleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.roleLabel centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + [self.roleLabel.topAnchor constraintEqualToAnchor:self.nameLabel.bottomAnchor constant:10.0].active = YES; + + + self.followLabel = [[UILabel alloc] init]; + self.followLabel.backgroundColor = self.tintColour; + self.followLabel.text = @"Follow"; + self.followLabel.layer.cornerRadius = 22.5; + self.followLabel.font = [UIFont systemFontOfSize:18]; + self.followLabel.textAlignment = NSTextAlignmentCenter; + self.followLabel.clipsToBounds = true; + self.followLabel.textColor = UIColor.whiteColor; + [self.baseView addSubview:self.followLabel]; + + self.followLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.followLabel.widthAnchor constraintEqualToConstant:100].active = YES; + [self.followLabel.heightAnchor constraintEqualToConstant:45].active = YES; + [[self.followLabel centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + [self.followLabel.topAnchor constraintEqualToAnchor:self.roleLabel.bottomAnchor constant:10].active = YES; + + + } + + return self; +} + + +-(void)layoutSubviews { + + CALayer *mask = [CALayer layer]; + mask.contents = (id)[[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/crew-mask.png"] CGImage]; + mask.frame = CGRectMake(0, 0, self.frame.size.width, 120); + self.bannerImage.layer.mask = mask; + self.bannerImage.layer.masksToBounds = YES; + + self.bannerImage.frame = CGRectMake(0, 0, self.frame.size.width, 120); +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Cells/DrawerCell.h b/libTitanD3vUniversal/Drawer/Cells/DrawerCell.h new file mode 100644 index 0000000..63f64e2 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/DrawerCell.h @@ -0,0 +1,11 @@ +#import + +@interface DrawerCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; + +@end + diff --git a/libTitanD3vUniversal/Drawer/Cells/DrawerCell.m b/libTitanD3vUniversal/Drawer/Cells/DrawerCell.m new file mode 100644 index 0000000..91db7d8 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/DrawerCell.m @@ -0,0 +1,70 @@ +#import "DrawerCell.h" + +@implementation DrawerCell + + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + + self.baseView = [[UIView alloc] initWithFrame:CGRectZero]; + self.baseView.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.baseView.layer.cornerRadius = 10; + if(@available(iOS 13.0, *)) { + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.baseView.clipsToBounds = true; + self.baseView.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + self.baseView.layer.borderWidth = 0.5; + [self addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:10].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-10].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5].active = YES; + + + self.iconImage = [[UIImageView alloc] initWithFrame:CGRectZero]; + self.iconImage.layer.cornerRadius = 22.5; + self.iconImage.clipsToBounds = true; + [self.baseView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:45.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:45.0].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10.0].active = YES; + + + self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.titleLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.titleLabel.font = [UIFont boldSystemFontOfSize:16]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.titleLabel.topAnchor constraintEqualToAnchor:self.baseView.topAnchor constant:10.0].active = YES; + [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:10.0].active = YES; + + + self.subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.subtitleLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.subtitleLabel.font = [UIFont systemFontOfSize:13]; + self.subtitleLabel.textAlignment = NSTextAlignmentLeft; + self.subtitleLabel.numberOfLines = 1; + [self.baseView addSubview:self.subtitleLabel]; + + self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.subtitleLabel.bottomAnchor constraintEqualToAnchor:self.baseView.bottomAnchor constant:-10.0].active = YES; + [self.subtitleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:10.0].active = YES; + [self.subtitleLabel.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + } + + return self; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Cells/ProfileCell.h b/libTitanD3vUniversal/Drawer/Cells/ProfileCell.h new file mode 100644 index 0000000..2141b45 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/ProfileCell.h @@ -0,0 +1,11 @@ +#import + +@interface ProfileCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UITextField *textField; + +@end + diff --git a/libTitanD3vUniversal/Drawer/Cells/ProfileCell.m b/libTitanD3vUniversal/Drawer/Cells/ProfileCell.m new file mode 100644 index 0000000..6556a51 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/ProfileCell.m @@ -0,0 +1,76 @@ +#import "ProfileCell.h" + +@implementation ProfileCell + + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + + self.baseView = [[UIView alloc] initWithFrame:CGRectZero]; + self.baseView.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.baseView.layer.cornerRadius = 10; + if(@available(iOS 13.0, *)) { + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.baseView.clipsToBounds = true; + self.baseView.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + self.baseView.layer.borderWidth = 0.5; + [self.contentView addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:10].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-10].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-5].active = YES; + + + self.iconImage = [[UIImageView alloc] initWithFrame:CGRectZero]; + self.iconImage.layer.cornerRadius = 22.5; + self.iconImage.clipsToBounds = true; + [self.baseView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:45].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:45].active = YES; + [[self.iconImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.iconImage.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10.0].active = YES; + + + self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + self.titleLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.7]; + self.titleLabel.font = [UIFont boldSystemFontOfSize:14]; + self.titleLabel.textAlignment = NSTextAlignmentLeft; + [self.baseView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.titleLabel.widthAnchor constraintEqualToConstant:170.0].active = YES; + [[self.titleLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = true; + [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:10.0].active = YES; + + + self.textField = [[UITextField alloc] init]; + self.textField.font = [UIFont systemFontOfSize:15]; + self.textField.returnKeyType = UIReturnKeyDone; + self.textField.autocorrectionType = UITextAutocorrectionTypeNo; + self.textField.clearButtonMode = UITextFieldViewModeWhileEditing; + self.textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; + self.textField.delegate = self; + self.textField.backgroundColor = UIColor.clearColor; + self.textField.textColor = UIColor.whiteColor; + [self.baseView addSubview:self.textField]; + + self.textField.translatesAutoresizingMaskIntoConstraints = NO; + [self.textField.leadingAnchor constraintEqualToAnchor:self.titleLabel.trailingAnchor constant:10].active = YES; + [self.textField.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-10].active = YES; + [self.textField.topAnchor constraintEqualToAnchor:self.baseView.topAnchor constant:10].active = YES; + [self.textField.bottomAnchor constraintEqualToAnchor:self.baseView.bottomAnchor constant:-10].active = YES; + } + + return self; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Cells/ThemeCell.h b/libTitanD3vUniversal/Drawer/Cells/ThemeCell.h new file mode 100644 index 0000000..a9816d5 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/ThemeCell.h @@ -0,0 +1,10 @@ +#import + +@interface ThemeCell : UICollectionViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *colourView; +@property (nonatomic, retain) UIImageView *colourImage; +@property (nonatomic, retain) UILabel *titleLabel; + +@end diff --git a/libTitanD3vUniversal/Drawer/Cells/ThemeCell.m b/libTitanD3vUniversal/Drawer/Cells/ThemeCell.m new file mode 100644 index 0000000..1e54b12 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/ThemeCell.m @@ -0,0 +1,68 @@ +#import "ThemeCell.h" + +@implementation ThemeCell + + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor colorWithRed: 0.20 green: 0.20 blue: 0.20 alpha: 0.5]; + self.baseView.clipsToBounds = YES; + self.baseView.layer.cornerRadius = 15; + if(@available(iOS 13.0, *)) { + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + } + [self.contentView addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor].active = YES; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor].active = YES; + + + self.colourImage = [[UIImageView alloc] init]; + self.colourImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/colour-wheel.png"]; + self.colourImage.layer.cornerRadius = 30; + self.colourImage.clipsToBounds = true; + [self.baseView addSubview:self.colourImage]; + + self.colourImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.colourImage.widthAnchor constraintEqualToConstant:60.0].active = YES; + [self.colourImage.heightAnchor constraintEqualToConstant:60.0].active = YES; + [[self.colourImage centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor constant:-10].active = YES; + [[self.colourImage centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = YES; + + + self.colourView = [[UIView alloc] init]; + self.colourView.layer.cornerRadius = 27.5; + self.colourView.clipsToBounds = true; + [self.baseView addSubview:self.colourView]; + + self.colourView.translatesAutoresizingMaskIntoConstraints = NO; + [self.colourView.widthAnchor constraintEqualToConstant:55.0].active = YES; + [self.colourView.heightAnchor constraintEqualToConstant:55.0].active = YES; + [[self.colourView centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor constant:-10].active = YES; + [[self.colourView centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = YES; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.font = [UIFont systemFontOfSize:10]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.7]; + [self.baseView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.titleLabel centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = YES; + [self.titleLabel.topAnchor constraintEqualToAnchor:self.colourImage.bottomAnchor constant:10].active = YES; + + + } + return self; +} + + +@end diff --git a/libTitanD3vUniversal/Drawer/Cells/TweakCell.h b/libTitanD3vUniversal/Drawer/Cells/TweakCell.h new file mode 100644 index 0000000..aa99061 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/TweakCell.h @@ -0,0 +1,18 @@ +#import +#import "ConstraintExtension.h" + +@interface TweakCell : UITableViewCell + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UIView *nameView; +@property (nonatomic, retain) UILabel *nameLabel; +@property (nonatomic, retain) UIView *priceView; +@property (nonatomic, retain) UILabel *priceLabel; +@property (nonatomic, retain) UIView *versionView; +@property (nonatomic, retain) UILabel *versionLabel; +@property (nonatomic, retain) UIView *splitView; +@property (nonatomic, retain) UITextView *descriptionLabel; + +@end + diff --git a/libTitanD3vUniversal/Drawer/Cells/TweakCell.m b/libTitanD3vUniversal/Drawer/Cells/TweakCell.m new file mode 100644 index 0000000..db0d920 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Cells/TweakCell.m @@ -0,0 +1,136 @@ +#import "TweakCell.h" + +@implementation TweakCell + +-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self) { + + self.contentView.layer.cornerRadius = 30; + self.contentView.layer.cornerCurve = kCACornerCurveContinuous; + self.contentView.clipsToBounds = true; + + + self.baseView = [[UIView alloc] initWithFrame:CGRectZero]; + self.baseView.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.baseView.layer.cornerRadius = 30; + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + self.baseView.clipsToBounds = true; + self.baseView.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + self.baseView.layer.borderWidth = 0.5; + [self.contentView addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:10].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-10].active = YES; + [self.baseView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:5].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-5].active = YES; + + + self.iconImage = [[UIImageView alloc] initWithFrame:CGRectZero]; + self.iconImage.layer.cornerRadius = 15; + self.iconImage.layer.cornerCurve = kCACornerCurveContinuous; + self.iconImage.clipsToBounds = true; + [self.baseView addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(55, 55)]; + [self.iconImage top:self.baseView.topAnchor padding:15]; + [self.iconImage leading:self.baseView.leadingAnchor padding:15]; + + + self.nameView = [[UIView alloc] init]; + self.nameView.backgroundColor = UIColor.clearColor; + [self.baseView addSubview:self.nameView]; + + [self.nameView height:25]; + [self.nameView top:self.iconImage.topAnchor padding:0]; + [self.nameView leading:self.iconImage.trailingAnchor padding:10]; + [self.nameView trailing:self.baseView.trailingAnchor padding:-10]; + + + self.nameLabel = [[UILabel alloc] init]; + self.nameLabel.font = [UIFont boldSystemFontOfSize:16]; + self.nameLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.8]; + [self.nameView addSubview:self.nameLabel]; + + [self.nameLabel y:self.nameView.centerYAnchor]; + [self.nameLabel leading:self.nameView.leadingAnchor padding:0]; + + + self.priceView = [[UIView alloc] init]; + self.priceView.backgroundColor = [UIColor colorWithRed: 0.94 green: 0.27 blue: 0.18 alpha: 0.5]; + self.priceView.layer.cornerRadius = 5; + self.priceView.layer.cornerCurve = kCACornerCurveContinuous; + [self.baseView addSubview:self.priceView]; + + [self.priceView height:20]; + [self.priceView width:70]; + [self.priceView bottom:self.iconImage.bottomAnchor padding:0]; + [self.priceView leading:self.iconImage.trailingAnchor padding:10]; + + + self.priceLabel = [[UILabel alloc] init]; + self.priceLabel.font = [UIFont systemFontOfSize:12]; + self.priceLabel.textColor = UIColor.whiteColor; + [self.priceView addSubview:self.priceLabel]; + + [self.priceLabel x:self.priceView.centerXAnchor y:self.priceView.centerYAnchor]; + + + self.versionView = [[UIView alloc] init]; + self.versionView.backgroundColor = [UIColor colorWithRed: 0.94 green: 0.27 blue: 0.18 alpha: 0.5]; + self.versionView.layer.cornerRadius = 5; + self.versionView.layer.cornerCurve = kCACornerCurveContinuous; + [self.baseView addSubview:self.versionView]; + + [self.versionView height:20]; + [self.versionView width:70]; + [self.versionView y:self.priceView.centerYAnchor]; + [self.versionView leading:self.priceView.trailingAnchor padding:10]; + + + self.versionLabel = [[UILabel alloc] init]; + self.versionLabel.font = [UIFont systemFontOfSize:12]; + self.versionLabel.textColor = UIColor.whiteColor; + [self.versionView addSubview:self.versionLabel]; + + [self.versionLabel x:self.versionView.centerXAnchor y:self.versionView.centerYAnchor]; + + + self.splitView = [[UIView alloc] init]; + self.splitView.backgroundColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5]; + self.splitView.layer.cornerRadius = 1; + [self.baseView addSubview:self.splitView]; + + [self.splitView height:2]; + [self.splitView x:self.baseView.centerXAnchor]; + [self.splitView top:self.iconImage.bottomAnchor padding:15]; + [self.splitView leading:self.baseView.leadingAnchor padding:20]; + [self.splitView trailing:self.baseView.trailingAnchor padding:-20]; + + + self.descriptionLabel = [[UITextView alloc] init]; + self.descriptionLabel.font = [UIFont systemFontOfSize:18]; + self.descriptionLabel.textAlignment = NSTextAlignmentLeft; + self.descriptionLabel.delegate = self; + self.descriptionLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.8]; + self.descriptionLabel.scrollEnabled = NO; + self.descriptionLabel.editable = NO; + self.descriptionLabel.backgroundColor = UIColor.clearColor; + self.descriptionLabel.userInteractionEnabled = NO; + [self.baseView addSubview:self.descriptionLabel]; + + [self.descriptionLabel top:self.splitView.bottomAnchor padding:5];; + [self.descriptionLabel leading:self.baseView.leadingAnchor padding:15]; + [self.descriptionLabel trailing:self.baseView.trailingAnchor padding:-15]; + [self.descriptionLabel bottom:self.baseView.bottomAnchor padding:-10]; + + + } + + return self; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/BackupViewController.h b/libTitanD3vUniversal/Drawer/Controllers/BackupViewController.h new file mode 100644 index 0000000..1e29176 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/BackupViewController.h @@ -0,0 +1,20 @@ +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "TDUtilities.h" + +@interface BackupViewController : UIViewController +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) UIView *bannerView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIView *backupView; +@property (nonatomic, retain) UIImageView *backupImage; +@property (nonatomic, retain) UILabel *backupLabel; +@property (nonatomic, retain) UIView *resetView; +@property (nonatomic, retain) UIImageView *resetImage; +@property (nonatomic, retain) UILabel *resetLabel; +@property (nonatomic, retain) UIColor *tintColour; + +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/BackupViewController.m b/libTitanD3vUniversal/Drawer/Controllers/BackupViewController.m new file mode 100644 index 0000000..4b01c14 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/BackupViewController.m @@ -0,0 +1,453 @@ +#import "BackupViewController.h" +#import "DrawerCell.h" +#import "comman.m" + +NSString *TweakName; +NSMutableDictionary *backupDict; + +NSString *backupPathPlist = @"/var/mobile/Library/Preferences/com.TitanD3v.LibMainBackup.plist"; +NSString *prefsPathTobackup; + +__attribute__((unused)) static NSMutableString *outputForShellCommand(NSString *cmd); + +@implementation BackupViewController + +-(void)viewDidLoad { + [super viewDidLoad]; + + NSString *tweakNameString = [[TDPrefsManager sharedInstance] getTweakName]; + NSString *bundleIDString = [[TDPrefsManager sharedInstance] getBundleID]; + NSString *prefsPathString = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIDString]; + + TweakName = tweakNameString; + prefsPathTobackup = prefsPathString; + backupDict = [NSMutableDictionary dictionaryWithContentsOfFile:backupPathPlist][TweakName]; + NSLog(@"zzzzzzzzzzzzzzzzzzz TweakName:-%@ backupDict:-%@", TweakName, backupDict); + outputForShellCommand([NSString stringWithFormat:@"/bin/mkdir /Library/TitanD3v-Backup/%@", TweakName]); + + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.view.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + self.view.layer.maskedCorners = 12; + self.view.layer.cornerRadius = 30; + self.view.layer.cornerCurve = kCACornerCurveContinuous; + self.view.clipsToBounds = true; + + [self layoutBanner]; + [self layoutTableView]; + + backupDict = [NSMutableDictionary dictionaryWithContentsOfFile:backupPathPlist][TweakName]; +} + + +-(void)layoutBanner { + + self.bannerView = [[UIView alloc] init]; + self.bannerView.clipsToBounds = true; + [self.view addSubview:self.bannerView]; + + self.bannerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.bannerView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.bannerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.bannerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.bannerView.heightAnchor constraintEqualToConstant:140].active = YES; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/backup-restore.png"]; + self.iconImage.layer.cornerRadius = 15; + self.iconImage.clipsToBounds = true; + [self.bannerView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.heightAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.widthAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:self.bannerView.topAnchor constant:10].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.text = @"Backup & Restore"; + [self.bannerView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.titleLabel.topAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant:10].active = YES; + [[self.titleLabel centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + +} + + +-(NSString *)dateAndTime{ + NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"HH:mm:ss dd-MM-yyyy"]; + return [dateFormatter stringFromDate:[NSDate date]]; +} + + +-(void)layoutTableView { + + self.tableView = [[UITableView alloc] init]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + self.tableView.translatesAutoresizingMaskIntoConstraints = NO; + [self.tableView.topAnchor constraintEqualToAnchor:self.bannerView.bottomAnchor constant:5].active = YES; + [self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; + + + UIView *header = [[UIView alloc] init]; + header.frame = CGRectMake(0, 0, self.tableView.bounds.size.width, 110); + header.backgroundColor = UIColor.clearColor; + self.tableView.tableHeaderView = header; + + + self.backupView = [[UIView alloc] init]; + self.backupView.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.backupView.layer.cornerRadius = 10; + if(@available(iOS 13.0, *)) { + self.backupView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.backupView.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + self.backupView.layer.borderWidth = 0.5; + self.backupView.clipsToBounds = true; + [header addSubview:self.backupView]; + + self.backupView.translatesAutoresizingMaskIntoConstraints = NO; + [self.backupView.heightAnchor constraintEqualToConstant:80].active = YES; + [self.backupView.widthAnchor constraintEqualToConstant:130].active = YES; + [[self.backupView centerXAnchor] constraintEqualToAnchor:header.centerXAnchor constant:-75].active = true; + [[self.backupView centerYAnchor] constraintEqualToAnchor:header.centerYAnchor].active = true; + + + self.backupImage = [[UIImageView alloc] init]; + self.backupImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/backup-restore.png"]; + self.backupImage.layer.cornerRadius = 20; + self.backupImage.clipsToBounds = true; + [self.backupView addSubview:self.backupImage]; + + self.backupImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.backupImage.heightAnchor constraintEqualToConstant:40].active = YES; + [self.backupImage.widthAnchor constraintEqualToConstant:40].active = YES; + [[self.backupImage centerXAnchor] constraintEqualToAnchor:self.backupView.centerXAnchor].active = true; + [self.backupImage.topAnchor constraintEqualToAnchor:self.backupView.topAnchor constant:10].active = YES; + + + self.backupLabel = [[UILabel alloc] init]; + self.backupLabel.textAlignment = NSTextAlignmentCenter; + self.backupLabel.font = [UIFont systemFontOfSize:12]; + self.backupLabel.text = @"Create new backup"; + self.backupLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.7]; + [self.backupView addSubview:self.backupLabel]; + + self.backupLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.backupLabel centerXAnchor] constraintEqualToAnchor:self.backupView.centerXAnchor].active = true; + [self.backupLabel.topAnchor constraintEqualToAnchor:self.backupImage.bottomAnchor constant:10].active = YES; + + + self.resetView = [[UIView alloc] init]; + self.resetView.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.resetView.layer.cornerRadius = 10; + if(@available(iOS 13.0, *)) { + self.resetView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.resetView.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + self.resetView.layer.borderWidth = 0.5; + self.resetView.clipsToBounds = true; + [header addSubview:self.resetView]; + + self.resetView.translatesAutoresizingMaskIntoConstraints = NO; + [self.resetView.heightAnchor constraintEqualToConstant:80].active = YES; + [self.resetView.widthAnchor constraintEqualToConstant:130].active = YES; + [[self.resetView centerXAnchor] constraintEqualToAnchor:header.centerXAnchor constant:75].active = true; + [[self.resetView centerYAnchor] constraintEqualToAnchor:header.centerYAnchor].active = true; + + + self.resetImage = [[UIImageView alloc] init]; + self.resetImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/restore.png"]; + self.resetImage.layer.cornerRadius = 20; + self.resetImage.clipsToBounds = true; + [self.resetView addSubview:self.resetImage]; + + self.resetImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.resetImage.heightAnchor constraintEqualToConstant:40].active = YES; + [self.resetImage.widthAnchor constraintEqualToConstant:40].active = YES; + [[self.resetImage centerXAnchor] constraintEqualToAnchor:self.resetView.centerXAnchor].active = true; + [self.resetImage.topAnchor constraintEqualToAnchor:self.resetView.topAnchor constant:10].active = YES; + + + self.resetLabel = [[UILabel alloc] init]; + self.resetLabel.textAlignment = NSTextAlignmentCenter; + self.resetLabel.font = [UIFont systemFontOfSize:12]; + self.resetLabel.text = @"Reset to default"; + self.resetLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.7]; + [self.resetView addSubview:self.resetLabel]; + + self.resetLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.resetLabel centerXAnchor] constraintEqualToAnchor:self.resetView.centerXAnchor].active = true; + [self.resetLabel.topAnchor constraintEqualToAnchor:self.resetImage.bottomAnchor constant:10].active = YES; + + + [self.backupView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(createNewBackup)]]; + [self.resetView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(resetPrefs)]]; + +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + backupDict = [NSMutableDictionary dictionaryWithContentsOfFile:backupPathPlist][TweakName]; + return (long long)[backupDict count]; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + DrawerCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[DrawerCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"SocialCell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = [UIColor clearColor]; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + backupDict = [NSMutableDictionary dictionaryWithContentsOfFile:backupPathPlist][TweakName]; + NSArray *sortedArray = [[backupDict allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + NSString *index = [NSString stringWithFormat:@"%@", sortedArray[indexPath.row]]; + + if([backupDict[index] count] !=0){ + cell.titleLabel.text = backupDict[index][@"name"]; + cell.subtitleLabel.text = backupDict[index][@"time"]; + } + + cell.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/backup-restore.png"]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 70; +} + + +-(void)showAlert:(NSString*)title msg:(NSString*)msg{ + + invokeHapticFeedback(); + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + [[TDUtilities sharedInstance] haptic:0]; + }]; + [alertController addAction:okAction]; + alertController.view.tintColor = self.tintColour; + [self presentViewController:alertController animated:YES completion:nil]; +} + +-(void)fileManager:(NSString *)mode fromPath:(NSString*)fromPath toPath:(NSString*)toPath{ + NSLog(@"zzzzzzzzzzzzzzzzzzz didSelectRowAtIndexPath mode:-%@", mode); + + if([mode isEqualToString:@"replace"]){ + NSString *cmd = [NSString stringWithFormat:@"/bin/rm %@", toPath]; + outputForShellCommand(cmd); + cmd = [NSString stringWithFormat:@"/bin/cp %@ %@", fromPath, toPath]; + outputForShellCommand(cmd); + NSLog(@"zzzzzzzzzzzzzzzzzzz didSelectRowAtIndexPath replace toPath:-%@, fromPath:-%@", toPath, fromPath); + } + + if([mode isEqualToString:@"copy"]){ + NSString *cmd = [NSString stringWithFormat:@"/bin/cp %@ %@ 2>/tmp/2.txt 1>/tmp/1.txt", fromPath, toPath]; + outputForShellCommand(cmd); + NSLog(@"zzzzzzzzzzzzzzzzzzz didSelectRowAtIndexPath copy toPath:-%@, fromPath:-%@", toPath, fromPath); + } + + if([mode isEqualToString:@"delete"]){ + NSString *cmd = [NSString stringWithFormat:@"/bin/rm %@", fromPath]; + outputForShellCommand(cmd); + NSLog(@"zzzzzzzzzzzzzzzzzzz didSelectRowAtIndexPath delete toPath:-%@, fromPath:-%@", toPath, fromPath); + } +} + +-(void)writeBackup:(NSString *)key value:(NSDictionary*)value{ + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:backupPathPlist]]; + if (![settings objectForKey:TweakName] || [settings[TweakName] count] == 0) { + [settings setObject:[NSMutableDictionary new] forKey:TweakName]; + } + NSLog(@"zzzzzzzzzzzzzzzzzzz writeBackup11111 key:-%@ , value:-%@", key, value); + [(NSMutableDictionary*)settings[TweakName] setObject:value forKey:key]; + [settings writeToFile:backupPathPlist atomically:YES]; +} + +-(void)deleteAndUpdate:(NSString *)key{ + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:backupPathPlist]]; + [settings[TweakName] removeObjectForKey:key]; + [settings writeToFile:backupPathPlist atomically:YES]; +} + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + invokeHapticFeedback(); + + backupDict = [NSMutableDictionary dictionaryWithContentsOfFile:backupPathPlist][TweakName]; + NSArray *sortedArray = [[backupDict allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + NSString *index = [NSString stringWithFormat:@"%@", sortedArray[indexPath.row]]; + NSLog(@"zzzzzzzzzzzzzzzzzzz didSelectRowAtIndexPath index:-%@", index); + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Options" message:@"" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *filzaAction = [UIAlertAction actionWithTitle:@"Open in Filza" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"filza://%@", backupDict[index][@"filePath"]]] options:@{} completionHandler:nil]; + [[TDUtilities sharedInstance] haptic:0]; + }]; + [alertController addAction:filzaAction]; + + UIAlertAction *restoreAction = [UIAlertAction actionWithTitle:@"Restore Backup" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + NSString *filePath = backupDict[index][@"filePath"]; + NSLog(@"zzzzzzzzzzzzzzzzzzz Restore:-%d", [[NSFileManager defaultManager] fileExistsAtPath:filePath]); + if([[NSFileManager defaultManager] fileExistsAtPath:filePath]){ + [self fileManager:@"replace" fromPath:filePath toPath:prefsPathTobackup]; + [self showAlert:TweakName msg:@"Backup restored successfuly"]; + } + else{ + NSString *msg = [NSString stringWithFormat:@"Backup file not found for %@.\nPls delete this Backup and create new Backup", backupDict[index][@"name"]]; + [self showAlert:TweakName msg:msg]; + } + [[TDUtilities sharedInstance] haptic:0]; + }]; + [alertController addAction:restoreAction]; + + UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:@"Delete Backup" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + NSString *filePath = backupDict[index][@"filePath"]; + NSLog(@"zzzzzzzzzzzzzzzzzzz deleteAction:-%@, filePath:-%@", backupDict[index][@"name"], filePath); + [self deleteAndUpdate:backupDict[index][@"name"]]; + [self fileManager:@"delete" fromPath:filePath toPath:nil]; + [self.tableView reloadData]; + [self showAlert:TweakName msg:@"Backup deleted successfuly"]; + [[TDUtilities sharedInstance] haptic:0]; + }]; + [alertController addAction:deleteAction]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + + }]; + [alertController addAction:cancelAction]; + + [self presentViewController:alertController animated:YES completion:nil]; + alertController.view.tintColor = self.tintColour; + + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + +} + +-(void)createNewBackup { + + invokeHapticFeedback(); + + backupDict = [NSMutableDictionary dictionaryWithContentsOfFile:backupPathPlist][TweakName]; + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Create New Backup:" message:@"Backup Name" preferredStyle:UIAlertControllerStyleAlert]; + [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { + textField.placeholder = @"Backup name..."; + }]; + + UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"Create Backup" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + + NSString *backupName = alertController.textFields.firstObject.text; + if(!backupDict[backupName]){ + backupDict = [NSMutableDictionary dictionaryWithContentsOfFile:backupPathPlist][TweakName]; + NSString *backupFile = [NSString stringWithFormat:@"/Library/TitanD3v-Backup/%@/%@.plist", TweakName, backupName]; + NSDictionary *dic = @{@"name" : backupName, @"filePath" : backupFile, @"time" : [self dateAndTime]}; + NSLog(@"zzzzzzzzzzzzzzzzzzz backupName:-%@ backupFile:-%@, dic:-%@", backupName, backupFile, dic); + + if([[NSFileManager defaultManager] fileExistsAtPath:prefsPathTobackup]){ + [self writeBackup:backupName value:dic]; + [self fileManager:@"copy" fromPath:prefsPathTobackup toPath:backupFile]; + [self.tableView reloadData]; + } + else + [self showAlert:TweakName msg:[NSString stringWithFormat:@"Backup can not be created because %@ prefs file doesn't exists.", TweakName]]; + } + else{ + [self showAlert:TweakName msg:[NSString stringWithFormat:@"Backup with name %@ already exists\n\nPls use another name and try again.", backupName]]; + [self createNewBackup]; + } + [[TDUtilities sharedInstance] haptic:0]; + }]; + [alertController addAction:confirmAction]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + }]; + [alertController addAction:cancelAction]; + alertController.view.tintColor = self.tintColour; + [self presentViewController:alertController animated:YES completion:nil]; + +} + +-(void)resetPrefs { + + invokeHapticFeedback(); + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Reset" message:@"Are you sure you want to reset your preference settings to default?" preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [self fileManager:@"delete" fromPath:prefsPathTobackup toPath:nil]; + [self showAlert:TweakName msg:@"Prefs reset successful"]; + [[TDUtilities sharedInstance] haptic:0]; + }]; + [alertController addAction:confirmAction]; + + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + }]; + [alertController addAction:cancelAction]; + alertController.view.tintColor = self.tintColour; + [self presentViewController:alertController animated:YES completion:nil]; +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/ChangelogViewController.h b/libTitanD3vUniversal/Drawer/Controllers/ChangelogViewController.h new file mode 100644 index 0000000..c8d505e --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/ChangelogViewController.h @@ -0,0 +1,16 @@ +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "ChangelogCell.h" + +@interface ChangelogViewController : UIViewController + +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) UIView *bannerView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *versionLabel; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) NSArray *changelogArray; + +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/ChangelogViewController.m b/libTitanD3vUniversal/Drawer/Controllers/ChangelogViewController.m new file mode 100644 index 0000000..8083836 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/ChangelogViewController.m @@ -0,0 +1,164 @@ +#import "ChangelogViewController.h" + +@implementation ChangelogViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.view.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + self.view.layer.maskedCorners = 12; + self.view.layer.cornerRadius = 30; + self.view.layer.cornerCurve = kCACornerCurveContinuous; + self.view.clipsToBounds = true; + [self layoutTableView]; + +} + +-(void)layoutTableView { + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *changelogPlistPath = [[TDPrefsManager sharedInstance] getChangelogPlistPath]; + NSString *changelogString = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, changelogPlistPath]; + + self.changelogArray = [[NSArray alloc]initWithContentsOfFile:changelogString]; + + + NSString *versionString = [[TDPrefsManager sharedInstance] getCurrentVersion]; + + self.bannerView = [[UIView alloc] init]; + self.bannerView.clipsToBounds = true; + [self.view addSubview:self.bannerView]; + + self.bannerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.bannerView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.bannerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.bannerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.bannerView.heightAnchor constraintEqualToConstant:140].active = YES; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/changelog.png"]; + self.iconImage.userInteractionEnabled = YES; + self.iconImage.layer.cornerRadius = 15; + self.iconImage.clipsToBounds = true; + [self.bannerView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.heightAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.widthAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:self.bannerView.topAnchor constant:10].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + + + self.versionLabel = [[UILabel alloc] init]; + self.versionLabel.textAlignment = NSTextAlignmentCenter; + self.versionLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.versionLabel.font = [UIFont systemFontOfSize:16]; + self.versionLabel.text = versionString; + [self.bannerView addSubview:self.versionLabel]; + + self.versionLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.versionLabel.topAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant:10].active = YES; + [[self.versionLabel centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + + + self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + self.tableView.estimatedRowHeight = 60; + self.tableView.rowHeight = UITableViewAutomaticDimension; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + self.tableView.translatesAutoresizingMaskIntoConstraints = NO; + [self.tableView.topAnchor constraintEqualToAnchor:self.bannerView.bottomAnchor constant:5].active = YES; + [self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; + +} + + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return self.changelogArray.count; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [[[self.changelogArray objectAtIndex: section] objectForKey: @"ChangelogDescription"] count]; +} + + +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + return 45.0f; +} + + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { + + UIView *sectionHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 45)]; + sectionHeaderView.backgroundColor = UIColor.clearColor; + sectionHeaderView.clipsToBounds = true; + + + UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, sectionHeaderView.frame.size.height /2 -7.5, 200, 15)]; + headerLabel.backgroundColor = [UIColor clearColor]; + headerLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + headerLabel.textAlignment = NSTextAlignmentLeft; + headerLabel.font = [UIFont boldSystemFontOfSize:16]; + headerLabel.text = [[self.changelogArray objectAtIndex: section] objectForKey: @"Date"]; + [sectionHeaderView addSubview:headerLabel]; + + return sectionHeaderView; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ChangelogCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[ChangelogCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + + cell.versionLabel.text = [[self.changelogArray objectAtIndex: indexPath.section] objectForKey: @"Version"]; + cell.messageLabel.text = [[[[self.changelogArray objectAtIndex: indexPath.section] objectForKey: @"ChangelogDescription"] objectAtIndex: indexPath.row] stringByReplacingOccurrencesOfString:@"\\n" withString:@"\n"]; + + NSInteger categories = [[[[self.changelogArray objectAtIndex: indexPath.section] objectForKey: @"updateCategories"] objectAtIndex: indexPath.row] intValue]; + + if (categories == 0) { + cell.categoriesLabel.text = @"Initial Release"; + cell.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/initial-release.png"]; + } else if (categories == 1) { + cell.categoriesLabel.text = @"Bug Fixes"; + cell.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/bug-fix.png"]; + } else if (categories == 2) { + cell.categoriesLabel.text = @"Improvements"; + cell.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/improvements.png"]; + } else if (categories == 3) { + cell.categoriesLabel.text = @"New Features"; + cell.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/new-features.png"]; + } + + return cell; + +} + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/CrewViewController.h b/libTitanD3vUniversal/Drawer/Controllers/CrewViewController.h new file mode 100644 index 0000000..c2f5d1e --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/CrewViewController.h @@ -0,0 +1,17 @@ +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "CrewCell.h" + +@interface CrewViewController : UIViewController { + NSString *crewString; +} + +@property (nonatomic, retain) UIView *bannerView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) NSArray *crewArray; +@property (nonatomic, retain) UIColor *tintColour; +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/CrewViewController.m b/libTitanD3vUniversal/Drawer/Controllers/CrewViewController.m new file mode 100644 index 0000000..c524d73 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/CrewViewController.m @@ -0,0 +1,167 @@ +#import "CrewViewController.h" + + +@implementation CrewViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.view.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + self.view.layer.maskedCorners = 12; + self.view.layer.cornerRadius = 30; + self.view.layer.cornerCurve = kCACornerCurveContinuous; + self.view.clipsToBounds = true; + [self layoutBanner]; + [self layoutTableView]; +} + + +-(void)layoutBanner { + + self.bannerView = [[UIView alloc] init]; + self.bannerView.clipsToBounds = true; + [self.view addSubview:self.bannerView]; + + self.bannerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.bannerView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.bannerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.bannerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.bannerView.heightAnchor constraintEqualToConstant:140].active = YES; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/crew.png"]; + self.iconImage.layer.cornerRadius = 15; + self.iconImage.clipsToBounds = true; + [self.bannerView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.heightAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.widthAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:self.bannerView.topAnchor constant:10].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + BOOL useAssets = [[TDPrefsManager sharedInstance] populateAssetsFromLibrary]; + if (useAssets) { + self.titleLabel.text = @"Crew"; + } else { + self.titleLabel.text = [[TDPrefsManager sharedInstance] getCrewTitle]; + } + [self.bannerView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.titleLabel.topAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant:10].active = YES; + [[self.titleLabel centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + +} + + +-(void)layoutTableView { + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *crewPlistPath = [[TDPrefsManager sharedInstance] getCrewPlistPath]; + BOOL useAssets = [[TDPrefsManager sharedInstance] populateAssetsFromLibrary]; + if (useAssets) { + crewString = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/crew.plist"]; + } else { + crewString = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, crewPlistPath]; + } + + self.crewArray = [[NSArray alloc]initWithContentsOfFile:crewString]; + + self.tableView = [[UITableView alloc] init]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + self.tableView.translatesAutoresizingMaskIntoConstraints = NO; + [self.tableView.topAnchor constraintEqualToAnchor:self.bannerView.bottomAnchor constant:5].active = YES; + [self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.crewArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + CrewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[CrewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *crewImagePath = [[TDPrefsManager sharedInstance] getCrewImagePath]; + BOOL useAssets = [[TDPrefsManager sharedInstance] populateAssetsFromLibrary]; + if (useAssets) { + crewString = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/"]; + } else { + crewString = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, crewImagePath]; + } + NSString *bannerString = (NSString*)[[self.crewArray objectAtIndex:indexPath.row] objectForKey:@"banner"]; + NSString *avatarString = (NSString*)[[self.crewArray objectAtIndex:indexPath.row] objectForKey:@"avatar"]; + + NSString *bannerImageString = [NSString stringWithFormat:@"%@/%@", crewString, bannerString]; + NSString *avatarImageString = [NSString stringWithFormat:@"%@/%@", crewString, avatarString]; + + + cell.backgroundColor = UIColor.clearColor; + cell.bannerImage.image = [UIImage imageWithContentsOfFile:bannerImageString]; + cell.iconImage.image = [UIImage imageWithContentsOfFile:avatarImageString]; + cell.nameLabel.text = (NSString*)[[self.crewArray objectAtIndex:indexPath.row] objectForKey:@"name"]; + cell.roleLabel.text = (NSString*)[[self.crewArray objectAtIndex:indexPath.row] objectForKey:@"role"]; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 300; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + invokeHapticFeedback(); + + NSString *urlPath = (NSString*)[[self.crewArray objectAtIndex:indexPath.row] objectForKey:@"url"]; + + UIApplication *application = [UIApplication sharedApplication]; + NSURL *URL = [NSURL URLWithString:urlPath]; + [application openURL:URL options:@{} completionHandler:nil]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissDrawer" object:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"ResetDrawer" object:self]; + + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; +} + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/ProfileViewController.h b/libTitanD3vUniversal/Drawer/Controllers/ProfileViewController.h new file mode 100644 index 0000000..c747a67 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/ProfileViewController.h @@ -0,0 +1,20 @@ +#import +#import "TDPrefsManager.h" +#import "GlobalPrefs.h" +#import "TDAppearance.h" +#import "ProfileCell.h" +#import "TDAlertViewController.h" + +@interface ProfileViewController : UIViewController + +@property (nonatomic, retain) UIView *bannerView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIButton *tipsButton; +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) UIColor *containerColour; +@property (nonatomic, retain) UIColor *labelColour; +@property (nonatomic, retain) UIColor *tintColour; +@end + + diff --git a/libTitanD3vUniversal/Drawer/Controllers/ProfileViewController.m b/libTitanD3vUniversal/Drawer/Controllers/ProfileViewController.m new file mode 100644 index 0000000..0a49bc0 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/ProfileViewController.m @@ -0,0 +1,210 @@ +#import "ProfileViewController.h" + +@implementation ProfileViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.containerColour = [[TDAppearance sharedInstance] containerColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + self.view.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + self.view.layer.maskedCorners = 12; + self.view.layer.cornerRadius = 30; + self.view.layer.cornerCurve = kCACornerCurveContinuous; + self.view.clipsToBounds = true; + [self layoutBanner]; + [self layoutTableView]; +} + + +-(void)layoutBanner { + + self.bannerView = [[UIView alloc] init]; + self.bannerView.clipsToBounds = true; + [self.view addSubview:self.bannerView]; + + self.bannerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.bannerView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.bannerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.bannerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.bannerView.heightAnchor constraintEqualToConstant:140].active = YES; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/profile.png"]; + self.iconImage.layer.cornerRadius = 15; + self.iconImage.clipsToBounds = true; + [self.bannerView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.heightAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.widthAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:self.bannerView.topAnchor constant:10].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.text = @"Profile"; + [self.bannerView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.titleLabel.topAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant:10].active = YES; + [[self.titleLabel centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + + + self.tipsButton = [[UIButton alloc] init]; + self.tipsButton.backgroundColor = self.tintColour; + UIImage *tipsImage = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Tips/tips.png"]; + [self.tipsButton setImage:tipsImage forState:UIControlStateNormal]; + self.tipsButton.imageEdgeInsets = UIEdgeInsetsMake(3, 3, 3, 3); + [self.tipsButton addTarget:self action:@selector(showTipsTapped:) forControlEvents:UIControlEventTouchUpInside]; + self.tipsButton.layer.cornerRadius = 10; + [self.bannerView addSubview:self.tipsButton]; + + self.tipsButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.tipsButton.widthAnchor constraintEqualToConstant:20.0].active = YES; + [self.tipsButton.heightAnchor constraintEqualToConstant:20.0].active = YES; + [self.tipsButton.topAnchor constraintEqualToAnchor:self.bannerView.topAnchor constant:10].active = YES; + [self.tipsButton.trailingAnchor constraintEqualToAnchor:self.bannerView.trailingAnchor constant:-10].active = YES; + +} + + +-(void)layoutTableView { + + self.tableView = [[UITableView alloc] init]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + self.tableView.translatesAutoresizingMaskIntoConstraints = NO; + [self.tableView.topAnchor constraintEqualToAnchor:self.bannerView.bottomAnchor constant:5].active = YES; + [self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 2; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ProfileCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[ProfileCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + + cell.backgroundColor = UIColor.clearColor; + cell.textField.delegate = self; + cell.textField.tag = indexPath.row; + + if (indexPath.row == 0) { + + NSString *nameString = [[TDPrefsManager sharedInstance] objectForKey:@"profileName" defaultValue:@"UserName"]; + + cell.titleLabel.text = @"Your name:"; + cell.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/profile.png"]; + cell.textField.placeholder = @"Your name"; + cell.textField.text = nameString; + + } else if (indexPath.row == 1) { + + NSString *dobString = [[TDPrefsManager sharedInstance] objectForKey:@"profileDOB" defaultValue:@"22/11"]; + + cell.titleLabel.text = @"Birthday date & month:"; + cell.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/dob.png"]; + cell.textField.placeholder = @"dd/MM"; + cell.textField.text = dobString; + } + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 70; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; +} + + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + [textField resignFirstResponder]; + return YES; +} + + +- (void)textFieldDidEndEditing:(UITextField *)textField { + + if (textField.tag == 0) { + NSString *nameString = textField.text; + [[TDPrefsManager sharedInstance] setObject:nameString forKey:@"profileName"]; + + } else if (textField.tag == 1) { + NSString *dobString = textField.text; + [[TDPrefsManager sharedInstance] setObject:dobString forKey:@"profileDOB"]; + } + +} + + +-(void)showTipsTapped:(UIButton *)sender { + + invokeHapticFeedback(); + + NSString *titleString = @"FAQ"; + NSString *messageString = @"Q: Why is it asking me for my name? \nA: It's asking you for your name because on the main page banner will display a greeting message with your name E.G Good Morning, TitanD3v. You won't need to enter your real name, you can use a nickname or any name you want it to display. \n\nQ: Why is it asking me for my birthday? \nA: It's asking you for your birthday so when your birthday come's it will display a Happy Birthday message on the banner and you can test it out by entering today's date. It will display other holidays messages E.G Merry Christmas, Happy New Year and Happy Halloween et cetera."; + + + TDAlertViewControllerConfiguration *configuration = [TDAlertViewControllerConfiguration new]; + configuration.alertViewBackgroundColor = self.containerColour; + configuration.titleTextColor = self.labelColour; + configuration.messageTextColor = self.labelColour; + configuration.transitionStyle = TDAlertViewControllerTransitionStyleSlideFromTop; + configuration.backgroundTapDismissalGestureEnabled = YES; + configuration.swipeDismissalGestureEnabled = YES; + configuration.alwaysArrangesActionButtonsVertically = YES; + configuration.buttonConfiguration.titleColor = self.tintColour; + configuration.cancelButtonConfiguration.titleColor = self.tintColour; + configuration.cancelButtonConfiguration.titleFont = [UIFont systemFontOfSize:16]; + configuration.alertViewCornerRadius = 20; + configuration.showsSeparators = NO; + + + TDAlertAction *okAction = [[TDAlertAction alloc] initWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]; + + TDAlertViewController *alertViewController = [[TDAlertViewController alloc] initWithOptions:configuration title:titleString message:messageString actions:@[okAction]]; + + [self presentViewController:alertViewController animated:YES completion:nil]; + +} + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/SocialViewController.h b/libTitanD3vUniversal/Drawer/Controllers/SocialViewController.h new file mode 100644 index 0000000..b144c53 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/SocialViewController.h @@ -0,0 +1,21 @@ +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface SocialViewController : UIViewController { + NSString *avatarImageString; + NSString *twitterName; + NSString *socialString; + NSString *twitterURL; +} + +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) UIView *bannerView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UIView *twitterView; +@property (nonatomic, retain) UIImageView *twitterImage; +@property (nonatomic, retain) UILabel *twitterLabel; +@property (nonatomic, retain) NSArray *socialArray; +@property (nonatomic, retain) UIColor *tintColour; +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/SocialViewController.m b/libTitanD3vUniversal/Drawer/Controllers/SocialViewController.m new file mode 100644 index 0000000..026be83 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/SocialViewController.m @@ -0,0 +1,256 @@ +#import "SocialViewController.h" +#import "DrawerCell.h" + +@implementation SocialViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.view.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + self.view.layer.maskedCorners = 12; + self.view.layer.cornerRadius = 30; + self.view.layer.cornerCurve = kCACornerCurveContinuous; + self.view.clipsToBounds = true; + + [self layoutBanner]; + [self layoutTableView]; + +} + + +-(void)layoutBanner { + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *avatarPath = [[TDPrefsManager sharedInstance] getTwitterAvatarPath]; + BOOL useAssets = [[TDPrefsManager sharedInstance] populateAssetsFromLibrary]; + if (useAssets) { + avatarImageString = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/avatar.png"]; + twitterName = @"TitanD3v"; + } else { + avatarImageString = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, avatarPath]; + twitterName = [[TDPrefsManager sharedInstance] getTwitterName]; + } + + self.bannerView = [[UIView alloc] init]; + self.bannerView.clipsToBounds = true; + [self.view addSubview:self.bannerView]; + + self.bannerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.bannerView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.bannerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.bannerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.bannerView.heightAnchor constraintEqualToConstant:140].active = YES; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:avatarImageString]; + self.iconImage.layer.cornerRadius = 45; + self.iconImage.clipsToBounds = true; + self.iconImage.userInteractionEnabled = YES; + [self.bannerView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.heightAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.widthAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:self.bannerView.topAnchor constant:10].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + + + self.twitterView = [[UIView alloc] init]; + self.twitterView.backgroundColor = [UIColor colorWithRed: 0.20 green: 0.20 blue: 0.20 alpha: 0.5];; + self.twitterView.layer.cornerRadius = 15; + self.twitterView.layer.borderWidth = 1; + UIColor *twitterBorder = [self.tintColour colorWithAlphaComponent:0.3]; + self.twitterView.layer.borderColor = twitterBorder.CGColor; + self.twitterView.clipsToBounds = true; + [self.bannerView addSubview:self.twitterView]; + + self.twitterView.translatesAutoresizingMaskIntoConstraints = NO; + [self.twitterView.heightAnchor constraintEqualToConstant:30].active = YES; + [self.twitterView.widthAnchor constraintEqualToConstant:30].active = YES; + [self.twitterView.trailingAnchor constraintEqualToAnchor:self.iconImage.trailingAnchor constant:0].active = YES; + [self.twitterView.bottomAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant:0].active = YES; + + + self.twitterImage = [[UIImageView alloc] init]; + self.twitterImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/twitter.png"]; + [self.twitterView addSubview:self.twitterImage]; + + self.twitterImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.twitterImage.heightAnchor constraintEqualToConstant:20].active = YES; + [self.twitterImage.widthAnchor constraintEqualToConstant:20].active = YES; + [[self.twitterImage centerXAnchor] constraintEqualToAnchor:self.twitterView.centerXAnchor].active = true; + [[self.twitterImage centerYAnchor] constraintEqualToAnchor:self.twitterView.centerYAnchor].active = true; + + + self.twitterLabel = [[UILabel alloc] init]; + self.twitterLabel.textAlignment = NSTextAlignmentCenter; + self.twitterLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.twitterLabel.font = [UIFont systemFontOfSize:16]; + self.twitterLabel.text = twitterName; + [self.bannerView addSubview:self.twitterLabel]; + + self.twitterLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.twitterLabel.topAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant:10].active = YES; + [[self.twitterLabel centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + + + [self.iconImage addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(launchTwitter)]]; +} + + +-(void)layoutTableView { + + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *socialPlistPath = [[TDPrefsManager sharedInstance] getSocialPlistPath]; + BOOL useAssets = [[TDPrefsManager sharedInstance] populateAssetsFromLibrary]; + if (useAssets) { + socialString = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/social.plist"]; + } else { + socialString = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, socialPlistPath]; + } + self.socialArray = [[NSArray alloc]initWithContentsOfFile:socialString]; + + + self.tableView = [[UITableView alloc] init]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.showsVerticalScrollIndicator = NO; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + self.tableView.translatesAutoresizingMaskIntoConstraints = NO; + [self.tableView.topAnchor constraintEqualToAnchor:self.bannerView.bottomAnchor constant:5].active = YES; + [self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; + +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return self.socialArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + DrawerCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[DrawerCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"SocialCell"]; + } + + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = (NSString*)[[self.socialArray objectAtIndex:indexPath.row] objectForKey:@"title"]; + cell.subtitleLabel.text = (NSString*)[[self.socialArray objectAtIndex:indexPath.row] objectForKey:@"subtitle"]; + + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *socialIconPath = [[TDPrefsManager sharedInstance] getSocialIconPath]; + BOOL useAssets = [[TDPrefsManager sharedInstance] populateAssetsFromLibrary]; + if (useAssets) { + socialString = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/"]; + } else { + socialString = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, socialIconPath]; + } + NSString *imageString = (NSString*)[[self.socialArray objectAtIndex:indexPath.row] objectForKey:@"icon"]; + + NSString *socialImageString = [NSString stringWithFormat:@"%@/%@", socialString, imageString]; + + cell.iconImage.image = [UIImage imageWithContentsOfFile:socialImageString]; + + UIImageView *linkImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)]; + linkImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/link.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + UIColor *linkTint = [self.tintColour colorWithAlphaComponent:0.3]; + linkImage.tintColor = linkTint; + cell.accessoryView = linkImage; + + return cell; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return 70; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + invokeHapticFeedback(); + + NSString *urlPath = (NSString*)[[self.socialArray objectAtIndex:indexPath.row] objectForKey:@"url"]; + + UIApplication *application = [UIApplication sharedApplication]; + NSURL *URL = [NSURL URLWithString:urlPath]; + [application openURL:URL options:@{} completionHandler:nil]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissDrawer" object:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"ResetDrawer" object:self]; + + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + +} + + +-(void)launchTwitter { + + invokeHapticFeedback(); + + BOOL useAssets = [[TDPrefsManager sharedInstance] populateAssetsFromLibrary]; + if (useAssets) { + twitterURL = @"https://twitter.com/D3vTitan"; + } else { + twitterURL = [[TDPrefsManager sharedInstance] getTwitterURL]; + } + + UIApplication *application = [UIApplication sharedApplication]; + NSURL *URL = [NSURL URLWithString:twitterURL]; + [application openURL:URL options:@{} completionHandler:nil]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissDrawer" object:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"ResetDrawer" object:self]; +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/ThemeViewController.h b/libTitanD3vUniversal/Drawer/Controllers/ThemeViewController.h new file mode 100644 index 0000000..a0510b6 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/ThemeViewController.h @@ -0,0 +1,20 @@ +#import +#import "TDColorPickerViewController.h" +#import "TDPrefsManager.h" +#import "GlobalPrefs.h" +#import "TDAppearance.h" +#import "HEXColour.h" +#import "ThemeCell.h" +#import "BlurBannerView.h" + +@interface ThemeViewController : UIViewController { + NSInteger colourPickerIndex; +} + +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSArray *themeArray; +@property (nonatomic, retain) BlurBannerView *bannerView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIColor *tintColour; +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/ThemeViewController.m b/libTitanD3vUniversal/Drawer/Controllers/ThemeViewController.m new file mode 100644 index 0000000..0128182 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/ThemeViewController.m @@ -0,0 +1,218 @@ +#import "ThemeViewController.h" + + +@implementation ThemeViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.view.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + self.view.layer.maskedCorners = 12; + self.view.layer.cornerRadius = 30; + self.view.layer.cornerCurve = kCACornerCurveContinuous; + self.view.clipsToBounds = true; + + [self layoutBannerView]; + [self layoutCollectionView]; + +} + + +-(void)layoutBannerView { + + self.bannerView = [[BlurBannerView alloc] init]; + self.bannerView.clipsToBounds = true; + [self.view addSubview:self.bannerView]; + + self.bannerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.bannerView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.bannerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.bannerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.bannerView.heightAnchor constraintEqualToConstant:140].active = YES; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/themes.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + UIColor *iconTint = [self.tintColour colorWithAlphaComponent:0.7]; + self.iconImage.tintColor = iconTint; + [self.bannerView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.heightAnchor constraintEqualToConstant:70].active = YES; + [self.iconImage.widthAnchor constraintEqualToConstant:70].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:self.bannerView.topAnchor constant:10].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = UIColor.whiteColor; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.text = @"Themes"; + [self.bannerView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.titleLabel.topAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant:10].active = YES; + [[self.titleLabel centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; +} + + +-(void)layoutCollectionView { + + self.themeArray = [[NSArray alloc] initWithObjects:@"Navigation Bar", @"Tint", @"Background", @"Cells", @"Label", @"Banner", @"Container", @"Border", nil]; + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[ThemeCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.view addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + [self.collectionView.topAnchor constraintEqualToAnchor:self.bannerView.bottomAnchor constant:20].active = YES; + [self.collectionView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20].active = YES; + [self.collectionView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20].active = YES; + [self.collectionView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-20].active = YES; + +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.themeArray.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + ThemeCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = [self.themeArray objectAtIndex:indexPath.row]; + + if (indexPath.row == 0) { + cell.colourView.backgroundColor = [[TDAppearance sharedInstance] navigationBarColour]; + } else if (indexPath.row == 1) { + cell.colourView.backgroundColor = [[TDAppearance sharedInstance] tintColour]; + } else if (indexPath.row == 2) { + cell.colourView.backgroundColor = [[TDAppearance sharedInstance] backgroundColour]; + } else if (indexPath.row == 3) { + cell.colourView.backgroundColor = [[TDAppearance sharedInstance] cellColour]; + } else if (indexPath.row == 4) { + cell.colourView.backgroundColor = [[TDAppearance sharedInstance] labelColour]; + } else if (indexPath.row == 5) { + cell.colourView.backgroundColor = [[TDAppearance sharedInstance] bannerColour]; + } else if (indexPath.row == 6) { + cell.colourView.backgroundColor = [[TDAppearance sharedInstance] containerColour]; + } else if (indexPath.row == 7) { + cell.colourView.backgroundColor = [[TDAppearance sharedInstance] borderColour]; + } + + return cell; + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + + return CGSizeMake(100, 120); + +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + invokeHapticFeedback(); + + colourPickerIndex = indexPath.row; + UIColor *currentColor; + + if (indexPath.row == 0) { + currentColor = [[TDAppearance sharedInstance] navigationBarColour]; + } else if (indexPath.row == 1) { + currentColor = [[TDAppearance sharedInstance] tintColour]; + } else if (indexPath.row == 2) { + currentColor = [[TDAppearance sharedInstance] backgroundColour]; + } else if (indexPath.row == 3) { + currentColor = [[TDAppearance sharedInstance] cellColour]; + } else if (indexPath.row == 4) { + currentColor = [[TDAppearance sharedInstance] labelColour]; + } else if (indexPath.row == 5) { + currentColor = [[TDAppearance sharedInstance] bannerColour]; + } else if (indexPath.row == 6) { + currentColor = [[TDAppearance sharedInstance] containerColour]; + } else if (indexPath.row == 7) { + currentColor = [[TDAppearance sharedInstance] borderColour]; + } + + + [self presentViewController:[[TDColorPickerViewController alloc] initWithColor:currentColor stackType:TDColorSpaceTypeHSBA delegate:self] animated:YES completion:nil]; + +} + + +-(void)colorPickerDidUpdateColor:(UIColor *)color { + + NSString *hex = stringFromColor(color); + + + if (colourPickerIndex == 0) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"navigationBarTheme"]; + } else if (colourPickerIndex == 1) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"tintTheme"]; + } else if (colourPickerIndex == 2) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"backgroundTheme"]; + } else if (colourPickerIndex == 3) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"cellTheme"]; + } else if (colourPickerIndex == 4) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"labelTheme"]; + } else if (colourPickerIndex == 5) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"bannerTheme"]; + } else if (colourPickerIndex == 6) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"containerTheme"]; + } else if (colourPickerIndex == 7) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"borderTheme"]; + } + + [self.collectionView reloadData]; + +} + + +-(void)colorPickerDidChangeColor:(UIColor *)color { + + NSString *hex = stringFromColor(color); + + if (colourPickerIndex == 0) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"navigationBarTheme"]; + } else if (colourPickerIndex == 1) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"tintTheme"]; + } else if (colourPickerIndex == 2) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"backgroundTheme"]; + } else if (colourPickerIndex == 3) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"cellTheme"]; + } else if (colourPickerIndex == 4) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"labelTheme"]; + } else if (colourPickerIndex == 5) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"bannerTheme"]; + } else if (colourPickerIndex == 6) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"containerTheme"]; + } else if (colourPickerIndex == 7) { + [[TDPrefsManager sharedInstance] setObject:hex forKey:@"borderTheme"]; + } + + [self.collectionView reloadData]; + +} + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/TweakViewController.h b/libTitanD3vUniversal/Drawer/Controllers/TweakViewController.h new file mode 100644 index 0000000..e1d93e3 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/TweakViewController.h @@ -0,0 +1,15 @@ +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + +@interface TweakViewController : UIViewController { + NSString *tweakString; +} +@property (nonatomic, retain) UITableView *tableView; +@property (nonatomic, retain) UIView *bannerView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) NSArray *tweakArray; +@property (nonatomic, retain) UIColor *tintColour; +@end \ No newline at end of file diff --git a/libTitanD3vUniversal/Drawer/Controllers/TweakViewController.m b/libTitanD3vUniversal/Drawer/Controllers/TweakViewController.m new file mode 100644 index 0000000..3caabf3 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/TweakViewController.m @@ -0,0 +1,188 @@ +#import "TweakViewController.h" +#import "TweakCell.h" + + +@implementation TweakViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.view.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + self.view.layer.maskedCorners = 12; + self.view.layer.cornerRadius = 30; + self.view.layer.cornerCurve = kCACornerCurveContinuous; + self.view.clipsToBounds = true; + + [self layoutBanner]; + [self layoutTableView]; + +} + + +-(void)layoutBanner { + + self.bannerView = [[UIView alloc] init]; + self.bannerView.clipsToBounds = true; + [self.view addSubview:self.bannerView]; + + self.bannerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.bannerView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.bannerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.bannerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.bannerView.heightAnchor constraintEqualToConstant:140].active = YES; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/tweaks.png"]; + self.iconImage.userInteractionEnabled = YES; + self.iconImage.layer.cornerRadius = 15; + self.iconImage.clipsToBounds = true; + [self.bannerView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.heightAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.widthAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:self.bannerView.topAnchor constant:10].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.text = @"You might like other tweaks"; + [self.bannerView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.titleLabel.topAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant:10].active = YES; + [[self.titleLabel centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + +} + + +-(void)layoutTableView { + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *tweakPlistPath = [[TDPrefsManager sharedInstance] getTweakPlistPath]; + BOOL useAssets = [[TDPrefsManager sharedInstance] populateAssetsFromLibrary]; + if (useAssets) { + tweakString = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/tweak.plist"]; + } else { + tweakString = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, tweakPlistPath]; + } + self.tweakArray = [[NSArray alloc]initWithContentsOfFile:tweakString]; + + + self.tableView = [[UITableView alloc] init]; + self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.tableView.editing = NO; + self.tableView.backgroundColor = UIColor.clearColor; + [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + self.tableView.estimatedRowHeight = 60; + self.tableView.rowHeight = UITableViewAutomaticDimension; + [self.view addSubview:self.tableView]; + + self.tableView.dataSource = self; + self.tableView.delegate = self; + + self.tableView.translatesAutoresizingMaskIntoConstraints = NO; + [self.tableView.topAnchor constraintEqualToAnchor:self.bannerView.bottomAnchor constant:5].active = YES; + [self.tableView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.tableView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.tableView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; + +} + + +- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + + return self.tweakArray.count; +} + + +- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { + + TweakCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; + + if (cell == nil) { + + cell = [[TweakCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"]; + } + + UIView *selectionView = [UIView new]; + selectionView.backgroundColor = UIColor.clearColor; + [[UITableViewCell appearance] setSelectedBackgroundView:selectionView]; + + + NSString *prefsBundle = [[TDPrefsManager sharedInstance] getPrefsBundle]; + NSString *tweakIconPath = [[TDPrefsManager sharedInstance] getTweakIconPath]; + BOOL useAssets = [[TDPrefsManager sharedInstance] populateAssetsFromLibrary]; + if (useAssets) { + tweakString = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/"]; + } else { + tweakString = [NSString stringWithFormat:@"/Library/PreferenceBundles/%@/%@", prefsBundle, tweakIconPath]; + } + NSString *imageString = (NSString*)[[self.tweakArray objectAtIndex:indexPath.row] objectForKey:@"icon"]; + + NSString *tweakImageString = [NSString stringWithFormat:@"%@/%@", tweakString, imageString]; + + + cell.backgroundColor = UIColor.clearColor; + cell.iconImage.image = [UIImage imageWithContentsOfFile:tweakImageString]; + cell.nameLabel.text = (NSString*)[[self.tweakArray objectAtIndex:indexPath.row] objectForKey:@"name"]; + cell.priceLabel.text = (NSString*)[[self.tweakArray objectAtIndex:indexPath.row] objectForKey:@"price"]; + cell.versionLabel.text = (NSString*)[[self.tweakArray objectAtIndex:indexPath.row] objectForKey:@"compatibility"]; + cell.descriptionLabel.text = (NSString*)[[self.tweakArray objectAtIndex:indexPath.row] objectForKey:@"description"]; + + return cell; +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + + invokeHapticFeedback(); + + NSString *urlPath = (NSString*)[[self.tweakArray objectAtIndex:indexPath.row] objectForKey:@"url"]; + + UIApplication *application = [UIApplication sharedApplication]; + NSURL *URL = [NSURL URLWithString:urlPath]; + [application openURL:URL options:@{} completionHandler:nil]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissDrawer" object:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"ResetDrawer" object:self]; + + [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; + +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +@end diff --git a/libTitanD3vUniversal/Drawer/Controllers/comman.m b/libTitanD3vUniversal/Drawer/Controllers/comman.m new file mode 100644 index 0000000..3ce5737 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/Controllers/comman.m @@ -0,0 +1,19 @@ +#import + +__attribute__((unused)) static NSMutableString *outputForShellCommand(NSString *cmd) { + FILE *fp; + char buf[1024]; + NSMutableString* finalRet; + fp = popen([cmd UTF8String], "r"); + if (fp == NULL) { + return nil; + } + + fgets(buf, 1024, fp); + finalRet = [NSMutableString stringWithUTF8String:buf]; + if(pclose(fp) != 0) { + return nil; + } + + return finalRet; +} diff --git a/libTitanD3vUniversal/Drawer/DrawerBlurEffect/BlurBannerView.h b/libTitanD3vUniversal/Drawer/DrawerBlurEffect/BlurBannerView.h new file mode 100644 index 0000000..d9b3de9 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/DrawerBlurEffect/BlurBannerView.h @@ -0,0 +1,6 @@ +#import + +@interface BlurBannerView : UIView +@property (nonatomic, retain) UIImageView *backgroundImage; +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@end diff --git a/libTitanD3vUniversal/Drawer/DrawerBlurEffect/BlurBannerView.m b/libTitanD3vUniversal/Drawer/DrawerBlurEffect/BlurBannerView.m new file mode 100644 index 0000000..89b3e0c --- /dev/null +++ b/libTitanD3vUniversal/Drawer/DrawerBlurEffect/BlurBannerView.m @@ -0,0 +1,48 @@ +#import "BlurBannerView.h" + +extern CFArrayRef CPBitmapCreateImagesFromData(CFDataRef cpbitmap, void*, int, void*); + +@implementation BlurBannerView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + + NSData *wallpaperData = [NSData dataWithContentsOfFile:@"/User/Library/SpringBoard/OriginalLockBackground.cpbitmap"]; + CFArrayRef wallpaperArrayRef = CPBitmapCreateImagesFromData((__bridge CFDataRef)wallpaperData, NULL, 1, NULL); + NSArray *wallpaperArray = (__bridge NSArray *)wallpaperArrayRef; + UIImage *wallpaper = [[UIImage alloc] initWithCGImage:(__bridge CGImageRef)(wallpaperArray[0])]; + CFRelease(wallpaperArrayRef); + + self.backgroundImage = [[UIImageView alloc] init]; + self.backgroundImage.image = wallpaper; + [self addSubview:self.backgroundImage]; + + self.backgroundImage.translatesAutoresizingMaskIntoConstraints = false; + [self.backgroundImage.topAnchor constraintEqualToAnchor:self.topAnchor constant:0].active = YES; + [self.backgroundImage.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0].active = YES; + [self.backgroundImage.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:0].active = YES; + [self.backgroundImage.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0].active = YES; + + + self.blurEffectView = [[UIVisualEffectView alloc] init]; + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + [self addSubview:self.blurEffectView]; + + self.blurEffectView.translatesAutoresizingMaskIntoConstraints = false; + [self.blurEffectView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0].active = YES; + [self.blurEffectView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0].active = YES; + [self.blurEffectView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:0].active = YES; + [self.blurEffectView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0].active = YES; + + + } + + return self; + +} + + +@end diff --git a/libTitanD3vUniversal/Drawer/DrawerBlurEffect/TDBlurBaseView.h b/libTitanD3vUniversal/Drawer/DrawerBlurEffect/TDBlurBaseView.h new file mode 100644 index 0000000..1ba73f3 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/DrawerBlurEffect/TDBlurBaseView.h @@ -0,0 +1,5 @@ +#import + +@interface TDBlurBaseView : UIView +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@end diff --git a/libTitanD3vUniversal/Drawer/DrawerBlurEffect/TDBlurBaseView.m b/libTitanD3vUniversal/Drawer/DrawerBlurEffect/TDBlurBaseView.m new file mode 100644 index 0000000..47085af --- /dev/null +++ b/libTitanD3vUniversal/Drawer/DrawerBlurEffect/TDBlurBaseView.m @@ -0,0 +1,29 @@ +#import "TDBlurBaseView.h" + +@implementation TDBlurBaseView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + + self.blurEffectView = [[UIVisualEffectView alloc] init]; + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + [self insertSubview:self.blurEffectView atIndex:0]; + + self.blurEffectView.translatesAutoresizingMaskIntoConstraints = false; + [self.blurEffectView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0].active = YES; + [self.blurEffectView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0].active = YES; + [self.blurEffectView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:0].active = YES; + [self.blurEffectView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0].active = YES; + + + } + + return self; + +} + + +@end diff --git a/libTitanD3vUniversal/Drawer/DrawerViewController.h b/libTitanD3vUniversal/Drawer/DrawerViewController.h new file mode 100644 index 0000000..66359f7 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/DrawerViewController.h @@ -0,0 +1,28 @@ +#import +#import "TDAppearance.h" +#import "GlobalPrefs.h" +#import "TDBlurBaseView.h" +#import "CategoriesCell.h" +#import "SocialViewController.h" +#import "ChangelogViewController.h" +#import "TweakViewController.h" +#import "BackupViewController.h" +//#import "ThemeViewController.h" +#import "ProfileViewController.h" +#import "CrewViewController.h" +#import "ConstraintExtension.h" + +@interface DrawerViewController : UIViewController + +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *categoriesArray; +@property (nonatomic, retain) NSArray *imageArray; +@property (nonatomic, retain) SocialViewController *socialVC; +@property (nonatomic, retain) ChangelogViewController *changelogVC; +@property (nonatomic, retain) TweakViewController *tweakVC; +@property (nonatomic, retain) BackupViewController *backupVC; +@property (nonatomic, retain) ProfileViewController *profileVC; +@property (nonatomic, retain) CrewViewController *crewVC; +@property (nonatomic, retain) UIColor *tintColour; +@end + diff --git a/libTitanD3vUniversal/Drawer/DrawerViewController.m b/libTitanD3vUniversal/Drawer/DrawerViewController.m new file mode 100644 index 0000000..18149e3 --- /dev/null +++ b/libTitanD3vUniversal/Drawer/DrawerViewController.m @@ -0,0 +1,288 @@ +#import "DrawerViewController.h" + +static NSInteger categoriesSelectedIndex = 0; + +@implementation DrawerViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + self.view.backgroundColor = [UIColor colorWithRed: 0.11 green: 0.11 blue: 0.11 alpha: 1.00]; + + [self layoutCollectionView]; + [self checkCategoriesIndex]; + [self layoutSocialVC]; + [self layoutChangelogVC]; + [self layoutBackupVC]; + [self layoutTweakVC]; + [self layoutProfileVC]; + [self layoutCrewVC]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resetDrawerNotification:) name:@"ResetDrawer" object:nil]; +} + + +- (void)resetDrawerNotification:(NSNotification *) notification { + + if ([[notification name] isEqualToString:@"ResetDrawer"]){ + [self resetIndex]; + } +} + + +-(void)resetIndex { + + categoriesSelectedIndex = 0; + [self.collectionView reloadData]; + [self checkCategoriesIndex]; + +} + + +-(void)layoutCollectionView { + + self.categoriesArray = [[NSMutableArray alloc] init]; + [self.categoriesArray addObject:@"Social"]; + [self.categoriesArray addObject:@"Changelog"]; + [self.categoriesArray addObject:@"Backup/Restore"]; + [self.categoriesArray addObject:@"Tweaks"]; + [self.categoriesArray addObject:@"Profile"]; + [self.categoriesArray addObject:@"Crew"]; + + self.imageArray = [[NSArray alloc] initWithObjects:@"link.circle.fill", @"list.bullet.rectangle", @"archivebox.fill", @"hammer.fill", @"person.crop.circle.fill", @"person.2.circle.fill", nil]; + + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[CategoriesCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.view addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + [self.collectionView height:80]; + [self.collectionView leading:self.view.leadingAnchor padding:20]; + [self.collectionView trailing:self.view.trailingAnchor padding:-20]; + [self.collectionView bottom:self.view.bottomAnchor padding:0]; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.categoriesArray.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + CategoriesCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.titleLabel.text = [self.categoriesArray objectAtIndex:indexPath.row]; + cell.iconImage.image = [UIImage systemImageNamed:[self.imageArray objectAtIndex:indexPath.row]]; + + if (indexPath.row == categoriesSelectedIndex) { + cell.selectedView.alpha = 1; + cell.gradientView.alpha = 1; + cell.iconImage.tintColor = [UIColor colorWithRed: 0.95 green: 0.27 blue: 0.17 alpha: 1.00]; + cell.titleLabel.alpha = 1; + } else { + cell.gradientView.alpha = 0; + cell.selectedView.alpha = 0; + cell.iconImage.tintColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.5]; + cell.titleLabel.alpha = 0; + } + + return cell; + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + return CGSizeMake(80, 80); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + invokeHapticFeedback(); + + categoriesSelectedIndex = indexPath.row; + [self.collectionView reloadData]; + [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES]; + [self checkCategoriesIndex]; + +} + + +-(void)checkCategoriesIndex { + + if (categoriesSelectedIndex == 0) { + [UIView animateWithDuration:0.2 animations:^ { + self.socialVC.view.alpha = 1; + self.changelogVC.view.alpha = 0; + self.backupVC.view.alpha = 0; + self.tweakVC.view.alpha = 0; + self.profileVC.view.alpha = 0; + self.crewVC.view.alpha = 0; + }]; + } else if (categoriesSelectedIndex == 1) { + [UIView animateWithDuration:0.2 animations:^ { + self.socialVC.view.alpha = 0; + self.changelogVC.view.alpha = 1; + self.backupVC.view.alpha = 0; + self.tweakVC.view.alpha = 0; + self.profileVC.view.alpha = 0; + self.crewVC.view.alpha = 0; + }]; + } else if (categoriesSelectedIndex == 2) { + [UIView animateWithDuration:0.2 animations:^ { + self.socialVC.view.alpha = 0; + self.changelogVC.view.alpha = 0; + self.backupVC.view.alpha = 1; + self.tweakVC.view.alpha = 0; + self.profileVC.view.alpha = 0; + self.crewVC.view.alpha = 0; + }]; + } else if (categoriesSelectedIndex == 3) { + [UIView animateWithDuration:0.2 animations:^ { + self.socialVC.view.alpha = 0; + self.changelogVC.view.alpha = 0; + self.backupVC.view.alpha = 0; + self.tweakVC.view.alpha = 1; + self.profileVC.view.alpha = 0; + self.crewVC.view.alpha = 0; + }]; + } else if (categoriesSelectedIndex == 4) { + [UIView animateWithDuration:0.2 animations:^ { + self.socialVC.view.alpha = 0; + self.changelogVC.view.alpha = 0; + self.backupVC.view.alpha = 0; + self.tweakVC.view.alpha = 0; + self.profileVC.view.alpha = 1; + self.crewVC.view.alpha = 0; + }]; + } else if (categoriesSelectedIndex == 5) { + [UIView animateWithDuration:0.2 animations:^ { + self.socialVC.view.alpha = 0; + self.changelogVC.view.alpha = 0; + self.backupVC.view.alpha = 0; + self.tweakVC.view.alpha = 0; + self.profileVC.view.alpha = 0; + self.crewVC.view.alpha = 1; + }]; + } + +} + + +-(void)layoutSocialVC { + + self.socialVC = [[SocialViewController alloc] init]; + [self addChildViewController:self.socialVC]; + [self.view addSubview:self.socialVC.view]; + + self.socialVC.view.translatesAutoresizingMaskIntoConstraints = NO; + [self.socialVC.view.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.socialVC.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.socialVC.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.socialVC.view.bottomAnchor constraintEqualToAnchor:self.collectionView.topAnchor constant:-10].active = YES; +} + + +-(void)layoutChangelogVC { + + self.changelogVC = [[ChangelogViewController alloc] init]; + self.changelogVC.view.alpha = 0; + [self addChildViewController:self.changelogVC]; + [self.view addSubview:self.changelogVC.view]; + + self.changelogVC.view.translatesAutoresizingMaskIntoConstraints = NO; + [self.changelogVC.view.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.changelogVC.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.changelogVC.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.changelogVC.view.bottomAnchor constraintEqualToAnchor:self.collectionView.topAnchor constant:-10].active = YES; +} + + +-(void)layoutBackupVC { + + self.backupVC = [[BackupViewController alloc] init]; + self.backupVC.view.alpha = 0; + [self addChildViewController:self.backupVC]; + [self.view addSubview:self.backupVC.view]; + + self.backupVC.view.translatesAutoresizingMaskIntoConstraints = NO; + [self.backupVC.view.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.backupVC.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.backupVC.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.backupVC.view.bottomAnchor constraintEqualToAnchor:self.collectionView.topAnchor constant:-10].active = YES; + +} + + +-(void)layoutTweakVC { + + self.tweakVC = [[TweakViewController alloc] init]; + self.tweakVC.view.alpha = 0; + [self addChildViewController:self.tweakVC]; + [self.view addSubview:self.tweakVC.view]; + + self.tweakVC.view.translatesAutoresizingMaskIntoConstraints = NO; + [self.tweakVC.view.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.tweakVC.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.tweakVC.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.tweakVC.view.bottomAnchor constraintEqualToAnchor:self.collectionView.topAnchor constant:-10].active = YES; +} + + +-(void)layoutProfileVC { + + self.profileVC = [[ProfileViewController alloc] init]; + self.profileVC.view.alpha = 0; + [self addChildViewController:self.profileVC]; + [self.view addSubview:self.profileVC.view]; + + self.profileVC.view.translatesAutoresizingMaskIntoConstraints = NO; + [self.profileVC.view.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.profileVC.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.profileVC.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.profileVC.view.bottomAnchor constraintEqualToAnchor:self.collectionView.topAnchor constant:-10].active = YES; + +} + + +-(void)layoutCrewVC { + + self.crewVC = [[CrewViewController alloc] init]; + self.crewVC.view.alpha = 0; + [self addChildViewController:self.crewVC]; + [self.view addSubview:self.crewVC.view]; + + self.crewVC.view.translatesAutoresizingMaskIntoConstraints = NO; + [self.crewVC.view.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.crewVC.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.crewVC.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.crewVC.view.bottomAnchor constraintEqualToAnchor:self.collectionView.topAnchor constant:-10].active = YES; + +} + + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:(BOOL)animated]; + [self resetIndex]; +} + + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +@end diff --git a/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCell.h b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCell.h new file mode 100644 index 0000000..af3811c --- /dev/null +++ b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCell.h @@ -0,0 +1,7 @@ +#import +#import "ConstraintExtension.h" + +@interface TDEmojiPickerCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *emojiLabel; +@end diff --git a/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCell.m b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCell.m new file mode 100644 index 0000000..9221023 --- /dev/null +++ b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCell.m @@ -0,0 +1,31 @@ +#import "TDEmojiPickerCell.h" + +@implementation TDEmojiPickerCell + +- (instancetype)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] initWithFrame:self.contentView.bounds]; + [self.contentView addSubview:self.baseView]; + + self.emojiLabel = [[UILabel alloc] init]; + self.emojiLabel.textAlignment = NSTextAlignmentCenter; + self.emojiLabel.font = [UIFont systemFontOfSize:30]; + [self.baseView addSubview:self.emojiLabel]; + + [self.emojiLabel x:self.baseView.centerXAnchor y:self.baseView.centerYAnchor]; + + } + return self; +} + + +-(void)prepareForReuse { + [super prepareForReuse]; + self.emojiLabel.text = nil; +} + + +@end diff --git a/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCellHeaderView.h b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCellHeaderView.h new file mode 100644 index 0000000..999f2da --- /dev/null +++ b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCellHeaderView.h @@ -0,0 +1,8 @@ +#import + +@interface TDEmojiPickerCellHeaderView : UICollectionReusableView +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UILabel *headerLabel; +@end + + diff --git a/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCellHeaderView.m b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCellHeaderView.m new file mode 100644 index 0000000..e9f9faa --- /dev/null +++ b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerCellHeaderView.m @@ -0,0 +1,28 @@ +#import "TDEmojiPickerCellHeaderView.h" + +@implementation TDEmojiPickerCellHeaderView + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] initWithFrame:self.bounds]; + self.baseView.clipsToBounds = YES; + [self addSubview:self.baseView]; + + + self.headerLabel = [[UILabel alloc] init]; + self.headerLabel.textColor = UIColor.tertiaryLabelColor; + self.headerLabel.font = [UIFont boldSystemFontOfSize:18]; + [self.baseView addSubview:self.headerLabel]; + + self.headerLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.headerLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = YES; + [self.headerLabel.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:20].active = YES; + + } + return self; +} + +@end diff --git a/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerViewController.h b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerViewController.h new file mode 100644 index 0000000..6c3a493 --- /dev/null +++ b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerViewController.h @@ -0,0 +1,21 @@ +#import +#import "ConstraintExtension.h" +#import "TDEmojiPickerCell.h" +#import "TDEmojiPickerCellHeaderView.h" +#import "PrivateBlurEffect.h" + +@protocol TDEmojiPickerProtocol +@required +-(void)didSelectEmoji:(NSString *)emoji; +-(void)didDismissedEmojiPicker; +@end + +@interface TDEmojiPickerViewController : UIViewController +@property (nonatomic, strong) _UIBackdropViewSettings *blurSetting; +@property (nonatomic, strong) _UIBackdropView *blurView; +@property (nonatomic, retain) UIVisualEffectView *grabberView; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSMutableArray *emojiArray; +@property(nonatomic,assign)id delegate; +@property (nonatomic) BOOL didSelectEmoji; +@end diff --git a/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerViewController.m b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerViewController.m new file mode 100644 index 0000000..a78cec7 --- /dev/null +++ b/libTitanD3vUniversal/EmojiPicker/TDEmojiPickerViewController.m @@ -0,0 +1,134 @@ +#import "TDEmojiPickerViewController.h" + +@implementation TDEmojiPickerViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.clearColor; + + self.blurSetting = [_UIBackdropViewSettings settingsForStyle:2]; + self.blurView = [[_UIBackdropView alloc] initWithSettings:self.blurSetting]; + self.blurView.frame = self.view.bounds; + [self.view insertSubview:self.blurView atIndex:0]; + + + NSString *myFile = @"/Library/Application Support/TitanKit.bundle/Emoji/Emoji.plist"; + self.emojiArray = [[NSMutableArray alloc] initWithContentsOfFile:myFile]; + + [self layoutGrabberView]; + [self layoutCollectionView]; +} + + +-(void)layoutGrabberView { + + self.grabberView = [[UIVisualEffectView alloc] init]; + self.grabberView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemMaterial]; + self.grabberView.layer.cornerRadius = 3; + self.grabberView.clipsToBounds = YES; + [self.view addSubview:self.grabberView]; + + [self.grabberView size:CGSizeMake(40, 6)]; + [self.grabberView x:self.view.centerXAnchor]; + [self.grabberView top:self.view.topAnchor padding:10]; +} + + +-(void)layoutCollectionView { + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[TDEmojiPickerCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.collectionView registerClass:[TDEmojiPickerCellHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView"]; + [self.view addSubview:self.collectionView]; + + [self.collectionView top:self.grabberView.bottomAnchor padding:20]; + [self.collectionView bottom:self.view.bottomAnchor padding:-20]; + [self.collectionView leading:self.view.leadingAnchor padding:0]; + [self.collectionView trailing:self.view.trailingAnchor padding:0]; + + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; +} + + +- (NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView { + return self.emojiArray.count; +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section { + return CGSizeMake(self.view.frame.size.width, 45); +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return [[[self.emojiArray objectAtIndex: section] objectForKey:@"Emojis"] count]; +} + + +-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + UICollectionReusableView *reusableview = nil; + + if (kind == UICollectionElementKindSectionHeader) { + + TDEmojiPickerCellHeaderView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeaderView" forIndexPath:indexPath]; + headerView.headerLabel.text = [[self.emojiArray objectAtIndex:indexPath.section] objectForKey: @"Title"]; + reusableview = headerView; + } + + return reusableview; + +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + TDEmojiPickerCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + cell.emojiLabel.text = [[[self.emojiArray objectAtIndex: indexPath.section] objectForKey: @"Emojis"] objectAtIndex: indexPath.row]; + + return cell; + +} + + +- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { + return UIEdgeInsetsMake(0,20,0,20); +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ + return CGSizeMake(self.view.frame.size.width/8, self.view.frame.size.width/8); +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + self.didSelectEmoji = YES; + [self.delegate didSelectEmoji:[[[self.emojiArray objectAtIndex: indexPath.section] objectForKey: @"Emojis"] objectAtIndex: indexPath.row]]; + [self dismissVC]; +} + + +-(void)dismissVC { + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + + if (!self.didSelectEmoji) { + [self.delegate didDismissedEmojiPicker]; + } +} + +@end diff --git a/libTitanD3vUniversal/ExternalController/TDExternalController.h b/libTitanD3vUniversal/ExternalController/TDExternalController.h new file mode 100644 index 0000000..770905d --- /dev/null +++ b/libTitanD3vUniversal/ExternalController/TDExternalController.h @@ -0,0 +1,20 @@ + +#import +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "TDUtilities.h" +#import "GlobalPrefs.h" +#import "TDGridCell.h" + +@interface TDExternalController : PSListController + +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (nonatomic, retain) UIColor *navigationBarColour; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *backgroundColour; +@property (nonatomic, retain) UIColor *cellsColour; +@property (nonatomic, retain) UIColor *labelColour; + +@end diff --git a/libTitanD3vUniversal/ExternalController/TDExternalController.m b/libTitanD3vUniversal/ExternalController/TDExternalController.m new file mode 100644 index 0000000..8f45513 --- /dev/null +++ b/libTitanD3vUniversal/ExternalController/TDExternalController.m @@ -0,0 +1,151 @@ +#import "TDExternalController.h" + +@implementation TDExternalController + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + self.navigationBarColour = [[TDAppearance sharedInstance] navigationBarColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.backgroundColour = [[TDAppearance sharedInstance] backgroundColour]; + self.cellsColour = [[TDAppearance sharedInstance] cellColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = self.tintColour; + + + UINavigationBar *bar = self.navigationController.navigationController.navigationBar; + bar.barTintColor = self.navigationBarColour; + bar.tintColor = self.tintColour; + [[UIButton appearance]setTintColor:self.tintColour]; + self.view.tintColor = self.tintColour; + + UITableView *tableView = self.view.subviews[0]; + tableView.backgroundColor = self.backgroundColour; + [tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + [tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES]; + + + [[UILabel appearance] setTextColor:self.labelColour]; + +} + + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [[UINavigationBar appearance] tintColor]; + + UINavigationBar *bar = self.navigationController.navigationController.navigationBar; + bar.tintColor = nil; + bar.barTintColor = nil; + self.view.tintColor = nil; + [[UIButton appearance]setTintColor:nil]; + [[UILabel appearance] setTextColor:nil]; + +} + + +-(void)tableView:(UITableView*)tableView willDisplayCell:(PSTableCell*)cell forRowAtIndexPath:(NSIndexPath*)indexPath{ + + UIBezierPath *maskPath; + if ([self rowsForGroup:indexPath.section] == 1) { + maskPath=[UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight|UIRectCornerBottomLeft|UIRectCornerBottomRight cornerRadii:[self cornerRadiiForSection:indexPath.section]]; + } else if (indexPath.row == 0) { + maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:UIRectCornerTopLeft| UIRectCornerTopRight cornerRadii:[self cornerRadiiForSection:indexPath.section]]; + } else if (indexPath.row == [self rowsForGroup:indexPath.section] - 1) { + maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerBottomRight cornerRadii:[self cornerRadiiForSection:indexPath.section]]; + } else { + maskPath = [UIBezierPath bezierPathWithRect:cell.bounds]; + } + + CAShapeLayer *maskLayer = [CAShapeLayer layer]; + maskLayer.frame = cell.bounds; + maskLayer.path = maskPath.CGPath; + cell.layer.mask = maskLayer; + cell.layer.shadowPath = maskPath.CGPath; + + cell.backgroundColor = self.cellsColour; +} + + +- (CGSize)cornerRadiiForSection:(NSInteger)section{ + return CGSizeMake(10, 10); +} + + +- (void)openController:(GridButton *)sender { + + invokeHapticFeedback(); + + NSString *className = sender.identifier; + PSListController *controller = [[NSClassFromString(className) alloc] init]; + [[self navigationController] pushViewController:controller animated:YES]; +} + + +- (id)readPreferenceValue:(PSSpecifier*)specifier { + NSString *path = [NSString stringWithFormat:@"/User/Library/Preferences/%@.plist", specifier.properties[@"defaults"]]; + NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:path]; + return (plist[specifier.properties[@"key"]]) ?: specifier.properties[@"default"]; +} + + +- (void)setPreferenceValue:(id)value specifier:(PSSpecifier*)specifier { + NSString *path = [NSString stringWithFormat:@"/User/Library/Preferences/%@.plist", specifier.properties[@"defaults"]]; + NSMutableDictionary *plist = [NSMutableDictionary dictionaryWithContentsOfFile:path] ?: [NSMutableDictionary new]; + plist[specifier.properties[@"key"]] = value; + [plist writeToFile:path atomically:true]; + CFStringRef notificationName = (__bridge CFStringRef)specifier.properties[@"PostNotification"]; + if (notificationName) { + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), notificationName, NULL, NULL, true); + } +} + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/libTitanD3vUniversal/ExtraTools/Macros.h b/libTitanD3vUniversal/ExtraTools/Macros.h new file mode 100644 index 0000000..802c6b5 --- /dev/null +++ b/libTitanD3vUniversal/ExtraTools/Macros.h @@ -0,0 +1,10 @@ +#define MAIN_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width +#define MAIN_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height +#define iPhone_SE ([[UIScreen mainScreen] bounds].size.height == 568) // iPhone SE +#define iPhone_6_8 ([[UIScreen mainScreen] bounds].size.height == 667) // iPhone 6, 6s, 7 and 8 +#define iPhone_6_8_Plus ([[UIScreen mainScreen] bounds].size.height == 736) // iPhone 6, 6s, 7 and 8 Plus +#define iPhone_X_XS_11Pro ([[UIScreen mainScreen] bounds].size.height == 812) // iPhone X, XS, 11 Pro +#define iPhone_XR_XS_11Pro ([[UIScreen mainScreen] bounds].size.height == 896) // iPhone XR, XS Max, 11 Pro Max +#define iPhone_12_Pro ([[UIScreen mainScreen] bounds].size.height == 844) // iPhone 12 & 12 Pro +#define iPhone_12_mini ([[UIScreen mainScreen] bounds].size.height == 780) // iPhone 12 mini +#define iPhone_12_Pro_Max ([[UIScreen mainScreen] bounds].size.height == 926) // iPhone 12 Pro Max \ No newline at end of file diff --git a/libTitanD3vUniversal/ExtraTools/MobileGestalt.h b/libTitanD3vUniversal/ExtraTools/MobileGestalt.h new file mode 100644 index 0000000..fa830d5 --- /dev/null +++ b/libTitanD3vUniversal/ExtraTools/MobileGestalt.h @@ -0,0 +1,173 @@ +#ifndef LIBMOBILEGESTALT_H_ +#define LIBMOBILEGESTALT_H_ + +#include + +#if __cplusplus +extern "C" { +#endif + +#pragma mark - API + + CFPropertyListRef MGCopyAnswer(CFStringRef property); + + Boolean MGGetBoolAnswer(CFStringRef property); + + CFPropertyListRef MGCopyMultipleAnswers(CFArrayRef questions, int __unknown0); + + int MGSetAnswer(CFStringRef question, CFTypeRef answer); + +#pragma mark - Identifying Information + + static const CFStringRef kMGDiskUsage = CFSTR("DiskUsage"); + static const CFStringRef kMGModelNumber = CFSTR("ModelNumber"); + static const CFStringRef kMGSIMTrayStatus = CFSTR("SIMTrayStatus"); + static const CFStringRef kMGSerialNumber = CFSTR("SerialNumber"); + static const CFStringRef kMGMLBSerialNumber = CFSTR("MLBSerialNumber"); + static const CFStringRef kMGUniqueDeviceID = CFSTR("UniqueDeviceID"); + static const CFStringRef kMGUniqueDeviceIDData = CFSTR("UniqueDeviceIDData"); + static const CFStringRef kMGUniqueChipID = CFSTR("UniqueChipID"); + static const CFStringRef kMGInverseDeviceID = CFSTR("InverseDeviceID"); + static const CFStringRef kMGDiagnosticsData = CFSTR("DiagData"); + static const CFStringRef kMGDieID = CFSTR("DieId"); + static const CFStringRef kMGCPUArchitecture = CFSTR("CPUArchitecture"); + static const CFStringRef kMGPartitionType = CFSTR("PartitionType"); + static const CFStringRef kMGUserAssignedDeviceName = CFSTR("UserAssignedDeviceName"); + +#pragma mark - Bluetooth Information + + static const CFStringRef kMGBluetoothAddress = CFSTR("BluetoothAddress"); + +#pragma mark - Battery Information + + static const CFStringRef kMGRequiredBatteryLevelForSoftwareUpdate = CFSTR("RequiredBatteryLevelForSoftwareUpdate"); + static const CFStringRef kMGBatteryIsFullyCharged = CFSTR("BatteryIsFullyCharged"); + static const CFStringRef kMGBatteryIsCharging = CFSTR("BatteryIsCharging"); + static const CFStringRef kMGBatteryCurrentCapacity = CFSTR("BatteryCurrentCapacity"); + static const CFStringRef kMGExternalPowerSourceConnected = CFSTR("ExternalPowerSourceConnected"); + +#pragma mark - Baseband Information + +static const CFStringRef kMGBasebandSerialNumber = CFSTR("BasebandSerialNumber"); + static const CFStringRef kMGBasebandCertId = CFSTR("BasebandCertId"); + static const CFStringRef kMGBasebandChipId = CFSTR("BasebandChipId"); + static const CFStringRef kMGBasebandFirmwareManifestData = CFSTR("BasebandFirmwareManifestData"); + static const CFStringRef kMGBasebandFirmwareVersion = CFSTR("BasebandFirmwareVersion"); + static const CFStringRef kMGBasebandKeyHashInformation = CFSTR("BasebandKeyHashInformation"); + +#pragma mark - Telephony Information + + static const CFStringRef kMGCarrierBundleInfo = CFSTR("CarrierBundleInfoArray"); + static const CFStringRef kMGCarrierInstallCapability = CFSTR("CarrierInstallCapability"); + static const CFStringRef kMGInternationalMobileEquipmentIdentity = CFSTR("InternationalMobileEquipmentIdentity"); + static const CFStringRef kMGMobileSubscriberCountryCode = CFSTR("MobileSubscriberCountryCode"); + static const CFStringRef kMGMobileSubscriberNetworkCode = CFSTR("MobileSubscriberNetworkCode"); + +#pragma mark - Device Information + + static const CFStringRef kMGChipID = CFSTR("ChipID"); + static const CFStringRef kMGComputerName = CFSTR("ComputerName"); + static const CFStringRef kMGDeviceVariant = CFSTR("DeviceVariant"); + static const CFStringRef kMGHWModel = CFSTR("HWModelStr"); + static const CFStringRef kMGBoardId = CFSTR("BoardId"); + static const CFStringRef kMGHardwarePlatform = CFSTR("HardwarePlatform"); + static const CFStringRef kMGDeviceName = CFSTR("DeviceName"); + static const CFStringRef kMGDeviceColor = CFSTR("DeviceColor"); + static const CFStringRef kMGDeviceClassNumber = CFSTR("DeviceClassNumber"); + static const CFStringRef kMGDeviceClass = CFSTR("DeviceClass"); + static const CFStringRef kMGBuildVersion = CFSTR("BuildVersion"); + static const CFStringRef kMGProductName = CFSTR("ProductName"); + static const CFStringRef kMGProductType = CFSTR("ProductType"); + static const CFStringRef kMGProductVersion = CFSTR("ProductVersion"); + static const CFStringRef kMGFirmwareNonce = CFSTR("FirmwareNonce"); + static const CFStringRef kMGFirmwareVersion = CFSTR("FirmwareVersion"); + static const CFStringRef kMGFirmwarePreflightInfo = CFSTR("FirmwarePreflightInfo"); + static const CFStringRef kMGIntegratedCircuitCardIdentifier = CFSTR("IntegratedCircuitCardIdentifier"); + static const CFStringRef kMGAirplaneMode = CFSTR("AirplaneMode"); + static const CFStringRef kMGAllowYouTube = CFSTR("AllowYouTube"); + static const CFStringRef kMGAllowYouTubePlugin = CFSTR("AllowYouTubePlugin"); + static const CFStringRef kMGMinimumSupportediTunesVersion = CFSTR("MinimumSupportediTunesVersion"); + static const CFStringRef kMGProximitySensorCalibration = CFSTR("ProximitySensorCalibration"); + static const CFStringRef kMGRegionCode = CFSTR("RegionCode"); + static const CFStringRef kMGRegionInfo = CFSTR("RegionInfo"); + static const CFStringRef kMGRegulatoryIdentifiers = CFSTR("RegulatoryIdentifiers"); + static const CFStringRef kMGSBAllowSensitiveUI = CFSTR("SBAllowSensitiveUI"); + static const CFStringRef kMGSBCanForceDebuggingInfo = CFSTR("SBCanForceDebuggingInfo"); + static const CFStringRef kMGSDIOManufacturerTuple = CFSTR("SDIOManufacturerTuple"); + static const CFStringRef kMGSDIOProductInfo = CFSTR("SDIOProductInfo"); + static const CFStringRef kMGShouldHactivate = CFSTR("ShouldHactivate"); + static const CFStringRef kMGSigningFuse = CFSTR("SigningFuse"); + static const CFStringRef kMGSoftwareBehavior = CFSTR("SoftwareBehavior"); + static const CFStringRef kMGSoftwareBundleVersion = CFSTR("SoftwareBundleVersion"); + static const CFStringRef kMGSupportedDeviceFamilies = CFSTR("SupportedDeviceFamilies"); + static const CFStringRef kMSupportedKeyboards = CFSTR("SupportedKeyboards"); + static const CFStringRef kMGTotalSystemAvailable = CFSTR("TotalSystemAvailable"); + +#pragma mark - Capability Information + + static const CFStringRef kMGAllDeviceCapabilities = CFSTR("AllDeviceCapabilities"); + static const CFStringRef kMGAppleInternalInstallCapability = CFSTR("AppleInternalInstallCapability"); + static const CFStringRef kMGExternalChargeCapability = CFSTR("ExternalChargeCapability"); + static const CFStringRef kMGForwardCameraCapability = CFSTR("ForwardCameraCapability"); + static const CFStringRef kMGPanoramaCameraCapability = CFSTR("PanoramaCameraCapability"); + static const CFStringRef kMGRearCameraCapability = CFSTR("RearCameraCapability"); + static const CFStringRef kMGHasAllFeaturesCapability = CFSTR("HasAllFeaturesCapability"); + static const CFStringRef kMGHasBaseband = CFSTR("HasBaseband"); + static const CFStringRef kMGHasInternalSettingsBundle = CFSTR("HasInternalSettingsBundle"); + static const CFStringRef kMGHasSpringBoard = CFSTR("HasSpringBoard"); + static const CFStringRef kMGInternalBuild = CFSTR("InternalBuild"); + static const CFStringRef kMGIsSimulator = CFSTR("IsSimulator"); + static const CFStringRef kMGIsThereEnoughBatteryLevelForSoftwareUpdate = CFSTR("IsThereEnoughBatteryLevelForSoftwareUpdate"); + static const CFStringRef kMGIsUIBuild = CFSTR("IsUIBuild"); + +#pragma mark - Regional Behaviour + + static const CFStringRef kMGRegionalBehaviorAll = CFSTR("RegionalBehaviorAll"); + static const CFStringRef kMGRegionalBehaviorChinaBrick = CFSTR("RegionalBehaviorChinaBrick"); + static const CFStringRef kMGRegionalBehaviorEUVolumeLimit = CFSTR("RegionalBehaviorEUVolumeLimit"); + static const CFStringRef kMGRegionalBehaviorGB18030 = CFSTR("RegionalBehaviorGB18030"); + static const CFStringRef kMGRegionalBehaviorGoogleMail = CFSTR("RegionalBehaviorGoogleMail"); + static const CFStringRef kMGRegionalBehaviorNTSC = CFSTR("RegionalBehaviorNTSC"); + static const CFStringRef kMGRegionalBehaviorNoPasscodeLocationTiles = CFSTR("RegionalBehaviorNoPasscodeLocationTiles"); + static const CFStringRef kMGRegionalBehaviorNoVOIP = CFSTR("RegionalBehaviorNoVOIP"); + static const CFStringRef kMGRegionalBehaviorNoWiFi = CFSTR("RegionalBehaviorNoWiFi"); + static const CFStringRef kMGRegionalBehaviorShutterClick = CFSTR("RegionalBehaviorShutterClick"); + static const CFStringRef kMGRegionalBehaviorVolumeLimit = CFSTR("RegionalBehaviorVolumeLimit"); + +#pragma mark - Wireless Information + + static const CFStringRef kMGActiveWirelessTechnology = CFSTR("ActiveWirelessTechnology"); + static const CFStringRef kMGWifiAddress = CFSTR("WifiAddress"); + static const CFStringRef kMGWifiAddressData = CFSTR("WifiAddressData"); + static const CFStringRef kMGWifiVendor = CFSTR("WifiVendor"); + +#pragma mark - FaceTime Information + + static const CFStringRef kMGFaceTimeBitRate2G = CFSTR("FaceTimeBitRate2G"); + static const CFStringRef kMGFaceTimeBitRate3G = CFSTR("FaceTimeBitRate3G"); + static const CFStringRef kMGFaceTimeBitRateLTE = CFSTR("FaceTimeBitRateLTE"); + static const CFStringRef kMGFaceTimeBitRateWiFi = CFSTR("FaceTimeBitRateWiFi"); + static const CFStringRef kMGFaceTimeDecodings = CFSTR("FaceTimeDecodings"); + static const CFStringRef kMGFaceTimeEncodings = CFSTR("FaceTimeEncodings"); + static const CFStringRef kMGFaceTimePreferredDecoding = CFSTR("FaceTimePreferredDecoding"); + static const CFStringRef kMGFaceTimePreferredEncoding = CFSTR("FaceTimePreferredEncoding"); + +#pragma mark - More Device Capabilities + + static const CFStringRef kMGDeviceSupportsFaceTime = CFSTR("DeviceSupportsFaceTime"); + static const CFStringRef kMGDeviceSupportsTethering = CFSTR("DeviceSupportsTethering"); + static const CFStringRef kMGDeviceSupportsSimplisticRoadMesh = CFSTR("DeviceSupportsSimplisticRoadMesh"); + static const CFStringRef kMGDeviceSupportsNavigation = CFSTR("DeviceSupportsNavigation"); + static const CFStringRef kMGDeviceSupportsLineIn = CFSTR("DeviceSupportsLineIn"); + static const CFStringRef kMGDeviceSupports9Pin = CFSTR("DeviceSupports9Pin"); + static const CFStringRef kMGDeviceSupports720p = CFSTR("DeviceSupports720p"); + static const CFStringRef kMGDeviceSupports4G = CFSTR("DeviceSupports4G"); + static const CFStringRef kMGDeviceSupports3DMaps = CFSTR("DeviceSupports3DMaps"); + static const CFStringRef kMGDeviceSupports3DImagery = CFSTR("DeviceSupports3DImagery"); + static const CFStringRef kMGDeviceSupports1080p = CFSTR("DeviceSupports1080p"); + +#if __cplusplus +} +#endif + +#endif diff --git a/libTitanD3vUniversal/ExtraTools/NSTask.h b/libTitanD3vUniversal/ExtraTools/NSTask.h new file mode 100644 index 0000000..4808dba --- /dev/null +++ b/libTitanD3vUniversal/ExtraTools/NSTask.h @@ -0,0 +1,49 @@ +#import +#import + +@class NSArray, NSDictionary, NSString; + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, NSTaskTerminationReason) { + NSTaskTerminationReasonExit = 1, + NSTaskTerminationReasonUncaughtSignal = 2 +} NS_ENUM_AVAILABLE(10_6, NA); + +@interface NSTask : NSObject +- (instancetype)init NS_DESIGNATED_INITIALIZER; +@property (nullable, copy) NSURL *executableURL API_AVAILABLE(macos(10.13)) API_UNAVAILABLE(ios, watchos, tvos); +@property (nullable, copy) NSArray *arguments; +@property (nullable, copy) NSDictionary *environment; +@property (nullable, copy) NSURL *currentDirectoryURL API_AVAILABLE(macos(10.13)) API_UNAVAILABLE(ios, watchos, tvos); +@property (nullable, retain) id standardInput; +@property (nullable, retain) id standardOutput; +@property (nullable, retain) id standardError; +- (BOOL)launchAndReturnError:(out NSError **_Nullable)error API_AVAILABLE(macos(10.13)) API_UNAVAILABLE(ios, watchos, tvos); +- (void)interrupt; +- (void)terminate; +- (BOOL)suspend; +- (BOOL)resume; +@property (readonly) int processIdentifier; +@property (readonly, getter=isRunning) BOOL running; +@property (readonly) int terminationStatus; +@property (readonly) NSTaskTerminationReason terminationReason API_AVAILABLE(macos(10.6)) API_UNAVAILABLE(ios, watchos, tvos); +@property (nullable, copy) void (^terminationHandler)(NSTask *) API_AVAILABLE(macos(10.7)) API_UNAVAILABLE(ios, watchos, tvos); +@property NSQualityOfService qualityOfService API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0)); // read-only after the task is launched +@end + +@interface NSTask (NSTaskConveniences) ++ (nullable NSTask *)launchedTaskWithExecutableURL:(NSURL *)url arguments:(NSArray *)arguments error:(out NSError ** _Nullable)error terminationHandler:(void (^_Nullable)(NSTask *))terminationHandler API_AVAILABLE(macos(10.13)) API_UNAVAILABLE(ios, watchos, tvos); +- (void)waitUntilExit; +@end + +@interface NSTask (NSDeprecated) +@property (nullable, copy) NSString *launchPath; +@property (copy) NSString *currentDirectoryPath; +- (void)launch; ++ (NSTask *)launchedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments; +@end + +FOUNDATION_EXPORT NSNotificationName const NSTaskDidTerminateNotification; + +NS_ASSUME_NONNULL_END diff --git a/libTitanD3vUniversal/ExtraTools/Prefix.h b/libTitanD3vUniversal/ExtraTools/Prefix.h new file mode 100644 index 0000000..701a41f --- /dev/null +++ b/libTitanD3vUniversal/ExtraTools/Prefix.h @@ -0,0 +1,12 @@ +#include +#include + +#ifndef __APPLE__ +int __isOSVersionAtLeast(int major, int minor, int patch) { + NSOperatingSystemVersion version; + version.majorVersion = major; + version.minorVersion = minor; + version.patchVersion = patch; + return [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:version]; +} +#endif \ No newline at end of file diff --git a/libTitanD3vUniversal/ExtraTools/Reachability.h b/libTitanD3vUniversal/ExtraTools/Reachability.h new file mode 100644 index 0000000..3935d9f --- /dev/null +++ b/libTitanD3vUniversal/ExtraTools/Reachability.h @@ -0,0 +1,52 @@ +#import +#import + +FOUNDATION_EXPORT double ReachabilityVersionNumber; +FOUNDATION_EXPORT const unsigned char ReachabilityVersionString[]; + +#ifndef NS_ENUM +#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type +#endif + +extern NSString *const kReachabilityChangedNotification; + +typedef NS_ENUM(NSInteger, NetworkStatus) { + NotReachable = 0, + ReachableViaWiFi = 2, + ReachableViaWWAN = 1 +}; + +@class Reachability; + +typedef void (^NetworkReachable)(Reachability * reachability); +typedef void (^NetworkUnreachable)(Reachability * reachability); +typedef void (^NetworkReachability)(Reachability * reachability, SCNetworkConnectionFlags flags); + + +@interface Reachability : NSObject +@property (nonatomic, copy) NetworkReachable reachableBlock; +@property (nonatomic, copy) NetworkUnreachable unreachableBlock; +@property (nonatomic, copy) NetworkReachability reachabilityBlock; +@property (nonatomic, assign) BOOL reachableOnWWAN; ++(instancetype)reachabilityWithHostname:(NSString*)hostname; ++(instancetype)reachabilityWithHostName:(NSString*)hostname; ++(instancetype)reachabilityForInternetConnection; ++(instancetype)reachabilityWithAddress:(void *)hostAddress; ++(instancetype)reachabilityForLocalWiFi; ++(instancetype)reachabilityWithURL:(NSURL*)url; +-(instancetype)initWithReachabilityRef:(SCNetworkReachabilityRef)ref; +-(BOOL)startNotifier; +-(void)stopNotifier; +-(BOOL)isReachable; +-(BOOL)isReachableViaWWAN; +-(BOOL)isReachableViaWiFi; +-(BOOL)isConnectionRequired; +-(BOOL)connectionRequired; +-(BOOL)isConnectionOnDemand; +-(BOOL)isInterventionRequired; +-(NetworkStatus)currentReachabilityStatus; +-(SCNetworkReachabilityFlags)reachabilityFlags; +-(NSString*)currentReachabilityString; +-(NSString*)currentReachabilityFlags; + +@end diff --git a/libTitanD3vUniversal/ExtraTools/Reachability.m b/libTitanD3vUniversal/ExtraTools/Reachability.m new file mode 100644 index 0000000..6851450 --- /dev/null +++ b/libTitanD3vUniversal/ExtraTools/Reachability.m @@ -0,0 +1,482 @@ +#import "Reachability.h" + +#import +#import +#import +#import +#import +#import + + +NSString *const kReachabilityChangedNotification = @"kReachabilityChangedNotification"; + + +@interface Reachability () + +@property (nonatomic, assign) SCNetworkReachabilityRef reachabilityRef; +@property (nonatomic, strong) dispatch_queue_t reachabilitySerialQueue; +@property (nonatomic, strong) id reachabilityObject; + +-(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags; +-(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags; + +@end + + +static NSString *reachabilityFlags(SCNetworkReachabilityFlags flags) +{ + return [NSString stringWithFormat:@"%c%c %c%c%c%c%c%c%c", +#if TARGET_OS_IPHONE + (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', +#else + 'X', +#endif + (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', + (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', + (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', + (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', + (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-']; +} + +// Start listening for reachability notifications on the current run loop +static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) +{ +#pragma unused (target) + + Reachability *reachability = ((__bridge Reachability*)info); + + // We probably don't need an autoreleasepool here, as GCD docs state each queue has its own autorelease pool, + // but what the heck eh? + @autoreleasepool + { + [reachability reachabilityChanged:flags]; + } +} + + +@implementation Reachability + +#pragma mark - Class Constructor Methods + ++(instancetype)reachabilityWithHostName:(NSString*)hostname +{ + return [Reachability reachabilityWithHostname:hostname]; +} + ++(instancetype)reachabilityWithHostname:(NSString*)hostname +{ + SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]); + if (ref) + { + id reachability = [[self alloc] initWithReachabilityRef:ref]; + + return reachability; + } + + return nil; +} + ++(instancetype)reachabilityWithAddress:(void *)hostAddress +{ + SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); + if (ref) + { + id reachability = [[self alloc] initWithReachabilityRef:ref]; + + return reachability; + } + + return nil; +} + ++(instancetype)reachabilityForInternetConnection +{ + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + + return [self reachabilityWithAddress:&zeroAddress]; +} + ++(instancetype)reachabilityForLocalWiFi +{ + struct sockaddr_in localWifiAddress; + bzero(&localWifiAddress, sizeof(localWifiAddress)); + localWifiAddress.sin_len = sizeof(localWifiAddress); + localWifiAddress.sin_family = AF_INET; + // IN_LINKLOCALNETNUM is defined in as 169.254.0.0 + localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); + + return [self reachabilityWithAddress:&localWifiAddress]; +} + ++(instancetype)reachabilityWithURL:(NSURL*)url +{ + id reachability; + + NSString *host = url.host; + BOOL isIpAddress = [self isIpAddress:host]; + + if (isIpAddress) + { + NSNumber *port = url.port ?: [url.scheme isEqualToString:@"https"] ? @(443) : @(80); + + struct sockaddr_in address; + address.sin_len = sizeof(address); + address.sin_family = AF_INET; + address.sin_port = htons([port intValue]); + address.sin_addr.s_addr = inet_addr([host UTF8String]); + + reachability = [self reachabilityWithAddress:&address]; + } + else + { + reachability = [self reachabilityWithHostname:host]; + } + + return reachability; +} + ++(BOOL)isIpAddress:(NSString*)host +{ + struct in_addr pin; + return 1 == inet_aton([host UTF8String], &pin); +} + + +// Initialization methods + +-(instancetype)initWithReachabilityRef:(SCNetworkReachabilityRef)ref +{ + self = [super init]; + if (self != nil) + { + self.reachableOnWWAN = YES; + self.reachabilityRef = ref; + + // We need to create a serial queue. + // We allocate this once for the lifetime of the notifier. + + self.reachabilitySerialQueue = dispatch_queue_create("com.tonymillion.reachability", NULL); + } + + return self; +} + +-(void)dealloc +{ + [self stopNotifier]; + // [super dealloc]; + + if(self.reachabilityRef) + { + CFRelease(self.reachabilityRef); + self.reachabilityRef = nil; + } + + self.reachableBlock = nil; + self.unreachableBlock = nil; + self.reachabilityBlock = nil; + self.reachabilitySerialQueue = nil; +} + +#pragma mark - Notifier Methods + +// Notifier +// NOTE: This uses GCD to trigger the blocks - they *WILL NOT* be called on THE MAIN THREAD +// - In other words DO NOT DO ANY UI UPDATES IN THE BLOCKS. +// INSTEAD USE dispatch_async(dispatch_get_main_queue(), ^{UISTUFF}) (or dispatch_sync if you want) + +-(BOOL)startNotifier +{ + // allow start notifier to be called multiple times + if(self.reachabilityObject && (self.reachabilityObject == self)) + { + return YES; + } + + + SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL }; + context.info = (__bridge void *)self; + + if(SCNetworkReachabilitySetCallback(self.reachabilityRef, TMReachabilityCallback, &context)) + { + // Set it as our reachability queue, which will retain the queue + if(SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, self.reachabilitySerialQueue)) + { + // this should do a retain on ourself, so as long as we're in notifier mode we shouldn't disappear out from under ourselves + // woah + self.reachabilityObject = self; + return YES; + } + else + { +#ifdef DEBUG + NSLog(@"SCNetworkReachabilitySetDispatchQueue() failed: %s", SCErrorString(SCError())); +#endif + + // UH OH - FAILURE - stop any callbacks! + SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL); + } + } + else + { +#ifdef DEBUG + NSLog(@"SCNetworkReachabilitySetCallback() failed: %s", SCErrorString(SCError())); +#endif + } + + // if we get here we fail at the internet + self.reachabilityObject = nil; + return NO; +} + +-(void)stopNotifier +{ + // First stop, any callbacks! + SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL); + + // Unregister target from the GCD serial dispatch queue. + SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, NULL); + + self.reachabilityObject = nil; +} + +#pragma mark - reachability tests + +// This is for the case where you flick the airplane mode; +// you end up getting something like this: +//Reachability: WR ct----- +//Reachability: -- ------- +//Reachability: WR ct----- +//Reachability: -- ------- +// We treat this as 4 UNREACHABLE triggers - really apple should do better than this + +#define testcase (kSCNetworkReachabilityFlagsConnectionRequired | kSCNetworkReachabilityFlagsTransientConnection) + +-(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags +{ + BOOL connectionUP = YES; + + if(!(flags & kSCNetworkReachabilityFlagsReachable)) + connectionUP = NO; + + if( (flags & testcase) == testcase ) + connectionUP = NO; + +#if TARGET_OS_IPHONE + if(flags & kSCNetworkReachabilityFlagsIsWWAN) + { + // We're on 3G. + if(!self.reachableOnWWAN) + { + // We don't want to connect when on 3G. + connectionUP = NO; + } + } +#endif + + return connectionUP; +} + +-(BOOL)isReachable +{ + SCNetworkReachabilityFlags flags; + + if(!SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + return NO; + + return [self isReachableWithFlags:flags]; +} + +-(BOOL)isReachableViaWWAN +{ +#if TARGET_OS_IPHONE + + SCNetworkReachabilityFlags flags = 0; + + if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + // Check we're REACHABLE + if(flags & kSCNetworkReachabilityFlagsReachable) + { + // Now, check we're on WWAN + if(flags & kSCNetworkReachabilityFlagsIsWWAN) + { + return YES; + } + } + } +#endif + + return NO; +} + +-(BOOL)isReachableViaWiFi +{ + SCNetworkReachabilityFlags flags = 0; + + if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + // Check we're reachable + if((flags & kSCNetworkReachabilityFlagsReachable)) + { +#if TARGET_OS_IPHONE + // Check we're NOT on WWAN + if((flags & kSCNetworkReachabilityFlagsIsWWAN)) + { + return NO; + } +#endif + return YES; + } + } + + return NO; +} + + +// WWAN may be available, but not active until a connection has been established. +// WiFi may require a connection for VPN on Demand. +-(BOOL)isConnectionRequired +{ + return [self connectionRequired]; +} + +-(BOOL)connectionRequired +{ + SCNetworkReachabilityFlags flags; + + if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + return (flags & kSCNetworkReachabilityFlagsConnectionRequired); + } + + return NO; +} + +// Dynamic, on demand connection? +-(BOOL)isConnectionOnDemand +{ + SCNetworkReachabilityFlags flags; + + if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && + (flags & (kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand))); + } + + return NO; +} + +// Is user intervention required? +-(BOOL)isInterventionRequired +{ + SCNetworkReachabilityFlags flags; + + if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && + (flags & kSCNetworkReachabilityFlagsInterventionRequired)); + } + + return NO; +} + + +#pragma mark - reachability status stuff + +-(NetworkStatus)currentReachabilityStatus +{ + if([self isReachable]) + { + if([self isReachableViaWiFi]) + return ReachableViaWiFi; + +#if TARGET_OS_IPHONE + return ReachableViaWWAN; +#endif + } + + return NotReachable; +} + +-(SCNetworkReachabilityFlags)reachabilityFlags +{ + SCNetworkReachabilityFlags flags = 0; + + if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + { + return flags; + } + + return 0; +} + +-(NSString*)currentReachabilityString +{ + NetworkStatus temp = [self currentReachabilityStatus]; + + if(temp == ReachableViaWWAN) + { + // Updated for the fact that we have CDMA phones now! + return NSLocalizedString(@"Cellular", @""); + } + if (temp == ReachableViaWiFi) + { + return NSLocalizedString(@"WiFi", @""); + } + + return NSLocalizedString(@"No Connection", @""); +} + +-(NSString*)currentReachabilityFlags +{ + return reachabilityFlags([self reachabilityFlags]); +} + +#pragma mark - Callback function calls this method + +-(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags +{ + if([self isReachableWithFlags:flags]) + { + if(self.reachableBlock) + { + self.reachableBlock(self); + } + } + else + { + if(self.unreachableBlock) + { + self.unreachableBlock(self); + } + } + + if(self.reachabilityBlock) + { + self.reachabilityBlock(self, flags); + } + + // this makes sure the change notification happens on the MAIN THREAD + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification + object:self]; + }); +} + +#pragma mark - Debug Description + +- (NSString *) description +{ + NSString *description = [NSString stringWithFormat:@"<%@: %p (%@)>", + NSStringFromClass([self class]), self, [self currentReachabilityFlags]]; + return description; +} + +@end diff --git a/libTitanD3vUniversal/ImagePicker/TDImageListCell.h b/libTitanD3vUniversal/ImagePicker/TDImageListCell.h new file mode 100644 index 0000000..e8c8c06 --- /dev/null +++ b/libTitanD3vUniversal/ImagePicker/TDImageListCell.h @@ -0,0 +1,50 @@ +#import +#import +#import +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + + +@interface UIImage(TD) ++(id)imageAtPath:(id)arg1; +@end + + +@interface TDImageListCell : PSTableCell { + + UIImageView* previewImage; + float inset; +} + +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) NSString* key; +@property (nonatomic, retain) NSString* defaults; +@property (nonatomic) BOOL usesJPEG; +@property (nonatomic) BOOL usesGIF; +@property (nonatomic) CGFloat compressionQuality; +@property (nonatomic) BOOL allowsVideos; +@property (nonatomic, retain) NSString* videoPath; +@property (nonatomic, retain) UIColor *containerColour; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *borderColour; + +@property (nonatomic) BOOL saveImageToFolder; +@property (nonatomic) BOOL formatterPNG; +@property (nonatomic, retain) NSString* folderPath; +@property (nonatomic, retain) NSString* imageName; + +@end + +@interface NSUserDefaults (TD) +-(id)objectForKey:(id)arg1 inDomain:(id)arg2; +-(void)setObject:(id)arg1 forKey:(id)arg2 inDomain:(id)arg3; +@end + +@interface PHAsset (TD) +@property (nonatomic,readonly) BOOL isVideo; +@end diff --git a/libTitanD3vUniversal/ImagePicker/TDImageListCell.m b/libTitanD3vUniversal/ImagePicker/TDImageListCell.m new file mode 100644 index 0000000..9867bb1 --- /dev/null +++ b/libTitanD3vUniversal/ImagePicker/TDImageListCell.m @@ -0,0 +1,263 @@ +#include +#include "TDImageListCell.h" + +@implementation TDImageListCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { + + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; + + specifier.properties[@"height"] = [NSNumber numberWithInt:70]; + + if (self) { + + + self.key = [[specifier properties] valueForKey:@"key"]; + self.defaults = [[specifier properties] valueForKey:@"defaults"]; + self.usesJPEG = [[specifier properties] valueForKey:@"usesJPEG"] ? [[[specifier properties] valueForKey:@"usesJPEG"] boolValue] : NO; + self.usesGIF = [[specifier properties] valueForKey:@"usesGIF"] ? [[[specifier properties] valueForKey:@"usesGIF"] boolValue] : NO; + self.compressionQuality = [[specifier properties] valueForKey:@"compressionQuality"] ? [[[specifier properties] valueForKey:@"compressionQuality"] floatValue] : 1.0; + self.allowsVideos = [[specifier properties] valueForKey:@"allowsVideos"] ? [[[specifier properties] valueForKey:@"allowsVideos"] boolValue] : NO; + self.videoPath = [[specifier properties] valueForKey:@"videoPath"]; + self.saveImageToFolder = [[specifier properties] valueForKey:@"saveImageToFolder"] ? [[[specifier properties] valueForKey:@"saveImageToFolder"] boolValue] : NO; + self.formatterPNG = [[specifier properties] valueForKey:@"formatterPNG"] ? [[[specifier properties] valueForKey:@"formatterPNG"] boolValue] : NO; +self.imageName = [[specifier properties] valueForKey:@"imageName"]; +self.folderPath = [[specifier properties] valueForKey:@"folderPath"]; + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.containerColour = [[TDAppearance sharedInstance] containerColour]; + self.borderColour = [[TDAppearance sharedInstance] borderColour]; + +self.baseView = [[UIView alloc] initWithFrame:self.bounds]; +self.baseView.backgroundColor = [[TDAppearance sharedInstance] cellColour]; +[self addSubview:self.baseView]; + + + self.iconImage = [[UIImageView alloc]initWithFrame:CGRectMake(13,15,40,40)]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/photo.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + self.iconImage.tintColor = self.tintColour; + [self addSubview:self.iconImage]; + + + self.headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(65,25,200,20)]; + self.headerLabel.text = [[specifier properties] valueForKey:@"title"]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + } + + return self; +} + + +- (id)target { + return self; +} + + +- (id)cellTarget { + return self; +} + + +- (SEL)action { + return @selector(chooseImage); +} + + +- (SEL)cellAction { + return @selector(chooseImage); +} + + +-(void)didMoveToWindow { + [super didMoveToWindow]; + + [self.specifier setTarget:self]; + [self.specifier setButtonAction:@selector(chooseImage)]; + + + if (!previewImage) { + + previewImage = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 50, 50)]; + [previewImage setContentMode:UIViewContentModeScaleAspectFill]; + [previewImage setClipsToBounds:YES]; + previewImage.layer.cornerRadius = 12; + [self setAccessoryView:previewImage]; + + + NSString *bundleID = self.defaults; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + + NSData* data = [settings objectForKey:self.key]; + UIImage* img = [UIImage imageWithData:data]; + if (img) { + + previewImage.image = img; + + + } else if (self.videoPath) { + + NSURL* fileURL = [NSURL fileURLWithPath:self.videoPath]; + //get image from video + AVURLAsset* asset = [AVURLAsset URLAssetWithURL:fileURL options:nil]; + AVAssetImageGenerator* imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset]; + UIImage* image = [UIImage imageWithCGImage:[imageGenerator copyCGImageAtTime:CMTimeMake(0, 1) actualTime:nil error:nil]]; + previewImage.image = image; + } + + if (img) { + + previewImage.layer.borderWidth = 1; + previewImage.layer.borderColor = self.borderColour.CGColor; + + } + + } +} + + +-(void)chooseImage { + + UIImagePickerController* picker = [[UIImagePickerController alloc] init]; + picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + + if (self.allowsVideos) { + + picker.mediaTypes = @[(NSString*)kUTTypeImage, (NSString*)kUTTypeMovie]; + } + + picker.delegate = self; + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController presentViewController:picker animated:YES completion:nil]; +} + + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { + + UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + spinner.frame = picker.view.frame; + spinner.hidesWhenStopped = YES; + [picker.view addSubview:spinner]; + [spinner startAnimating]; + + NSURL* refURL = [info objectForKey:UIImagePickerControllerReferenceURL]; + if (refURL) { + + PHAsset* asset = [[PHAsset fetchAssetsWithALAssetURLs:@[refURL] options:nil] lastObject]; + + if (asset) { + + if (asset.isVideo) { + + //user chose a video + [[PHImageManager defaultManager] requestExportSessionForVideo:asset options:nil exportPreset:AVAssetExportPresetHighestQuality resultHandler:^(AVAssetExportSession* exportSession, NSDictionary* info) { + NSURL* fileURL = [NSURL fileURLWithPath:self.videoPath]; + exportSession.outputURL = fileURL; + + if ([[self.videoPath lowercaseString] hasSuffix:@".mov"]) { + + exportSession.outputFileType = AVFileTypeQuickTimeMovie; + + } else { + + exportSession.outputFileType = AVFileTypeMPEG4; + } + + [exportSession exportAsynchronouslyWithCompletionHandler:^{ + //get image from video + AVURLAsset* asset = [AVURLAsset URLAssetWithURL:fileURL options:nil]; + AVAssetImageGenerator* imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset]; + UIImage* image = [UIImage imageWithCGImage:[imageGenerator copyCGImageAtTime:CMTimeMake(0, 1) actualTime:nil error:nil]]; + previewImage.image = image; + }]; + }]; + + + } else { + + //delete video + if (self.videoPath) { + + [[NSFileManager defaultManager] removeItemAtPath:self.videoPath error:nil]; + } + + //user chose an image + [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData * _Nullable data, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { + + if (data) { + + UIImage* image = [UIImage imageWithData:data]; + + if (self.usesJPEG) { + + data = UIImageJPEGRepresentation(image, self.compressionQuality); + + } else if (!self.usesGIF) { + + data = UIImagePNGRepresentation(image); + } + + NSString *bundleID = self.defaults; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:data forKey:self.key]; + [settings writeToFile:prefsPath atomically:YES]; + +if (self.saveImageToFolder) { + + if (self.formatterPNG) { + NSString *imageNameString = [NSString stringWithFormat:@"%@.png", self.imageName]; + NSString *imageString = [self.folderPath stringByAppendingPathComponent:imageNameString]; + NSData *imageData = UIImagePNGRepresentation(image); + [imageData writeToFile:imageString atomically:YES]; + } else { + NSString *imageNameString = [NSString stringWithFormat:@"%@.jpg", self.imageName]; + NSString *imageString = [self.folderPath stringByAppendingPathComponent:imageNameString]; + NSData *imageData = UIImageJPEGRepresentation(image, 1.0f); + [imageData writeToFile:imageString atomically:YES]; + } + +} + + previewImage.image = image; + } + }]; + } + +UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController dismissViewControllerAnimated:YES completion:^{ + [spinner stopAnimating]; + }]; + } + } +} + + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + + UIViewController *prefsController = [self _viewControllerForAncestor]; + [prefsController dismissViewControllerAnimated:YES completion:nil]; + +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + + +- (void)layoutSubviews { + [super layoutSubviews]; + self.baseView.frame = self.bounds; +} + +@end diff --git a/libTitanD3vUniversal/ImagePicker/TDImagePicker.h b/libTitanD3vUniversal/ImagePicker/TDImagePicker.h new file mode 100644 index 0000000..bb3edd9 --- /dev/null +++ b/libTitanD3vUniversal/ImagePicker/TDImagePicker.h @@ -0,0 +1,10 @@ +#import + +#ifdef __cplusplus +extern "C" { +#endif +UIImage *TDParseImage(NSData *imageDataFromPrefs); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/libTitanD3vUniversal/ImagePicker/TDImagePicker.mm b/libTitanD3vUniversal/ImagePicker/TDImagePicker.mm new file mode 100644 index 0000000..91c7c74 --- /dev/null +++ b/libTitanD3vUniversal/ImagePicker/TDImagePicker.mm @@ -0,0 +1,8 @@ +#import +#import +#import "TDImagePicker.h" + +UIImage *TDParseImage(NSData *imageDataFromPrefs) +{ + return [UIImage imageWithData:imageDataFromPrefs]; +} diff --git a/libTitanD3vUniversal/ImagePicker/TDImagePickerCell.h b/libTitanD3vUniversal/ImagePicker/TDImagePickerCell.h new file mode 100644 index 0000000..b499fa0 --- /dev/null +++ b/libTitanD3vUniversal/ImagePicker/TDImagePickerCell.h @@ -0,0 +1,48 @@ +#import +#import +#import +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "GlobalPrefs.h" + + +@interface UIImage(TD) ++(id)imageAtPath:(id)arg1; +@end + + +@interface TDImagePickerCell : PSTableCell { + + UIViewController* listController; + UIImageView* previewImage; + float inset; +} + +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *headerLabel; +@property (nonatomic, retain) UILabel *subtitleLabel; +@property (nonatomic, retain) NSString* key; +@property (nonatomic, retain) NSString* defaults; +//@property (nonatomic, retain) NSString* postNotification; +@property (nonatomic) BOOL usesJPEG; +@property (nonatomic) BOOL usesGIF; +@property (nonatomic) CGFloat compressionQuality; +@property (nonatomic) BOOL allowsVideos; +@property (nonatomic, retain) NSString* videoPath; +@property (nonatomic, retain) UIColor *containerColour; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *borderColour; +-(id)initWithStyle:(long long)arg1 reuseIdentifier:(id)arg2 specifier:(id)arg3; +-(void)chooseImage; +@end + +@interface NSUserDefaults (TD) +-(id)objectForKey:(id)arg1 inDomain:(id)arg2; +-(void)setObject:(id)arg1 forKey:(id)arg2 inDomain:(id)arg3; +@end + +@interface PHAsset (TD) +@property (nonatomic,readonly) BOOL isVideo; +@end diff --git a/libTitanD3vUniversal/ImagePicker/TDImagePickerCell.m b/libTitanD3vUniversal/ImagePicker/TDImagePickerCell.m new file mode 100644 index 0000000..2778cc1 --- /dev/null +++ b/libTitanD3vUniversal/ImagePicker/TDImagePickerCell.m @@ -0,0 +1,242 @@ +#include +#include "TDImagePickerCell.h" + +@implementation TDImagePickerCell + +-(id)initWithStyle:(long long)arg1 reuseIdentifier:(id)arg2 specifier:(PSSpecifier*)arg3 { + + self = [super initWithStyle:arg1 reuseIdentifier:arg2 specifier:arg3]; + + if (self) { + + arg3.properties[@"height"] = [NSNumber numberWithInt:70]; + + listController = [arg3 target]; + [arg3 setTarget:self]; + + self.key = [[arg3 properties] valueForKey:@"key"]; + self.defaults = [[arg3 properties] valueForKey:@"defaults"]; + self.usesJPEG = [[arg3 properties] valueForKey:@"usesJPEG"] ? [[[arg3 properties] valueForKey:@"usesJPEG"] boolValue] : NO; + self.usesGIF = [[arg3 properties] valueForKey:@"usesGIF"] ? [[[arg3 properties] valueForKey:@"usesGIF"] boolValue] : NO; + self.compressionQuality = [[arg3 properties] valueForKey:@"compressionQuality"] ? [[[arg3 properties] valueForKey:@"compressionQuality"] floatValue] : 1.0; + self.allowsVideos = [[arg3 properties] valueForKey:@"allowsVideos"] ? [[[arg3 properties] valueForKey:@"allowsVideos"] boolValue] : NO; + self.videoPath = [[arg3 properties] valueForKey:@"videoPath"]; + + + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.containerColour = [[TDAppearance sharedInstance] containerColour]; + self.borderColour = [[TDAppearance sharedInstance] borderColour]; + + NSString *customIconPath = [NSString stringWithFormat:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/%@.png", arg3.properties[@"iconName"]]; + + + self.iconImage = [[UIImageView alloc]initWithFrame:CGRectMake(13,15,40,40)]; + self.iconImage.image = [[UIImage imageWithContentsOfFile:customIconPath]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + self.iconImage.layer.cornerRadius = 20; + self.iconImage.clipsToBounds = true; + [self addSubview:self.iconImage]; + + + self.headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(65,17.5,200,20)]; + self.headerLabel.text = [[arg3 properties] valueForKey:@"title"]; + [self.headerLabel setFont:[self.headerLabel.font fontWithSize:15]]; + [self addSubview:self.headerLabel]; + + self.subtitleLabel = [[UILabel alloc]initWithFrame:CGRectMake(65,35,200,20)]; + self.subtitleLabel.text = [[arg3 properties] valueForKey:@"subtitle"]; + [self.subtitleLabel setFont:[self.subtitleLabel.font fontWithSize:10]]; + [self addSubview:self.subtitleLabel]; + + + } + + return self; +} + + +- (id)target { + return self; +} + + +- (id)cellTarget { + return self; +} + + +- (SEL)action { + return @selector(chooseImage); +} + + +- (SEL)cellAction { + return @selector(chooseImage); +} + + +-(void)didMoveToWindow { + [super didMoveToWindow]; + + [self.specifier setTarget:self]; + [self.specifier setButtonAction:@selector(chooseImage)]; + + if (!previewImage) { + + previewImage = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 50, 50)]; + [previewImage setContentMode:UIViewContentModeScaleAspectFill]; + [previewImage setClipsToBounds:YES]; + previewImage.layer.cornerRadius = 12; + [self setAccessoryView:previewImage]; + + + NSString *bundleID = self.defaults; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + + NSData* data = [settings objectForKey:self.key]; + UIImage* img = [UIImage imageWithData:data]; + if (img) { + + previewImage.image = img; + + + } else if (self.videoPath) { + + NSURL* fileURL = [NSURL fileURLWithPath:self.videoPath]; + //get image from video + AVURLAsset* asset = [AVURLAsset URLAssetWithURL:fileURL options:nil]; + AVAssetImageGenerator* imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset]; + UIImage* image = [UIImage imageWithCGImage:[imageGenerator copyCGImageAtTime:CMTimeMake(0, 1) actualTime:nil error:nil]]; + previewImage.image = image; + } + + if (img) { + + previewImage.layer.borderWidth = 1; + previewImage.layer.borderColor = self.borderColour.CGColor; + + } + + } +} + + +-(void)chooseImage { + + UIImagePickerController* picker = [[UIImagePickerController alloc] init]; + picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + + if (self.allowsVideos) { + + picker.mediaTypes = @[(NSString*)kUTTypeImage, (NSString*)kUTTypeMovie]; + } + + picker.delegate = self; + [listController presentViewController:picker animated:YES completion:nil]; +} + + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { + + UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + spinner.frame = picker.view.frame; + spinner.hidesWhenStopped = YES; + [picker.view addSubview:spinner]; + [spinner startAnimating]; + + NSURL* refURL = [info objectForKey:UIImagePickerControllerReferenceURL]; + if (refURL) { + + PHAsset* asset = [[PHAsset fetchAssetsWithALAssetURLs:@[refURL] options:nil] lastObject]; + + if (asset) { + + if (asset.isVideo) { + + //user chose a video + [[PHImageManager defaultManager] requestExportSessionForVideo:asset options:nil exportPreset:AVAssetExportPresetHighestQuality resultHandler:^(AVAssetExportSession* exportSession, NSDictionary* info) { + NSURL* fileURL = [NSURL fileURLWithPath:self.videoPath]; + exportSession.outputURL = fileURL; + + if ([[self.videoPath lowercaseString] hasSuffix:@".mov"]) { + + exportSession.outputFileType = AVFileTypeQuickTimeMovie; + + } else { + + exportSession.outputFileType = AVFileTypeMPEG4; + } + + [exportSession exportAsynchronouslyWithCompletionHandler:^{ + //get image from video + AVURLAsset* asset = [AVURLAsset URLAssetWithURL:fileURL options:nil]; + AVAssetImageGenerator* imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset]; + UIImage* image = [UIImage imageWithCGImage:[imageGenerator copyCGImageAtTime:CMTimeMake(0, 1) actualTime:nil error:nil]]; + previewImage.image = image; + }]; + }]; + + + } else { + + //delete video + if (self.videoPath) { + + [[NSFileManager defaultManager] removeItemAtPath:self.videoPath error:nil]; + } + + //user chose an image + [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData * _Nullable data, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { + + if (data) { + + UIImage* image = [UIImage imageWithData:data]; + + if (self.usesJPEG) { + + data = UIImageJPEGRepresentation(image, self.compressionQuality); + + } else if (!self.usesGIF) { + + data = UIImagePNGRepresentation(image); + } + + NSString *bundleID = self.defaults; + NSString *prefsPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + NSMutableDictionary *settings = [NSMutableDictionary dictionary]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefsPath]]; + + [settings setObject:data forKey:self.key]; + [settings writeToFile:prefsPath atomically:YES]; + + + previewImage.image = image; + } + }]; + } + + [listController dismissViewControllerAnimated:YES completion:^{ + [spinner stopAnimating]; + }]; + } + } +} + + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { + + [listController dismissViewControllerAnimated:YES completion:nil]; + +} + + +- (void)setFrame:(CGRect)frame { + inset = 10; + frame.origin.x += inset; + frame.size.width -= 2 * inset; + [super setFrame:frame]; +} + +@end diff --git a/libTitanD3vUniversal/ListController/TDListController.h b/libTitanD3vUniversal/ListController/TDListController.h new file mode 100644 index 0000000..af0da85 --- /dev/null +++ b/libTitanD3vUniversal/ListController/TDListController.h @@ -0,0 +1,12 @@ +#import +#import +#import +#import "TDAppearance.h" + +@interface TDListController : PSListItemsController +@property (nonatomic, retain) UIColor *navigationBarColour; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *backgroundColour; +@property (nonatomic, retain) UIColor *cellsColour; +@property (nonatomic, retain) UIColor *labelColour; +@end diff --git a/libTitanD3vUniversal/ListController/TDListController.m b/libTitanD3vUniversal/ListController/TDListController.m new file mode 100644 index 0000000..45afcd9 --- /dev/null +++ b/libTitanD3vUniversal/ListController/TDListController.m @@ -0,0 +1,83 @@ +#import "TDListController.h" + +@implementation TDListController + +- (void)viewDidLoad { + [super viewDidLoad]; + +} + + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + self.navigationBarColour = [[TDAppearance sharedInstance] navigationBarColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.backgroundColour = [[TDAppearance sharedInstance] backgroundColour]; + self.cellsColour = [[TDAppearance sharedInstance] cellColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + + UINavigationBar *bar = self.navigationController.navigationController.navigationBar; + bar.barTintColor = self.navigationBarColour; + bar.tintColor = self.tintColour; + [[UIButton appearance]setTintColor:self.tintColour]; + self.view.tintColor = self.tintColour; + + + UITableView *tableView = self.view.subviews[0]; + tableView.backgroundColor = self.backgroundColour; + [tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + + [[UILabel appearance] setTextColor:self.labelColour]; + + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = self.tintColour; + +} + + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [[UINavigationBar appearance] tintColor]; + + + UINavigationBar *bar = self.navigationController.navigationController.navigationBar; + bar.barTintColor = [[UINavigationBar appearance] barTintColor]; + bar.tintColor = [[UINavigationBar appearance] tintColor]; + + self.view.tintColor = nil; + [[UIButton appearance]setTintColor:nil]; + [[UILabel appearance] setTextColor:nil]; + +} + + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + PSTableCell *cell = (PSTableCell *)[super tableView:tableView cellForRowAtIndexPath:indexPath]; + cell.backgroundColor = self.cellsColour; + cell.titleLabel.textColor = self.labelColour; + return cell; +} + +@end diff --git a/libTitanD3vUniversal/Makefile b/libTitanD3vUniversal/Makefile new file mode 100644 index 0000000..dd8fd21 --- /dev/null +++ b/libTitanD3vUniversal/Makefile @@ -0,0 +1,37 @@ +ARCHS = arm64 arm64e + +TARGET = iphone:clang:14.0:13.0 + +export PREFIX=$(THEOS)/toolchain/Xcode.xctoolchain/usr/bin/ +export CFLAGS = -include $(realpath ./ExtraTools/Prefix.h) + +FINALPACKAGE = 1 +DEBUG = 0 + +include $(THEOS)/makefiles/common.mk + +LIBRARY_NAME = libTitanD3vUniversal + +dtoim = $(foreach d,$(1),-I$(d)) +_IMPORTS += $(shell /bin/ls -d ./*) +_IMPORTS += $(shell /bin/ls -d ./*/*) +IMPORTS = -I$./ $(call dtoim, $(_IMPORTS)) + +SOURCES = $(shell find . -name '*.m') + +libTitanD3vUniversal_FILES = $(SOURCES) $(wildcard ImagePicker/*.mm) +libTitanD3vUniversal_PUBLIC_HEADERS = $(IMPORTS) +libTitanD3vUniversal_FRAMEWORKS = UIKit Photos MobileCoreServices +libTitanD3vUniversal_PRIVATE_FRAMEWORKS = Preferences AppSupport +libTitanD3vUniversal_CFLAGS = -fobjc-arc -Wno-deprecated-declarations -Wunused-function $(IMPORTS) + +include $(THEOS_MAKE_PATH)/library.mk +include $(THEOS_MAKE_PATH)/aggregate.mk + +after-all:: + echo "Copying library and headers..." + cp -rf $(THEOS_OBJ_DIR)/libTitanD3vUniversal.dylib $(THEOS)/lib/libTitanD3vUniversal.dylib + rm -rf $(THEOS)/include/TitanD3vUniversal/ + mkdir $(THEOS)/include/TitanD3vUniversal/ + cp -rf $(wildcard *.h PrimraryController/*.h SecondaryController/*.h ExternalController/*.h ListController/*.h PrefsManager/*.h Appearance/*.h Cells/*.h Alert/*.h Alert/Private/*.h Banner/*.h ImagePicker/*.h ColourPicker/*.h ColourPicker/*/*.h Weather/*.h Drawer/*.h Drawer/*/*.h MarqueeLabel/*.h Utilities/*.h TweakManager/*.h BlurView/*.h Constraints/*.h CustomViews/*.h AppList/*.h ReportBugs/*.h CollectionView/*.h Confetti/*.h ExtraTools/*.h RNCryptor/*.h Review/*.h PrivateFrameworks/*.h EmojiPicker/*.h ContactPicker/*.h AvatarPicker/*.h) $(THEOS)/include/TitanD3vUniversal/ + echo "Done." diff --git a/libTitanD3vUniversal/MarqueeLabel/TDMarqueeLabel.h b/libTitanD3vUniversal/MarqueeLabel/TDMarqueeLabel.h new file mode 100644 index 0000000..f4f3e8b --- /dev/null +++ b/libTitanD3vUniversal/MarqueeLabel/TDMarqueeLabel.h @@ -0,0 +1,31 @@ +#import + +typedef NS_ENUM(NSInteger, TDMarqueeLabelDirection) { + TDMarqueeLabelDirectionRight, + TDMarqueeLabelDirectionLeft +}; + +@interface TDMarqueeLabel : UIView + +@property (nonatomic) TDMarqueeLabelDirection scrollDirection; +@property (nonatomic) float scrollSpeed; +@property (nonatomic) NSTimeInterval pauseInterval; +@property (nonatomic) NSInteger labelSpacing; +@property (nonatomic) UIViewAnimationOptions animationOptions; +@property (nonatomic, readonly) BOOL scrolling; +@property (nonatomic) CGFloat fadeLength; +@property (nonatomic, strong, nonnull) UIFont *font; +@property (nonatomic, copy, nullable) NSString *text; +@property (nonatomic, copy, nullable) NSAttributedString *attributedText; +@property (nonatomic, strong, nonnull) UIColor *textColor; +@property (nonatomic) NSTextAlignment textAlignment; +@property (nonatomic, strong, nullable) UIColor *shadowColor; +@property (nonatomic) CGSize shadowOffset; + +- (void)refreshLabels; +- (void)setText:(nullable NSString *)text refreshLabels:(BOOL)refresh; +- (void)setAttributedText:(nullable NSAttributedString *)theText refreshLabels:(BOOL)refresh; +- (void)scrollLabelIfNeeded; +- (void)observeApplicationNotifications; + +@end diff --git a/libTitanD3vUniversal/MarqueeLabel/TDMarqueeLabel.m b/libTitanD3vUniversal/MarqueeLabel/TDMarqueeLabel.m new file mode 100644 index 0000000..0e2ad09 --- /dev/null +++ b/libTitanD3vUniversal/MarqueeLabel/TDMarqueeLabel.m @@ -0,0 +1,407 @@ +#import "TDMarqueeLabel.h" +#import + +#define kLabelCount 2 +#define kDefaultFadeLength 7.f +#define kDefaultLabelBufferSpace 20 +#define kDefaultPixelsPerSecond 30 +#define kDefaultPauseTime 1.5f + +static void each_object(NSArray *objects, void (^block)(id object)) { + for (id obj in objects) { + block(obj); + } +} + +#define EACH_LABEL(ATTR, VALUE) each_object(self.labels, ^(UILabel *label) { label.ATTR = VALUE; }); + +@interface TDMarqueeLabel () + +@property (nonatomic, strong) NSArray *labels; +@property (nonatomic, strong, readonly) UILabel *mainLabel; +@property (nonatomic, strong) UIScrollView *scrollView; + +@end + +@implementation TDMarqueeLabel + +- (id)initWithCoder:(NSCoder *)aDecoder { + if ((self = [super initWithCoder:aDecoder])) { + [self commonInit]; + } + return self; +} + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + [self commonInit]; + } + return self; +} + +- (void)commonInit { + // create the labels + NSMutableSet *labelSet = [[NSMutableSet alloc] initWithCapacity:kLabelCount]; + + for (int index = 0; index < kLabelCount; ++index) { + UILabel *label = [[UILabel alloc] init]; + label.backgroundColor = [UIColor clearColor]; + label.autoresizingMask = self.autoresizingMask; + + // store labels + [self.scrollView addSubview:label]; + [labelSet addObject:label]; + } + + self.labels = [labelSet.allObjects copy]; + + // default values + _scrollDirection = TDMarqueeLabelDirectionLeft; + _scrollSpeed = kDefaultPixelsPerSecond; + self.pauseInterval = kDefaultPauseTime; + self.labelSpacing = kDefaultLabelBufferSpace; + self.textAlignment = NSTextAlignmentLeft; + self.animationOptions = UIViewAnimationOptionCurveLinear; + self.scrollView.showsVerticalScrollIndicator = NO; + self.scrollView.showsHorizontalScrollIndicator = NO; + self.scrollView.scrollEnabled = NO; + self.userInteractionEnabled = NO; + self.backgroundColor = [UIColor clearColor]; + self.clipsToBounds = YES; + self.fadeLength = kDefaultFadeLength; +} + +- (void)dealloc { + [NSObject cancelPreviousPerformRequestsWithTarget:self]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)setFrame:(CGRect)frame { + [super setFrame:frame]; + + [self didChangeFrame]; +} + +// For autolayout +- (void)setBounds:(CGRect)bounds { + [super setBounds:bounds]; + + [self didChangeFrame]; +} + +- (void)didMoveToWindow { + [super didMoveToWindow]; + + if (self.window) { + [self scrollLabelIfNeeded]; + } +} + +#pragma mark - Properties + +- (UIScrollView *)scrollView { + if (_scrollView == nil) { + _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds]; + _scrollView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + _scrollView.backgroundColor = [UIColor clearColor]; + + [self addSubview:_scrollView]; + } + return _scrollView; +} + +- (void)setFadeLength:(CGFloat)fadeLength { + if (_fadeLength != fadeLength) { + _fadeLength = fadeLength; + + [self refreshLabels]; + [self applyGradientMaskForFadeLength:fadeLength enableFade:NO]; + } +} + +- (UILabel *)mainLabel { + return [self.labels firstObject]; +} + +- (void)setText:(NSString *)theText { + [self setText:theText refreshLabels:YES]; +} + +- (void)setText:(NSString *)theText refreshLabels:(BOOL)refresh { + // ignore identical text changes + if ([theText isEqualToString:self.text]) + return; + + EACH_LABEL(text, theText) + + if (refresh) + [self refreshLabels]; +} + +- (NSString *)text { + return self.mainLabel.text; +} + +- (void)setAttributedText:(NSAttributedString *)theText { + [self setAttributedText:theText refreshLabels:YES]; +} + +- (void)setAttributedText:(NSAttributedString *)theText refreshLabels:(BOOL)refresh { + // ignore identical text changes + if ([theText.string isEqualToString:self.attributedText.string]) + return; + + EACH_LABEL(attributedText, theText) + + if (refresh) + [self refreshLabels]; +} + +- (NSAttributedString *)attributedText { + return self.mainLabel.attributedText; +} + +- (void)setTextColor:(UIColor *)color { + EACH_LABEL(textColor, color) +} + +- (UIColor *)textColor { + return self.mainLabel.textColor; +} + +- (void)setFont:(UIFont *)font { + if (self.mainLabel.font == font) + return; + + EACH_LABEL(font, font) + + [self refreshLabels]; + [self invalidateIntrinsicContentSize]; +} + +- (UIFont *)font { + return self.mainLabel.font; +} + +- (void)setScrollSpeed:(float)speed { + _scrollSpeed = speed; + + [self scrollLabelIfNeeded]; +} + +- (void)setScrollDirection:(TDMarqueeLabelDirection)direction { + _scrollDirection = direction; + + [self scrollLabelIfNeeded]; +} + +- (void)setShadowColor:(UIColor *)color { + EACH_LABEL(shadowColor, color) +} + +- (UIColor *)shadowColor { + return self.mainLabel.shadowColor; +} + +- (void)setShadowOffset:(CGSize)offset { + EACH_LABEL(shadowOffset, offset) +} + +- (CGSize)shadowOffset { + return self.mainLabel.shadowOffset; +} + +#pragma mark - Autolayout + +- (CGSize)intrinsicContentSize { + return CGSizeMake(0, [self.mainLabel intrinsicContentSize].height); +} + +#pragma mark - Misc + +- (void)observeApplicationNotifications { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + // restart scrolling when the app has been activated + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(scrollLabelIfNeeded) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(scrollLabelIfNeeded) + name:UIApplicationDidBecomeActiveNotification + object:nil]; + + #ifndef TARGET_OS_TV + // refresh labels when interface orientation is changed + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(onUIApplicationDidChangeStatusBarOrientationNotification:) + name:UIApplicationDidChangeStatusBarOrientationNotification + object:nil]; + #endif + +} + +- (void)enableShadow { + _scrolling = YES; + [self applyGradientMaskForFadeLength:self.fadeLength enableFade:YES]; +} + +- (void)scrollLabelIfNeeded { + if (!self.text.length) + return; + + CGFloat labelWidth = CGRectGetWidth(self.mainLabel.bounds); + if (labelWidth <= CGRectGetWidth(self.bounds)) + return; + + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(scrollLabelIfNeeded) object:nil]; + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(enableShadow) object:nil]; + + [self.scrollView.layer removeAllAnimations]; + + BOOL doScrollLeft = (self.scrollDirection == TDMarqueeLabelDirectionLeft); + self.scrollView.contentOffset = (doScrollLeft ? CGPointZero : CGPointMake(labelWidth + self.labelSpacing, 0)); + + // Add the left shadow after delay + [self performSelector:@selector(enableShadow) withObject:nil afterDelay:self.pauseInterval]; + + // animate the scrolling + NSTimeInterval duration = labelWidth / self.scrollSpeed; + [UIView animateWithDuration:duration delay:self.pauseInterval options:self.animationOptions | UIViewAnimationOptionAllowUserInteraction animations:^{ + // adjust offset + self.scrollView.contentOffset = (doScrollLeft ? CGPointMake(labelWidth + self.labelSpacing, 0) : CGPointZero); + } completion:^(BOOL finished) { + self->_scrolling = NO; + + // remove the left shadow + [self applyGradientMaskForFadeLength:self.fadeLength enableFade:NO]; + + // setup pause delay/loop + if (finished) { + [self performSelector:@selector(scrollLabelIfNeeded) withObject:nil]; + } + }]; +} + +- (void)refreshLabels { + __block float offset = 0; + + each_object(self.labels, ^(UILabel *label) { + [label sizeToFit]; + + CGRect frame = label.frame; + frame.origin = CGPointMake(offset, 0); + frame.size.height = CGRectGetHeight(self.bounds); + label.frame = frame; + + // Recenter label vertically within the scroll view + label.center = CGPointMake(label.center.x, roundf(self.center.y - CGRectGetMinY(self.frame))); + + offset += CGRectGetWidth(label.bounds) + self.labelSpacing; + }); + + self.scrollView.contentOffset = CGPointZero; + [self.scrollView.layer removeAllAnimations]; + + // if the label is bigger than the space allocated, then it should scroll + if (CGRectGetWidth(self.mainLabel.bounds) > CGRectGetWidth(self.bounds)) { + CGSize size; + size.width = CGRectGetWidth(self.mainLabel.bounds) + CGRectGetWidth(self.bounds) + self.labelSpacing; + size.height = CGRectGetHeight(self.bounds); + self.scrollView.contentSize = size; + + EACH_LABEL(hidden, NO) + + [self applyGradientMaskForFadeLength:self.fadeLength enableFade:self.scrolling]; + + [self scrollLabelIfNeeded]; + } else { + // Hide the other labels + EACH_LABEL(hidden, (self.mainLabel != label)) + + // adjust the scroll view and main label + self.scrollView.contentSize = self.bounds.size; + self.mainLabel.frame = self.bounds; + self.mainLabel.hidden = NO; + self.mainLabel.textAlignment = self.textAlignment; + + // cleanup animation + [self.scrollView.layer removeAllAnimations]; + + [self applyGradientMaskForFadeLength:0 enableFade:NO]; + } +} + +// bounds or frame has been changed +- (void)didChangeFrame { + [self refreshLabels]; + [self applyGradientMaskForFadeLength:self.fadeLength enableFade:self.scrolling]; +} + +#pragma mark - Gradient + +// ref: https://github.com/cbpowell/MarqueeLabel +- (void)applyGradientMaskForFadeLength:(CGFloat)fadeLength enableFade:(BOOL)fade { + CGFloat labelWidth = CGRectGetWidth(self.mainLabel.bounds); + + if (labelWidth <= CGRectGetWidth(self.bounds)) + fadeLength = 0; + + if (fadeLength) { + // Recreate gradient mask with new fade length + CAGradientLayer *gradientMask = [CAGradientLayer layer]; + + gradientMask.bounds = self.layer.bounds; + gradientMask.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); + + gradientMask.shouldRasterize = YES; + gradientMask.rasterizationScale = [UIScreen mainScreen].scale; + + gradientMask.startPoint = CGPointMake(0, CGRectGetMidY(self.frame)); + gradientMask.endPoint = CGPointMake(1, CGRectGetMidY(self.frame)); + + // setup fade mask colors and location + id transparent = (id)[UIColor clearColor].CGColor; + id opaque = (id)[UIColor blackColor].CGColor; + gradientMask.colors = @[transparent, opaque, opaque, transparent]; + + // calcluate fade + CGFloat fadePoint = fadeLength / CGRectGetWidth(self.bounds); + NSNumber *leftFadePoint = @(fadePoint); + NSNumber *rightFadePoint = @(1 - fadePoint); + if (!fade) switch (self.scrollDirection) { + case TDMarqueeLabelDirectionLeft: + leftFadePoint = @0; + break; + + case TDMarqueeLabelDirectionRight: + leftFadePoint = @0; + rightFadePoint = @1; + break; + } + + // apply calculations to mask + gradientMask.locations = @[@0, leftFadePoint, rightFadePoint, @1]; + + // don't animate the mask change + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + self.layer.mask = gradientMask; + [CATransaction commit]; + } else { + // Remove gradient mask for 0.0f length fade length + self.layer.mask = nil; + } +} + +#pragma mark - Notifications + +- (void)onUIApplicationDidChangeStatusBarOrientationNotification:(NSNotification *)notification { + // delay to have it re-calculate on next runloop + [self performSelector:@selector(refreshLabels) withObject:nil afterDelay:.1f]; + [self performSelector:@selector(scrollLabelIfNeeded) withObject:nil afterDelay:.1f]; +} + +@end diff --git a/libTitanD3vUniversal/PrefsManager/GlobalPrefs.h b/libTitanD3vUniversal/PrefsManager/GlobalPrefs.h new file mode 100644 index 0000000..82f7ac3 --- /dev/null +++ b/libTitanD3vUniversal/PrefsManager/GlobalPrefs.h @@ -0,0 +1,11 @@ +#import "TDPrefsManager.h" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" + +static UIImpactFeedbackGenerator *hapticFeedback; + +static void invokeHapticFeedback () { + + hapticFeedback = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; + [hapticFeedback impactOccurred]; +} diff --git a/libTitanD3vUniversal/PrefsManager/TDPrefsManager.h b/libTitanD3vUniversal/PrefsManager/TDPrefsManager.h new file mode 100644 index 0000000..7a0f68e --- /dev/null +++ b/libTitanD3vUniversal/PrefsManager/TDPrefsManager.h @@ -0,0 +1,107 @@ +#import +#import +#import "HEXColour.h" + +@interface PSTableCell (Private) +- (UIViewController *)_viewControllerForAncestor; +@end + + +@interface TDPrefsManager : NSObject { + + NSString *bannerTitle; + NSString *bannerSubtitle; + NSString *developerName; + NSString *bannerIconPath; + NSString *bannerCoverPath; + NSString *changelogPlistPath; + NSString *currentVersion; + NSString *socialPlistPath; + NSString *socialIconPath; + NSString *twitterName; + NSString *twitterAvatar; + NSString *twitterURL; + NSString *tweakPlistPath; + NSString *tweakIconPath; + NSString *crewTitle; + NSString *crewPlistPath; + NSString *crewImagePath; + + BOOL bannerCoverImage; + BOOL bannerIconTint; + BOOL useLibraryAssets; + BOOL externalCellInset; + +} + ++(instancetype)sharedInstance; +-(id)init; + +-(void)initWithBundleID:(NSString *)bundleID tweakName:(NSString*)tweakName prefsBundle:(NSString*)prefsBundle; +-(void)initWithBundleID:(NSString *)bundleID; +-(void)bannerTitle:(NSString *)title subtitle:(NSString*)subtitle devName:(NSString*)devName coverImagePath:(NSString*)coverPath showCoverImage:(BOOL)showCover iconPath:(NSString*)iconPath iconTint:(BOOL)iconTint; +-(void)changelogPlistPath:(NSString *)path currentVersion:(NSString *)currentVersionString; +-(void)socialPlistPath:(NSString *)plistPathString iconsPath:(NSString *)iconsPathString twitterName:(NSString *)twitterNameString twitterAvatar:(NSString *)twitterAvatarString twitterURL:(NSString *)twitterURLString; +-(void)tweakPlistPath:(NSString *)plistPathString iconsPath:(NSString *)iconsPathString; +-(void)crewTitle:(NSString *)titleString plistPath:(NSString *)plistPathString imagePath:(NSString *)imagePathString ; +-(void)useAssetsFromLibrary:(BOOL)libraryAssets; +-(void)enableExternalCellInset:(BOOL)cellInset; + +- (void)setBool:(BOOL)anObject forKey:(id)aKey; + - (void)setObject:(id)anObject forKey:(id)aKey; +- (void)setFloat:(long long)anObject forKey:(id)aKey; +- (void)setInt:(int)anObject forKey:(id)aKey; + +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue; +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue; +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue; +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue; + +- (bool)boolForKey:(id)aKey; +- (id)objectForKey:(id)aKey; +- (long long)floatForKey:(id)aKey; +- (int)intForKey:(id)aKey; + +-(NSString *)getBundleID; +-(NSString *)getTweakName; +-(NSString *)getPrefsBundle; +-(NSString *)getBannerTitle; +-(NSString *)getBannerSubtitle; +-(NSString *)getDeveloperName; +-(NSString *)getBannerCoverPath; +-(NSString *)getBannerIconPath; +-(NSString *)getChangelogPlistPath; +-(NSString *)getCurrentVersion; +-(NSString *)getSocialPlistPath; +-(NSString *)getSocialIconPath; +-(NSString *)getTwitterName; +-(NSString *)getTwitterAvatarPath; +-(NSString *)getTwitterURL; +-(NSString *)getTweakPlistPath; +-(NSString *)getTweakIconPath; +-(NSString *)getCrewTitle; +-(NSString *)getCrewPlistPath; +-(NSString *)getCrewImagePath; + +-(BOOL)bannerWithIconTint; +-(BOOL)bannerWithCoverImage; +-(BOOL)populateAssetsFromLibrary; +-(BOOL)externalCellInset; + + +// New code +- (void)setBool:(BOOL)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (void)setObject:(id)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (void)setFloat:(long long)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (void)setInt:(int)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue ID:(NSString*)bundleIdentifier; +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue ID:(NSString*)bundleIdentifier; +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue ID:(NSString*)bundleIdentifier; +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue ID:(NSString*)bundleIdentifier; +- (bool)boolForKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (id)objectForKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (long long)floatForKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (int)intForKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (UIColor *)colourForKey:(id)aKey defaultValue:(id)defaultValue ID:(NSString*)bundleIdentifier; + +@end diff --git a/libTitanD3vUniversal/PrefsManager/TDPrefsManager.m b/libTitanD3vUniversal/PrefsManager/TDPrefsManager.m new file mode 100644 index 0000000..426fbfe --- /dev/null +++ b/libTitanD3vUniversal/PrefsManager/TDPrefsManager.m @@ -0,0 +1,385 @@ +#import "TDPrefsManager.h" + +static NSString *BundleID; +static NSString *prefPath; +static NSString *TweakName; +static NSString *PrefsBundle; +static NSMutableDictionary *settings; + +@implementation TDPrefsManager + ++(instancetype)sharedInstance { + static TDPrefsManager *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[TDPrefsManager alloc] init]; + settings = [NSMutableDictionary dictionary]; + }); + return sharedInstance; +} + +-(id)init { + return self; +} + +-(void)initWithBundleID:(NSString *)bundleID tweakName:(NSString*)tweakName prefsBundle:(NSString*)prefsBundle { + BundleID = bundleID; + TweakName = tweakName; + PrefsBundle = prefsBundle; + prefPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; +} + +-(void)initWithBundleID:(NSString *)bundleID { + prefPath = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleID]; + [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath]]; +} + +-(void)bannerTitle:(NSString *)title subtitle:(NSString*)subtitle devName:(NSString*)devName coverImagePath:(NSString*)coverPath showCoverImage:(BOOL)showCover iconPath:(NSString*)iconPath iconTint:(BOOL)iconTint { + + bannerTitle = title; + bannerSubtitle = subtitle; + developerName = devName; + bannerCoverPath = coverPath; + bannerCoverImage = showCover; + bannerIconPath = iconPath; + bannerIconTint = iconTint; + +} + +-(void)changelogPlistPath:(NSString *)path currentVersion:(NSString *)currentVersionString{ + changelogPlistPath = path; + currentVersion = currentVersionString; +} + +-(void)socialPlistPath:(NSString *)plistPathString iconsPath:(NSString *)iconsPathString twitterName:(NSString *)twitterNameString twitterAvatar:(NSString *)twitterAvatarString twitterURL:(NSString *)twitterURLString { + + socialPlistPath = plistPathString; + socialIconPath = iconsPathString; + twitterName = twitterNameString; + twitterAvatar = twitterAvatarString; + twitterURL = twitterURLString; + +} + +-(void)tweakPlistPath:(NSString *)plistPathString iconsPath:(NSString *)iconsPathString { + + tweakPlistPath = plistPathString; + tweakIconPath = iconsPathString; +} + +-(void)crewTitle:(NSString *)titleString plistPath:(NSString *)plistPathString imagePath:(NSString *)imagePathString { + + crewTitle = titleString; + crewPlistPath = plistPathString; + crewImagePath = imagePathString; +} + +-(void)useAssetsFromLibrary:(BOOL)libraryAssets { + useLibraryAssets = libraryAssets; +} + +-(void)enableExternalCellInset:(BOOL)cellInset { + externalCellInset = cellInset; +} + +- (void)setBool:(BOOL)anObject forKey:(id)aKey { + [settings setObject:[NSNumber numberWithBool:anObject] forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (void)setObject:(id)anObject forKey:(id)aKey { + [settings setObject:anObject forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (void)setFloat:(long long)anObject forKey:(id)aKey{ + [settings setObject:@(anObject) forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (void)setInt:(int)anObject forKey:(id)aKey { + [settings setObject:@(anObject) forKey:aKey]; + [settings writeToFile:prefPath atomically:YES]; +} + +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue { + if([settings objectForKey:aKey] == NULL){ + return defaultValue; + } + return [[settings objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue { + return [settings objectForKey:aKey]?:defaultValue; +} + +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue { + return [[settings objectForKey:aKey] longLongValue]?:defaultValue; +} + +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue { + return [[settings objectForKey:aKey] intValue]?:defaultValue; +} + +- (bool)boolForKey:(id)aKey { + return [[settings objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey { + return [settings objectForKey:aKey]; +} + +- (long long)floatForKey:(id)aKey { + return [[settings objectForKey:aKey] longLongValue]; +} + +- (int)intForKey:(id)aKey { + return [[settings objectForKey:aKey] intValue]; +} + +-(void)writeToPlist { + [settings writeToFile:prefPath atomically:YES]; +} + +-(NSString *)getBundleID { + return BundleID; +} + +-(NSString *)getTweakName { + return TweakName; +} + +-(NSString *)getPrefsBundle { + return PrefsBundle; +} + +-(NSString *)getBannerTitle { + return bannerTitle; +} + +-(NSString *)getBannerSubtitle { + return bannerSubtitle; +} + +-(NSString *)getDeveloperName { + return developerName; +} + +-(NSString *)getBannerCoverPath { + return bannerCoverPath; +} + +-(BOOL)bannerWithCoverImage { + return bannerCoverImage; +} + +-(NSString *)getBannerIconPath { + return bannerIconPath; +} + +-(BOOL)bannerWithIconTint { + return bannerIconTint; +} + +-(NSString *)getChangelogPlistPath { + return changelogPlistPath; +} + +-(NSString *)getCurrentVersion { + return currentVersion; +} + +-(NSString *)getSocialPlistPath { + return socialPlistPath; +} + +-(NSString *)getSocialIconPath { + return socialIconPath; +} + +-(NSString *)getTwitterName { + return twitterName; +} + +-(NSString *)getTwitterAvatarPath { + return twitterAvatar; +} + +-(NSString *)getTwitterURL { + return twitterURL; +} + +-(NSString *)getTweakPlistPath { + return tweakPlistPath; +} + +-(NSString *)getTweakIconPath { + return tweakIconPath; +} + +-(NSString *)getCrewTitle { + return crewTitle; +} + +-(NSString *)getCrewPlistPath { + return crewPlistPath; +} + +-(NSString *)getCrewImagePath { + return crewImagePath; +} + +-(BOOL)populateAssetsFromLibrary { + return useLibraryAssets; +} + +-(BOOL)externalCellInset { + return externalCellInset; +} + + +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +// New code +// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +- (void)setBool:(BOOL)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + [settings2 setObject:[NSNumber numberWithBool:anObject] forKey:aKey]; + [settings2 writeToFile:prefPath2 atomically:YES]; + } +} + +- (void)setObject:(id)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + [settings2 setObject:anObject forKey:aKey]; + [settings2 writeToFile:prefPath2 atomically:YES]; + } +} + +- (void)setFloat:(long long)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + [settings2 setObject:@(anObject) forKey:aKey]; + [settings2 writeToFile:prefPath2 atomically:YES]; + } +} + +- (void)setInt:(int)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + [settings2 setObject:@(anObject) forKey:aKey]; + [settings2 writeToFile:prefPath2 atomically:YES]; + } +} + +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + if([settings2 objectForKey:aKey] == NULL){ + return defaultValue; + } + return [[settings2 objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [settings2 objectForKey:aKey]?:defaultValue; +} + +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [[settings2 objectForKey:aKey] longLongValue]?:defaultValue; +} + +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [[settings2 objectForKey:aKey] intValue]?:defaultValue; +} + +- (bool)boolForKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [[settings2 objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [settings2 objectForKey:aKey]; +} + +- (long long)floatForKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [[settings2 objectForKey:aKey] longLongValue]; +} + +- (int)intForKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [[settings2 objectForKey:aKey] intValue]; +} + +- (UIColor *)colourForKey:(id)aKey defaultValue:(id)defaultValue ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + NSString *colourString = [settings2 objectForKey:aKey]?:defaultValue; + UIColor *color = colorFromHexString(colourString); + return color; +} + +@end diff --git a/libTitanD3vUniversal/PrimraryController/TDPrimraryController.h b/libTitanD3vUniversal/PrimraryController/TDPrimraryController.h new file mode 100644 index 0000000..1f3f5e5 --- /dev/null +++ b/libTitanD3vUniversal/PrimraryController/TDPrimraryController.h @@ -0,0 +1,42 @@ + +#import +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "TDUtilities.h" +#import "GlobalPrefs.h" +#import "TDBannerView.h" +#import "TDGridCell.h" +#import "DrawerViewController.h" +#import "TDBlurView.h" +#import "ConstraintExtension.h" + +@interface TDPrimraryController : PSListController + +@property (nonatomic, retain) UILabel *greetingLabel; +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (nonatomic, retain) NSString *bundleID; +@property (nonatomic, retain) UIColor *navigationBarColour; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *backgroundColour; +@property (nonatomic, retain) UIColor *cellsColour; +@property (nonatomic, retain) UIColor *labelColour; +@property (nonatomic, retain) TDBannerView *bannerView; +@property (nonatomic, retain) DrawerViewController *drawerVC; +@property (nonatomic, retain) UIRefreshControl *respringController; +@property (nonatomic, retain) TDBlurView *tutorialView; +@property (nonatomic, retain) UIImageView *tutorialImage; +@property (nonatomic) NSInteger licenceStatus; +@property (nonatomic, retain) UIImageView *licenceImage; +-(void)updateLicenceStatus; +@end + + +@interface UIStatusBar : NSObject +@property (nonatomic, assign) UIColor *foregroundColor; +@end + +@interface UIApplication (Private) +@property (nonatomic, retain) UIStatusBar *statusBar; +@end diff --git a/libTitanD3vUniversal/PrimraryController/TDPrimraryController.m b/libTitanD3vUniversal/PrimraryController/TDPrimraryController.m new file mode 100644 index 0000000..87e99dc --- /dev/null +++ b/libTitanD3vUniversal/PrimraryController/TDPrimraryController.m @@ -0,0 +1,345 @@ +#import "TDPrimraryController.h" +#import + +#define MAIN_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width +#define MAIN_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height + +@implementation TDPrimraryController + +- (void)viewDidLoad { + [super viewDidLoad]; + +} + + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + + UIButton *drawerButton = [[UIButton alloc] init]; + drawerButton.backgroundColor = UIColor.clearColor; + UIImage *drawerImage = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/drawer-menu.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [drawerButton setImage:drawerImage forState:UIControlStateNormal]; + [drawerButton addTarget:self action:@selector(openDrawer) forControlEvents:UIControlEventTouchUpInside]; + drawerButton.tintColor = self.tintColour; + + [drawerButton.widthAnchor constraintEqualToConstant:25].active = YES; + [drawerButton.heightAnchor constraintEqualToConstant:25].active = YES; + + UIBarButtonItem *drawerItem = [[UIBarButtonItem alloc] initWithCustomView:drawerButton]; + self.navigationItem.rightBarButtonItems = @[drawerItem]; + + + self.navigationBarColour = [[TDAppearance sharedInstance] navigationBarColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.backgroundColour = [[TDAppearance sharedInstance] backgroundColour]; + self.cellsColour = [[TDAppearance sharedInstance] cellColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + + UINavigationBar *bar = self.navigationController.navigationController.navigationBar; + bar.barTintColor = self.navigationBarColour; + bar.tintColor = self.tintColour; + [[UIButton appearance]setTintColor:self.tintColour]; + self.view.tintColor = self.tintColour; + + + UITableView *tableView = self.view.subviews[0]; + tableView.backgroundColor = self.backgroundColour; + [tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + + [[UILabel appearance] setTextColor:self.labelColour]; + + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = self.tintColour; + + + UIView *navbarContainerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 150, 50)]; + NSString *profileNameString = [[TDPrefsManager sharedInstance] objectForKey:@"profileName" defaultValue:@"UserName"]; + self.greetingLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,0,150,50)]; + self.greetingLabel.font = [UIFont systemFontOfSize:10]; + self.greetingLabel.textColor = self.labelColour; + self.greetingLabel.textAlignment = NSTextAlignmentCenter; + self.greetingLabel.numberOfLines = 2; + self.greetingLabel.alpha = 0; + self.greetingLabel.text = [NSString stringWithFormat:@"%@ \n%@", [[TDUtilities sharedInstance] greeting], profileNameString]; + [navbarContainerView addSubview:self.greetingLabel]; + + self.navigationItem.titleView = navbarContainerView; + + + TDBannerView *header = [[TDBannerView alloc] init]; + header.frame = CGRectMake(0, 0, tableView.bounds.size.width, 250); + tableView.tableHeaderView = header; + + + self.licenceImage = [[UIImageView alloc] init]; + // if (self.licenceStatus == 0) { + // self.licenceImage.image = nil; + // } else if (self.licenceStatus == 1) { + // self.licenceImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Licence/unowned.png"]; + // } else if (self.licenceStatus == 2) { + // self.licenceImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Licence/trial.png"]; + // } else if (self.licenceStatus == 3) { + // self.licenceImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Licence/owned.png"]; + // } + [header.baseView addSubview:self.licenceImage]; + + [self.licenceImage size:CGSizeMake(65, 65)]; + [self.licenceImage top:header.topAnchor padding:5]; + [self.licenceImage trailing:header.trailingAnchor padding:-5]; + + + self.blurEffectView = [[UIVisualEffectView alloc] init]; + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + self.blurEffectView.alpha = 0; + [self.view addSubview:self.blurEffectView]; + + self.blurEffectView.translatesAutoresizingMaskIntoConstraints = false; + [self.blurEffectView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.blurEffectView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.blurEffectView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.blurEffectView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; + + + self.respringController = [[UIRefreshControl alloc] init]; + [self.respringController addTarget:self action:@selector(beginRespring:) forControlEvents:UIControlEventValueChanged]; + NSString *title = @"Respring"; + NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject:self.tintColour forKey:NSForegroundColorAttributeName]; + NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:title attributes:attrsDictionary]; + self.respringController.attributedTitle = attributedTitle; + self.respringController.tintColor = self.tintColour; + [tableView addSubview:self.respringController]; + + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissDrawerNotification:) name:@"DismissDrawer" object:nil]; + + + self.tutorialView = [[TDBlurView alloc] initWithFrame:self.view.bounds style:Dark]; + self.tutorialView.clipsToBounds = true; + self.tutorialView.layer.cornerRadius = 30; + self.tutorialView.alpha = 0; + [self.view addSubview:self.tutorialView]; + + self.tutorialView.translatesAutoresizingMaskIntoConstraints = NO; + [self.tutorialView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-15].active = YES; + [self.tutorialView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-15].active = YES; + [self.tutorialView.widthAnchor constraintEqualToConstant:60].active = YES; + [self.tutorialView.heightAnchor constraintEqualToConstant:60].active = YES; + + + self.tutorialImage = [[UIImageView alloc] init]; + self.tutorialImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Icons/tutorial.png"]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + [self.tutorialView addSubview:self.tutorialImage]; + + self.tutorialImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.tutorialImage.widthAnchor constraintEqualToConstant:45].active = YES; + [self.tutorialImage.heightAnchor constraintEqualToConstant:45].active = YES; + [[self.tutorialImage centerYAnchor] constraintEqualToAnchor:self.tutorialView.centerYAnchor].active = true; + [[self.tutorialImage centerXAnchor] constraintEqualToAnchor:self.tutorialView.centerXAnchor].active = true; + + [self.tutorialView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(presentTutorialVC)]]; + + + [UIView animateWithDuration:1.0 animations:^{ + self.greetingLabel.alpha = 1; + self.tutorialView.alpha = 1; + }]; + +} + + +- (void)dismissDrawerNotification:(NSNotification *) notification { + + if ([[notification name] isEqualToString:@"DismissDrawer"]){ + [self dismissDrawerVC]; + } +} + + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [[UINavigationBar appearance] tintColor]; + + + UINavigationBar *bar = self.navigationController.navigationController.navigationBar; + bar.barTintColor = [[UINavigationBar appearance] barTintColor]; + bar.tintColor = [[UINavigationBar appearance] tintColor]; + + self.view.tintColor = nil; + [[UIButton appearance]setTintColor:nil]; + [[UILabel appearance] setTextColor:nil]; + + [UIView animateWithDuration:0.4 animations:^{ + self.greetingLabel.alpha = 0; + self.tutorialView.alpha = 0; + }]; + +} + + +-(void)tableView:(UITableView*)tableView willDisplayCell:(PSTableCell*)cell forRowAtIndexPath:(NSIndexPath*)indexPath{ + + UIBezierPath *maskPath; + if ([self rowsForGroup:indexPath.section] == 1) { + maskPath=[UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight|UIRectCornerBottomLeft|UIRectCornerBottomRight cornerRadii:[self cornerRadiiForSection:indexPath.section]]; + } else if (indexPath.row == 0) { + maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:UIRectCornerTopLeft| UIRectCornerTopRight cornerRadii:[self cornerRadiiForSection:indexPath.section]]; + } else if (indexPath.row == [self rowsForGroup:indexPath.section] - 1) { + maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerBottomRight cornerRadii:[self cornerRadiiForSection:indexPath.section]]; + } else { + maskPath = [UIBezierPath bezierPathWithRect:cell.bounds]; + } + + CAShapeLayer *maskLayer = [CAShapeLayer layer]; + maskLayer.frame = cell.bounds; + maskLayer.path = maskPath.CGPath; + cell.layer.mask = maskLayer; + cell.layer.shadowPath = maskPath.CGPath; + + cell.backgroundColor = self.cellsColour; +} + + +- (CGSize)cornerRadiiForSection:(NSInteger)section{ + return CGSizeMake(10, 10); +} + + +- (void)openController:(GridButton *)sender { + + invokeHapticFeedback(); + + NSString *className = sender.identifier; + PSListController *controller = [[NSClassFromString(className) alloc] init]; + [[self navigationController] pushViewController:controller animated:YES]; +} + + +-(void)openDrawer { + + invokeHapticFeedback(); + + self.drawerVC = [[DrawerViewController alloc] init]; + [self presentViewController:self.drawerVC animated:YES completion:nil]; +} + + +-(void)dismissDrawerVC { + + [self.drawerVC dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)beginRespring:(id)sender { + + [self.respringController endRefreshing]; + + [UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + self.blurEffectView.alpha = 1; + } completion:^(BOOL finished) { + [[TDUtilities sharedInstance] respring]; + }]; + +} + + +- (id)readPreferenceValue:(PSSpecifier*)specifier { + NSString *path = [NSString stringWithFormat:@"/User/Library/Preferences/%@.plist", specifier.properties[@"defaults"]]; + NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:path]; + return (plist[specifier.properties[@"key"]]) ?: specifier.properties[@"default"]; +} + + +- (void)setPreferenceValue:(id)value specifier:(PSSpecifier*)specifier { + NSString *path = [NSString stringWithFormat:@"/User/Library/Preferences/%@.plist", specifier.properties[@"defaults"]]; + NSMutableDictionary *plist = [NSMutableDictionary dictionaryWithContentsOfFile:path] ?: [NSMutableDictionary new]; + plist[specifier.properties[@"key"]] = value; + [plist writeToFile:path atomically:true]; + CFStringRef notificationName = (__bridge CFStringRef)specifier.properties[@"PostNotification"]; + if (notificationName) { + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), notificationName, NULL, NULL, true); + } +} + + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + + if (scrollView.contentOffset.y < 0) { + [UIView animateWithDuration:0.5 animations:^{ + self.greetingLabel.alpha = 1; + self.tutorialView.alpha = 1; + }]; + + } else if (scrollView.contentOffset.y >= 20) { + [UIView animateWithDuration:0.5 animations:^{ + self.greetingLabel.alpha = 0; + self.tutorialView.alpha = 0; + }]; + } +} + + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + + +-(void)updateLicenceStatus { + + if (self.licenceStatus == 0) { + self.licenceImage.image = nil; + } else if (self.licenceStatus == 1) { + self.licenceImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Licence/unowned.png"]; + } else if (self.licenceStatus == 2) { + self.licenceImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Licence/trial.png"]; + } else if (self.licenceStatus == 3) { + self.licenceImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Licence/owned.png"]; + } +} + +@end diff --git a/libTitanD3vUniversal/PrivateFrameworks/PrivateBlurEffect.h b/libTitanD3vUniversal/PrivateFrameworks/PrivateBlurEffect.h new file mode 100644 index 0000000..b1a9c13 --- /dev/null +++ b/libTitanD3vUniversal/PrivateFrameworks/PrivateBlurEffect.h @@ -0,0 +1,24 @@ +#import + +@interface _UIBackdropView : UIView +-(id)initWithFrame:(CGRect)arg1 autosizesToFitSuperview:(BOOL)arg2 settings:(id)arg3 ; +-(id)initWithSettings:(id)arg1 ; +-(id)initWithStyle:(long long)arg1 ; +- (void)setBlurFilterWithRadius:(float)arg1 blurQuality:(id)arg2 blurHardEdges:(int)arg3; +- (void)setBlurFilterWithRadius:(float)arg1 blurQuality:(id)arg2; +- (void)setBlurHardEdges:(int)arg1; +- (void)setBlurQuality:(id)arg1; +- (void)setBlurRadius:(float)arg1; +- (void)setBlurRadiusSetOnce:(BOOL)arg1; +- (void)setBlursBackground:(BOOL)arg1; +- (void)setBlursWithHardEdges:(BOOL)arg1; +@end + +@interface _UIBackdropViewSettings : NSObject +@property (assign,getter=isEnabled,nonatomic) BOOL enabled; +@property (assign,nonatomic) double blurRadius; +@property (nonatomic,copy) NSString * blurQuality; +@property (assign,nonatomic) BOOL usesBackdropEffectView; +-(id)initWithDefaultValues; ++(id)settingsForStyle:(long long)arg1 ; +@end diff --git a/libTitanD3vUniversal/RNCryptor/RNCryptor+Private.h b/libTitanD3vUniversal/RNCryptor/RNCryptor+Private.h new file mode 100755 index 0000000..7fb2fbb --- /dev/null +++ b/libTitanD3vUniversal/RNCryptor/RNCryptor+Private.h @@ -0,0 +1,28 @@ +#import +#import "RNCryptor.h" + +@class RNCryptorEngine; + +@interface RNCryptor () +@property (nonatomic, readwrite, strong) RNCryptorEngine *engine; +#if OS_OBJECT_USE_OBJC +@property (nonatomic, readwrite, strong) dispatch_queue_t queue; +#else +@property (nonatomic, readwrite, assign) dispatch_queue_t queue; +#endif +@property (nonatomic, readonly) NSMutableData *outData; +@property (nonatomic, readwrite, copy) RNCryptorHandler handler; +@property (nonatomic, readwrite, assign) NSUInteger HMACLength; +@property (nonatomic, readwrite, strong) NSError *error; +@property (nonatomic, readwrite, assign, getter=isFinished) BOOL finished; +@property (nonatomic, readwrite, assign) RNCryptorOptions options; + +- (id)initWithHandler:(RNCryptorHandler)handler; ++ (NSData *)synchronousResultForCryptor:(RNCryptor *)cryptor data:(NSData *)inData error:(NSError **)anError; +- (void)cleanupAndNotifyWithError:(NSError *)error; +- (BOOL)hasHMAC; +@end + +@interface NSMutableData (RNCryptor) +- (NSData *)_RNConsumeToIndex:(NSUInteger)index; +@end diff --git a/libTitanD3vUniversal/RNCryptor/RNCryptor.h b/libTitanD3vUniversal/RNCryptor/RNCryptor.h new file mode 100755 index 0000000..179346b --- /dev/null +++ b/libTitanD3vUniversal/RNCryptor/RNCryptor.h @@ -0,0 +1,85 @@ +#import +#import + +// NOTE: No CommonCrypto types may be used in this file. Swift can't handle them. + +extern NSString *const kRNCryptorErrorDomain; +extern const uint8_t kRNCryptorFileVersion; + +typedef struct _RNCryptorKeyDerivationSettings +{ + size_t keySize; + size_t saltSize; + /* CCPBKDFAlgorithm */ uint32_t PBKDFAlgorithm; + /* CCPseudoRandomAlgorithm */ uint32_t PRF; + uint rounds; + BOOL hasV2Password; // See Issue #77. V2 incorrectly handled multi-byte characters. +} RNCryptorKeyDerivationSettings; + +typedef struct _RNCryptorSettings +{ + /* CCAlgorithm */ uint32_t algorithm; + size_t blockSize; + size_t IVSize; + /* CCOptions */ uint32_t options; + /* CCHmacAlgorithm */ uint32_t HMACAlgorithm; + size_t HMACLength; + RNCryptorKeyDerivationSettings keySettings; + RNCryptorKeyDerivationSettings HMACKeySettings; +} RNCryptorSettings; + +extern const RNCryptorSettings kRNCryptorAES256Settings; + +enum _RNCryptorOptions +{ + kRNCryptorOptionHasPassword = 1 << 0, +}; +typedef uint8_t RNCryptorOptions; + +enum +{ + kRNCryptorHMACMismatch = 1, + kRNCryptorUnknownHeader = 2, +}; + +@class RNCryptor; + +typedef void (^RNCryptorHandler)(RNCryptor *cryptor, NSData *data); + +///** Encryptor/Decryptor for iOS +// +// Provides an easy-to-use, Objective-C interface to the AES functionality of CommonCrypto. Simplifies correct handling of +// password stretching (PBKDF2), salting, and IV. For more information on these terms, see "Properly encrypting with AES +// with CommonCrypto," and iOS 5 Programming Pushing the Limits, Chapter 11. Also includes automatic HMAC handling to integrity-check messages. +// +// RNCryptor is abstract. Use RNEncryptor to encrypt or RNDecryptor to decrypt +// */ +// + +@interface RNCryptor : NSObject +@property (nonatomic, readonly, strong) NSError *error; +@property (nonatomic, readonly, getter=isFinished) BOOL finished; +@property (nonatomic, readonly, copy) RNCryptorHandler handler; +@property (nonatomic, readwrite) dispatch_queue_t responseQueue; + +- (void)addData:(NSData *)data; +- (void)finish; + +/** Generate key given a password and salt using a PBKDF + * + * @param password Password to use for PBKDF + * @param salt Salt for password + * @param keySettings Settings for the derivation (RNCryptorKeyDerivationSettings) + * @returns Key + * @throws if settings are illegal + */ ++ (NSData *)keyForPassword:(NSString *)password salt:(NSData *)salt settings:(RNCryptorKeyDerivationSettings)keySettings; + +/** Generate random data + * + * @param length Length of data to generate + * @returns random data + */ ++ (NSData *)randomDataOfLength:(size_t)length; + +@end diff --git a/libTitanD3vUniversal/RNCryptor/RNCryptor.m b/libTitanD3vUniversal/RNCryptor/RNCryptor.m new file mode 100755 index 0000000..ce5784b --- /dev/null +++ b/libTitanD3vUniversal/RNCryptor/RNCryptor.m @@ -0,0 +1,464 @@ +#import "RNCryptor.h" +#import "RNCryptor+Private.h" + +#import +#import +#import +#import + +const RNCryptorSettings kRNCryptorAES256Settings = { + .algorithm = kCCAlgorithmAES128, + .blockSize = kCCBlockSizeAES128, + .IVSize = kCCBlockSizeAES128, + .options = kCCOptionPKCS7Padding, + .HMACAlgorithm = kCCHmacAlgSHA256, + .HMACLength = CC_SHA256_DIGEST_LENGTH, + + .keySettings = { + .keySize = kCCKeySizeAES256, + .saltSize = 8, + .PBKDFAlgorithm = kCCPBKDF2, + .PRF = kCCPRFHmacAlgSHA1, + .rounds = 10000 + }, + + .HMACKeySettings = { + .keySize = kCCKeySizeAES256, + .saltSize = 8, + .PBKDFAlgorithm = kCCPBKDF2, + .PRF = kCCPRFHmacAlgSHA1, + .rounds = 10000 + } +}; + +// Provide internal symbols for 10.6. These were made available in 10.7. +#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED +#if __MAC_OS_X_VERSION_MAX_ALLOWED <= 1060 +extern int SecRandomCopyBytes(SecRandomRef rnd, size_t count, uint8_t *bytes) __attribute__((weak_import)); +extern int +CCKeyDerivationPBKDF( CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen, + const uint8_t *salt, size_t saltLen, + CCPseudoRandomAlgorithm prf, uint rounds, + uint8_t *derivedKey, size_t derivedKeyLen) __attribute__((weak_import)); +#endif +#endif + +NSString *const kRNCryptorErrorDomain = @"net.robnapier.RNCryptManager"; +const uint8_t kRNCryptorFileVersion = 3; + +// TODO: This is a slightly expensive solution, but it's convenient. May want to create a "walkable" data object +@implementation NSMutableData (RNCryptor) +- (NSData *)_RNConsumeToIndex:(NSUInteger)index +{ + NSData *removed = [self subdataWithRange:NSMakeRange(0, index)]; + [self replaceBytesInRange:NSMakeRange(0, self.length - index) withBytes:([self mutableBytes] + index)]; + [self setLength:self.length - index]; + return removed; +} +@end + + +@implementation RNCryptor +@synthesize responseQueue = _responseQueue; +@synthesize engine = _engine; +@synthesize outData = __outData; +@synthesize queue = _queue; +@synthesize HMACLength = __HMACLength; +@synthesize error = _error; +@synthesize finished = _finished; +@synthesize options = _options; +@synthesize handler = _handler; + ++ (NSData *)synchronousResultForCryptor:(RNCryptor *)cryptor data:(NSData *)inData error:(NSError **)anError +{ + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + + NSMutableData *data = [NSMutableData data]; + __block NSError *returnedError = nil; + + RNCryptorHandler handler = ^(RNCryptor *c, NSData *d) { + [data appendData:d]; + if (c.isFinished) { + returnedError = c.error; + dispatch_semaphore_signal(sem); + } + }; + + cryptor.handler = handler; + + dispatch_queue_t queue = dispatch_queue_create("net.robnapier.RNEncryptor.response", DISPATCH_QUEUE_SERIAL); + cryptor.responseQueue = queue; + [cryptor addData:inData]; + [cryptor finish]; + + + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + +#if !OS_OBJECT_USE_OBJC + dispatch_release(sem); + if (queue) { + dispatch_release(queue); + } +#endif + + if (returnedError) { + if (anError) { + *anError = returnedError; + } + return nil; + } + else { + return data; + } +} + +// For use with OS X 10.6 +// Based on http://opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/API/CommonKeyDerivation.c +/*- + * Copyright (c) 2008 Damien Bergamini + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#define CC_MAX_PRF_WORKSPACE 128+4 +#define kCCPRFHmacAlgSHA1hlen CC_SHA1_DIGEST_LENGTH +#define kCCPRFHmacAlgSHA224hlen CC_SHA224_DIGEST_LENGTH +#define kCCPRFHmacAlgSHA256hlen CC_SHA256_DIGEST_LENGTH +#define kCCPRFHmacAlgSHA384hlen CC_SHA384_DIGEST_LENGTH +#define kCCPRFHmacAlgSHA512hlen CC_SHA512_DIGEST_LENGTH + +static size_t +getPRFhlen(CCPseudoRandomAlgorithm prf) +{ + switch(prf) { + case kCCPRFHmacAlgSHA1: return kCCPRFHmacAlgSHA1hlen; + case kCCPRFHmacAlgSHA224: return kCCPRFHmacAlgSHA224hlen; + case kCCPRFHmacAlgSHA256: return kCCPRFHmacAlgSHA256hlen; + case kCCPRFHmacAlgSHA384: return kCCPRFHmacAlgSHA384hlen; + case kCCPRFHmacAlgSHA512: return kCCPRFHmacAlgSHA512hlen; + default: + NSCAssert(NO, @"Unknown prf: %d", prf); + return 1; + } +} + +static void +PRF(CCPseudoRandomAlgorithm prf, const char *password, size_t passwordLen, u_int8_t *salt, size_t saltLen, u_int8_t *output) +{ + switch(prf) { + case kCCPRFHmacAlgSHA1: + CCHmac(kCCHmacAlgSHA1, password, passwordLen, salt, saltLen, output); + break; + case kCCPRFHmacAlgSHA224: + CCHmac(kCCHmacAlgSHA224, password, passwordLen, salt, saltLen, output); + break; + case kCCPRFHmacAlgSHA256: + CCHmac(kCCHmacAlgSHA256, password, passwordLen, salt, saltLen, output); + break; + case kCCPRFHmacAlgSHA384: + CCHmac(kCCHmacAlgSHA384, password, passwordLen, salt, saltLen, output); + break; + case kCCPRFHmacAlgSHA512: + CCHmac(kCCHmacAlgSHA512, password, passwordLen, salt, saltLen, output); + break; + } +} + +static int +RN_CCKeyDerivationPBKDF( CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen, + const uint8_t *salt, size_t saltLen, + CCPseudoRandomAlgorithm prf, uint rounds, + uint8_t *derivedKey, size_t derivedKeyLen) +{ + u_int8_t oldbuffer[CC_MAX_PRF_WORKSPACE], newbuffer[CC_MAX_PRF_WORKSPACE], + saltCopy[CC_MAX_PRF_WORKSPACE+4], collector[CC_MAX_PRF_WORKSPACE]; + int rawblock, i, j; + size_t r, nblocks; + size_t hlen, offset; + + if(algorithm != kCCPBKDF2) return -1; + + /* + * Check initial parameters + */ + + if (rounds < 1 || derivedKeyLen == 0) + return -1; // bad parameters + if (saltLen == 0 || saltLen > CC_MAX_PRF_WORKSPACE) + return -1; // out of bounds parameters + + hlen = getPRFhlen(prf); + + /* + * FromSpec: Let l be the number of hLen-octet blocks in the derived key, rounding up, + * and let r be the number of octets in the last block: + */ + + nblocks = (derivedKeyLen+hlen-1)/hlen; // in the spec nblocks is referred to as l + r = derivedKeyLen % hlen; + r = (r) ? r: hlen; + + /* + * Make a copy of the salt buffer so we can concatenate the + * block counter for each series of rounds. + */ + + memcpy(saltCopy, salt, saltLen); + bzero(derivedKey, derivedKeyLen); + + /* + * FromSpec: + * + * For each block of the derived key apply the function F defined below to the password P, + * the salt S, the iteration count c, and the block index to compute the block: + * + * F(P,S,c,i)=U1 \xorU2 \xor⋅⋅⋅\xorUc + * + * where + * U1 =PRF(P,S||INT (i)), + * U2 =PRF(P,U1), + * ... + * Uc = PRF (P, Uc-1) . + */ + + for(rawblock = 0; rawblock < nblocks; rawblock++) { + int block = rawblock+1; + size_t copyLen; + + offset = rawblock * hlen; + copyLen = (block != nblocks) ? hlen: r; + + /* + * FromSpec: Here, INT (i) is a four-octet encoding of the integer i, most significant octet first. + */ + + for(i=0; i<4; i++) saltCopy[saltLen+i] = (block >> 8*(3-i)) & 0xff; + + PRF(prf, password, passwordLen, saltCopy, saltLen+4, oldbuffer); // Initial PRF with the modified salt + + memcpy(collector, oldbuffer, hlen); // Initial value for this block of the derived key. + + for(i = 1; i < rounds; i++) { + PRF(prf, password, passwordLen, oldbuffer, hlen, newbuffer); // Subsequent PRF with the previous result as the salt + memcpy(oldbuffer, newbuffer, hlen); + for(j = 0; j < hlen; j++) collector[j] ^= newbuffer[j]; // Xoring the round into the collector + } + memcpy(derivedKey+offset, collector, copyLen); + } + + /* + * Clear temp buffers. + */ + + bzero(oldbuffer, CC_MAX_PRF_WORKSPACE); + bzero(newbuffer, CC_MAX_PRF_WORKSPACE); + bzero(collector, CC_MAX_PRF_WORKSPACE); + bzero(saltCopy, CC_MAX_PRF_WORKSPACE+4); + + return 0; +} + +/* End code derived from CommonKeyDerivation.c */ + + ++ (NSData *)keyForPassword:(NSString *)password salt:(NSData *)salt settings:(RNCryptorKeyDerivationSettings)keySettings +{ + NSMutableData *derivedKey = [NSMutableData dataWithLength:keySettings.keySize]; + + // See Issue #77. V2 incorrectly calculated key for multi-byte characters. + NSData *passwordData; + if (keySettings.hasV2Password) { + passwordData = [NSData dataWithBytes:[password UTF8String] length:[password length]]; + } + else { + passwordData = [password dataUsingEncoding:NSUTF8StringEncoding]; + } + + // Use the built-in PBKDF2 if it's available. Otherwise, we have our own. Hello crazy function pointer. + int result; + int (*PBKDF)(CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen, + const uint8_t *salt, size_t saltLen, + CCPseudoRandomAlgorithm prf, uint rounds, + uint8_t *derivedKey, size_t derivedKeyLen); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" + PBKDF = CCKeyDerivationPBKDF ?: RN_CCKeyDerivationPBKDF; +#pragma clang diagnostic pop + + result = PBKDF(keySettings.PBKDFAlgorithm, // algorithm + passwordData.bytes, // password + passwordData.length, // passwordLength + salt.bytes, // salt + salt.length, // saltLen + keySettings.PRF, // PRF + keySettings.rounds, // rounds + derivedKey.mutableBytes, // derivedKey + derivedKey.length); // derivedKeyLen + + // Do not log password here + NSAssert(result == kCCSuccess, @"Unable to create AES key for password: %d", result); + + return derivedKey; +} + +// For use on OS X 10.6 +// Based on http://www.opensource.apple.com/source/Security/Security-55179.1/sec/Security/SecFramework.c +// Modified by Rob Napier April, 2013. +/* + * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +static int RN_SecRandomCopyBytes(void *rnd, size_t count, uint8_t *bytes) { + static int kSecRandomFD; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + kSecRandomFD = open("/dev/random", O_RDONLY); + }); + + if (kSecRandomFD < 0) + return -1; + while (count) { + ssize_t bytes_read = read(kSecRandomFD, bytes, count); + if (bytes_read == -1) { + if (errno == EINTR) + continue; + return -1; + } + if (bytes_read == 0) { + return -1; + } + bytes += bytes_read; + count -= bytes_read; + } + + return 0; +} +/* End code dervied from SecFramework.c */ + ++ (NSData *)randomDataOfLength:(size_t)length +{ + NSMutableData *data = [NSMutableData dataWithLength:length]; + + int result; + if (&SecRandomCopyBytes != NULL) { + result = SecRandomCopyBytes(NULL, length, data.mutableBytes); + } + else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" + result = RN_SecRandomCopyBytes(NULL, length, data.mutableBytes); +#pragma clang diagnostic pop + } + NSAssert(result == 0, @"Unable to generate random bytes: %d", errno); + + return data; +} + +- (id)initWithHandler:(RNCryptorHandler)handler +{ + NSParameterAssert(handler); + self = [super init]; + if (self) { + NSString *responseQueueName = [@"net.robnapier.response." stringByAppendingString:NSStringFromClass([self class])]; + _responseQueue = dispatch_queue_create([responseQueueName UTF8String], NULL); + + NSString *queueName = [@"net.robnapier." stringByAppendingString:NSStringFromClass([self class])]; + _queue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL); + __outData = [NSMutableData data]; + + _handler = [handler copy]; + } + return self; +} + +- (void)dealloc +{ + if (_responseQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_responseQueue); +#endif + _responseQueue = NULL; + } + + if (_queue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_queue); +#endif + _queue = NULL; + } +} + +- (void)setResponseQueue:(dispatch_queue_t)aResponseQueue +{ + if (aResponseQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_retain(aResponseQueue); +#endif + } + + if (_responseQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_responseQueue); +#endif + } + + _responseQueue = aResponseQueue; +} + +- (void)addData:(NSData *)data +{ + +} + +- (void)finish +{ + +} + +- (void)cleanupAndNotifyWithError:(NSError *)error +{ + self.error = error; + self.finished = YES; + if (self.handler) { + dispatch_sync(self.responseQueue, ^{ + self.handler(self, self.outData); + }); + self.handler = nil; + } +} + +- (BOOL)hasHMAC +{ + return self.HMACLength > 0; +} + + +@end diff --git a/libTitanD3vUniversal/RNCryptor/RNCryptorEngine.h b/libTitanD3vUniversal/RNCryptor/RNCryptorEngine.h new file mode 100755 index 0000000..a1336a8 --- /dev/null +++ b/libTitanD3vUniversal/RNCryptor/RNCryptorEngine.h @@ -0,0 +1,9 @@ +#import +#import +#import "RNCryptor.h" + +@interface RNCryptorEngine : NSObject +- (RNCryptorEngine *)initWithOperation:(CCOperation)operation settings:(RNCryptorSettings)settings key:(NSData *)key IV:(NSData *)IV error:(NSError **)error; +- (NSData *)addData:(NSData *)data error:(NSError **)error; +- (NSData *)finishWithError:(NSError **)error; +@end diff --git a/libTitanD3vUniversal/RNCryptor/RNCryptorEngine.m b/libTitanD3vUniversal/RNCryptor/RNCryptorEngine.m new file mode 100755 index 0000000..309dedd --- /dev/null +++ b/libTitanD3vUniversal/RNCryptor/RNCryptorEngine.m @@ -0,0 +1,88 @@ +#import "RNCryptorEngine.h" + +@interface RNCryptorEngine () +@property (nonatomic, readonly) CCCryptorRef cryptor; +@property (nonatomic, readonly) NSMutableData *buffer; +@end + +@implementation RNCryptorEngine +@synthesize cryptor = __cryptor; +@synthesize buffer = __buffer; + + +- (RNCryptorEngine *)initWithOperation:(CCOperation)operation settings:(RNCryptorSettings)settings key:(NSData *)key IV:(NSData *)IV error:(NSError **)error +{ + self = [super init]; + if (self) { + CCCryptorStatus + cryptorStatus = CCCryptorCreate(operation, + settings.algorithm, + settings.options, + key.bytes, + key.length, + IV.bytes, + &__cryptor); + if (cryptorStatus != kCCSuccess || __cryptor == NULL) { + if (error) { + *error = [NSError errorWithDomain:kRNCryptorErrorDomain code:cryptorStatus userInfo:nil]; + } + self = nil; + return nil; + } + + __buffer = [NSMutableData data]; + } + return self; +} + +- (void)dealloc +{ + if (__cryptor) { + CCCryptorRelease(__cryptor); + } +} + +- (NSData *)addData:(NSData *)data error:(NSError **)error +{ + NSMutableData *buffer = self.buffer; + [buffer setLength:CCCryptorGetOutputLength(self.cryptor, [data length], true)]; // We'll reuse the buffer in -finish + + size_t dataOutMoved; + CCCryptorStatus + cryptorStatus = CCCryptorUpdate(self.cryptor, // cryptor + data.bytes, // dataIn + data.length, // dataInLength (verified > 0 above) + buffer.mutableBytes, // dataOut + buffer.length, // dataOutAvailable + &dataOutMoved); // dataOutMoved + + if (cryptorStatus != kCCSuccess) { + if (error) { + *error = [NSError errorWithDomain:kRNCryptorErrorDomain code:cryptorStatus userInfo:nil]; + } + return nil; + } + + return [buffer subdataWithRange:NSMakeRange(0, dataOutMoved)]; +} + +- (NSData *)finishWithError:(NSError **)error +{ + NSMutableData *buffer = self.buffer; + size_t dataOutMoved; + CCCryptorStatus + cryptorStatus = CCCryptorFinal(self.cryptor, // cryptor + buffer.mutableBytes, // dataOut + buffer.length, // dataOutAvailable + &dataOutMoved); // dataOutMoved + if (cryptorStatus != kCCSuccess) { + if (error) { + *error = [NSError errorWithDomain:kRNCryptorErrorDomain code:cryptorStatus userInfo:nil]; + } + return nil; + } + + return [buffer subdataWithRange:NSMakeRange(0, dataOutMoved)]; +} + +@end diff --git a/libTitanD3vUniversal/RNCryptor/RNDecryptor.h b/libTitanD3vUniversal/RNCryptor/RNDecryptor.h new file mode 100755 index 0000000..cc1a768 --- /dev/null +++ b/libTitanD3vUniversal/RNCryptor/RNDecryptor.h @@ -0,0 +1,20 @@ +#import +#import "RNCryptor.h" + + +@interface RNDecryptor : RNCryptor + +- (RNDecryptor *)initWithEncryptionKey:(NSData *)encryptionKey + HMACKey:(NSData *)HMACKey + handler:(RNCryptorHandler)handler; + +- (RNDecryptor *)initWithPassword:(NSString *)password + handler:(RNCryptorHandler)handler; + ++ (NSData *)decryptData:(NSData *)theCipherText withSettings:(RNCryptorSettings)settings password:(NSString *)aPassword error:(NSError **)anError; ++ (NSData *)decryptData:(NSData *)theCipherText withSettings:(RNCryptorSettings)settings encryptionKey:(NSData *)encryptionKey HMACKey:(NSData *)HMACKey error:(NSError **)anError; + ++ (NSData *)decryptData:(NSData *)data withPassword:(NSString *)password error:(NSError **)error; ++ (NSData *)decryptData:(NSData *)data withEncryptionKey:(NSData *)encryptionKey HMACKey:(NSData *)HMACKey error:(NSError **)error; + +@end diff --git a/libTitanD3vUniversal/RNCryptor/RNDecryptor.m b/libTitanD3vUniversal/RNCryptor/RNDecryptor.m new file mode 100755 index 0000000..e36fffb --- /dev/null +++ b/libTitanD3vUniversal/RNCryptor/RNDecryptor.m @@ -0,0 +1,295 @@ +#import "RNDecryptor.h" +#import "RNCryptor+Private.h" +#import "RNCryptorEngine.h" + +#import + +static const NSUInteger kPreambleSize = 2; + +@interface NSData (RNCryptor_ConsistentCompare) + +- (BOOL)rnc_isEqualInConsistentTime:(NSData *)otherData; + +@end + +@implementation NSData (RNCryptor_ConstantCompare) + +- (BOOL)rnc_isEqualInConsistentTime:(NSData *)otherData { + // The point of this routine is XOR the bytes of each data and accumulate the results with OR. + // If any bytes are different, then the OR will accumulate some non-0 value. + + const uint8_t *myBytes = [self bytes]; + const NSUInteger myLength = [self length]; + const uint8_t *otherBytes = [otherData bytes]; + const NSUInteger otherLength = [otherData length]; + + uint8_t result = otherLength != myLength; // Start with 0 (equal) only if our lengths are equal + + for (NSUInteger i = 0; i < otherLength; ++i) { + // Use mod to wrap around ourselves if they are longer than we are. + // Remember, we already broke equality if our lengths are different. + result |= myBytes[i % myLength] ^ otherBytes[i]; + } + + return result == 0; +} + +@end + + +@interface RNDecryptor () +@property (nonatomic, readonly, strong) NSMutableData *inData; +@property (nonatomic, readwrite, copy) NSData *encryptionKey; +@property (nonatomic, readwrite, copy) NSData *HMACKey; +@property (nonatomic, readwrite, copy) NSString *password; +@property (nonatomic, readwrite, assign) BOOL hasV1HMAC; + +@property (nonatomic, readwrite, assign) RNCryptorSettings settings; + +@end + +@implementation RNDecryptor +{ + CCHmacContext _HMACContext; + NSMutableData *__inData; +} +@synthesize encryptionKey = _encryptionKey; +@synthesize HMACKey = _HMACKey; +@synthesize password = _password; +@synthesize settings = _settings; + ++ (NSData *)decryptData:(NSData *)theCipherText withSettings:(RNCryptorSettings)settings password:(NSString *)aPassword error:(NSError **)anError +{ + RNDecryptor *cryptor = [[self alloc] initWithPassword:aPassword + handler:^(RNCryptor *c, NSData *d) {}]; + cryptor.settings = settings; + return [self synchronousResultForCryptor:cryptor data:theCipherText error:anError]; +} + ++ (NSData *)decryptData:(NSData *)theCipherText withSettings:(RNCryptorSettings)settings encryptionKey:(NSData *)encryptionKey HMACKey:(NSData *)HMACKey error:(NSError **)anError +{ + RNDecryptor *cryptor = [[self alloc] initWithEncryptionKey:encryptionKey + HMACKey:HMACKey + handler:^(RNCryptor *c, NSData *d) {}]; + cryptor.settings = settings; + return [self synchronousResultForCryptor:cryptor data:theCipherText error:anError]; +} + ++ (NSData *)decryptData:(NSData *)theCipherText withPassword:(NSString *)aPassword error:(NSError **)anError +{ + RNDecryptor *cryptor = [[self alloc] initWithPassword:aPassword + handler:^(RNCryptor *c, NSData *d) {}]; + return [self synchronousResultForCryptor:cryptor data:theCipherText error:anError]; +} + ++ (NSData *)decryptData:(NSData *)theCipherText withEncryptionKey:(NSData *)encryptionKey HMACKey:(NSData *)HMACKey error:(NSError **)anError; +{ + RNDecryptor *cryptor = [[self alloc] initWithEncryptionKey:encryptionKey + HMACKey:HMACKey + handler:^(RNCryptor *c, NSData *d) {}]; + return [self synchronousResultForCryptor:cryptor data:theCipherText error:anError]; +} + +- (RNDecryptor *)initWithEncryptionKey:(NSData *)anEncryptionKey HMACKey:(NSData *)anHMACKey handler:(RNCryptorHandler)aHandler +{ + self = [super initWithHandler:aHandler]; + if (self) { + _encryptionKey = [anEncryptionKey copy]; + _HMACKey = [anHMACKey copy]; + _settings = kRNCryptorAES256Settings; + } + + return self; +} + +- (RNDecryptor *)initWithPassword:(NSString *)aPassword handler:(RNCryptorHandler)aHandler +{ + NSParameterAssert(aPassword != nil); + + self = [self initWithEncryptionKey:nil HMACKey:nil handler:aHandler]; + if (self) { + _password = [aPassword copy]; + _settings = kRNCryptorAES256Settings; + } + return self; +} + +- (NSMutableData *)inData +{ + if (!__inData) { + __inData = [NSMutableData data]; + } + return __inData; +} + +- (void)decryptData:(NSData *)data +{ + dispatch_async(self.queue, ^{ + if (self.hasHMAC) { + CCHmacUpdate(&self->_HMACContext, data.bytes, data.length); + } + + NSError *error = nil; + NSData *decryptedData = [self.engine addData:data error:&error]; + + if (!decryptedData) { + [self cleanupAndNotifyWithError:error]; + return; + } + + [self.outData appendData:decryptedData]; + + dispatch_sync(self.responseQueue, ^{ + self.handler(self, self.outData); + }); + [self.outData setLength:0]; + }); +} + +- (void)addData:(NSData *)theData +{ + if (self.isFinished) { + return; + } + + [self.inData appendData:theData]; + if (!self.engine) { + [self consumeHeaderFromData:self.inData]; + } + if (self.engine) { + NSUInteger HMACLength = self.HMACLength; + if (self.inData.length > HMACLength) { + NSData *data = [self.inData _RNConsumeToIndex:self.inData.length - HMACLength]; + [self decryptData:data]; + } + } +} + +- (BOOL)updateOptionsForPreamble:(NSData *)preamble +{ + const uint8_t *bytes = [preamble bytes]; + + // See http://robnapier.net/blog/rncryptor-hmac-vulnerability-827 for information on the v1 bad HMAC +#ifdef RNCRYPTOR_ALLOW_V1_BAD_HMAC + if (bytes[0] == 1) { + self.options = bytes[1]; + self.hasV1HMAC = YES; + return YES; + } +#endif + + if (bytes[0] == 2) { + self.options = bytes[1]; + + RNCryptorSettings settings = self.settings; + settings.keySettings.hasV2Password = YES; + settings.HMACKeySettings.hasV2Password = YES; + self.settings = settings; + return YES; + } + + if (bytes[0] == kRNCryptorFileVersion) { + self.options = bytes[1]; + return YES; + } + + return NO; +} + +- (void)consumeHeaderFromData:(NSMutableData *)data +{ + if (data.length < kPreambleSize) { + return; + } + + if (![self updateOptionsForPreamble:[data subdataWithRange:NSMakeRange(0, kPreambleSize)]]) { + [self cleanupAndNotifyWithError:[NSError errorWithDomain:kRNCryptorErrorDomain + code:kRNCryptorUnknownHeader + userInfo:[NSDictionary dictionaryWithObject:@"Unknown header" /* DNL */ + forKey:NSLocalizedDescriptionKey]]]; + return; + } + + NSUInteger headerSize = kPreambleSize + self.settings.IVSize; + if (self.options & kRNCryptorOptionHasPassword) { + headerSize += self.settings.keySettings.saltSize + self.settings.HMACKeySettings.saltSize; + } + + if (data.length < headerSize) { + return; + } + + NSData *header = [data subdataWithRange:NSMakeRange(0, headerSize)]; // We'll need this for the HMAC later + + [[data _RNConsumeToIndex:kPreambleSize] mutableCopy]; // Throw away the preamble + + NSError *error = nil; + + // If we were called with a password and the format thinks there's a password + // (The format might think there's a password because it's corrupt, and we don't want to assert in that case.) + if ((self.options & kRNCryptorOptionHasPassword) && self.password) { + NSAssert(!self.encryptionKey && !self.HMACKey, @"Both password and the key (%d) or HMACKey (%d) are set.", self.encryptionKey != nil, self.HMACKey != nil); + + NSData *encryptionKeySalt = [data _RNConsumeToIndex:self.settings.keySettings.saltSize]; + NSData *HMACKeySalt = [data _RNConsumeToIndex:self.settings.HMACKeySettings.saltSize]; + self.encryptionKey = [[self class] keyForPassword:self.password salt:encryptionKeySalt settings:self.settings.keySettings]; + self.HMACKey = [[self class] keyForPassword:self.password salt:HMACKeySalt settings:self.settings.HMACKeySettings]; + + self.password = nil; // Don't need this anymore. + } + + NSData *IV = [data _RNConsumeToIndex:self.settings.IVSize]; + + self.engine = [[RNCryptorEngine alloc] initWithOperation:kCCDecrypt settings:self.settings key:self.encryptionKey IV:IV error:&error]; + self.encryptionKey = nil; // Don't need this anymore + if (!self.engine) { + [self cleanupAndNotifyWithError:error]; + return; + } + + if (self.HMACKey) { + CCHmacInit(&_HMACContext, self.settings.HMACAlgorithm, self.HMACKey.bytes, self.HMACKey.length); + self.HMACLength = self.settings.HMACLength; + self.HMACKey = nil; // Don't need this anymore + + if (! self.hasV1HMAC) { + CCHmacUpdate(&_HMACContext, [header bytes], [header length]); + } + } +} + +- (void)finish +{ + if (self.isFinished) { + return; + } + + dispatch_async(self.queue, ^{ + NSError *error = nil; + + if (self.hasHMAC) { + NSMutableData *HMACData = [NSMutableData dataWithLength:self.HMACLength]; + CCHmacFinal(&self->_HMACContext, [HMACData mutableBytes]); + + if (![HMACData rnc_isEqualInConsistentTime:self.inData]) { + [self cleanupAndNotifyWithError:[NSError errorWithDomain:kRNCryptorErrorDomain + code:kRNCryptorHMACMismatch + userInfo:[NSDictionary dictionaryWithObject:@"HMAC Mismatch" /* DNL */ + forKey:NSLocalizedDescriptionKey]]]; + return; + } + } + + NSData *decryptedData = [self.engine finishWithError:&error]; + + if (!decryptedData) { + [self cleanupAndNotifyWithError:error]; + return; + } + [self.outData appendData:decryptedData]; + + [self cleanupAndNotifyWithError:nil]; + }); +} + +@end diff --git a/libTitanD3vUniversal/RNCryptor/RNEncryptor.h b/libTitanD3vUniversal/RNCryptor/RNEncryptor.h new file mode 100755 index 0000000..ceebcd7 --- /dev/null +++ b/libTitanD3vUniversal/RNCryptor/RNEncryptor.h @@ -0,0 +1,51 @@ +#import +#import "RNCryptor.h" + +@interface RNEncryptor : RNCryptor +- (RNEncryptor *)initWithSettings:(RNCryptorSettings)settings + encryptionKey:(NSData *)encryptionKey + HMACKey:(NSData *)HMACKey + handler:(RNCryptorHandler)handler; + + +- (RNEncryptor *)initWithSettings:(RNCryptorSettings)settings + password:(NSString *)password + handler:(RNCryptorHandler)handler; + +// This form with manual IV is generally only used for testing +- (RNEncryptor *)initWithSettings:(RNCryptorSettings)theSettings + encryptionKey:(NSData *)anEncryptionKey + HMACKey:(NSData *)anHMACKey + IV:(NSData *)anIV + handler:(RNCryptorHandler)aHandler; + +// This form with manual IV and salts is generally only used for testing +- (RNEncryptor *)initWithSettings:(RNCryptorSettings)settings + password:(NSString *)password + IV:(NSData *)anIV + encryptionSalt:(NSData *)anEncryptionSalt + HMACSalt:(NSData *)anHMACSalt + handler:(RNCryptorHandler)handler; + + ++ (NSData *)encryptData:(NSData *)data withSettings:(RNCryptorSettings)settings password:(NSString *)password error:(NSError **)error; ++ (NSData *)encryptData:(NSData *)data withSettings:(RNCryptorSettings)settings encryptionKey:(NSData *)encryptionKey HMACKey:(NSData *)HMACKey error:(NSError **)error; + +// This form with manual IV is generally only used for testing ++ (NSData *)encryptData:(NSData *)thePlaintext + withSettings:(RNCryptorSettings)theSettings + encryptionKey:(NSData *)anEncryptionKey + HMACKey:(NSData *)anHMACKey + IV:(NSData *)anIV + error:(NSError **)anError; + +// This form with manual IV and salts is generally only used for testing ++ (NSData *)encryptData:(NSData *)data + withSettings:(RNCryptorSettings)settings + password:(NSString *)password + IV:(NSData *)anIV + encryptionSalt:(NSData *)anEncryptionSalt + HMACSalt:(NSData *)anHMACSalt + error:(NSError **)error; + +@end diff --git a/libTitanD3vUniversal/RNCryptor/RNEncryptor.m b/libTitanD3vUniversal/RNCryptor/RNEncryptor.m new file mode 100755 index 0000000..a8a0356 --- /dev/null +++ b/libTitanD3vUniversal/RNCryptor/RNEncryptor.m @@ -0,0 +1,219 @@ +#import "RNEncryptor.h" +#import "RNCryptor+Private.h" +#import "RNCryptorEngine.h" + +#import + +@interface RNEncryptor () +@property (nonatomic, readwrite, strong) NSData *encryptionSalt; +@property (nonatomic, readwrite, strong) NSData *HMACSalt; +@property (nonatomic, readwrite, strong) NSData *IV; +@property (nonatomic, readwrite, assign) BOOL haveWrittenHeader; +@end + +@implementation RNEncryptor +{ + CCHmacContext _HMACContext; +} +@synthesize encryptionSalt = _encryptionSalt; +@synthesize HMACSalt = _HMACSalt; +@synthesize IV = _IV; +@synthesize haveWrittenHeader = _haveWrittenHeader; + + ++ (NSData *)encryptData:(NSData *)thePlaintext withSettings:(RNCryptorSettings)theSettings password:(NSString *)aPassword error:(NSError **)anError +{ + RNEncryptor *cryptor = [[self alloc] initWithSettings:theSettings + password:aPassword + handler:^(RNCryptor *c, NSData *d) {}]; + return [self synchronousResultForCryptor:cryptor data:thePlaintext error:anError]; +} + ++ (NSData *)encryptData:(NSData *)thePlaintext + withSettings:(RNCryptorSettings)theSettings + password:(NSString *)aPassword + IV:(NSData *)anIV + encryptionSalt:(NSData *)anEncryptionSalt + HMACSalt:(NSData *)anHMACSalt + error:(NSError **)anError +{ + RNEncryptor *cryptor = [[self alloc] initWithSettings:theSettings + password:aPassword + IV:anIV + encryptionSalt:anEncryptionSalt + HMACSalt:anHMACSalt + handler:^(RNCryptor *c, NSData *d) {}]; + return [self synchronousResultForCryptor:cryptor data:thePlaintext error:anError]; +} + ++ (NSData *)encryptData:(NSData *)thePlaintext withSettings:(RNCryptorSettings)theSettings encryptionKey:(NSData *)anEncryptionKey HMACKey:(NSData *)anHMACKey error:(NSError **)anError { + RNEncryptor *cryptor = [[self alloc] initWithSettings:theSettings + encryptionKey:anEncryptionKey + HMACKey:anHMACKey + handler:^(RNCryptor *c, NSData *d) {}]; + return [self synchronousResultForCryptor:cryptor data:thePlaintext error:anError]; +} + + ++ (NSData *)encryptData:(NSData *)thePlaintext + withSettings:(RNCryptorSettings)theSettings + encryptionKey:(NSData *)anEncryptionKey + HMACKey:(NSData *)anHMACKey + IV:(NSData *)anIV + error:(NSError **)anError +{ + RNEncryptor *cryptor = [[self alloc] initWithSettings:theSettings + encryptionKey:anEncryptionKey + HMACKey:anHMACKey + IV:anIV + handler:^(RNCryptor *c, NSData *d) {}]; + return [self synchronousResultForCryptor:cryptor data:thePlaintext error:anError]; +} + +- (RNEncryptor *)initWithSettings:(RNCryptorSettings)theSettings + encryptionKey:(NSData *)anEncryptionKey + HMACKey:(NSData *)anHMACKey + handler:(RNCryptorHandler)aHandler { + return [self initWithSettings:kRNCryptorAES256Settings + encryptionKey:anEncryptionKey + HMACKey:anHMACKey + IV:[[self class] randomDataOfLength:theSettings.IVSize] + handler:aHandler]; +} + +- (RNEncryptor *)initWithSettings:(RNCryptorSettings)theSettings + encryptionKey:(NSData *)anEncryptionKey + HMACKey:(NSData *)anHMACKey + IV:(NSData *)anIV + handler:(RNCryptorHandler)aHandler +{ + self = [super initWithHandler:aHandler]; + if (self) { + self.IV = anIV; + + if (anHMACKey) { + CCHmacInit(&_HMACContext, theSettings.HMACAlgorithm, anHMACKey.bytes, anHMACKey.length); + self.HMACLength = theSettings.HMACLength; + } + + NSError *error = nil; + self.engine = [[RNCryptorEngine alloc] initWithOperation:kCCEncrypt + settings:theSettings + key:anEncryptionKey + IV:self.IV + error:&error]; + if (!self.engine) { + [self cleanupAndNotifyWithError:error]; + self = nil; + return nil; + } + } + + return self; +} + +- (RNEncryptor *)initWithSettings:(RNCryptorSettings)theSettings password:(NSString *)aPassword handler:(RNCryptorHandler)aHandler { + return [self initWithSettings:theSettings + password:aPassword + IV:[[self class] randomDataOfLength:theSettings.IVSize] + encryptionSalt:[[self class] randomDataOfLength:theSettings.keySettings.saltSize] + HMACSalt:[[self class] randomDataOfLength:theSettings.HMACKeySettings.saltSize] + handler:aHandler]; +} + + +- (RNEncryptor *)initWithSettings:(RNCryptorSettings)theSettings + password:(NSString *)aPassword + IV:(NSData *)anIV + encryptionSalt:(NSData *)anEncryptionSalt + HMACSalt:(NSData *)anHMACSalt + handler:(RNCryptorHandler)aHandler; +{ + NSParameterAssert(aPassword.length > 0); // We'll go forward, but this is undefined behavior for RNCryptor + NSParameterAssert(anIV); + NSParameterAssert(anEncryptionSalt); + NSParameterAssert(anHMACSalt); + + NSData *encryptionKey = [[self class] keyForPassword:aPassword salt:anEncryptionSalt settings:theSettings.keySettings]; + NSData *HMACKey = [[self class] keyForPassword:aPassword salt:anHMACSalt settings:theSettings.HMACKeySettings]; + + self = [self initWithSettings:theSettings + encryptionKey:encryptionKey + HMACKey:HMACKey + IV:anIV + handler:aHandler]; + if (self) { + self.options |= kRNCryptorOptionHasPassword; + self.encryptionSalt = anEncryptionSalt; + self.HMACSalt = anHMACSalt; + } + return self; +} + +- (NSData *)header +{ + uint8_t header[2] = {kRNCryptorFileVersion, self.options}; + NSMutableData *headerData = [NSMutableData dataWithBytes:header length:sizeof(header)]; + if (self.options & kRNCryptorOptionHasPassword) { + [headerData appendData:self.encryptionSalt]; + [headerData appendData:self.HMACSalt]; + } + [headerData appendData:self.IV]; + return headerData; +} + +- (void)addData:(NSData *)data +{ + if (self.isFinished) { + return; + } + + dispatch_async(self.queue, ^{ + if (!self.haveWrittenHeader) { + NSData *header = [self header]; + [self.outData setData:header]; + if (self.hasHMAC) { + CCHmacUpdate(&self->_HMACContext, [header bytes], [header length]); + } + self.haveWrittenHeader = YES; + } + + NSError *error = nil; + NSData *encryptedData = [self.engine addData:data error:&error]; + if (!encryptedData) { + [self cleanupAndNotifyWithError:error]; + } + if (self.hasHMAC) { + CCHmacUpdate(&self->_HMACContext, encryptedData.bytes, encryptedData.length); + } + + [self.outData appendData:encryptedData]; + + dispatch_sync(self.responseQueue, ^{ + self.handler(self, self.outData); + }); + [self.outData setLength:0]; + }); +} + +- (void)finish +{ + if (self.isFinished) { + return; + } + + dispatch_async(self.queue, ^{ + NSError *error = nil; + NSData *encryptedData = [self.engine finishWithError:&error]; + [self.outData appendData:encryptedData]; + if (self.hasHMAC) { + CCHmacUpdate(&self->_HMACContext, encryptedData.bytes, encryptedData.length); + NSMutableData *HMACData = [NSMutableData dataWithLength:self.HMACLength]; + CCHmacFinal(&self->_HMACContext, [HMACData mutableBytes]); + [self.outData appendData:HMACData]; + } + [self cleanupAndNotifyWithError:error]; + }); +} + +@end diff --git a/libTitanD3vUniversal/ReportBugs/TDReportBugViewController.h b/libTitanD3vUniversal/ReportBugs/TDReportBugViewController.h new file mode 100644 index 0000000..a2fd248 --- /dev/null +++ b/libTitanD3vUniversal/ReportBugs/TDReportBugViewController.h @@ -0,0 +1,28 @@ +#import +#import +#import "TDAppearance.h" +#import "TDUtilities.h" + +@interface TDReportBugViewController : UIViewController +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIView *bannerView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UIButton *reportButton; +@property (nonatomic, retain) UIButton *cancelButton; +@property (nonatomic, retain) UIView *messageView; +@property (nonatomic, retain) UILabel *messageLabel; +@property (nonatomic, retain) UICollectionView *collectionView; +@property (nonatomic, retain) NSArray *categoriesArray; +@property (nonatomic, retain) UIView *composeView; +@property (nonatomic, retain) UITextView *textView; +@property (nonatomic, retain) UIView *attachmentView; +@property (nonatomic, retain) UIButton *fileButton; +@property (nonatomic, retain) UIButton *imageButton; +@property (nonatomic, retain) UIButton *urlButton; +@property (nonatomic, retain) UILabel *fileLabel; +@property (nonatomic, retain) UILabel *imageLabel; +@property (nonatomic, retain) UILabel *urlLabel; +@property (nonatomic, retain) UIColor *tintColour; +@end + diff --git a/libTitanD3vUniversal/ReportBugs/TDReportBugViewController.m b/libTitanD3vUniversal/ReportBugs/TDReportBugViewController.m new file mode 100644 index 0000000..1e93048 --- /dev/null +++ b/libTitanD3vUniversal/ReportBugs/TDReportBugViewController.m @@ -0,0 +1,683 @@ +#import "TDReportBugViewController.h" +#import "TDReportCell.h" + +#define iPhone_SE ([[UIScreen mainScreen] bounds].size.height == 568) // iPhone SE +#define iPhone_6_8 ([[UIScreen mainScreen] bounds].size.height == 667) // iPhone 6, 6s, 7 and 8 +#define iPhone_6_8_Plus ([[UIScreen mainScreen] bounds].size.height == 736) // iPhone 6, 6s, 7 and 8 Plus +#define iPhone_X_XS_11Pro ([[UIScreen mainScreen] bounds].size.height == 812) // iPhone X, XS, 11 Pro +#define iPhone_XR_XS_11Pro ([[UIScreen mainScreen] bounds].size.height == 896) // iPhone XR, XS Max, 11 Pro Max +#define iPhone_12_Pro ([[UIScreen mainScreen] bounds].size.height == 844) // iPhone 12 & 12 Pro +#define iPhone_12_mini ([[UIScreen mainScreen] bounds].size.height == 780) // iPhone 12 mini +#define iPhone_12_Pro_Max ([[UIScreen mainScreen] bounds].size.height == 926) // iPhone 12 Pro Max + +static UIImagePickerController *pickerView; +static NSInteger categoriesSelectedIndex = 0; +NSData *documentData; +NSData *imageData; +NSString *urlString; +NSString *messageString; + +float basePadding; +float cancelPadding; +float collectionTopPadding; +float attachmentPadding; +float messageHeight; +float composeHeight; + +@implementation TDReportBugViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = UIColor.clearColor; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + + [self layoutDeviceSize]; + [self layoutBaseView]; + [self layoutBanner]; + [self layoutButton]; + [self layoutAttachment]; + [self layoutMessage]; + [self layoutCollectionView]; + [self layoutCompose]; +} + + +-(void)layoutDeviceSize { + + if (iPhone_6_8) { + + basePadding = 25; + cancelPadding = 10; + collectionTopPadding = 10; + attachmentPadding = 25; + messageHeight = 50; + composeHeight = 280; + + } else if (iPhone_6_8_Plus) { + + basePadding = 25; + cancelPadding = 10; + collectionTopPadding = 10; + attachmentPadding = 25; + messageHeight = 50; + composeHeight = 300; + + } else if (iPhone_X_XS_11Pro) { + + basePadding = 40; + cancelPadding = 20; + collectionTopPadding = 10; + attachmentPadding = 35; + messageHeight = 60; + composeHeight = 320; + + } else if (iPhone_XR_XS_11Pro) { + + basePadding = 70; + cancelPadding = 35; + collectionTopPadding = 10; + attachmentPadding = 55; + messageHeight = 60; + composeHeight = 370; + + } else if (iPhone_12_Pro) { + + basePadding = 70; + cancelPadding = 35; + collectionTopPadding = 10; + attachmentPadding = 55; + messageHeight = 60; + composeHeight = 370; + + } else if (iPhone_12_mini) { + + basePadding = 90; + cancelPadding = 10; + collectionTopPadding = 10; + attachmentPadding = 25; + messageHeight = 50; + composeHeight = 280; + + } else if (iPhone_12_Pro_Max) { + + basePadding = 70; + cancelPadding = 35; + collectionTopPadding = 10; + attachmentPadding = 55; + messageHeight = 60; + composeHeight = 370; + } +} + + +-(void)layoutBaseView { + + self.baseView = [[UIView alloc] init]; + self.baseView.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + self.baseView.layer.cornerRadius = 20; + self.baseView.layer.maskedCorners = 3; + if(@available(iOS 13.0, *)) { + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.baseView.clipsToBounds = true; + [self.view addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; + [self.baseView.widthAnchor constraintEqualToConstant:self.view.frame.size.width].active = YES; + [self.baseView.heightAnchor constraintEqualToConstant:self.view.frame.size.height -basePadding].active = YES; +} + + +-(void)layoutBanner { + + self.bannerView = [[UIView alloc] init]; + self.bannerView.clipsToBounds = true; + [self.baseView addSubview:self.bannerView]; + + self.bannerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.bannerView.topAnchor constraintEqualToAnchor:self.baseView.topAnchor].active = YES; + [self.bannerView.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor].active = YES; + [self.bannerView.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor].active = YES; + [self.bannerView.heightAnchor constraintEqualToConstant:140].active = YES; + + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/bug.png"]; + self.iconImage.clipsToBounds = true; + self.iconImage.layer.cornerRadius = 15; + [self.bannerView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.heightAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.widthAnchor constraintEqualToConstant:90].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:self.bannerView.topAnchor constant:10].active = YES; + [[self.iconImage centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.titleLabel.font = [UIFont systemFontOfSize:16]; + self.titleLabel.text = @"Bug report"; + [self.bannerView addSubview:self.titleLabel]; + + self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [self.titleLabel.topAnchor constraintEqualToAnchor:self.iconImage.bottomAnchor constant:10].active = YES; + [[self.titleLabel centerXAnchor] constraintEqualToAnchor:self.bannerView.centerXAnchor].active = true; + +} + + +-(void)layoutButton { + + self.cancelButton = [[UIButton alloc] init]; + [self.cancelButton addTarget:self action:@selector(dismissVC) forControlEvents:UIControlEventTouchUpInside]; + [self.cancelButton setTitle:@"Cancel" forState:UIControlStateNormal]; + [self.cancelButton setTitleColor:self.tintColour forState:UIControlStateNormal]; + [self.baseView addSubview:self.cancelButton]; + + self.cancelButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.cancelButton.heightAnchor constraintEqualToConstant:30].active = YES; + [self.cancelButton.widthAnchor constraintEqualToConstant:100].active = YES; + [self.cancelButton.bottomAnchor constraintEqualToAnchor:self.baseView.bottomAnchor constant:-cancelPadding].active = YES; + [[self.cancelButton centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + + + self.reportButton = [[UIButton alloc] init]; + [self.reportButton addTarget:self action:@selector(prepareReport) forControlEvents:UIControlEventTouchUpInside]; + [self.reportButton setTitle:@"Report" forState:UIControlStateNormal]; + [self.reportButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; + self.reportButton.backgroundColor = self.tintColour; + self.reportButton.layer.cornerRadius = 10; + [self.baseView addSubview:self.reportButton]; + + self.reportButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.reportButton.heightAnchor constraintEqualToConstant:50].active = YES; + [self.reportButton.widthAnchor constraintEqualToConstant:200].active = YES; + [self.reportButton.bottomAnchor constraintEqualToAnchor:self.cancelButton.topAnchor constant:-10].active = YES; + [[self.reportButton centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; +} + + +-(void)layoutAttachment { + + self.attachmentView = [[UIView alloc] init]; + self.attachmentView.backgroundColor = UIColor.clearColor; + [self.baseView addSubview:self.attachmentView]; + + self.attachmentView.translatesAutoresizingMaskIntoConstraints = NO; + [self.attachmentView.heightAnchor constraintEqualToConstant:60].active = YES; + [self.attachmentView.widthAnchor constraintEqualToConstant:250].active = YES; + [[self.attachmentView centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + [self.attachmentView.bottomAnchor constraintEqualToAnchor:self.reportButton.topAnchor constant:-attachmentPadding].active = YES; + + + self.fileButton = [[UIButton alloc] init]; + self.fileButton.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.fileButton.layer.cornerRadius = 25; + [self.fileButton addTarget:self action:@selector(presentDocumentVC) forControlEvents:UIControlEventTouchUpInside]; + UIImage *fileImage = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/file.png"]; + [self.fileButton setImage:fileImage forState:UIControlStateNormal]; + self.fileButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10); + [self.attachmentView addSubview:self.fileButton]; + + self.fileButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.fileButton.heightAnchor constraintEqualToConstant:50].active = YES; + [self.fileButton.widthAnchor constraintEqualToConstant:50].active = YES; + [[self.fileButton centerYAnchor] constraintEqualToAnchor:self.attachmentView.centerYAnchor].active = true; + [[self.fileButton centerXAnchor] constraintEqualToAnchor:self.attachmentView.centerXAnchor constant:-65].active = true; + + + self.fileLabel = [[UILabel alloc] init]; + self.fileLabel.text = @"File"; + self.fileLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.fileLabel.textAlignment = NSTextAlignmentCenter; + self.fileLabel.font = [UIFont systemFontOfSize:10]; + [self.attachmentView addSubview:self.fileLabel]; + + self.fileLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.fileLabel centerXAnchor] constraintEqualToAnchor:self.fileButton.centerXAnchor].active = true; + [self.fileLabel.topAnchor constraintEqualToAnchor:self.fileButton.bottomAnchor constant:5].active = YES; + + + self.imageButton = [[UIButton alloc] init]; + self.imageButton.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.imageButton.layer.cornerRadius = 25; + [self.imageButton addTarget:self action:@selector(presentPhotoVC) forControlEvents:UIControlEventTouchUpInside]; + UIImage *imageImage = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/image.png"]; + [self.imageButton setImage:imageImage forState:UIControlStateNormal]; + self.imageButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10); + [self.attachmentView addSubview:self.imageButton]; + + self.imageButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.imageButton.heightAnchor constraintEqualToConstant:50].active = YES; + [self.imageButton.widthAnchor constraintEqualToConstant:50].active = YES; + [[self.imageButton centerYAnchor] constraintEqualToAnchor:self.attachmentView.centerYAnchor].active = true; + [[self.imageButton centerXAnchor] constraintEqualToAnchor:self.attachmentView.centerXAnchor].active = true; + + + self.imageLabel = [[UILabel alloc] init]; + self.imageLabel.text = @"Photo"; + self.imageLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.imageLabel.textAlignment = NSTextAlignmentCenter; + self.imageLabel.font = [UIFont systemFontOfSize:10]; + [self.attachmentView addSubview:self.imageLabel]; + + self.imageLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.imageLabel centerXAnchor] constraintEqualToAnchor:self.imageButton.centerXAnchor].active = true; + [self.imageLabel.topAnchor constraintEqualToAnchor:self.imageButton.bottomAnchor constant:5].active = YES; + + + self.urlButton = [[UIButton alloc] init]; + self.urlButton.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.urlButton.layer.cornerRadius = 25; + [self.urlButton addTarget:self action:@selector(presentURLVC) forControlEvents:UIControlEventTouchUpInside]; + UIImage *urlImage = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/url-link.png"]; + [self.urlButton setImage:urlImage forState:UIControlStateNormal]; + self.urlButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10); + [self.attachmentView addSubview:self.urlButton]; + + self.urlButton.translatesAutoresizingMaskIntoConstraints = NO; + [self.urlButton.heightAnchor constraintEqualToConstant:50].active = YES; + [self.urlButton.widthAnchor constraintEqualToConstant:50].active = YES; + [[self.urlButton centerYAnchor] constraintEqualToAnchor:self.attachmentView.centerYAnchor].active = true; + [[self.urlButton centerXAnchor] constraintEqualToAnchor:self.attachmentView.centerXAnchor constant:65].active = true; + + + self.urlLabel = [[UILabel alloc] init]; + self.urlLabel.text = @"URL"; + self.urlLabel.textColor = [UIColor colorWithRed: 1.00 green: 1.00 blue: 1.00 alpha: 0.6]; + self.urlLabel.textAlignment = NSTextAlignmentCenter; + self.urlLabel.font = [UIFont systemFontOfSize:10]; + [self.attachmentView addSubview:self.urlLabel]; + + self.urlLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.urlLabel centerXAnchor] constraintEqualToAnchor:self.urlButton.centerXAnchor].active = true; + [self.urlLabel.topAnchor constraintEqualToAnchor:self.urlButton.bottomAnchor constant:5].active = YES; +} + + +-(void)layoutMessage { + + self.messageView = [[UIView alloc] init]; + self.messageView.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.messageView.layer.cornerRadius = 15; + self.messageView.clipsToBounds = true; + self.messageView.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + self.messageView.layer.borderWidth = 0.5; + [self.baseView addSubview:self.messageView]; + + self.messageView.translatesAutoresizingMaskIntoConstraints = NO; + [self.messageView.heightAnchor constraintEqualToConstant:messageHeight].active = YES; + [self.messageView.bottomAnchor constraintEqualToAnchor:self.attachmentView.topAnchor constant:-10].active = YES; + [self.messageView.widthAnchor constraintEqualToConstant:350].active = YES; + [[self.messageView centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + + + self.messageLabel = [[UILabel alloc] init]; + self.messageLabel.textColor = UIColor.whiteColor; + self.messageLabel.text = @"Describe more about a bug"; + self.messageLabel.textAlignment = NSTextAlignmentLeft; + self.messageLabel.alpha = 0.6; + [self.messageView addSubview:self.messageLabel]; + + self.messageLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.messageLabel centerYAnchor] constraintEqualToAnchor:self.messageView.centerYAnchor].active = true; + [self.messageLabel.leadingAnchor constraintEqualToAnchor:self.messageView.leadingAnchor constant:10].active = YES; + [self.messageLabel.trailingAnchor constraintEqualToAnchor:self.messageView.trailingAnchor constant:10].active = YES; + + [self.messageView addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(composeDescription)]]; +} + + +-(void)layoutCollectionView { + + self.categoriesArray = [[NSArray alloc] initWithObjects:@"Bug", @"Performance", @"Crashed", @"Prefs Bundle \nError", @"Respring Loop", @"Safe Mode", @"Other", nil]; + + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout]; + self.collectionView.backgroundColor = UIColor.clearColor; + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.collectionView setShowsHorizontalScrollIndicator:NO]; + [self.collectionView setShowsVerticalScrollIndicator:NO]; + [self.collectionView registerClass:[TDReportCell class] forCellWithReuseIdentifier:@"Cell"]; + [self.baseView addSubview:self.collectionView]; + + self.collectionView.delegate = self; + self.collectionView.dataSource = self; + + self.collectionView.translatesAutoresizingMaskIntoConstraints = NO; + [self.collectionView.topAnchor constraintEqualToAnchor:self.bannerView.bottomAnchor constant:collectionTopPadding].active = YES; + [self.collectionView.widthAnchor constraintEqualToConstant:350].active = YES; + [[self.collectionView centerXAnchor] constraintEqualToAnchor:self.baseView.centerXAnchor].active = true; + [self.collectionView.bottomAnchor constraintEqualToAnchor:self.messageView.topAnchor constant:-20].active = YES; +} + + +- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + return self.categoriesArray.count; +} + + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { + + TDReportCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath]; + + cell.backgroundColor = UIColor.clearColor; + cell.baseView.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + cell.appLabel.text = [self.categoriesArray objectAtIndex:indexPath.row]; + + if (indexPath.row == categoriesSelectedIndex) { + cell.baseView.layer.borderColor = self.tintColour.CGColor; + cell.iconImage.image = [[UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Cells/checked.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + cell.iconImage.tintColor = self.tintColour; + cell.baseView.layer.borderWidth = 1.5; + } else { + cell.baseView.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + cell.iconImage.image = nil; + cell.baseView.layer.borderWidth = 0.6; + } + + return cell; + +} + + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { + + return CGSizeMake(170, 90); + +} + + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { + + [[TDUtilities sharedInstance] haptic:0]; + categoriesSelectedIndex = indexPath.row; + [self.collectionView reloadData]; + +} + + +-(void)layoutCompose { + + self.composeView = [[UIView alloc] initWithFrame:self.view.bounds]; + self.composeView.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + self.composeView.alpha = 0; + [self.view addSubview:self.composeView]; + + + self.textView = [[UITextView alloc] init]; + self.textView.clipsToBounds = YES; + self.textView.contentInset = UIEdgeInsetsZero; + self.textView.delegate = self; + self.textView.editable = YES; + self.textView.font = [UIFont systemFontOfSize:18]; + self.textView.backgroundColor = [UIColor colorWithRed: 0.10 green: 0.10 blue: 0.10 alpha: 0.7]; + self.textView.scrollEnabled = YES; + self.textView.textAlignment = NSTextAlignmentLeft; + self.textView.textColor = UIColor.whiteColor;; + self.textView.textContainerInset = UIEdgeInsetsMake(10, 10, 10, 10); + self.textView.layer.cornerRadius = 15; + if(@available(iOS 13.0, *)) { + self.textView.layer.cornerCurve = kCACornerCurveContinuous; + } + self.textView.layer.borderColor = [UIColor colorWithRed: 0.12 green: 0.12 blue: 0.12 alpha: 0.5].CGColor; + self.textView.layer.borderWidth = 0.5; + [self.composeView addSubview:self.textView]; + + self.textView.translatesAutoresizingMaskIntoConstraints = NO; + [self.textView.heightAnchor constraintEqualToConstant:composeHeight].active = YES; + [self.textView.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:50].active = YES; + [self.textView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20].active = YES; + [self.textView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20].active = YES; +} + + +-(void)composeDescription { + + self.composeView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.001, 0.001); + self.composeView.alpha = 1.0; + + [UIView animateWithDuration:0.4/1.5 animations:^{ + self.composeView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.0, 1.0); + }]; + + [self.textView becomeFirstResponder]; + +} + + +- (BOOL)textViewShouldBeginEditing:(UITextView *)textView { + + UIToolbar *textToolbar = [[UIToolbar alloc] init]; + [textToolbar sizeToFit]; + textToolbar.barStyle = UIBarStyleDefault; + textToolbar.tintColor = self.tintColour; + textToolbar.items = [self textToolBarButtons]; + self.textView.inputAccessoryView = textToolbar; + + return YES; + +} + + +-(NSArray *)textToolBarButtons { + + NSMutableArray *textButtons = [[NSMutableArray alloc] init]; + + [textButtons addObject:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil]]; + + [textButtons addObject:[[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStylePlain target:self action:@selector(dismissKeyboard)]]; + + return [textButtons copy]; + +} + + +-(void)dismissKeyboard { + + [[TDUtilities sharedInstance] haptic:0]; + + [UIView animateWithDuration:0.4/1.5 animations:^{ + self.composeView.alpha = 0; + }]; + + [self.textView resignFirstResponder]; + if (self.textView.text && self.textView.text.length > 0) { + NSString *composeString = self.textView.text; + self.messageLabel.text = composeString; + } else { + self.messageLabel.text = @"Describe more about a bug"; + } +} + + +-(void)presentDocumentVC { + + [[TDUtilities sharedInstance] haptic:0]; + + UIDocumentPickerViewController* documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.item"] inMode:UIDocumentPickerModeImport]; + documentPicker.delegate = self; + documentPicker.modalPresentationStyle = UIModalPresentationFormSheet; + [self presentViewController:documentPicker animated:YES completion:nil]; + +} + + +- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url { + if (controller.documentPickerMode == UIDocumentPickerModeImport) { + + NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil]; + NSError *error = nil; + [coordinator coordinateReadingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) { + documentData = [NSData dataWithContentsOfURL:newURL]; + NSLog(@"%@", documentData); + }]; + } +} + + +-(void)presentPhotoVC { + + [[TDUtilities sharedInstance] haptic:0]; + + pickerView = [[UIImagePickerController alloc] init]; + pickerView.allowsEditing = YES; + pickerView.delegate = self; + [pickerView setSourceType:UIImagePickerControllerSourceTypePhotoLibrary]; + [self presentViewController:pickerView animated:YES completion:nil]; + +} + + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ + + [pickerView dismissViewControllerAnimated:YES completion:nil]; + UIImage *img = [info valueForKey:UIImagePickerControllerEditedImage]; + imageData = UIImageJPEGRepresentation(img, 1.0); + +} + + +-(void)presentURLVC { + + [[TDUtilities sharedInstance] haptic:0]; + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"URL" message:@"Paste the URL for the crash report from pastebin, ghostbin or any pasteboard website." preferredStyle:UIAlertControllerStyleAlert]; + [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) { + textField.placeholder = @"URL"; + }]; + + UIAlertAction *confirmAction = [UIAlertAction actionWithTitle:@"Done" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + + urlString = alertController.textFields.firstObject.text; + NSLog(@"url:%@", urlString); + + }]; + [alertController addAction:confirmAction]; + + [self presentViewController:alertController animated:YES completion:nil]; + +} + + +-(void)prepareReport { + + [[TDUtilities sharedInstance] haptic:0]; + + if ([MFMailComposeViewController canSendMail]) { + + if (self.textView.text && self.textView.text.length > 0) { + + MFMailComposeViewController * composeEmailVC = [MFMailComposeViewController new]; + composeEmailVC.mailComposeDelegate = self; + + NSString *subjectString = [self.categoriesArray objectAtIndex:categoriesSelectedIndex]; + [composeEmailVC setSubject:subjectString]; + + NSString *composeString = self.textView.text; + if (urlString != nil) { + messageString = [NSString stringWithFormat:@"(Description)\n%@ \n\n(URL) \n%@", composeString, urlString]; + } else { + messageString = [NSString stringWithFormat:@"Description:\n%@", composeString]; + } + [composeEmailVC setMessageBody:messageString isHTML:NO]; + + if (documentData != nil) { + [composeEmailVC addAttachmentData:documentData mimeType:@"text/plain" fileName:@"crash-report.txt"]; + } + + if (imageData != nil) { + [composeEmailVC addAttachmentData:imageData mimeType:@"image/jpeg" fileName:@"ScreenShot"]; + } + + NSString *emailAddressString = @"support@titand3v.com"; + [composeEmailVC setToRecipients:[NSArray arrayWithObjects:emailAddressString, nil]]; + + [self presentViewController:composeEmailVC animated:YES completion:nil]; + + + } else { + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Sorry!" message:@"The description is blank, you will need to describe more about the bug you are experiencing before you can report the bug." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + + }]; + [alertController addAction:okAction]; + alertController.view.tintColor = self.tintColour; + [self presentViewController:alertController animated:YES completion:nil]; + + } + + } else { + + NSLog(@"Mail services are not available or configure to your device"); + } + +} + + +- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(nullable NSError *)error { + + switch (result) { + case MFMailComposeResultCancelled: + NSLog(@"Mail cancelled"); + + break; + + case MFMailComposeResultSaved: + NSLog(@"Mail saved"); + + break; + + case MFMailComposeResultSent: + NSLog(@"Mail sent"); + [self performSelector:@selector(showConfirmation) withObject:nil afterDelay:1.0]; + + break; + + case MFMailComposeResultFailed: + NSLog(@"Mail sent failure: %@",error.description); + + break; + } + + [controller dismissViewControllerAnimated:true completion:nil]; + +} + + +-(void)showConfirmation { + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Sent!" message:@"Thank you for report the bug, the team will be in touch in the next 48 hours." preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + [self dismissVC]; + }]; + [alertController addAction:okAction]; + alertController.view.tintColor = self.tintColour; + [self presentViewController:alertController animated:YES completion:nil]; + +} + + +-(void)dismissVC { + categoriesSelectedIndex = 0; + // documentData = nil; + // imageData = nil; + urlString = nil; + [self.collectionView reloadData]; + [[TDUtilities sharedInstance] haptic:0]; + [self dismissViewControllerAnimated:YES completion:nil]; +} + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +@end diff --git a/libTitanD3vUniversal/ReportBugs/TDReportCell.h b/libTitanD3vUniversal/ReportBugs/TDReportCell.h new file mode 100644 index 0000000..fe040e9 --- /dev/null +++ b/libTitanD3vUniversal/ReportBugs/TDReportCell.h @@ -0,0 +1,7 @@ +#import + +@interface TDReportCell : UICollectionViewCell +@property (nonatomic, retain) UIView *baseView; +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *appLabel; +@end diff --git a/libTitanD3vUniversal/ReportBugs/TDReportCell.m b/libTitanD3vUniversal/ReportBugs/TDReportCell.m new file mode 100644 index 0000000..dad3d9f --- /dev/null +++ b/libTitanD3vUniversal/ReportBugs/TDReportCell.m @@ -0,0 +1,52 @@ +#import "TDReportCell.h" + +@implementation TDReportCell + + +- (id)initWithFrame:(CGRect)frame { + + self = [super initWithFrame:frame]; + if (self) { + + self.baseView = [[UIView alloc] init]; + self.baseView.clipsToBounds = YES; + self.baseView.layer.cornerRadius = 10; + if(@available(iOS 13.0, *)) { + self.baseView.layer.cornerCurve = kCACornerCurveContinuous; + } + [self.contentView addSubview:self.baseView]; + + self.baseView.translatesAutoresizingMaskIntoConstraints = NO; + [self.baseView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor].active = YES; + [self.baseView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor].active = YES; + [self.baseView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor].active = YES; + [self.baseView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor].active = YES; + + + self.iconImage = [[UIImageView alloc] init]; + [self.baseView addSubview:self.iconImage]; + + self.iconImage.translatesAutoresizingMaskIntoConstraints = NO; + [self.iconImage.widthAnchor constraintEqualToConstant:25.0].active = YES; + [self.iconImage.heightAnchor constraintEqualToConstant:25.0].active = YES; + [self.iconImage.topAnchor constraintEqualToAnchor:self.baseView.topAnchor constant:5].active = YES; + [self.iconImage.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant:-5].active = YES; + + + self.appLabel = [[UILabel alloc] init]; + self.appLabel.font = [UIFont systemFontOfSize:16]; + self.appLabel.textAlignment = NSTextAlignmentLeft; + self.appLabel.numberOfLines = 2; + [self.baseView addSubview:self.appLabel]; + + self.appLabel.translatesAutoresizingMaskIntoConstraints = NO; + [[self.appLabel centerYAnchor] constraintEqualToAnchor:self.baseView.centerYAnchor].active = YES; + [self.appLabel.leadingAnchor constraintEqualToAnchor:self.baseView.leadingAnchor constant:10].active = YES; + [self.appLabel.trailingAnchor constraintEqualToAnchor:self.baseView.trailingAnchor constant: -15].active = YES; + + } + return self; +} + + +@end diff --git a/libTitanD3vUniversal/Review/TDAnimationFactory.h b/libTitanD3vUniversal/Review/TDAnimationFactory.h new file mode 100644 index 0000000..49bee7a --- /dev/null +++ b/libTitanD3vUniversal/Review/TDAnimationFactory.h @@ -0,0 +1,16 @@ +#import +#import "TDRate.h" +#import "TDGradient.h" + +@interface TDAnimationFactory : NSObject + ++ (CAAnimation *)mouthAnimationWithFrame:(CGRect)frame; ++ (CAAnimation *)eyeCircleCoverAnimationWithOffset:(CGFloat)offset; ++ (CAAnimation *)eyeRectCoverAnimationWithOffset:(CGFloat)offset; ++ (CAAnimation *)descriptionAnimationWithRate:(TDRate)rate offset:(CGFloat)offset; ++ (CAAnimation *)gradientAnimationWithBadGradient:(TDGradient *)badGradient + ughGradient:(TDGradient *)ughGradient + okGradient:(TDGradient *)okGradient + goodGradient:(TDGradient *)goodGradient; + +@end diff --git a/libTitanD3vUniversal/Review/TDAnimationFactory.m b/libTitanD3vUniversal/Review/TDAnimationFactory.m new file mode 100644 index 0000000..0c166ea --- /dev/null +++ b/libTitanD3vUniversal/Review/TDAnimationFactory.m @@ -0,0 +1,235 @@ +#import "TDConstants.h" +#import "UIColor+Utils.h" +#import "TDAnimationFactory.h" + +@implementation TDAnimationFactory + ++ (CAAnimation *)mouthAnimationWithFrame:(CGRect)frame { + CGPoint center = CGPointMake(frame.size.width / 2, frame.size.height / 2); + NSArray *mouthPaths = [TDAnimationFactory mouthPathsWithCenter:center]; + CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animation]; + pathAnimation.keyPath = @"path"; + pathAnimation.values = mouthPaths; + pathAnimation.duration = 1; + + CAKeyframeAnimation *yAnimation = [CAKeyframeAnimation animation]; + yAnimation.keyPath = @"transform.translation.y"; + yAnimation.values = @[[NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:-5], + [NSNumber numberWithFloat:-8], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:-5], + [NSNumber numberWithFloat:-8], + [NSNumber numberWithFloat:0]]; + + CAAnimationGroup *group = [CAAnimationGroup animation]; + group.duration = 1; + group.animations = @[pathAnimation, yAnimation]; + group.removedOnCompletion = NO; + group.fillMode = kCAFillModeBoth; + return group; +} + ++ (CAAnimation *)eyeCircleCoverAnimationWithOffset:(CGFloat)offset { + CAKeyframeAnimation *xAnimation = [CAKeyframeAnimation animation]; + xAnimation.keyPath = @"transform.translation.x"; + xAnimation.values = @[[NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:offset], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:offset], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0]]; + + CAKeyframeAnimation *yAnimation = [CAKeyframeAnimation animation]; + yAnimation.keyPath = @"transform.translation.y"; + yAnimation.values = @[[NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:fabs(offset)], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:fabs(offset)], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0]]; + + CAAnimationGroup *group = [CAAnimationGroup animation]; + group.duration = 1; + group.animations = @[xAnimation, yAnimation]; + group.removedOnCompletion = NO; + group.fillMode = kCAFillModeBoth; + return group; +} + ++ (CAAnimation *)eyeRectCoverAnimationWithOffset:(CGFloat)offset { + CAKeyframeAnimation *xAnimation = [CAKeyframeAnimation animation]; + xAnimation.keyPath = @"transform.translation.x"; + xAnimation.values = @[[NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:offset], + [NSNumber numberWithFloat:offset], + [NSNumber numberWithFloat:offset], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:offset], + [NSNumber numberWithFloat:offset], + [NSNumber numberWithFloat:offset], + [NSNumber numberWithFloat:0]]; + + CAKeyframeAnimation *yAnimation = [CAKeyframeAnimation animation]; + yAnimation.keyPath = @"transform.translation.y"; + yAnimation.values = @[[NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:-fabs(offset)], + [NSNumber numberWithFloat:-fabs(offset)], + [NSNumber numberWithFloat:-fabs(offset)], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:-fabs(offset)], + [NSNumber numberWithFloat:-fabs(offset)], + [NSNumber numberWithFloat:-fabs(offset)], + [NSNumber numberWithFloat:0]]; + + CAAnimationGroup *group = [CAAnimationGroup animation]; + group.duration = 1; + group.animations = @[xAnimation, yAnimation]; + group.removedOnCompletion = NO; + group.fillMode = kCAFillModeBoth; + return group; +} + ++ (CAAnimation *)descriptionAnimationWithRate:(TDRate)rate offset:(CGFloat)offset { + NSMutableArray *xAnimationValues = [NSMutableArray new]; + NSMutableArray *opacityAnimationValues = [NSMutableArray new]; + + for (NSUInteger i = 0; i < 9; i++) { + NSUInteger current = i % 4; + NSUInteger prev = (i == 0 ? 8 : i - 1) % 4; + NSNumber *xAnimationValue; + NSNumber *opacityAnimationValue; + if (current == rate) { + xAnimationValue = [NSNumber numberWithFloat:0]; + opacityAnimationValue = [NSNumber numberWithFloat:1]; + } else { + xAnimationValue = [NSNumber numberWithFloat:prev == rate ? -offset : offset]; + opacityAnimationValue = [NSNumber numberWithFloat:0]; + } + [xAnimationValues addObject:xAnimationValue]; + [opacityAnimationValues addObject:opacityAnimationValue]; + } + + CAKeyframeAnimation *xAnimation = [CAKeyframeAnimation animation]; + xAnimation.keyPath = @"transform.translation.x"; + xAnimation.values = xAnimationValues; + + CAKeyframeAnimation *opacityAnimation = [CAKeyframeAnimation animation]; + opacityAnimation.keyPath = @"opacity"; + opacityAnimation.values = opacityAnimationValues; + + CAAnimationGroup *group = [CAAnimationGroup animation]; + group.duration = 1; + group.animations = @[xAnimation, opacityAnimation]; + group.removedOnCompletion = NO; + group.fillMode = kCAFillModeBoth; + return group; +} + ++ (CAAnimation *)gradientAnimationWithBadGradient:(TDGradient *)badGradient + ughGradient:(TDGradient *)ughGradient + okGradient:(TDGradient *)okGradient + goodGradient:(TDGradient *)goodGradient { + NSArray *colors = @[@[(__bridge id) badGradient.startGradientColor.CGColor, + (__bridge id) badGradient.endGradientColor.CGColor], + @[(__bridge id) ughGradient.startGradientColor.CGColor, + (__bridge id) ughGradient.endGradientColor.CGColor], + @[(__bridge id) okGradient.startGradientColor.CGColor, + (__bridge id) okGradient.endGradientColor.CGColor], + @[(__bridge id) goodGradient.startGradientColor.CGColor, + (__bridge id) goodGradient.endGradientColor.CGColor], + @[(__bridge id) badGradient.startGradientColor.CGColor, + (__bridge id) badGradient.endGradientColor.CGColor], + @[(__bridge id) ughGradient.startGradientColor.CGColor, + (__bridge id) ughGradient.endGradientColor.CGColor], + @[(__bridge id) okGradient.startGradientColor.CGColor, + (__bridge id) okGradient.endGradientColor.CGColor], + @[(__bridge id) goodGradient.startGradientColor.CGColor, + (__bridge id) goodGradient.endGradientColor.CGColor], + @[(__bridge id) badGradient.startGradientColor.CGColor, + (__bridge id) badGradient.endGradientColor.CGColor]]; + CAKeyframeAnimation *colorsAnimation = [CAKeyframeAnimation animation]; + colorsAnimation.keyPath = @"colors"; + colorsAnimation.values = colors; + colorsAnimation.duration = 1; + + CAKeyframeAnimation *startPointYAnimation = [CAKeyframeAnimation animation]; + startPointYAnimation.keyPath = @"startPoint.y"; + startPointYAnimation.values = @[[NSNumber numberWithFloat:.5], + [NSNumber numberWithFloat:.5], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:.5], + [NSNumber numberWithFloat:.5], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:0], + [NSNumber numberWithFloat:.5]]; + startPointYAnimation.duration = 1; + + CAKeyframeAnimation *endPointYAnimation = [CAKeyframeAnimation animation]; + endPointYAnimation.keyPath = @"endPoint.y"; + endPointYAnimation.values = @[[NSNumber numberWithFloat:.5], + [NSNumber numberWithFloat:.5], + [NSNumber numberWithFloat:1], + [NSNumber numberWithFloat:1], + [NSNumber numberWithFloat:.5], + [NSNumber numberWithFloat:.5], + [NSNumber numberWithFloat:1], + [NSNumber numberWithFloat:1], + [NSNumber numberWithFloat:.5]]; + endPointYAnimation.duration = 1; + + CAAnimationGroup *group = [CAAnimationGroup animation]; + group.duration = 1; + group.animations = @[colorsAnimation, startPointYAnimation, endPointYAnimation]; + group.removedOnCompletion = NO; + group.fillMode = kCAFillModeBoth; + return group; +} + ++ (NSArray *)mouthPathsWithCenter:(CGPoint)center { + CGFloat width = center.x - 10; + CGFloat height = center.y - 10; + + UIBezierPath *path1 = [UIBezierPath bezierPath]; + [path1 moveToPoint:CGPointMake(center.x - width, center.y)]; + [path1 addQuadCurveToPoint:CGPointMake(center.x, center.y - height) + controlPoint:CGPointMake(center.x - width * 0.7, center.y - height)]; + [path1 addQuadCurveToPoint:CGPointMake(center.x + width, center.y) + controlPoint:CGPointMake(center.x + width * 0.7, center.y - height)]; + + UIBezierPath *path2 = [UIBezierPath bezierPath]; + [path2 moveToPoint:CGPointMake(center.x - width, center.y)]; + [path2 addQuadCurveToPoint:CGPointMake(center.x, center.y - height) + controlPoint:CGPointMake(center.x - width * 0.7, center.y - height)]; + [path2 addQuadCurveToPoint:CGPointMake(center.x + width, center.y - height) + controlPoint:CGPointMake(center.x + width / 2, center.y - height)]; + + UIBezierPath *path3 = [UIBezierPath bezierPath]; + [path3 moveToPoint:CGPointMake(center.x - width, center.y)]; + [path3 addQuadCurveToPoint:CGPointMake(center.x, center.y) + controlPoint:CGPointMake(center.x - width / 2, center.y)]; + [path3 addQuadCurveToPoint:CGPointMake(center.x + width, center.y) + controlPoint:CGPointMake(center.x + width / 2, center.y)]; + + UIBezierPath *path4 = [UIBezierPath bezierPath]; + [path4 moveToPoint:CGPointMake(center.x - width, center.y)]; + [path4 addQuadCurveToPoint:CGPointMake(center.x, center.y + height) + controlPoint:CGPointMake(center.x - width * 0.7, center.y + height)]; + [path4 addQuadCurveToPoint:CGPointMake(center.x + width, center.y) + controlPoint:CGPointMake(center.x + width * 0.7, center.y + height)]; + + return @[(__bridge id) path1.CGPath, (__bridge id) path2.CGPath, (__bridge id) path3.CGPath, (__bridge id) path4.CGPath, + (__bridge id) path1.CGPath, (__bridge id) path2.CGPath, (__bridge id) path3.CGPath, (__bridge id) path4.CGPath, + (__bridge id) path1.CGPath]; +} + +@end diff --git a/libTitanD3vUniversal/Review/TDConfirmView.h b/libTitanD3vUniversal/Review/TDConfirmView.h new file mode 100644 index 0000000..e56227c --- /dev/null +++ b/libTitanD3vUniversal/Review/TDConfirmView.h @@ -0,0 +1,16 @@ +#import +#import "TDGradient.h" + +@interface TDConfirmView : UIView +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (strong, nonatomic) UIButton *button; + +- (void)configureWithBackgroundColor:(UIColor *)backgroundColor + title:(NSString *)title + badGradient:(TDGradient *)badGradient + ughGradient:(TDGradient *)ughGradient + okGradient:(TDGradient *)okGradient + goodGradient:(TDGradient *)goodGradient; +- (void)updateLayers:(CGFloat)progress; + +@end diff --git a/libTitanD3vUniversal/Review/TDConfirmView.m b/libTitanD3vUniversal/Review/TDConfirmView.m new file mode 100644 index 0000000..0038c37 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDConfirmView.m @@ -0,0 +1,64 @@ +#import "TDConfirmView.h" +#import "TDAnimationFactory.h" +#import "TDLayerFactory.h" + +@implementation TDConfirmView { + CALayer *gradientLayer; +} + +- (void)configureSubmitButtonWithTitle:(NSString *)title + badGradient:(TDGradient *)badGradient + ughGradient:(TDGradient *)ughGradient + okGradient:(TDGradient *)okGradient + goodGradient:(TDGradient *)goodGradient { + + self.clipsToBounds = true; + self.blurEffectView = [[UIVisualEffectView alloc] initWithFrame:self.bounds]; + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + [self insertSubview:self.blurEffectView atIndex:0]; + + + + _button = [UIButton buttonWithType:UIButtonTypeSystem]; + _button.frame = CGRectMake(self.bounds.size.width / 2 - 75, self.bounds.size.height / 8, 150, 50); + _button.layer.cornerRadius = _button.frame.size.height / 2; + [_button setTitle:title forState:UIControlStateNormal]; + [_button setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; + + CAAnimation *gradientAnimation = [TDAnimationFactory gradientAnimationWithBadGradient:badGradient + ughGradient:ughGradient + okGradient:okGradient + goodGradient:goodGradient]; + gradientLayer = [TDLayerFactory gradientLayerWithMask:nil frame:_button.bounds]; + gradientLayer.cornerRadius = _button.layer.cornerRadius; + [_button.layer insertSublayer:gradientLayer atIndex:0]; + [gradientLayer addAnimation:gradientAnimation forKey:@"animateGradient"]; + gradientLayer.speed = 0; + + [self addSubview:_button]; +} + +- (void)configureWithBackgroundColor:(UIColor *)backgroundColor + title:(NSString *)title + badGradient:(TDGradient *)badGradient + ughGradient:(TDGradient *)ughGradient + okGradient:(TDGradient *)okGradient + goodGradient:(TDGradient *)goodGradient { + self.backgroundColor = UIColor.clearColor; + self.layer.cornerRadius = self.bounds.size.width / 2; + self.layer.shadowColor = UIColor.blackColor.CGColor; + self.layer.shadowOffset = CGSizeMake(0, 0); + self.layer.shadowRadius = 10; + self.layer.shadowOpacity = 0.3; + [self configureSubmitButtonWithTitle:(NSString *)title + badGradient:badGradient + ughGradient:ughGradient + okGradient:okGradient + goodGradient:goodGradient]; +} + +- (void)updateLayers:(CGFloat)progress { + gradientLayer.timeOffset = progress; +} + +@end diff --git a/libTitanD3vUniversal/Review/TDConstants.h b/libTitanD3vUniversal/Review/TDConstants.h new file mode 100644 index 0000000..7860283 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDConstants.h @@ -0,0 +1,15 @@ +#import + +extern NSString *const BAD_START; +extern NSString *const BAD_END; +extern NSString *const UGH_START; +extern NSString *const UGH_END; +extern NSString *const OK_START; +extern NSString *const OK_END; +extern NSString *const GOOD_START; +extern NSString *const GOOD_END; +extern NSString *const BAD_TITLE; +extern NSString *const UGH_TITLE; +extern NSString *const OK_TITLE; +extern NSString *const GOOD_TITLE; +extern NSString *const MAIN_TITLE; diff --git a/libTitanD3vUniversal/Review/TDConstants.m b/libTitanD3vUniversal/Review/TDConstants.m new file mode 100644 index 0000000..580573d --- /dev/null +++ b/libTitanD3vUniversal/Review/TDConstants.m @@ -0,0 +1,15 @@ +#import "TDConstants.h" + +NSString *const BAD_START = @"#FE0D46"; +NSString *const BAD_END = @"#FEAD96"; +NSString *const UGH_START = @"#F9D975"; +NSString *const UGH_END = @"#F39F86"; +NSString *const OK_START = @"#12E6F9"; +NSString *const OK_END = @"#41B0FD"; +NSString *const GOOD_START = @"#3EE882"; +NSString *const GOOD_END = @"#3DF9CF"; +NSString *const BAD_TITLE = @"#FE5C6E"; +NSString *const UGH_TITLE = @"#F6BC7E"; +NSString *const OK_TITLE = @"#28CDFC"; +NSString *const GOOD_TITLE = @"#41F8C7"; +NSString *const MAIN_TITLE = @"#656565"; diff --git a/libTitanD3vUniversal/Review/TDDescriptionView.h b/libTitanD3vUniversal/Review/TDDescriptionView.h new file mode 100644 index 0000000..6ac7a94 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDDescriptionView.h @@ -0,0 +1,9 @@ +#import +#import "TDRate.h" + +@interface TDDescriptionView : UIView + +- (void)configureLabelWithRate:(TDRate)rate title:(NSString *)title color:(UIColor *)color; +- (void)updateLayers:(CGFloat)progress; + +@end diff --git a/libTitanD3vUniversal/Review/TDDescriptionView.m b/libTitanD3vUniversal/Review/TDDescriptionView.m new file mode 100644 index 0000000..8bf46a7 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDDescriptionView.m @@ -0,0 +1,50 @@ +#import "TDDescriptionView.h" +#import "TDConstants.h" +#import "UIColor+Utils.h" +#import "UIFont+Utils.h" +#import "TDAnimationFactory.h" +#import "TDLayerFactory.h" + +@implementation TDDescriptionView { + NSMutableArray *layers; +} + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + layers = [NSMutableArray new]; + } + return self; +} + +- (void)configureLabelWithRate:(TDRate)rate title:(NSString *)title color:(UIColor *)color { + UILabel *label = [UILabel new]; + label.frame = self.bounds; + label.text = title; + label.textAlignment = NSTextAlignmentCenter; + label.textColor = color; + [self addSubview:label]; + + CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + if(screenHeight == 480 || screenHeight == 568) { + label.font = [UIFont heavyFontOfSize:32]; + } else { + label.font = [UIFont heavyFontOfSize:48]; + } + } + + CGFloat offset = [[UIScreen mainScreen] bounds].size.width / 3; + CAAnimation *descriptionAnimation = [TDAnimationFactory descriptionAnimationWithRate:rate + offset:offset]; + [label.layer addAnimation:descriptionAnimation forKey:@"animateLabel"]; + label.layer.speed = 0; + [layers addObjectsFromArray:@[label.layer]]; +} + +- (void)updateLayers:(CGFloat)progress { + for (CALayer *layer in layers) { + layer.timeOffset = progress; + } +} + +@end diff --git a/libTitanD3vUniversal/Review/TDFaceView.h b/libTitanD3vUniversal/Review/TDFaceView.h new file mode 100644 index 0000000..4935131 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDFaceView.h @@ -0,0 +1,13 @@ +#import +#import "TDGradient.h" + +@interface TDFaceView : UIView + +- (void)configureWithBackgroundColor:(UIColor *)backgroundColor + badGradient:(TDGradient *)badGradient + ughGradient:(TDGradient *)ughGradient + okGradient:(TDGradient *)okGradient + goodGradient:(TDGradient *)goodGradient; +- (void)updateLayers:(CGFloat)progress; + +@end diff --git a/libTitanD3vUniversal/Review/TDFaceView.m b/libTitanD3vUniversal/Review/TDFaceView.m new file mode 100644 index 0000000..076b033 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDFaceView.m @@ -0,0 +1,144 @@ +#import "TDAnimationFactory.h" +#import "TDLayerFactory.h" +#import "TDFaceView.h" + +@implementation TDFaceView { + NSMutableArray *layers; +} + +- (void)configureMouthWithBadGradient:(TDGradient *)badGradient + ughGradient:(TDGradient *)ughGradient + okGradient:(TDGradient *)okGradient + goodGradient:(TDGradient *)goodGradient { + CGPoint mouthCenter = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2 + 45); + CGRect mouthFrame = CGRectMake(mouthCenter.x - 50, mouthCenter.y - 27.5, 100, 55); + + CAAnimation *mouthAnimation = [TDAnimationFactory mouthAnimationWithFrame:mouthFrame]; + CAAnimation *gradientAnimation = [TDAnimationFactory gradientAnimationWithBadGradient:badGradient + ughGradient:ughGradient + okGradient:okGradient + goodGradient:goodGradient]; + + CALayer *mouthLayer = [TDLayerFactory mouthLayer]; + CALayer *gradientLayer = [TDLayerFactory gradientLayerWithMask:mouthLayer frame:mouthFrame]; + + [self.layer addSublayer:gradientLayer]; + + [mouthLayer addAnimation:mouthAnimation forKey:@"animateMouth"]; + [gradientLayer addAnimation:gradientAnimation forKey:@"animateMouthGradient"]; + + mouthLayer.speed = 0; + gradientLayer.speed = 0; + + [layers addObjectsFromArray:@[mouthLayer, gradientLayer]]; +} + +- (void)configureEyesWithBackgroundColor:(UIColor *)backgroundColor + badGradient:(TDGradient *)badGradient + ughGradient:(TDGradient *)ughGradient + okGradient:(TDGradient *)okGradient + goodGradient:(TDGradient *)goodGradient { + CGPoint center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2); + CGRect leftEyeFrame = CGRectMake(center.x - 45, center.y - 35, 30, 30); + CGRect leftEyeCircleCoverFrame = CGRectMake(center.x - 60, center.y - 52, 20, 20); + CGRect leftEyeRectCoverFrame = CGRectMake(center.x - 48, center.y - 48, 40, 20); + CGRect rightEyeFrame = CGRectMake(center.x + 15, center.y - 35, 30, 30); + CGRect rightEyeCircleCoverFrame = CGRectMake(center.x + 40, center.y - 52, 20, 20); + CGRect rightEyeRectCoverFrame = CGRectMake(center.x + 8, center.y - 48, 40, 20); + CAAnimation *gradientAnimation = [TDAnimationFactory gradientAnimationWithBadGradient:badGradient + ughGradient:ughGradient + okGradient:okGradient + goodGradient:goodGradient]; + [self configureEyeWithFrame:leftEyeFrame + circleCoverFrame:leftEyeCircleCoverFrame + rectCoverFrame:leftEyeRectCoverFrame + animationOffset:10 + rectCoverAngleDegree:15 + gradientAnimation:gradientAnimation + backgroundColor:UIColor.clearColor]; + [self configureEyeWithFrame:rightEyeFrame + circleCoverFrame:rightEyeCircleCoverFrame + rectCoverFrame:rightEyeRectCoverFrame + animationOffset:-10 + rectCoverAngleDegree:-15 + gradientAnimation:gradientAnimation + backgroundColor:UIColor.clearColor]; +} + +- (void)configureEyeWithFrame:(CGRect)frame + circleCoverFrame:(CGRect)circleCoverFrame + rectCoverFrame:(CGRect)rectCoverFrame + animationOffset:(CGFloat)offset + rectCoverAngleDegree:(CGFloat)rectCoverAngleDegree + gradientAnimation:(CAAnimation *)gradientAnimation + backgroundColor:(UIColor *)backgroundColor { + CAAnimation *eyeCircleCoverAnimation = [TDAnimationFactory eyeCircleCoverAnimationWithOffset:offset]; + CAAnimation *eyeRectCoverAnimation = [TDAnimationFactory eyeRectCoverAnimationWithOffset:offset]; + + CALayer *eyeLayer = [TDLayerFactory eyeLayerWithSize:frame.size]; + CALayer *gradientLayer = [TDLayerFactory gradientLayerWithMask:eyeLayer frame:frame]; + CALayer *eyeCircleCoverLayer = [TDLayerFactory eyeCircleCoverLayerWithFrame:circleCoverFrame + backgroundColor:backgroundColor]; + CALayer *eyeRectCoverLayer = [TDLayerFactory eyeRectCoverLayerWithFrame:rectCoverFrame + angleDegree:rectCoverAngleDegree + backgroundColor:backgroundColor]; + + [self.layer addSublayer:gradientLayer]; + [self.layer addSublayer:eyeCircleCoverLayer]; + [self.layer addSublayer:eyeRectCoverLayer]; + + [gradientLayer addAnimation:gradientAnimation forKey:@"animateEyeGradient"]; + [eyeCircleCoverLayer addAnimation:eyeCircleCoverAnimation forKey:@"animateEyeCircleCover"]; + [eyeRectCoverLayer addAnimation:eyeRectCoverAnimation forKey:@"animateEyeRectCover"]; + + gradientLayer.speed = 0; + eyeCircleCoverLayer.speed = 0; + eyeRectCoverLayer.speed = 0; + + [layers addObjectsFromArray:@[gradientLayer, eyeCircleCoverLayer, eyeRectCoverLayer]]; +} + +- (void)configureFaceWithBadGradient:(TDGradient *)badGradient + ughGradient:(TDGradient *)ughGradient + okGradient:(TDGradient *)okGradient + goodGradient:(TDGradient *)goodGradient { + CAAnimation *gradientAnimation = [TDAnimationFactory gradientAnimationWithBadGradient:badGradient + ughGradient:ughGradient + okGradient:okGradient + goodGradient:goodGradient]; + + CALayer *faceLayer = [TDLayerFactory faceLayerWithSize:self.bounds.size]; + CALayer *gradientLayer = [TDLayerFactory gradientLayerWithMask:faceLayer frame:self.bounds]; + + [self.layer addSublayer:gradientLayer]; + + [gradientLayer addAnimation:gradientAnimation forKey:@"animateFaceGradient"]; + + gradientLayer.speed = 0; + + [layers addObjectsFromArray:@[gradientLayer]]; +} + +- (void)configureWithBackgroundColor:(UIColor *)backgroundColor + badGradient:(TDGradient *)badGradient + ughGradient:(TDGradient *)ughGradient + okGradient:(TDGradient *)okGradient + goodGradient:(TDGradient *)goodGradient { + self.backgroundColor = UIColor.clearColor; + layers = [NSMutableArray new]; + [self configureMouthWithBadGradient:badGradient ughGradient:ughGradient okGradient:okGradient goodGradient:goodGradient]; + [self configureEyesWithBackgroundColor:UIColor.clearColor + badGradient:badGradient + ughGradient:ughGradient + okGradient:okGradient + goodGradient:goodGradient]; + [self configureFaceWithBadGradient:badGradient ughGradient:ughGradient okGradient:okGradient goodGradient:goodGradient]; +} + +- (void)updateLayers:(CGFloat)progress { + for (CALayer *layer in layers) { + layer.timeOffset = progress; + } +} + +@end diff --git a/libTitanD3vUniversal/Review/TDGradient.h b/libTitanD3vUniversal/Review/TDGradient.h new file mode 100644 index 0000000..1eca59c --- /dev/null +++ b/libTitanD3vUniversal/Review/TDGradient.h @@ -0,0 +1,11 @@ +#import + +@interface TDGradient : NSObject + +- (instancetype)initWithStartGradientColor:(UIColor *)startGradientColor + endGradientColor:(UIColor *)endGradientColor; + +@property (strong, nonatomic) UIColor *startGradientColor; +@property (strong, nonatomic) UIColor *endGradientColor; + +@end diff --git a/libTitanD3vUniversal/Review/TDGradient.m b/libTitanD3vUniversal/Review/TDGradient.m new file mode 100644 index 0000000..8cb0552 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDGradient.m @@ -0,0 +1,14 @@ +#import "TDGradient.h" + +@implementation TDGradient + +- (instancetype)initWithStartGradientColor:(UIColor *)startGradientColor + endGradientColor:(UIColor *)endGradientColor { + if (self = [super init]) { + _startGradientColor = startGradientColor; + _endGradientColor = endGradientColor; + } + return self; +} + +@end diff --git a/libTitanD3vUniversal/Review/TDLayerFactory.h b/libTitanD3vUniversal/Review/TDLayerFactory.h new file mode 100644 index 0000000..b2d3fdb --- /dev/null +++ b/libTitanD3vUniversal/Review/TDLayerFactory.h @@ -0,0 +1,26 @@ +#import + +@interface TDLayerFactory : NSObject + ++ (CALayer *)mouthLayer; ++ (CALayer *)eyeLayerWithSize:(CGSize)size; ++ (CALayer *)eyeCircleCoverLayerWithFrame:(CGRect)frame backgroundColor:(UIColor *)backgroundColor; ++ (CALayer *)eyeRectCoverLayerWithFrame:(CGRect)frame angleDegree:(CGFloat)angleDegree backgroundColor:(UIColor *)backgroundColor; ++ (CALayer *)faceLayerWithSize:(CGSize)size; ++ (CALayer *)gradientLayerWithMask:(CALayer *)mask frame:(CGRect)frame; ++ (CALayer *)gradientLayerWithMask:(CALayer *)mask + frame:(CGRect)frame + colors:(NSArray *)colors + startPoint:(CGPoint)startPoint + endPoint:(CGPoint)endPoint; ++ (CALayer *)pieLayerWithFrame:(CGRect)frame + startAngleDegree:(CGFloat)startAngleDegree + endAngleDegree:(CGFloat)endAngleDegree; ++ (CALayer *)pieTitleLayerWithTitle:(NSString *)title + titleColor:(UIColor *)titleColor + frame:(CGRect)frame + angleDegree:(CGFloat)angleDegree; ++ (CALayer *)pieLinesLayerWithFrame:(CGRect)frame + startAngleDegree:(CGFloat)startAngleDegree; + +@end diff --git a/libTitanD3vUniversal/Review/TDLayerFactory.m b/libTitanD3vUniversal/Review/TDLayerFactory.m new file mode 100644 index 0000000..1ee1e8c --- /dev/null +++ b/libTitanD3vUniversal/Review/TDLayerFactory.m @@ -0,0 +1,160 @@ +#import "TDLayerFactory.h" + +@implementation TDLayerFactory + ++ (CALayer *)mouthLayer { + CAShapeLayer *layer = [CAShapeLayer new]; + layer.strokeColor = UIColor.blackColor.CGColor; + layer.fillColor = UIColor.clearColor.CGColor; + layer.lineWidth = 10; + layer.lineCap = @"round"; + layer.contentsScale = [[UIScreen mainScreen] scale]; + return layer; +} + ++ (CALayer *)eyeLayerWithSize:(CGSize)size { + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, size.width, size.height) + cornerRadius:size.height / 2]; + CAShapeLayer *layer = [CAShapeLayer new]; + layer.fillColor = UIColor.blackColor.CGColor; + layer.path = path.CGPath; + layer.contentsScale = [[UIScreen mainScreen] scale]; + return layer; +} + ++ (CALayer *)eyeCircleCoverLayerWithFrame:(CGRect)frame backgroundColor:(UIColor *)backgroundColor { + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, frame.size.width, frame.size.height) + cornerRadius:frame.size.height / 2]; + CAShapeLayer *layer = [CAShapeLayer new]; + layer.frame = frame; + layer.fillColor = backgroundColor.CGColor; + layer.path = path.CGPath; + layer.contentsScale = [[UIScreen mainScreen] scale]; + return layer; +} + ++ (CALayer *)eyeRectCoverLayerWithFrame:(CGRect)frame angleDegree:(CGFloat)angleDegree backgroundColor:(UIColor *)backgroundColor { + UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, frame.size.width, frame.size.height)]; + CAShapeLayer *layer = [CAShapeLayer new]; + layer.frame = frame; + layer.fillColor = backgroundColor.CGColor; + layer.path = path.CGPath; + CGFloat angle = angleDegree / 180.0 * M_PI; + layer.affineTransform = CGAffineTransformMakeRotation(angle); + layer.contentsScale = [[UIScreen mainScreen] scale]; + return layer; +} + ++ (CALayer *)faceLayerWithSize:(CGSize)size { + CGFloat width = size.width - 10; + CGFloat height = size.height - 10; + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(5, 5, width, height) + cornerRadius:height / 2]; + CAShapeLayer *layer = [CAShapeLayer new]; + layer.path = path.CGPath; + layer.strokeColor = UIColor.blackColor.CGColor; + layer.fillColor = UIColor.clearColor.CGColor; + layer.lineWidth = 10; + layer.contentsScale = [[UIScreen mainScreen] scale]; + return layer; +} + ++ (CALayer *)gradientLayerWithMask:(CALayer *)mask frame:(CGRect)frame { + return [self gradientLayerWithMask:mask + frame:frame + colors:@[(__bridge id) UIColor.blackColor.CGColor, (__bridge id) UIColor.blackColor.CGColor] + startPoint:CGPointMake(0, .5) + endPoint:CGPointMake(1, .5)]; +} + ++ (CALayer *)gradientLayerWithMask:(CALayer *)mask + frame:(CGRect)frame + colors:(NSArray *)colors + startPoint:(CGPoint)startPoint + endPoint:(CGPoint)endPoint { + CAGradientLayer *layer = [CAGradientLayer new]; + layer.frame = frame; + layer.colors = colors; + layer.startPoint = startPoint; + layer.endPoint = endPoint; + layer.mask = mask; + layer.contentsScale = [[UIScreen mainScreen] scale]; + return layer; +} + ++ (CALayer *)pieLayerWithFrame:(CGRect)frame + startAngleDegree:(CGFloat)startAngleDegree + endAngleDegree:(CGFloat)endAngleDegree { + CGPoint center = CGPointMake(frame.size.width / 2, frame.size.height / 2); + CGFloat radius = frame.size.height / 2; + UIBezierPath *path = [UIBezierPath bezierPath]; + [path moveToPoint:center]; + [path addArcWithCenter:center + radius:radius + startAngle:startAngleDegree / 180.0 * M_PI + endAngle:endAngleDegree / 180.0 * M_PI + clockwise:YES]; + [path addLineToPoint:center]; + [path closePath]; + CAShapeLayer *layer = [CAShapeLayer new]; + layer.fillColor = UIColor.blackColor.CGColor; + layer.path = path.CGPath; + layer.contentsScale = [[UIScreen mainScreen] scale]; + return layer; +} + ++ (CALayer *)pieLinesLayerWithFrame:(CGRect)frame + startAngleDegree:(CGFloat)startAngleDegree { + CGPoint center = CGPointMake(frame.size.width / 2, frame.size.height / 2); + CGFloat radius = frame.size.height / 2; + CGFloat longLength = radius * 0.7; + CGFloat shortLength = radius * 0.66; + CGFloat angleDegree = startAngleDegree; + CGFloat degreeBetweenLines = 7.5; + UIBezierPath *path = [UIBezierPath bezierPath]; + [path moveToPoint:center]; + [path addLineToPoint:CGPointMake(center.x - sin(angleDegree / 180.0 * M_PI) * longLength, + center.y + cos(angleDegree / 180.0 * M_PI) * longLength)]; + for (int i = 0; i < 2; i++) { + angleDegree -= degreeBetweenLines; + [path moveToPoint:center]; + [path addLineToPoint:CGPointMake(center.x - sin(angleDegree / 180.0 * M_PI) * shortLength, + center.y + cos(angleDegree / 180.0 * M_PI) * shortLength)]; + } + angleDegree -= degreeBetweenLines; + [path moveToPoint:center]; + [path addLineToPoint:CGPointMake(center.x - sin(angleDegree / 180.0 * M_PI) * longLength, + center.y + cos(angleDegree / 180.0 * M_PI) * longLength)]; + for (int i = 0; i < 2; i++) { + angleDegree -= degreeBetweenLines; + [path moveToPoint:center]; + [path addLineToPoint:CGPointMake(center.x - sin(angleDegree / 180.0 * M_PI) * shortLength, + center.y + cos(angleDegree / 180.0 * M_PI) * shortLength)]; + } + CAShapeLayer *layer = [CAShapeLayer new]; + layer.strokeColor = UIColor.clearColor.CGColor; + layer.fillColor = UIColor.clearColor.CGColor; + layer.lineWidth = 0.5; + layer.opacity = 0.6; + layer.path = path.CGPath; + layer.contentsScale = [[UIScreen mainScreen] scale]; + return layer; +} + ++ (CALayer *)pieTitleLayerWithTitle:(NSString *)title + titleColor:(UIColor *)titleColor + frame:(CGRect)frame + angleDegree:(CGFloat)angleDegree { + CATextLayer *layer = [CATextLayer new]; + layer.fontSize = 28; + layer.frame = frame; + layer.string = title; + layer.alignmentMode = kCAAlignmentCenter; + layer.foregroundColor = titleColor.CGColor; + CGFloat angle = angleDegree / 180.0 * M_PI; + layer.affineTransform = CGAffineTransformMakeRotation(angle); + layer.contentsScale = [[UIScreen mainScreen] scale]; + return layer; +} + +@end diff --git a/libTitanD3vUniversal/Review/TDPie.h b/libTitanD3vUniversal/Review/TDPie.h new file mode 100644 index 0000000..745abd1 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDPie.h @@ -0,0 +1,14 @@ +#import +#import "TDGradient.h" + +@interface TDPie : NSObject + +- (instancetype)initWithTitle:(NSString *)title + titleColor:(UIColor *)titleColor + gradient:(TDGradient *)gradient; + +@property (copy, nonatomic) NSString *title; +@property (strong, nonatomic) UIColor *titleColor; +@property (strong, nonatomic) TDGradient *gradient; + +@end diff --git a/libTitanD3vUniversal/Review/TDPie.m b/libTitanD3vUniversal/Review/TDPie.m new file mode 100644 index 0000000..e9445d5 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDPie.m @@ -0,0 +1,16 @@ +#import "TDPie.h" + +@implementation TDPie + +- (instancetype)initWithTitle:(NSString *)title + titleColor:(UIColor *)titleColor + gradient:(TDGradient *)gradient { + if (self = [super init]) { + _title = title; + _titleColor = titleColor; + _gradient = gradient; + } + return self; +} + +@end diff --git a/libTitanD3vUniversal/Review/TDRate.h b/libTitanD3vUniversal/Review/TDRate.h new file mode 100644 index 0000000..51b8e3c --- /dev/null +++ b/libTitanD3vUniversal/Review/TDRate.h @@ -0,0 +1,6 @@ +typedef NS_ENUM(NSUInteger, TDRate) { + TDRateBad = 0, + TDRateUgh = 1, + TDRateOk = 2, + TDRateGood = 3, +}; diff --git a/libTitanD3vUniversal/Review/TDReelView.h b/libTitanD3vUniversal/Review/TDReelView.h new file mode 100644 index 0000000..61e328b --- /dev/null +++ b/libTitanD3vUniversal/Review/TDReelView.h @@ -0,0 +1,11 @@ +#import +#import "TDPie.h" + +@interface TDReelView : UIView + +- (void)configureWithBadPie:(TDPie *)badPie + ughPie:(TDPie *)ughPie + okPie:(TDPie *)okPie + goodPie:(TDPie *)goodPie; + +@end diff --git a/libTitanD3vUniversal/Review/TDReelView.m b/libTitanD3vUniversal/Review/TDReelView.m new file mode 100644 index 0000000..b9d70cf --- /dev/null +++ b/libTitanD3vUniversal/Review/TDReelView.m @@ -0,0 +1,84 @@ +#import "TDConstants.h" +#import "UIColor+Utils.h" +#import "TDReelView.h" +#import "TDLayerFactory.h" + +@implementation TDReelView + +- (void)configurePieLayerWithTitle:(NSString *)title + titleColor:(UIColor *)titleColor + angleDegree:(CGFloat)angleDegree + colors:(NSArray *)colors + startPoint:(CGPoint)startPoint + endPoint:(CGPoint)endPoint { + CALayer *pieLayer = [TDLayerFactory pieLayerWithFrame:self.bounds + startAngleDegree:angleDegree + endAngleDegree:angleDegree + 45]; + + CALayer *gradientLayer = [TDLayerFactory gradientLayerWithMask:pieLayer + frame:self.bounds + colors:colors + startPoint:startPoint + endPoint:endPoint]; + + CGRect titleFrame = CGRectMake(50, 50, self.bounds.size.width - 100, self.bounds.size.height - 100); + CALayer *pieTitleLayer = [TDLayerFactory pieTitleLayerWithTitle:title + titleColor:titleColor + frame:titleFrame + angleDegree:angleDegree + 112.5]; + + CALayer *pieLinesLayer = [TDLayerFactory pieLinesLayerWithFrame:self.bounds + startAngleDegree:angleDegree - 45]; + + [self.layer addSublayer:gradientLayer]; + [self.layer addSublayer:pieTitleLayer]; + [self.layer addSublayer:pieLinesLayer]; +} + +- (void)configureWithBadPie:(TDPie *)badPie + ughPie:(TDPie *)ughPie + okPie:(TDPie *)okPie + goodPie:(TDPie *)goodPie { + NSArray *badGradient = @[(__bridge id) badPie.gradient.startGradientColor.CGColor, + (__bridge id) badPie.gradient.endGradientColor.CGColor]; + NSArray *ughGradient = @[(__bridge id) ughPie.gradient.startGradientColor.CGColor, + (__bridge id) ughPie.gradient.endGradientColor.CGColor]; + NSArray *okGradient = @[(__bridge id) okPie.gradient.startGradientColor.CGColor, + (__bridge id) okPie.gradient.endGradientColor.CGColor]; + NSArray *goodGradient = @[(__bridge id) goodPie.gradient.startGradientColor.CGColor, + (__bridge id) goodPie.gradient.endGradientColor.CGColor]; + + CGFloat angleDegree = 22.5; + [self configurePieLayerWithTitle:goodPie.title titleColor:goodPie.titleColor angleDegree:angleDegree + colors:goodGradient startPoint:CGPointMake(0.75, 0.5) endPoint:CGPointMake(0.5, 0.75)]; + + angleDegree += 45; + [self configurePieLayerWithTitle:badPie.title titleColor:badPie.titleColor angleDegree:angleDegree + colors:badGradient startPoint:CGPointMake(0.75, 0.75) endPoint:CGPointMake(0.25, 0.75)]; + + angleDegree += 45; + [self configurePieLayerWithTitle:ughPie.title titleColor:ughPie.titleColor angleDegree:angleDegree + colors:ughGradient startPoint:CGPointMake(0.5, 0.75) endPoint:CGPointMake(0.25, 0.5)]; + + angleDegree += 45; + [self configurePieLayerWithTitle:okPie.title titleColor:okPie.titleColor angleDegree:angleDegree + colors:okGradient startPoint:CGPointMake(0.25, 0.75) endPoint:CGPointMake(0.25, 0.25)]; + + angleDegree += 45; + [self configurePieLayerWithTitle:goodPie.title titleColor:goodPie.titleColor angleDegree:angleDegree + colors:goodGradient startPoint:CGPointMake(0.25, 0.5) endPoint:CGPointMake(0.5, 0.25)]; + + angleDegree += 45; + [self configurePieLayerWithTitle:badPie.title titleColor:badPie.titleColor angleDegree:angleDegree + colors:badGradient startPoint:CGPointMake(0.25, 0.25) endPoint:CGPointMake(0.75, 0.25)]; + + angleDegree += 45; + [self configurePieLayerWithTitle:ughPie.title titleColor:ughPie.titleColor angleDegree:angleDegree + colors:ughGradient startPoint:CGPointMake(0.5, 0.25) endPoint:CGPointMake(0.75, 0.5)]; + + angleDegree += 45; + [self configurePieLayerWithTitle:okPie.title titleColor:okPie.titleColor angleDegree:angleDegree + colors:okGradient startPoint:CGPointMake(0.75, 0.25) endPoint:CGPointMake(0.75, 0.75)]; +} + +@end diff --git a/libTitanD3vUniversal/Review/TDReviewViewController.h b/libTitanD3vUniversal/Review/TDReviewViewController.h new file mode 100644 index 0000000..f3dc694 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDReviewViewController.h @@ -0,0 +1,44 @@ +#import +#import "TDRate.h" +#import "Macros.h" + +@interface TDReviewViewController : UIViewController { + void(^_confirmHandler)(TDRate rate); + void(^_cancelHandler)(void); +} +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (copy, nonatomic) NSString *rateTitle; +@property (copy, nonatomic) NSString *badTitle; +@property (copy, nonatomic) NSString *ughTitle; +@property (copy, nonatomic) NSString *okTitle; +@property (copy, nonatomic) NSString *goodTitle; +@property (copy, nonatomic) NSString *confirmTitle; + +@property (strong, nonatomic) UIFont *rateTitleFont; +@property (strong, nonatomic) UIFont *confirmTitleFont; + +@property (strong, nonatomic) UIColor *backgroundColor; +@property (strong, nonatomic) UIColor *closeIconColor; + +@property (strong, nonatomic) UIColor *rateTitleColor; +@property (strong, nonatomic) UIColor *reelTitleColor; +@property (strong, nonatomic) UIColor *confirmTitleColor; + +@property (strong, nonatomic) UIColor *badTitleColor; +@property (strong, nonatomic) UIColor *ughTitleColor; +@property (strong, nonatomic) UIColor *okTitleColor; +@property (strong, nonatomic) UIColor *goodTitleColor; + +@property (strong, nonatomic) UIColor *badStartGradientColor; +@property (strong, nonatomic) UIColor *badEndGradientColor; +@property (strong, nonatomic) UIColor *ughStartGradientColor; +@property (strong, nonatomic) UIColor *ughEndGradientColor; +@property (strong, nonatomic) UIColor *okStartGradientColor; +@property (strong, nonatomic) UIColor *okEndGradientColor; +@property (strong, nonatomic) UIColor *goodStartGradientColor; +@property (strong, nonatomic) UIColor *goodEndGradientColor; + +- (void)onConfirmHandler:(void(^)(TDRate rate))confirmHandler; +- (void)onCancelHandler:(void(^)(void))cancelHandler; + +@end diff --git a/libTitanD3vUniversal/Review/TDReviewViewController.m b/libTitanD3vUniversal/Review/TDReviewViewController.m new file mode 100644 index 0000000..8baaed6 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDReviewViewController.m @@ -0,0 +1,289 @@ +#import "TDReviewViewController.h" +#import "TDFaceView.h" +#import "TDReelView.h" +#import "TDConfirmView.h" +#import "TDDescriptionView.h" +#import "TDConstants.h" +#import "UIColor+Utils.h" +#import "TDScrollView.h" +#import "TDPie.h" + +@interface TDReviewViewController () { + CGFloat currentProgress; + CGFloat screenWidth; + TDGradient *badGradient; + TDGradient *ughGradient; + TDGradient *okGradient; + TDGradient *goodGradient; + Boolean isViewDidAppear; +} + +@property (strong, nonatomic) UILabel *titleLabel; +@property (strong, nonatomic) TDReelView *reelView; +@property (strong, nonatomic) TDScrollView *scrollView; +@property (strong, nonatomic) TDFaceView *faceView; +@property (strong, nonatomic) TDConfirmView *confirmView; +@property (strong, nonatomic) TDDescriptionView *descriptionView; + +@end + +@implementation TDReviewViewController + +- (instancetype)init { + if (self = [super init]) { + _rateTitle = @"How was your experience with us?"; + _badTitle = @"BAD"; + _ughTitle = @"UGH"; + _okTitle = @"OK"; + _goodTitle = @"GOOD"; + _confirmTitle = @"SUBMIT"; + + _rateTitleFont = [UIFont systemFontOfSize:24]; + _confirmTitleFont = [UIFont systemFontOfSize:24]; + + _backgroundColor = UIColor.whiteColor; + _closeIconColor = [UIColor colorWithHexString:MAIN_TITLE]; + + _rateTitleColor = [UIColor colorWithHexString:MAIN_TITLE]; + _reelTitleColor = UIColor.whiteColor; + _confirmTitleColor = UIColor.whiteColor; + + _badTitleColor = [UIColor colorWithHexString:BAD_TITLE]; + _ughTitleColor = [UIColor colorWithHexString:UGH_TITLE]; + _okTitleColor = [UIColor colorWithHexString:OK_TITLE]; + _goodTitleColor = [UIColor colorWithHexString:GOOD_TITLE]; + + _badStartGradientColor = [UIColor colorWithHexString:BAD_START]; + _badEndGradientColor = [UIColor colorWithHexString:BAD_END]; + _ughStartGradientColor = [UIColor colorWithHexString:UGH_START]; + _ughEndGradientColor = [UIColor colorWithHexString:UGH_END]; + _okStartGradientColor = [UIColor colorWithHexString:OK_START]; + _okEndGradientColor = [UIColor colorWithHexString:OK_END]; + _goodStartGradientColor = [UIColor colorWithHexString:GOOD_START]; + _goodEndGradientColor = [UIColor colorWithHexString:GOOD_END]; + } + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = UIColor.clearColor; + screenWidth = [[UIScreen mainScreen] bounds].size.width; + + badGradient = [[TDGradient alloc] initWithStartGradientColor:_badStartGradientColor + endGradientColor:_badEndGradientColor]; + ughGradient = [[TDGradient alloc] initWithStartGradientColor:_ughStartGradientColor + endGradientColor:_ughEndGradientColor]; + okGradient = [[TDGradient alloc] initWithStartGradientColor:_okStartGradientColor + endGradientColor:_okEndGradientColor]; + goodGradient = [[TDGradient alloc] initWithStartGradientColor:_goodStartGradientColor + endGradientColor:_goodEndGradientColor]; + + [self layoutBlurView]; + [self configureTitle]; + [self configureFace]; + [self configureReel]; + [self configureDescription]; + [self configureConfirmation]; + [self configureCancel]; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + isViewDidAppear = YES; +} + + +-(void)layoutBlurView { + + self.blurEffectView = [[UIVisualEffectView alloc] initWithFrame:self.view.bounds]; + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + [self.view insertSubview:self.blurEffectView atIndex:0]; + +} + + +- (void)configureReel { + CGFloat reelWidth = screenWidth + 300; + CGRect reelViewRect = CGRectMake(0, 0, reelWidth, reelWidth); + _reelView = [[TDReelView alloc] initWithFrame:reelViewRect]; + _reelView.center = CGPointMake(self.view.center.x, self.view.bounds.size.height + 85); + [self.view addSubview:_reelView]; + TDPie *badPie = [[TDPie alloc] initWithTitle:_badTitle titleColor:_reelTitleColor gradient:badGradient]; + TDPie *ughPie = [[TDPie alloc] initWithTitle:_ughTitle titleColor:_reelTitleColor gradient:ughGradient]; + TDPie *okPie = [[TDPie alloc] initWithTitle:_okTitle titleColor:_reelTitleColor gradient:okGradient]; + TDPie *goodPie = [[TDPie alloc] initWithTitle:_goodTitle titleColor:_reelTitleColor gradient:goodGradient]; + [_reelView configureWithBadPie:badPie ughPie:ughPie okPie:okPie goodPie:goodPie]; + + _scrollView = [[TDScrollView alloc] initWithFrame:_reelView.frame]; + _scrollView.delegate = self; + [self.view addSubview:_scrollView]; + [_scrollView configure]; +} + +- (void)configureTitle { + _titleLabel = [UILabel new]; + CGFloat y = 50; + CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + if(screenHeight == 480 || screenHeight == 568) { + y = 20; + } else if (screenHeight == 812) { + y = 60; + } + } + _titleLabel.frame = CGRectMake(50, y, screenWidth - 100, 60); + _titleLabel.font = _rateTitleFont; + _titleLabel.numberOfLines = 2; + _titleLabel.textAlignment = NSTextAlignmentCenter; + _titleLabel.textColor = _rateTitleColor; + _titleLabel.text = _rateTitle; + [self.view addSubview:_titleLabel]; +} + +- (void)configureFace { + CGRect faceViewRect = CGRectMake(0, 0, 180, 180); + CGFloat titleLabelMaxY = _titleLabel.frame.origin.y + _titleLabel.frame.size.height; + _faceView = [[TDFaceView alloc] initWithFrame:faceViewRect]; + _faceView.center = CGPointMake(self.view.center.x, (self.view.center.y + titleLabelMaxY) / 2); + _faceView.backgroundColor = UIColor.clearColor; + [self.view addSubview:_faceView]; + [_faceView configureWithBackgroundColor:_backgroundColor + badGradient:badGradient + ughGradient:ughGradient + okGradient:okGradient + goodGradient:goodGradient]; +} + +- (void)configureDescription { + CGRect descriptionViewRect = CGRectMake(0, 0, 180, 50); + CGFloat faceViewMaxY = _faceView.frame.origin.y + _faceView.frame.size.height; + _descriptionView = [[TDDescriptionView alloc] initWithFrame:descriptionViewRect]; + _descriptionView.center = CGPointMake(self.view.center.x, (faceViewMaxY + _reelView.frame.origin.y) / 2); + [self.view addSubview:_descriptionView]; + [_descriptionView configureLabelWithRate:TDRateBad title:_badTitle color:_badTitleColor]; + [_descriptionView configureLabelWithRate:TDRateUgh title:_ughTitle color:_ughTitleColor]; + [_descriptionView configureLabelWithRate:TDRateOk title:_okTitle color:_okTitleColor]; + [_descriptionView configureLabelWithRate:TDRateGood title:_goodTitle color:_goodTitleColor]; +} + +- (void)configureConfirmation { + CGFloat confirmWidth = _reelView.frame.size.width * 0.64; + CGRect confirmViewRect = CGRectMake(0, 0, confirmWidth, confirmWidth); + _confirmView = [[TDConfirmView alloc] initWithFrame:confirmViewRect]; + _confirmView.center = CGPointMake(self.view.center.x, self.view.bounds.size.height + 55); + _confirmView.backgroundColor = UIColor.blueColor; + [self.view addSubview:_confirmView]; + [_confirmView configureWithBackgroundColor:_backgroundColor + title:_confirmTitle + badGradient:badGradient + ughGradient:ughGradient + okGradient:okGradient + goodGradient:goodGradient]; + _confirmView.button.titleLabel.font = _confirmTitleFont; + [_confirmView.button addTarget:self action:@selector(confirm) forControlEvents:UIControlEventTouchUpInside]; +} + +- (void)configureCancel { +// NSString *imageName = @"close.png"; +// NSBundle *bundle = [NSBundle bundleForClass:[self class]]; +// NSBundle *resources = [NSBundle bundleWithURL:[bundle URLForResource:@"RPInteraction" withExtension:@"bundle"]]; +// UIImage *closeIcon = [UIImage imageNamed:imageName]; +// if (closeIcon == nil) closeIcon = [UIImage imageNamed:imageName inBundle:resources compatibleWithTraitCollection:nil]; + + float bottomPadding; + + if (iPhone_6_8) { + bottomPadding = 7; + } else if (iPhone_6_8_Plus) { + bottomPadding = 10; + } else if (iPhone_X_XS_11Pro) { + bottomPadding = 10; + } else if (iPhone_XR_XS_11Pro) { + bottomPadding = 10; + } else if (iPhone_12_mini) { + bottomPadding = 10; + } else if (iPhone_12_Pro) { + bottomPadding = 10; + } else if (iPhone_12_Pro_Max) { + bottomPadding = 10; + } else { + bottomPadding = 20; + } + + UIButton *button = [[UIButton alloc] init]; + [button setTitle:@"Cancel" forState:UIControlStateNormal]; + [button setTitleColor:UIColor.systemRedColor forState:UIControlStateNormal]; + [button addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:button]; + + button.translatesAutoresizingMaskIntoConstraints = NO; + [button.widthAnchor constraintEqualToConstant:150.0].active = YES; + [button.heightAnchor constraintEqualToConstant:50.0].active = YES; + [[button centerXAnchor] constraintEqualToAnchor:self.view.centerXAnchor].active = true; + [button.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-bottomPadding].active = YES; +} + +- (void)onConfirmHandler:(void(^)(TDRate rate))confirmHandler { + _confirmHandler = [confirmHandler copy]; +} + +- (void)onCancelHandler:(void(^)(void))cancelHandler { + _cancelHandler = [cancelHandler copy]; +} + +- (void)confirm { + TDRate rate = TDRateGood; + if ((-0.1 < currentProgress && currentProgress < 0.1) || (0.4 < currentProgress && currentProgress < 0.6) + || (0.9 < currentProgress)) { + rate = TDRateBad; + } else if ((0.1 < currentProgress && currentProgress < 0.2) || (0.6 < currentProgress && currentProgress < 0.7)) { + rate = TDRateUgh; + } else if ((0.2 < currentProgress && currentProgress < 0.3) || (0.7 < currentProgress && currentProgress < 0.8)) { + rate = TDRateOk; + } + if (_confirmHandler) { + __weak TDReviewViewController *weakSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + TDReviewViewController *ref = weakSelf; + if (ref == nil) return; + ref->_confirmHandler(rate); + ref->_confirmHandler = nil; + }); + } +} + +- (void)cancel { + if (_cancelHandler) { + __weak TDReviewViewController *weakSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + TDReviewViewController *ref = weakSelf; + if (ref == nil) return; + ref->_cancelHandler(); + ref->_cancelHandler = nil; + }); + } +} + +#pragma mark ScrollViewDelegate + +- (void)scrollViewDidChangeProgress:(CGFloat)progress { + if (!isViewDidAppear) return; + CGFloat angle = -2 * M_PI * progress; + CGFloat newProgress = progress < 0 ? 1 + progress : progress; + currentProgress = newProgress; + __weak TDReviewViewController *weakSelf = self; + dispatch_block_t updateLayers = ^{ + weakSelf.reelView.transform = CGAffineTransformMakeRotation(angle); + [weakSelf.faceView updateLayers:newProgress]; + [weakSelf.confirmView updateLayers:newProgress]; + [weakSelf.descriptionView updateLayers:newProgress]; + }; + if ([NSThread isMainThread]) { + updateLayers(); + } else { + dispatch_sync(dispatch_get_main_queue(), updateLayers); + } +} + +@end diff --git a/libTitanD3vUniversal/Review/TDScrollView.h b/libTitanD3vUniversal/Review/TDScrollView.h new file mode 100644 index 0000000..5341eae --- /dev/null +++ b/libTitanD3vUniversal/Review/TDScrollView.h @@ -0,0 +1,17 @@ +#import +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshadow-ivar" + +@protocol ScrollViewDelegate + +- (void)scrollViewDidChangeProgress:(CGFloat)progress; + +@end + +@interface TDScrollView : UIView + +@property (weak) id delegate; + +- (void)configure; + +@end diff --git a/libTitanD3vUniversal/Review/TDScrollView.m b/libTitanD3vUniversal/Review/TDScrollView.m new file mode 100644 index 0000000..46feae2 --- /dev/null +++ b/libTitanD3vUniversal/Review/TDScrollView.m @@ -0,0 +1,44 @@ +#import "TDScrollView.h" + +@interface TDScrollView () +@end + +@implementation TDScrollView { + UIScrollView *scrollView; +} + +- (void)configure { + CGFloat radius = self.bounds.size.width / 2; + CGFloat circumference = 2 * M_PI * radius; + CGFloat initialOffset = M_PI_4 / (2 * M_PI) * circumference; + CGRect frame = self.bounds; + frame.size.width = initialOffset; + scrollView = [[UIScrollView alloc] initWithFrame:frame]; + scrollView.clipsToBounds = NO; + scrollView.pagingEnabled = YES; + scrollView.delegate = self; + scrollView.showsHorizontalScrollIndicator = false; + scrollView.contentSize = CGSizeMake(100000, self.bounds.size.height); + [scrollView setContentOffset:CGPointMake(initialOffset * 200, 0)]; + [self addSubview:scrollView]; +} + +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { + if ([self pointInside:point withEvent:event]) { + if ([self.subviews count] == 0) return nil; + else return [self.subviews lastObject]; + } + return nil; +} + +#pragma mark UIScrollViewDelegate + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + CGFloat radius = self.bounds.size.width / 2; + CGFloat circumference = 2 * M_PI * radius; + CGFloat offset = fmod(scrollView.contentOffset.x, circumference); + [self.delegate scrollViewDidChangeProgress:offset / circumference]; +} + + +@end diff --git a/libTitanD3vUniversal/Review/UIColor+Utils.h b/libTitanD3vUniversal/Review/UIColor+Utils.h new file mode 100644 index 0000000..c54cd60 --- /dev/null +++ b/libTitanD3vUniversal/Review/UIColor+Utils.h @@ -0,0 +1,8 @@ +#import + +@interface UIColor (Utils) + ++ (UIColor *)colorWithHexString:(NSString *)hex; ++ (UIColor *)colorWithHexValue:(NSInteger)hex; + +@end diff --git a/libTitanD3vUniversal/Review/UIColor+Utils.m b/libTitanD3vUniversal/Review/UIColor+Utils.m new file mode 100644 index 0000000..4d4879a --- /dev/null +++ b/libTitanD3vUniversal/Review/UIColor+Utils.m @@ -0,0 +1,25 @@ +#import "UIColor+Utils.h" + +@implementation UIColor (Utils) + ++ (UIColor *)colorWithHexString:(NSString *)hexstr { + NSScanner *scanner; + unsigned int rgbval; + + scanner = [NSScanner scannerWithString: hexstr]; + [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"#"]]; + [scanner scanHexInt: &rgbval]; + + return [UIColor colorWithHexValue: rgbval]; +} + ++ (UIColor *)colorWithHexValue:(NSInteger) rgbValue { + return [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 + green:((float)((rgbValue & 0xFF00) >> 8))/255.0 + blue:((float)(rgbValue & 0xFF))/255.0 + alpha:1.0]; + +} + + +@end diff --git a/libTitanD3vUniversal/Review/UIFont+Utils.h b/libTitanD3vUniversal/Review/UIFont+Utils.h new file mode 100644 index 0000000..3eefa81 --- /dev/null +++ b/libTitanD3vUniversal/Review/UIFont+Utils.h @@ -0,0 +1,7 @@ +#import + +@interface UIFont (Utils) + ++ (UIFont *)heavyFontOfSize:(CGFloat)fontSize; + +@end diff --git a/libTitanD3vUniversal/Review/UIFont+Utils.m b/libTitanD3vUniversal/Review/UIFont+Utils.m new file mode 100644 index 0000000..7c29720 --- /dev/null +++ b/libTitanD3vUniversal/Review/UIFont+Utils.m @@ -0,0 +1,12 @@ +#import "UIFont+Utils.h" + +@implementation UIFont (Utils) + ++ (UIFont *)heavyFontOfSize:(CGFloat)fontSize { + if (@available(iOS 8.2, *)) { + return [UIFont systemFontOfSize:fontSize weight:UIFontWeightHeavy]; + } + return [UIFont systemFontOfSize:fontSize]; +} + +@end diff --git a/libTitanD3vUniversal/SecondaryController/TDSecondaryController.h b/libTitanD3vUniversal/SecondaryController/TDSecondaryController.h new file mode 100644 index 0000000..00da79c --- /dev/null +++ b/libTitanD3vUniversal/SecondaryController/TDSecondaryController.h @@ -0,0 +1,21 @@ + +#import +#import +#import +#import "TDPrefsManager.h" +#import "TDAppearance.h" +#import "TDUtilities.h" +#import "GlobalPrefs.h" +#import "TDGridCell.h" + +@interface TDSecondaryController : PSListController + +@property (nonatomic, retain) UIVisualEffectView *blurEffectView; +@property (nonatomic, retain) UIRefreshControl *respringController; +@property (nonatomic, retain) UIColor *navigationBarColour; +@property (nonatomic, retain) UIColor *tintColour; +@property (nonatomic, retain) UIColor *backgroundColour; +@property (nonatomic, retain) UIColor *cellsColour; +@property (nonatomic, retain) UIColor *labelColour; + +@end diff --git a/libTitanD3vUniversal/SecondaryController/TDSecondaryController.m b/libTitanD3vUniversal/SecondaryController/TDSecondaryController.m new file mode 100644 index 0000000..38bd8ca --- /dev/null +++ b/libTitanD3vUniversal/SecondaryController/TDSecondaryController.m @@ -0,0 +1,192 @@ +#import "TDSecondaryController.h" + +@implementation TDSecondaryController + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + self.navigationBarColour = [[TDAppearance sharedInstance] navigationBarColour]; + self.tintColour = [[TDAppearance sharedInstance] tintColour]; + self.backgroundColour = [[TDAppearance sharedInstance] backgroundColour]; + self.cellsColour = [[TDAppearance sharedInstance] cellColour]; + self.labelColour = [[TDAppearance sharedInstance] labelColour]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = self.tintColour; + + + UINavigationBar *bar = self.navigationController.navigationController.navigationBar; + bar.barTintColor = self.navigationBarColour; + bar.tintColor = self.tintColour; + [[UIButton appearance]setTintColor:self.tintColour]; + self.view.tintColor = self.tintColour; + + UITableView *tableView = self.view.subviews[0]; + tableView.backgroundColor = self.backgroundColour; + [tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + + [[UILabel appearance] setTextColor:self.labelColour]; + + + self.blurEffectView = [[UIVisualEffectView alloc] init]; + self.blurEffectView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; + self.blurEffectView.alpha = 0; + [self.view addSubview:self.blurEffectView]; + + self.blurEffectView.translatesAutoresizingMaskIntoConstraints = false; + [self.blurEffectView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES; + [self.blurEffectView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; + [self.blurEffectView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; + [self.blurEffectView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; + + + self.respringController = [[UIRefreshControl alloc] init]; + [self.respringController addTarget:self action:@selector(beginRespring:) forControlEvents:UIControlEventValueChanged]; + NSString *title = @"Respring"; + NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject:self.tintColour forKey:NSForegroundColorAttributeName]; + NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:title attributes:attrsDictionary]; + self.respringController.attributedTitle = attributedTitle; + self.respringController.tintColor = self.tintColour; + [tableView addSubview:self.respringController]; + +} + + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + UIWindow *keyWindow = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (window.isKeyWindow) { + keyWindow = window; + break; + } + } + + keyWindow.tintColor = [[UINavigationBar appearance] tintColor]; + + UINavigationBar *bar = self.navigationController.navigationController.navigationBar; + bar.tintColor = nil; + bar.barTintColor = nil; + self.view.tintColor = nil; + [[UIButton appearance]setTintColor:nil]; + [[UILabel appearance] setTextColor:nil]; + +} + + +// - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + +// PSTableCell *cell = (PSTableCell *)[super tableView:tableView cellForRowAtIndexPath:indexPath]; +// cell.backgroundColor = self.cellsColour; +// return cell; +// } + + +-(void)tableView:(UITableView*)tableView willDisplayCell:(PSTableCell*)cell forRowAtIndexPath:(NSIndexPath*)indexPath{ + + UIBezierPath *maskPath; + if ([self rowsForGroup:indexPath.section] == 1) { + maskPath=[UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:UIRectCornerTopLeft|UIRectCornerTopRight|UIRectCornerBottomLeft|UIRectCornerBottomRight cornerRadii:[self cornerRadiiForSection:indexPath.section]]; + } else if (indexPath.row == 0) { + maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:UIRectCornerTopLeft| UIRectCornerTopRight cornerRadii:[self cornerRadiiForSection:indexPath.section]]; + } else if (indexPath.row == [self rowsForGroup:indexPath.section] - 1) { + maskPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds byRoundingCorners:UIRectCornerBottomLeft|UIRectCornerBottomRight cornerRadii:[self cornerRadiiForSection:indexPath.section]]; + } else { + maskPath = [UIBezierPath bezierPathWithRect:cell.bounds]; + } + + CAShapeLayer *maskLayer = [CAShapeLayer layer]; + maskLayer.frame = cell.bounds; + maskLayer.path = maskPath.CGPath; + cell.layer.mask = maskLayer; + cell.layer.shadowPath = maskPath.CGPath; + + cell.backgroundColor = self.cellsColour; +} + + +- (CGSize)cornerRadiiForSection:(NSInteger)section{ + return CGSizeMake(10, 10); +} + + +- (void)openController:(GridButton *)sender { + + invokeHapticFeedback(); + + NSString *className = sender.identifier; + PSListController *controller = [[NSClassFromString(className) alloc] init]; + [[self navigationController] pushViewController:controller animated:YES]; +} + + +-(void)beginRespring:(id)sender { + + [self.respringController endRefreshing]; + + [UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ + self.blurEffectView.alpha = 1; + } completion:^(BOOL finished) { + [[TDUtilities sharedInstance] respring]; + }]; + +} + + +- (id)readPreferenceValue:(PSSpecifier*)specifier { + NSString *path = [NSString stringWithFormat:@"/User/Library/Preferences/%@.plist", specifier.properties[@"defaults"]]; + NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:path]; + return (plist[specifier.properties[@"key"]]) ?: specifier.properties[@"default"]; +} + + +- (void)setPreferenceValue:(id)value specifier:(PSSpecifier*)specifier { + NSString *path = [NSString stringWithFormat:@"/User/Library/Preferences/%@.plist", specifier.properties[@"defaults"]]; + NSMutableDictionary *plist = [NSMutableDictionary dictionaryWithContentsOfFile:path] ?: [NSMutableDictionary new]; + plist[specifier.properties[@"key"]] = value; + [plist writeToFile:path atomically:true]; + CFStringRef notificationName = (__bridge CFStringRef)specifier.properties[@"PostNotification"]; + if (notificationName) { + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), notificationName, NULL, NULL, true); + } +} + +-(BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + return YES; +} + + +- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(0.97, 0.97); + cell.alpha = 0.5; + } completion:nil]; +} + + +- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath { + + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + [UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^(){ + cell.transform = CGAffineTransformMakeScale(1.0, 1.0); + cell.alpha = 1; + } completion:nil]; +} + +@end diff --git a/libTitanD3vUniversal/TermsandConditions/TDTermsAndConditionsVC.h b/libTitanD3vUniversal/TermsandConditions/TDTermsAndConditionsVC.h new file mode 100644 index 0000000..ec2ccb1 --- /dev/null +++ b/libTitanD3vUniversal/TermsandConditions/TDTermsAndConditionsVC.h @@ -0,0 +1,8 @@ +#import +#import "ConstraintExtension.h" + +@interface TDTermsAndConditionsVC : UIViewController +@property (nonatomic, retain) UIImageView *iconImage; +@property (nonatomic, retain) UILabel *titleLabel; +@property (nonatomic, retain) UITextView *textView; +@end diff --git a/libTitanD3vUniversal/TermsandConditions/TDTermsAndConditionsVC.m b/libTitanD3vUniversal/TermsandConditions/TDTermsAndConditionsVC.m new file mode 100644 index 0000000..cc0db9b --- /dev/null +++ b/libTitanD3vUniversal/TermsandConditions/TDTermsAndConditionsVC.m @@ -0,0 +1,63 @@ +#import "TDTermsAndConditionsVC.h" + +@implementation TDTermsAndConditionsVC + +- (void)viewDidLoad { + [super viewDidLoad]; + self.view.backgroundColor = [UIColor colorWithRed: 0.09 green: 0.09 blue: 0.09 alpha: 1.00]; + + [self layoutHeaderView]; + [self layoutTextView]; + +} + + +-(void)layoutHeaderView { + + self.iconImage = [[UIImageView alloc] init]; + self.iconImage.image = [UIImage imageWithContentsOfFile:@"/usr/lib/TitanD3v/TitanD3v.bundle/Terms&Conditions/titand3v.png"]; + [self.view addSubview:self.iconImage]; + + [self.iconImage size:CGSizeMake(70, 70)]; + [self.iconImage x:self.view.centerXAnchor]; + [self.iconImage top:self.view.topAnchor padding:25]; + + + self.titleLabel = [[UILabel alloc] init]; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.titleLabel.textColor = UIColor.whiteColor; + self.titleLabel.numberOfLines = 0; + self.titleLabel.font = [UIFont boldSystemFontOfSize:20]; + self.titleLabel.text = @"Downloadable Digital Products Terms and Conditions of Sale"; + [self.view addSubview:self.titleLabel]; + + [self.titleLabel x:self.view.centerXAnchor]; + [self.titleLabel top:self.iconImage.bottomAnchor padding:10]; + [self.titleLabel leading:self.view.leadingAnchor padding:20]; + [self.titleLabel trailing:self.view.trailingAnchor padding:-20]; + +} + + +-(void)layoutTextView { + + + self.textView = [[UITextView alloc] init]; + self.textView.delegate = self; + self.textView.editable = NO; + self.textView.text = @"1.0 Introduction \n\nThese terms and conditions set out the terms and conditions between you, the customer, and TitanD3v (“us”, “we”), governing the use of our repo and our downloadable digital recordings including the content therein (the “products”). Your use of our repo, and purchase, download and use of our products, constitutes your full acceptance of these terms and conditions. If you do not agree with these terms and conditions, you should not use our repo or purchase, download or use any of our products. \n\n2.0 License and Use \n\nYour purchase of one of our products constitutes our granting to you of a non-exclusive, non-sublicensable, non-transferable license to download and access that product for the purpose of your own personal use and reference, and print or convert the product to an image or vector format for your own storage, retention and reference (the “purpose”). You agree that under no circumstances shall you use, or permit to be used, any product other than for the aforesaid purpose. For the avoidance of doubt, you shall not copy, re-sell, sublicense, rent out, share or otherwise distribute any of our products, whether modified or not, to any third party. You agree not to use any of our products in a way which might be detrimental to us or damage our reputation. \n\n3.0 Intellectual Property \n\nThe products, whether modified or not, and all intellectual property and copyright contained therein, are and shall at all times remain our sole and exclusive property. You agree that under no circumstances, whether the product has been modified or not, shall you have or attempt to claim ownership of any intellectual property rights or copyright in the product. \n\n4.0 Refunds and Chargebacks \n\nOnce a product has been purchased by you, no right of cancellation or refund exists under the Consumer Protection (Distance Selling) Regulations 2000 due to the electronic nature of our products. Any refunds shall be at our sole and absolute discretion. You agree that under no circumstances whatsoever shall you initiate any chargebacks via your payment provider. You agree that any payments made by you for any of our products are final and may not be charged back. We reserve the right to alter any of our prices from time to time. \n\n5.0 Warranties and Liability \n\nWe make every effort to ensure that our products are accurate, authoritaive and fit for the use of our customers. However, we take no responsibility whatsoever for the suitability of the product, and we provide no warranties as to the function or use of the product, whether express, implied or statutory, including without limitation any warranties of merchantability or fitness for particular purpose. You agree to indemnify us against all liabilities, claims, demands, expenses, actions, costs, damages, or loss arising out of your breach of these terms and conditions. Furthermore, we shall not be liable to you or any party for consequential, indirect, special or exemplary damages including but not limited to damages for loss of profits, business or anticipated benefits whether arising under tort, contract, negligence or otherwise whether or not foreseen, reasonably foreseeable or advised of the possibility of such damages. \n\n6.0 General \n\nThese terms and conditions constitute the entire agreement and understanding between you and us for the supply of downloadable digital products, and shall supersede any prior agreements whether made in writing, orally, implied or otherwise. The failure by us to exercise or enforce any right(s) under these terms and conditions shall not be deemed to be a waiver of any such right(s) or operate so as to bar the exercise or enforcement thereof at any time(s) thereafter, as a waiver of another or constitute a continuing waiver. You agree that monetary damages may not be a sufficient remedy for the damage which may accrue to us by reason of your breach of these terms and conditions, therefore we shall be entitled to seek injunctive relief to enforce the obligations contained herein. The unenforceability of any single provision within these terms and conditions shall not affect any other provision hereof. These terms and conditions, your acceptance thereof, and our relationship with you shall be governed by and construed in accordance with English law and both us and you irrevocably submit to the exclusive jurisdiction of the English courts over any claim, dispute or matter arising under or in connection with these terms and conditions or our relationship with you. \n\nContacting Us \n\nPlease do not hesitate to contact us regarding any matter relating to this Downloadable Digital Products Terms and Conditions of Sale Policy via email support@titand3v.com"; + self.textView.font = [UIFont systemFontOfSize:18]; + self.textView.textAlignment = NSTextAlignmentLeft; + self.textView.backgroundColor = UIColor.clearColor; + self.textView.textColor = UIColor.whiteColor; + [self.view addSubview:self.textView]; + + [self.textView top:self.titleLabel.bottomAnchor padding:20]; + [self.textView leading:self.view.leadingAnchor padding:10]; + [self.textView trailing:self.view.trailingAnchor padding:-10]; + [self.textView bottom:self.view.bottomAnchor padding:0]; + +} + + +@end diff --git a/libTitanD3vUniversal/TitanD3vUniversal.h b/libTitanD3vUniversal/TitanD3vUniversal.h new file mode 100644 index 0000000..e07bb1c --- /dev/null +++ b/libTitanD3vUniversal/TitanD3vUniversal.h @@ -0,0 +1,46 @@ +#import "TDPrimraryController.h" +#import "TDSecondaryController.h" +#import "TDExternalController.h" +#import "TDListController.h" +#import "TDPrefsManager.h" +#import "TDTweakManager.h" +#import "TDAppearance.h" +#import "TDAlertViewController.h" +#import "TDColorPickerViewController.h" +#import "TDBannerView.h" +#import "TDWeather.h" +#import "TDMarqueeLabel.h" +#import "TDUtilities.h" +#import "ConstraintExtension.h" +#import "TDBlurView.h" +#import "BlurBannerView.h" +// #import "TDLabel.h" +#import "TDView.h" +#import "TDButton.h" +#import "TDImage.h" +#import "TDCyclePagerView.h" +#import "TDAppList.h" +#import "TDAppListController.h" +#import "TDAppsCell.h" +#import "TDResultsTableController.h" +#import "TDReportBugViewController.h" +#import "TDConfettiView.h" +#import "Prefix.h" +#import "Macros.h" +#import "NSTask.h" +#import "MobileGestalt.h" +#import "Reachability.h" +#import "RNCryptor.h" +#import "RNCryptor+Private.h" +#import "RNCryptorEngine.h" +#import "RNDecryptor.h" +#import "RNEncryptor.h" +#import "TDReviewViewController.h" +#import "PrivateBlurEffect.h" +#import "TDIndexBar.h" +#import "TDHeaderView.h" +#import "TDEmojiPickerViewController.h" +#import "TDContactPickerViewController.h" +#import "TDContact.h" +#import "TDContactPickerViewController.h" +#import "TDAvatarIdentityPickerViewController.h" diff --git a/libTitanD3vUniversal/TweakManager/TDTweakManager.h b/libTitanD3vUniversal/TweakManager/TDTweakManager.h new file mode 100644 index 0000000..4fe4947 --- /dev/null +++ b/libTitanD3vUniversal/TweakManager/TDTweakManager.h @@ -0,0 +1,25 @@ +#import +#import "HEXColour.h" + +@interface TDTweakManager : NSObject + ++(instancetype)sharedInstance; +-(id)init; + +- (void)setBool:(BOOL)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (void)setObject:(id)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (void)setFloat:(long long)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (void)setInt:(int)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue ID:(NSString*)bundleIdentifier; +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue ID:(NSString*)bundleIdentifier; +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue ID:(NSString*)bundleIdentifier; +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue ID:(NSString*)bundleIdentifier; +- (bool)boolForKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (id)objectForKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (long long)floatForKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (int)intForKey:(id)aKey ID:(NSString*)bundleIdentifier; +- (UIColor *)colourForKey:(id)aKey defaultValue:(id)defaultValue ID:(NSString*)bundleIdentifier; +- (UIColor *)systemColourForKey:(id)aKey defaultColour:(UIColor *)defaultColour ID:(NSString*)bundleIdentifier; +- (void)removeObjectForKey:(id)aKey ID:(NSString*)bundleIdentifier; + +@end diff --git a/libTitanD3vUniversal/TweakManager/TDTweakManager.m b/libTitanD3vUniversal/TweakManager/TDTweakManager.m new file mode 100644 index 0000000..9ad46c9 --- /dev/null +++ b/libTitanD3vUniversal/TweakManager/TDTweakManager.m @@ -0,0 +1,181 @@ +#import "TDTweakManager.h" + +@implementation TDTweakManager + ++(instancetype)sharedInstance { + static TDTweakManager *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[TDTweakManager alloc] init]; + }); + return sharedInstance; +} + +-(id)init { + return self; +} + + +- (void)setBool:(BOOL)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + [settings2 setObject:[NSNumber numberWithBool:anObject] forKey:aKey]; + [settings2 writeToFile:prefPath2 atomically:YES]; + } +} + +- (void)setObject:(id)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + [settings2 setObject:anObject forKey:aKey]; + [settings2 writeToFile:prefPath2 atomically:YES]; + } +} + +- (void)setFloat:(long long)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + [settings2 setObject:@(anObject) forKey:aKey]; + [settings2 writeToFile:prefPath2 atomically:YES]; + } +} + +- (void)setInt:(int)anObject forKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + [settings2 setObject:@(anObject) forKey:aKey]; + [settings2 writeToFile:prefPath2 atomically:YES]; + } +} + +- (bool)boolForKey:(id)aKey defaultValue:(BOOL)defaultValue ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + if([settings2 objectForKey:aKey] == NULL){ + return defaultValue; + } + return [[settings2 objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey defaultValue:(id)defaultValue ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [settings2 objectForKey:aKey]?:defaultValue; +} + +- (long long)floatForKey:(id)aKey defaultValue:(long long)defaultValue ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [[settings2 objectForKey:aKey] longLongValue]?:defaultValue; +} + +- (int)intForKey:(id)aKey defaultValue:(int)defaultValue ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [[settings2 objectForKey:aKey] intValue]?:defaultValue; +} + +- (bool)boolForKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [[settings2 objectForKey:aKey] boolValue]; +} + +- (id)objectForKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [settings2 objectForKey:aKey]; +} + +- (long long)floatForKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [[settings2 objectForKey:aKey] longLongValue]; +} + +- (int)intForKey:(id)aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + return [[settings2 objectForKey:aKey] intValue]; +} + +- (UIColor *)colourForKey:(id)aKey defaultValue:(id)defaultValue ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + NSString *colourString = [settings2 objectForKey:aKey]?:defaultValue; + UIColor *color = colorFromHexString(colourString); + return color; +} + +- (UIColor *)systemColourForKey:(id)aKey defaultColour:(UIColor *)defaultColour ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + } + NSData *decodedData = [settings2 objectForKey:aKey]; + UIColor *color = [NSKeyedUnarchiver unarchiveObjectWithData:decodedData]?:defaultColour; + return color; +} + +- (void)removeObjectForKey:aKey ID:(NSString*)bundleIdentifier { + NSMutableDictionary *settings2 = [NSMutableDictionary dictionary]; + NSString *BID = bundleIdentifier; + if ([BID isEqualToString:bundleIdentifier]) { + NSString *prefPath2 = [NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]; + [settings2 addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:prefPath2]]; + [settings2 removeObjectForKey:aKey]; + [settings2 writeToFile:prefPath2 atomically:YES]; + } +} + +@end diff --git a/libTitanD3vUniversal/Utilities/TDUtilities.h b/libTitanD3vUniversal/Utilities/TDUtilities.h new file mode 100644 index 0000000..0cce2fe --- /dev/null +++ b/libTitanD3vUniversal/Utilities/TDUtilities.h @@ -0,0 +1,26 @@ +#import +#import + +@interface TDUtilities : NSObject ++(instancetype)sharedInstance; +-(id)init; + +-(void)respring; +-(void)safemode; +-(void)reboot; +-(void)uicache; +-(NSString *)systemVersion; +-(NSString *)deviceName; +-(NSString *)deviceModel; +-(NSString *)timeWithFormat:(NSString *)string; +-(NSString *)dateWithFormat:(NSString *)string; +-(NSString *)greeting; +-(NSString *)battery; +-(void)launchURL:(NSString *)string; +-(void)launchApp:(NSString *)string; +-(void)haptic:(NSInteger)style; +@end + +@interface UIApplication (TD) +-(BOOL)launchApplicationWithIdentifier:(id)arg1 suspended:(BOOL)arg2; +@end \ No newline at end of file diff --git a/libTitanD3vUniversal/Utilities/TDUtilities.m b/libTitanD3vUniversal/Utilities/TDUtilities.m new file mode 100644 index 0000000..bca753d --- /dev/null +++ b/libTitanD3vUniversal/Utilities/TDUtilities.m @@ -0,0 +1,149 @@ +#import "TDUtilities.h" + +UIImpactFeedbackGenerator *haptic; + +@implementation TDUtilities + ++(instancetype)sharedInstance { + static TDUtilities *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[TDUtilities alloc] init]; + }); + return sharedInstance; +} + +-(id)init { + return self; +} + +-(void)respring { + pid_t pid; + int status; + const char* args[] = {"sbreload", NULL}; + posix_spawn(&pid, "/usr/bin/sbreload", NULL, NULL, (char* const*)args, NULL); + waitpid(pid, &status, WEXITED); +} + +-(void)safemode { + pid_t pid; + int status; + const char* args[] = {"killall", "-SEGV", "SpringBoard", NULL}; + posix_spawn(&pid, "/usr/bin/killall", NULL, NULL, (char* const*)args, NULL); + waitpid(pid, &status, WEXITED); +} + +-(void)reboot { + pid_t pid; + int status; + const char* args[] = {"mobileldrestart", NULL}; + posix_spawn(&pid, "/usr/bin/mobileldrestart", NULL, NULL, (char* const*)args, NULL); + waitpid(pid, &status, WEXITED); +} + +-(void)uicache{ + pid_t pid; + int status; + const char* args[] = {"uicache", NULL}; + posix_spawn(&pid, "/usr/bin/uicache", NULL, NULL, (char* const*)args, NULL); + waitpid(pid, &status, WEXITED); +} + +-(NSString *)systemVersion { + NSString *string = [[UIDevice currentDevice] systemVersion]; + return string; +} + +-(NSString *)deviceName { + NSString *string = [[UIDevice currentDevice] name]; + return string; +} + +-(NSString *)deviceModel { + NSString *string = [[UIDevice currentDevice] model]; + return string; +} + +-(NSString*)timeWithFormat:(NSString*)string { + + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + NSString *dateFormat = string; + + NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + [dateFormatter setLocale:enUSPOSIXLocale]; + [dateFormatter setTimeZone:[NSTimeZone localTimeZone]]; + + [dateFormatter setDateFormat:dateFormat]; + NSString *timeString = [dateFormatter stringFromDate:[NSDate date]]; + + return timeString; +} + +-(NSString*)dateWithFormat:(NSString*)string { + + NSDate *today = [NSDate date]; + NSDateFormatter *dformat = [[NSDateFormatter alloc] init]; + [dformat setDateFormat:string]; + + NSString *dateString = [dformat stringFromDate:today]; + + return dateString; +} + +-(NSString *)greeting { + + NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitHour fromDate:[NSDate date]]; + NSInteger currentHour = [components hour]; + + NSString *greetingMessage; + + if (currentHour >= 0 && currentHour < 12) { + greetingMessage = @"Good Morning"; + } else if (currentHour >= 12 && currentHour < 17) { + greetingMessage = @"Good Afternoon"; + } else if (currentHour >= 17 && currentHour < 21) { + greetingMessage = @"Good Evening"; + } else { + greetingMessage = @"Good Night"; + } + + return greetingMessage; +} + +-(NSString *)battery { + + UIDevice *myDevice = [UIDevice currentDevice]; + [myDevice setBatteryMonitoringEnabled:YES]; + + double remainingBattery = [myDevice batteryLevel] * 100; + + NSString * batteryLevel = [NSString stringWithFormat:@"%.f%%", remainingBattery]; + + return batteryLevel; +} + +-(void)launchURL:(NSString *)string { + + UIApplication *application = [UIApplication sharedApplication]; + NSURL *URL = [NSURL URLWithString:string]; + [application openURL:URL options:@{} completionHandler:nil]; +} + +-(void)launchApp:(NSString *)string { + [[UIApplication sharedApplication] launchApplicationWithIdentifier:string suspended:0]; +} + +-(void)haptic:(NSInteger)style { + + if (style == 0) { + haptic = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight]; + } else if (style == 1) { + haptic = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium]; + } else if (style == 2) { + haptic = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleHeavy]; + } + + [haptic impactOccurred]; +} + +@end diff --git a/libTitanD3vUniversal/Weather/TDWeather.h b/libTitanD3vUniversal/Weather/TDWeather.h new file mode 100644 index 0000000..3d5a5f8 --- /dev/null +++ b/libTitanD3vUniversal/Weather/TDWeather.h @@ -0,0 +1,16 @@ +@class UIImage; + +@interface TDWeather : NSObject ++ (instancetype)sharedInstance; +@property (nonatomic, copy, readonly) NSString *currentTemperature; +@property (nonatomic, copy, readonly) NSString *currentConditions; +@property (nonatomic, copy, readonly) NSString *currentLocation; +@property (nonatomic, strong, readonly) UIImage *currentConditionsImage; +@property(nonatomic, strong, readonly) NSDate *sunrise; +@property(nonatomic, strong, readonly) NSDate *sunset; +@property (nonatomic, strong, readonly) NSDictionary *weatherData; +- (void)refreshWeatherData; + +-(NSString *)highestTemperatureIn:(int)type; +-(NSString *)lowestTemperatureIn:(int)type; +@end \ No newline at end of file diff --git a/libTitanD3vUniversal/Weather/TDWeather.m b/libTitanD3vUniversal/Weather/TDWeather.m new file mode 100644 index 0000000..6ec4b9e --- /dev/null +++ b/libTitanD3vUniversal/Weather/TDWeather.m @@ -0,0 +1,181 @@ +#import "TDWeather.h" +#import + +@interface WFTemperature : NSObject +@property (assign,nonatomic) double celsius; +@property (assign,nonatomic) double fahrenheit; +@property (assign,nonatomic) double kelvin; +@end + +@interface WADayForecast : NSObject +@property (nonatomic,copy) WFTemperature * high; +@property (nonatomic,copy) WFTemperature * low; +@end + +@interface WACurrentForecast : NSObject +-(WFTemperature *)feelsLike; +@end + +@interface WAForecastModel : NSObject +-(NSDate *)sunrise; +-(NSDate *)sunset; +-(NSArray *)dailyForecasts; +@end + +@interface WALockscreenWidgetViewController : UIViewController +-(WAForecastModel *)currentForecastModel; +-(id)_temperature; +-(id)_conditionsLine; +-(id)_locationName; +-(id)_conditionsImage; +-(void)_updateTodayView; +-(void)updateWeather; +@end + +@interface TDWeather() +@property (nonatomic, retain, readonly) WALockscreenWidgetViewController *weatherWidget; +@end + +@implementation TDWeather +@dynamic currentTemperature; +@dynamic currentConditions; +@dynamic currentLocation; +@dynamic currentConditionsImage; +@dynamic sunrise; +@dynamic sunset; +@dynamic weatherData; +@synthesize weatherWidget = _weatherWidget; + ++ (instancetype)sharedInstance { + static dispatch_once_t p = 0; + static __strong TDWeather *_sharedSelf = nil; + dispatch_once(&p, ^{ + _sharedSelf = [[TDWeather alloc] init]; + }); + return _sharedSelf; +} + +- (WALockscreenWidgetViewController *)weatherWidget { + if (_weatherWidget) { + return _weatherWidget; + } + _weatherWidget = [[objc_getClass("WALockscreenWidgetViewController") alloc] init]; + return _weatherWidget; +} + +-(void)refreshWeatherData { + if ([self.weatherWidget respondsToSelector:@selector(updateWeather)]) { + [self.weatherWidget updateWeather]; + } + if ([self.weatherWidget respondsToSelector:@selector(_updateTodayView)]) { + [self.weatherWidget _updateTodayView]; + } +} + +-(NSDictionary *)weatherData { + NSMutableDictionary *data = [NSMutableDictionary dictionary]; + if (self.currentTemperature) [data setObject:self.currentTemperature forKey:@"temperature"]; else [data setObject:@"N/A" forKey:@"temperature"]; + if (self.currentConditions) [data setObject:self.currentConditions forKey:@"conditions"]; else [data setObject:@"N/A" forKey:@"conditions"]; + if (self.currentLocation) [data setObject:self.currentLocation forKey:@"location"]; else [data setObject:@"N/A" forKey:@"location"]; + if (self.sunrise) [data setObject:self.sunrise forKey:@"sunrise"]; + if (self.sunset) [data setObject:self.sunset forKey:@"sunset"]; + UIImage *currentConditionsImage = self.currentConditionsImage; + if (currentConditionsImage) { + [data setObject:currentConditionsImage forKey:@"conditionsImage"]; + } + return data; +} + +-(NSString *)currentTemperature { + if ([self.weatherWidget respondsToSelector:@selector(_temperature)]) { + return [self.weatherWidget _temperature]; + } + return @"N/A"; +} + +-(NSString *)currentConditions { + if ([self.weatherWidget respondsToSelector:@selector(_conditionsLine)]) { + return [self.weatherWidget _conditionsLine]; + } + return @"N/A"; +} + +-(NSString *)currentLocation { + if ([self.weatherWidget respondsToSelector:@selector(_locationName)]) { + return [self.weatherWidget _locationName]; + } + return @"N/A"; +} + +-(UIImage *)currentConditionsImage { + if ([self.weatherWidget respondsToSelector:@selector(_conditionsImage)]) { + return [self.weatherWidget _conditionsImage]; + } + return NULL; +} + +-(NSDate *)sunrise { + if ([self.weatherWidget respondsToSelector:@selector(currentForecastModel)]) { + if ([self.weatherWidget currentForecastModel]) { + return [[self.weatherWidget currentForecastModel] sunrise]; + } + } + return NULL; +} + +-(NSDate *)sunset { + if ([self.weatherWidget respondsToSelector:@selector(currentForecastModel)]) { + if ([self.weatherWidget currentForecastModel]) { + return [[self.weatherWidget currentForecastModel] sunset]; + } + } + return NULL; +} + +-(NSString *)highestTemperatureIn:(int)type { + /* + 0: celsius + 1: fahrenheit + 2: kelvin + */ + if ([self.weatherWidget respondsToSelector:@selector(currentForecastModel)]) { + if ([self.weatherWidget currentForecastModel]) { + WADayForecast *dailyForecast = [[self.weatherWidget currentForecastModel] dailyForecasts][0]; + if (type == 0) { + return [NSString stringWithFormat:@"%.0f°", dailyForecast.high.celsius]; + } else if (type == 1) { + return [NSString stringWithFormat:@"%.0f°", dailyForecast.high.fahrenheit]; + } else if (type == 2) { + return [NSString stringWithFormat:@"%.0f°", dailyForecast.high.kelvin]; + } else { + return @"BAD TYPE"; + } + } + } + return NULL; +} + +-(NSString *)lowestTemperatureIn:(int)type { + /* + 0: celsius + 1: fahrenheit + 2: kelvin + */ + if ([self.weatherWidget respondsToSelector:@selector(currentForecastModel)]) { + if ([self.weatherWidget currentForecastModel]) { + WADayForecast *dailyForecast = [[self.weatherWidget currentForecastModel] dailyForecasts][0]; + if (type == 0) { + return [NSString stringWithFormat:@"%.0f°", dailyForecast.low.celsius]; + } else if (type == 1) { + return [NSString stringWithFormat:@"%.0f°", dailyForecast.low.fahrenheit]; + } else if (type == 2) { + return [NSString stringWithFormat:@"%.0f°", dailyForecast.low.kelvin]; + } else { + return @"BAD TYPE"; + } + } + } + return NULL; +} + +@end diff --git a/libTitanD3vUniversal/control b/libTitanD3vUniversal/control new file mode 100644 index 0000000..f7b3c0e --- /dev/null +++ b/libTitanD3vUniversal/control @@ -0,0 +1,11 @@ +Package: com.titand3v.libtitand3vuniversal +Name: libTitanD3vUniversal +Version: 1.9 +Architecture: iphoneos-arm +Description: TitanD3v universal library! +Maintainer: TitanD3v +Author: TitanD3v +Section: System +Tag: role::developer +Depiction: https://titand3v.github.io/depictions/titand3vlib/index.html +Icon: https://titand3v.github.io/depictions/titand3vlib/assets/icon.png diff --git a/libTitanD3vUniversal/layout/.DS_Store b/libTitanD3vUniversal/layout/.DS_Store new file mode 100644 index 0000000..25e1180 Binary files /dev/null and b/libTitanD3vUniversal/layout/.DS_Store differ diff --git a/libTitanD3vUniversal/layout/DEBIAN/postinst b/libTitanD3vUniversal/layout/DEBIAN/postinst new file mode 100755 index 0000000..8fb70f8 --- /dev/null +++ b/libTitanD3vUniversal/layout/DEBIAN/postinst @@ -0,0 +1 @@ +chown mobile:wheel /Library/TitanD3v-Backup \ No newline at end of file diff --git a/libTitanD3vUniversal/layout/Library/Application Support/TitanKit.bundle/Emoji/Emoji.plist b/libTitanD3vUniversal/layout/Library/Application Support/TitanKit.bundle/Emoji/Emoji.plist new file mode 100644 index 0000000..f2fefa4 --- /dev/null +++ b/libTitanD3vUniversal/layout/Library/Application Support/TitanKit.bundle/Emoji/Emoji.plist @@ -0,0 +1,3136 @@ + + + + + + + Title + Smileys & People + Emojis + + 😀 + 😃 + 😄 + 😁 + 😆 + 😅 + 😂 + 🤣 + ☺️ + 😊 + 😇 + 🙂 + 🙃 + 😉 + 😌 + 😍 + 🥰 + 😘 + 😗 + 😙 + 😚 + 😋 + 😛 + 😝 + 😜 + 🤪 + 🤨 + 🧐 + 🤓 + 😎 + 🤩 + 🥳 + 😏 + 😒 + 😞 + 😔 + 😟 + 😕 + 🙁 + ☹️ + 😣 + 😖 + 😫 + 😩 + 🥺 + 😢 + 😭 + 😤 + 😠 + 😡 + 🤬 + 🤯 + 😳 + 🥵 + 🥶 + 😱 + 😨 + 😰 + 😥 + 😓 + 🤗 + 🤔 + 🤭 + 🤫 + 🤥 + 😶 + 😐 + 😑 + 😬 + 🙄 + 😯 + 😦 + 😧 + 😮 + 😲 + 🥱 + 😴 + 🤤 + 😪 + 😵 + 🤐 + 🥴 + 🤢 + 🤮 + 🤧 + 😷 + 🤒 + 🤕 + 🤑 + 🤠 + 😈 + 👿 + 👹 + 👺 + 🤡 + 💩 + 👻 + 💀 + ☠️ + 👽 + 👾 + 🤖 + 🎃 + 😺 + 😸 + 😹 + 😻 + 😼 + 😽 + 🙀 + 😿 + 😾 + 🤲 + 🤲🏻 + 🤲🏼 + 🤲🏽 + 🤲🏾 + 🤲🏿 + 👐 + 👐🏻 + 👐🏼 + 👐🏽 + 👐🏾 + 👐🏿 + 🙌 + 🙌🏻 + 🙌🏼 + 🙌🏽 + 🙌🏾 + 🙌🏿 + 👏 + 👏🏻 + 👏🏼 + 👏🏽 + 👏🏾 + 👏🏿 + 🤝 + 👍 + 👍🏻 + 👍🏼 + 👍🏽 + 👍🏾 + 👍🏿 + 👎 + 👎🏻 + 👎🏼 + 👎🏽 + 👎🏾 + 👎🏿 + 👊 + 👊🏻 + 👊🏼 + 👊🏽 + 👊🏾 + 👊🏿 + + ✊🏻 + ✊🏼 + ✊🏽 + ✊🏾 + ✊🏿 + 🤛 + 🤛🏻 + 🤛🏼 + 🤛🏽 + 🤛🏾 + 🤛🏿 + 🤜 + 🤜🏻 + 🤜🏼 + 🤜🏽 + 🤜🏾 + 🤜🏿 + 🤞 + 🤞🏻 + 🤞🏼 + 🤞🏽 + 🤞🏾 + 🤞🏿 + ✌️ + ✌🏻 + ✌🏼 + ✌🏽 + ✌🏾 + ✌🏿 + 🤟 + 🤟🏻 + 🤟🏼 + 🤟🏽 + 🤟🏾 + 🤟🏿 + 🤘 + 🤘🏻 + 🤘🏼 + 🤘🏽 + 🤘🏾 + 🤘🏿 + 👌 + 👌🏻 + 👌🏼 + 👌🏽 + 👌🏾 + 👌🏿 + 🤏 + 🤏🏻 + 🤏🏼 + 🤏🏽 + 🤏🏾 + 🤏🏿 + 👈 + 👈🏻 + 👈🏼 + 👈🏽 + 👈🏾 + 👈🏿 + 👉 + 👉🏻 + 👉🏼 + 👉🏽 + 👉🏾 + 👉🏿 + 👆 + 👆🏻 + 👆🏼 + 👆🏽 + 👆🏾 + 👆🏿 + 👇 + 👇🏻 + 👇🏼 + 👇🏽 + 👇🏾 + 👇🏿 + ☝️ + ☝🏻 + ☝🏼 + ☝🏽 + ☝🏾 + ☝🏿 + + ✋🏻 + ✋🏼 + ✋🏽 + ✋🏾 + ✋🏿 + 🤚 + 🤚🏻 + 🤚🏼 + 🤚🏽 + 🤚🏾 + 🤚🏿 + 🖐 + 🖐🏻 + 🖐🏼 + 🖐🏽 + 🖐🏾 + 🖐🏿 + 🖖 + 🖖🏻 + 🖖🏼 + 🖖🏽 + 🖖🏾 + 🖖🏿 + 👋 + 👋🏻 + 👋🏼 + 👋🏽 + 👋🏾 + 👋🏿 + 🤙 + 🤙🏻 + 🤙🏼 + 🤙🏽 + 🤙🏾 + 🤙🏿 + 💪 + 💪🏻 + 💪🏼 + 💪🏽 + 💪🏾 + 💪🏿 + 🦾 + 🖕 + 🖕🏻 + 🖕🏼 + 🖕🏽 + 🖕🏾 + 🖕🏿 + ✍️ + ✍🏻 + ✍🏼 + ✍🏽 + ✍🏾 + ✍🏿 + 🙏 + 🙏🏻 + 🙏🏼 + 🙏🏽 + 🙏🏾 + 🙏🏿 + 🦶 + 🦶🏻 + 🦶🏼 + 🦶🏽 + 🦶🏾 + 🦶🏿 + 🦵 + 🦵🏻 + 🦵🏼 + 🦵🏽 + 🦵🏾 + 🦵🏿 + 🦿 + 💄 + 💋 + 👄 + 🦷 + 👅 + 👂 + 👂🏻 + 👂🏼 + 👂🏽 + 👂🏾 + 👂🏿 + 🦻 + 🦻🏻 + 🦻🏼 + 🦻🏽 + 🦻🏾 + 🦻🏿 + 👃 + 👃🏻 + 👃🏼 + 👃🏽 + 👃🏾 + 👃🏿 + 👣 + 👁 + 👀 + 🧠 + 🗣 + 👤 + 👥 + 👶 + 👶🏻 + 👶🏼 + 👶🏽 + 👶🏾 + 👶🏿 + 👧 + 👧🏻 + 👧🏼 + 👧🏽 + 👧🏾 + 👧🏿 + 🧒 + 🧒🏻 + 🧒🏼 + 🧒🏽 + 🧒🏾 + 🧒🏿 + 👦 + 👦🏻 + 👦🏼 + 👦🏽 + 👦🏾 + 👦🏿 + 👩 + 👩🏻 + 👩🏼 + 👩🏽 + 👩🏾 + 👩🏿 + 🧑 + 🧑🏻 + 🧑🏼 + 🧑🏽 + 🧑🏾 + 🧑🏿 + 👨 + 👨🏻 + 👨🏼 + 👨🏽 + 👨🏾 + 👨🏿 + 👩‍🦱 + 👩🏻‍🦱 + 👩🏼‍🦱 + 👩🏽‍🦱 + 👩🏾‍🦱 + 👩🏿‍🦱 + 🧑‍🦱 + 🧑🏻‍🦱 + 🧑🏼‍🦱 + 🧑🏽‍🦱 + 🧑🏾‍🦱 + 🧑🏿‍🦱 + 👨‍🦱 + 👨🏻‍🦱 + 👨🏼‍🦱 + 👨🏽‍🦱 + 👨🏾‍🦱 + 👨🏿‍🦱 + 👩‍🦰 + 👩🏻‍🦰 + 👩🏼‍🦰 + 👩🏽‍🦰 + 👩🏾‍🦰 + 👩🏿‍🦰 + 🧑‍🦰 + 🧑🏻‍🦰 + 🧑🏼‍🦰 + 🧑🏽‍🦰 + 🧑🏾‍🦰 + 🧑🏿‍🦰 + 👨‍🦰 + 👨🏻‍🦰 + 👨🏼‍🦰 + 👨🏽‍🦰 + 👨🏾‍🦰 + 👨🏿‍🦰 + 👱‍♀️ + 👱🏻‍♀️ + 👱🏼‍♀️ + 👱🏽‍♀️ + 👱🏾‍♀️ + 👱🏿‍♀️ + 👱 + 👱🏻 + 👱🏼 + 👱🏽 + 👱🏾 + 👱🏿 + 👱‍♂️ + 👱🏻‍♂️ + 👱🏼‍♂️ + 👱🏽‍♂️ + 👱🏾‍♂️ + 👱🏿‍♂️ + 👩‍🦳 + 👩🏻‍🦳 + 👩🏼‍🦳 + 👩🏽‍🦳 + 👩🏾‍🦳 + 👩🏿‍🦳 + 🧑‍🦳 + 🧑🏻‍🦳 + 🧑🏼‍🦳 + 🧑🏽‍🦳 + 🧑🏾‍🦳 + 🧑🏿‍🦳 + 👨‍🦳 + 👨🏻‍🦳 + 👨🏼‍🦳 + 👨🏽‍🦳 + 👨🏾‍🦳 + 👨🏿‍🦳 + 👩‍🦲 + 👩🏻‍🦲 + 👩🏼‍🦲 + 👩🏽‍🦲 + 👩🏾‍🦲 + 👩🏿‍🦲 + 🧑‍🦲 + 🧑🏻‍🦲 + 🧑🏼‍🦲 + 🧑🏽‍🦲 + 🧑🏾‍🦲 + 🧑🏿‍🦲 + 👨‍🦲 + 👨🏻‍🦲 + 👨🏼‍🦲 + 👨🏽‍🦲 + 👨🏾‍🦲 + 👨🏿‍🦲 + 🧔 + 🧔🏻 + 🧔🏼 + 🧔🏽 + 🧔🏾 + 🧔🏿 + 👵 + 👵🏻 + 👵🏼 + 👵🏽 + 👵🏾 + 👵🏿 + 🧓 + 🧓🏻 + 🧓🏼 + 🧓🏽 + 🧓🏾 + 🧓🏿 + 👴 + 👴🏻 + 👴🏼 + 👴🏽 + 👴🏾 + 👴🏿 + 👲 + 👲🏻 + 👲🏼 + 👲🏽 + 👲🏾 + 👲🏿 + 👳‍♀️ + 👳🏻‍♀️ + 👳🏼‍♀️ + 👳🏽‍♀️ + 👳🏾‍♀️ + 👳🏿‍♀️ + 👳 + 👳🏻 + 👳🏼 + 👳🏽 + 👳🏾 + 👳🏿 + 👳‍♂️ + 👳🏻‍♂️ + 👳🏼‍♂️ + 👳🏽‍♂️ + 👳🏾‍♂️ + 👳🏿‍♂️ + 🧕 + 🧕🏻 + 🧕🏼 + 🧕🏽 + 🧕🏾 + 🧕🏿 + 👮‍♀️ + 👮🏻‍♀️ + 👮🏼‍♀️ + 👮🏽‍♀️ + 👮🏾‍♀️ + 👮🏿‍♀️ + 👮 + 👮🏻 + 👮🏼 + 👮🏽 + 👮🏾 + 👮🏿 + 👮‍♂️ + 👮🏻‍♂️ + 👮🏼‍♂️ + 👮🏽‍♂️ + 👮🏾‍♂️ + 👮🏿‍♂️ + 👷‍♀️ + 👷🏻‍♀️ + 👷🏼‍♀️ + 👷🏽‍♀️ + 👷🏾‍♀️ + 👷🏿‍♀️ + 👷 + 👷🏻 + 👷🏼 + 👷🏽 + 👷🏾 + 👷🏿 + 👷‍♂️ + 👷🏻‍♂️ + 👷🏼‍♂️ + 👷🏽‍♂️ + 👷🏾‍♂️ + 👷🏿‍♂️ + 💂‍♀️ + 💂🏻‍♀️ + 💂🏼‍♀️ + 💂🏽‍♀️ + 💂🏾‍♀️ + 💂🏿‍♀️ + 💂 + 💂🏻 + 💂🏼 + 💂🏽 + 💂🏾 + 💂🏿 + 💂‍♂️ + 💂🏻‍♂️ + 💂🏼‍♂️ + 💂🏽‍♂️ + 💂🏾‍♂️ + 💂🏿‍♂️ + 🕵️‍♀️ + 🕵🏻‍♀️ + 🕵🏼‍♀️ + 🕵🏽‍♀️ + 🕵🏾‍♀️ + 🕵🏿‍♀️ + 🕵️ + 🕵🏻 + 🕵🏼 + 🕵🏽 + 🕵🏾 + 🕵🏿 + 🕵️‍♂️ + 🕵🏻‍♂️ + 🕵🏼‍♂️ + 🕵🏽‍♂️ + 🕵🏾‍♂️ + 🕵🏿‍♂️ + 👩‍⚕️ + 👩🏻‍⚕️ + 👩🏼‍⚕️ + 👩🏽‍⚕️ + 👩🏾‍⚕️ + 👩🏿‍⚕️ + 🧑‍⚕️ + 🧑🏻‍⚕️ + 🧑🏼‍⚕️ + 🧑🏽‍⚕️ + 🧑🏾‍⚕️ + 🧑🏿‍⚕️ + 👨‍⚕️ + 👨🏻‍⚕️ + 👨🏼‍⚕️ + 👨🏽‍⚕️ + 👨🏾‍⚕️ + 👨🏿‍⚕️ + 👩‍🌾 + 👩🏻‍🌾 + 👩🏼‍🌾 + 👩🏽‍🌾 + 👩🏾‍🌾 + 👩🏿‍🌾 + 🧑‍🌾 + 🧑🏻‍🌾 + 🧑🏼‍🌾 + 🧑🏽‍🌾 + 🧑🏾‍🌾 + 🧑🏿‍🌾 + 👨‍🌾 + 👨🏻‍🌾 + 👨🏼‍🌾 + 👨🏽‍🌾 + 👨🏾‍🌾 + 👨🏿‍🌾 + 👩‍🍳 + 👩🏻‍🍳 + 👩🏼‍🍳 + 👩🏽‍🍳 + 👩🏾‍🍳 + 👩🏿‍🍳 + 🧑‍🍳 + 🧑🏻‍🍳 + 🧑🏼‍🍳 + 🧑🏽‍🍳 + 🧑🏾‍🍳 + 🧑🏿‍🍳 + 👨‍🍳 + 👨🏻‍🍳 + 👨🏼‍🍳 + 👨🏽‍🍳 + 👨🏾‍🍳 + 👨🏿‍🍳 + 👩‍🎓 + 👩🏻‍🎓 + 👩🏼‍🎓 + 👩🏽‍🎓 + 👩🏾‍🎓 + 👩🏿‍🎓 + 🧑‍🎓 + 🧑🏻‍🎓 + 🧑🏼‍🎓 + 🧑🏽‍🎓 + 🧑🏾‍🎓 + 🧑🏿‍🎓 + 👨‍🎓 + 👨🏻‍🎓 + 👨🏼‍🎓 + 👨🏽‍🎓 + 👨🏾‍🎓 + 👨🏿‍🎓 + 👩‍🎤 + 👩🏻‍🎤 + 👩🏼‍🎤 + 👩🏽‍🎤 + 👩🏾‍🎤 + 👩🏿‍🎤 + 🧑‍🎤 + 🧑🏻‍🎤 + 🧑🏼‍🎤 + 🧑🏽‍🎤 + 🧑🏾‍🎤 + 🧑🏿‍🎤 + 👨‍🎤 + 👨🏻‍🎤 + 👨🏼‍🎤 + 👨🏽‍🎤 + 👨🏾‍🎤 + 👨🏿‍🎤 + 👩‍🏫 + 👩🏻‍🏫 + 👩🏼‍🏫 + 👩🏽‍🏫 + 👩🏾‍🏫 + 👩🏿‍🏫 + 🧑‍🏫 + 🧑🏻‍🏫 + 🧑🏼‍🏫 + 🧑🏽‍🏫 + 🧑🏾‍🏫 + 🧑🏿‍🏫 + 👨‍🏫 + 👨🏻‍🏫 + 👨🏼‍🏫 + 👨🏽‍🏫 + 👨🏾‍🏫 + 👨🏿‍🏫 + 👩‍🏭 + 👩🏻‍🏭 + 👩🏼‍🏭 + 👩🏽‍🏭 + 👩🏾‍🏭 + 👩🏿‍🏭 + 🧑‍🏭 + 🧑🏻‍🏭 + 🧑🏼‍🏭 + 🧑🏽‍🏭 + 🧑🏾‍🏭 + 🧑🏿‍🏭 + 👨‍🏭 + 👨🏻‍🏭 + 👨🏼‍🏭 + 👨🏽‍🏭 + 👨🏾‍🏭 + 👨🏿‍🏭 + 👩‍💻 + 👩🏻‍💻 + 👩🏼‍💻 + 👩🏽‍💻 + 👩🏾‍💻 + 👩🏿‍💻 + 🧑‍💻 + 🧑🏻‍💻 + 🧑🏼‍💻 + 🧑🏽‍💻 + 🧑🏾‍💻 + 🧑🏿‍💻 + 👨‍💻 + 👨🏻‍💻 + 👨🏼‍💻 + 👨🏽‍💻 + 👨🏾‍💻 + 👨🏿‍💻 + 👩‍💼 + 👩🏻‍💼 + 👩🏼‍💼 + 👩🏽‍💼 + 👩🏾‍💼 + 👩🏿‍💼 + 🧑‍💼 + 🧑🏻‍💼 + 🧑🏼‍💼 + 🧑🏽‍💼 + 🧑🏾‍💼 + 🧑🏿‍💼 + 👨‍💼 + 👨🏻‍💼 + 👨🏼‍💼 + 👨🏽‍💼 + 👨🏾‍💼 + 👨🏿‍💼 + 👩‍🔧 + 👩🏻‍🔧 + 👩🏼‍🔧 + 👩🏽‍🔧 + 👩🏾‍🔧 + 👩🏿‍🔧 + 🧑‍🔧 + 🧑🏻‍🔧 + 🧑🏼‍🔧 + 🧑🏽‍🔧 + 🧑🏾‍🔧 + 🧑🏿‍🔧 + 👨‍🔧 + 👨🏻‍🔧 + 👨🏼‍🔧 + 👨🏽‍🔧 + 👨🏾‍🔧 + 👨🏿‍🔧 + 👩‍🔬 + 👩🏻‍🔬 + 👩🏼‍🔬 + 👩🏽‍🔬 + 👩🏾‍🔬 + 👩🏿‍🔬 + 🧑‍🔬 + 🧑🏻‍🔬 + 🧑🏼‍🔬 + 🧑🏽‍🔬 + 🧑🏾‍🔬 + 🧑🏿‍🔬 + 👨‍🔬 + 👨🏻‍🔬 + 👨🏼‍🔬 + 👨🏽‍🔬 + 👨🏾‍🔬 + 👨🏿‍🔬 + 👩‍🎨 + 👩🏻‍🎨 + 👩🏼‍🎨 + 👩🏽‍🎨 + 👩🏾‍🎨 + 👩🏿‍🎨 + 🧑‍🎨 + 🧑🏻‍🎨 + 🧑🏼‍🎨 + 🧑🏽‍🎨 + 🧑🏾‍🎨 + 🧑🏿‍🎨 + 👨‍🎨 + 👨🏻‍🎨 + 👨🏼‍🎨 + 👨🏽‍🎨 + 👨🏾‍🎨 + 👨🏿‍🎨 + 👩‍🚒 + 👩🏻‍🚒 + 👩🏼‍🚒 + 👩🏽‍🚒 + 👩🏾‍🚒 + 👩🏿‍🚒 + 🧑‍🚒 + 🧑🏻‍🚒 + 🧑🏼‍🚒 + 🧑🏽‍🚒 + 🧑🏾‍🚒 + 🧑🏿‍🚒 + 👨‍🚒 + 👨🏻‍🚒 + 👨🏼‍🚒 + 👨🏽‍🚒 + 👨🏾‍🚒 + 👨🏿‍🚒 + 👩‍✈️ + 👩🏻‍✈️ + 👩🏼‍✈️ + 👩🏽‍✈️ + 👩🏾‍✈️ + 👩🏿‍✈️ + 🧑‍✈️ + 🧑🏻‍✈️ + 🧑🏼‍✈️ + 🧑🏽‍✈️ + 🧑🏾‍✈️ + 🧑🏿‍✈️ + 👨‍✈️ + 👨🏻‍✈️ + 👨🏼‍✈️ + 👨🏽‍✈️ + 👨🏾‍✈️ + 👨🏿‍✈️ + 👩‍🚀 + 👩🏻‍🚀 + 👩🏼‍🚀 + 👩🏽‍🚀 + 👩🏾‍🚀 + 👩🏿‍🚀 + 🧑‍🚀 + 🧑🏻‍🚀 + 🧑🏼‍🚀 + 🧑🏽‍🚀 + 🧑🏾‍🚀 + 🧑🏿‍🚀 + 👨‍🚀 + 👨🏻‍🚀 + 👨🏼‍🚀 + 👨🏽‍🚀 + 👨🏾‍🚀 + 👨🏿‍🚀 + 👩‍⚖️ + 👩🏻‍⚖️ + 👩🏼‍⚖️ + 👩🏽‍⚖️ + 👩🏾‍⚖️ + 👩🏿‍⚖️ + 🧑‍⚖️ + 🧑🏻‍⚖️ + 🧑🏼‍⚖️ + 🧑🏽‍⚖️ + 🧑🏾‍⚖️ + 🧑🏿‍⚖️ + 👨‍⚖️ + 👨🏻‍⚖️ + 👨🏼‍⚖️ + 👨🏽‍⚖️ + 👨🏾‍⚖️ + 👨🏿‍⚖️ + 👰 + 👰🏻 + 👰🏼 + 👰🏽 + 👰🏾 + 👰🏿 + 🤵 + 🤵🏻 + 🤵🏼 + 🤵🏽 + 🤵🏾 + 🤵🏿 + 👸 + 👸🏻 + 👸🏼 + 👸🏽 + 👸🏾 + 👸🏿 + 🤴 + 🤴🏻 + 🤴🏼 + 🤴🏽 + 🤴🏾 + 🤴🏿 + 🦸‍♀️ + 🦸🏻‍♀️ + 🦸🏼‍♀️ + 🦸🏽‍♀️ + 🦸🏾‍♀️ + 🦸🏿‍♀️ + 🦸 + 🦸🏻 + 🦸🏼 + 🦸🏽 + 🦸🏾 + 🦸🏿 + 🦸‍♂️ + 🦸🏻‍♂️ + 🦸🏼‍♂️ + 🦸🏽‍♂️ + 🦸🏾‍♂️ + 🦸🏿‍♂️ + 🦹‍♀️ + 🦹🏻‍♀️ + 🦹🏼‍♀️ + 🦹🏽‍♀️ + 🦹🏾‍♀️ + 🦹🏿‍♀️ + 🦹 + 🦹🏻 + 🦹🏼 + 🦹🏽 + 🦹🏾 + 🦹🏿 + 🦹‍♂️ + 🦹🏻‍♂️ + 🦹🏼‍♂️ + 🦹🏽‍♂️ + 🦹🏾‍♂️ + 🦹🏿‍♂️ + 🤶 + 🤶🏻 + 🤶🏼 + 🤶🏽 + 🤶🏾 + 🤶🏿 + 🎅 + 🎅🏻 + 🎅🏼 + 🎅🏽 + 🎅🏾 + 🎅🏿 + 🧙‍♀️ + 🧙🏻‍♀️ + 🧙🏼‍♀️ + 🧙🏽‍♀️ + 🧙🏾‍♀️ + 🧙🏿‍♀️ + 🧙 + 🧙🏻 + 🧙🏼 + 🧙🏽 + 🧙🏾 + 🧙🏿 + 🧙‍♂️ + 🧙🏻‍♂️ + 🧙🏼‍♂️ + 🧙🏽‍♂️ + 🧙🏾‍♂️ + 🧙🏿‍♂️ + 🧝‍♀️ + 🧝🏻‍♀️ + 🧝🏼‍♀️ + 🧝🏽‍♀️ + 🧝🏾‍♀️ + 🧝🏿‍♀️ + 🧝 + 🧝🏻 + 🧝🏼 + 🧝🏽 + 🧝🏾 + 🧝🏿 + 🧝‍♂️ + 🧝🏻‍♂️ + 🧝🏼‍♂️ + 🧝🏽‍♂️ + 🧝🏾‍♂️ + 🧝🏿‍♂️ + 🧛‍♀️ + 🧛🏻‍♀️ + 🧛🏼‍♀️ + 🧛🏽‍♀️ + 🧛🏾‍♀️ + 🧛🏿‍♀️ + 🧛 + 🧛🏻 + 🧛🏼 + 🧛🏽 + 🧛🏾 + 🧛🏿 + 🧛‍♂️ + 🧛🏻‍♂️ + 🧛🏼‍♂️ + 🧛🏽‍♂️ + 🧛🏾‍♂️ + 🧛🏿‍♂️ + 🧟‍♀️ + 🧟 + 🧟‍♂️ + 🧞‍♀️ + 🧞 + 🧞‍♂️ + 🧜‍♀️ + 🧜🏻‍♀️ + 🧜🏼‍♀️ + 🧜🏽‍♀️ + 🧜🏾‍♀️ + 🧜🏿‍♀️ + 🧜 + 🧜🏻 + 🧜🏼 + 🧜🏽 + 🧜🏾 + 🧜🏿 + 🧜‍♂️ + 🧜🏻‍♂️ + 🧜🏼‍♂️ + 🧜🏽‍♂️ + 🧜🏾‍♂️ + 🧜🏿‍♂️ + 🧚‍♀️ + 🧚🏻‍♀️ + 🧚🏼‍♀️ + 🧚🏽‍♀️ + 🧚🏾‍♀️ + 🧚🏿‍♀️ + 🧚 + 🧚🏻 + 🧚🏼 + 🧚🏽 + 🧚🏾 + 🧚🏿 + 🧚‍♂️ + 🧚🏻‍♂️ + 🧚🏼‍♂️ + 🧚🏽‍♂️ + 🧚🏾‍♂️ + 🧚🏿‍♂️ + 👼 + 👼🏻 + 👼🏼 + 👼🏽 + 👼🏾 + 👼🏿 + 🤰 + 🤰🏻 + 🤰🏼 + 🤰🏽 + 🤰🏾 + 🤰🏿 + 🤱 + 🤱🏻 + 🤱🏼 + 🤱🏽 + 🤱🏾 + 🤱🏿 + 🙇‍♀️ + 🙇🏻‍♀️ + 🙇🏼‍♀️ + 🙇🏽‍♀️ + 🙇🏾‍♀️ + 🙇🏿‍♀️ + 🙇 + 🙇🏻 + 🙇🏼 + 🙇🏽 + 🙇🏾 + 🙇🏿 + 🙇‍♂️ + 🙇🏻‍♂️ + 🙇🏼‍♂️ + 🙇🏽‍♂️ + 🙇🏾‍♂️ + 🙇🏿‍♂️ + 💁‍♀️ + 💁🏻‍♀️ + 💁🏼‍♀️ + 💁🏽‍♀️ + 💁🏾‍♀️ + 💁🏿‍♀️ + 💁 + 💁🏻 + 💁🏼 + 💁🏽 + 💁🏾 + 💁🏿 + 💁‍♂️ + 💁🏻‍♂️ + 💁🏼‍♂️ + 💁🏽‍♂️ + 💁🏾‍♂️ + 💁🏿‍♂️ + 🙅‍♀️ + 🙅🏻‍♀️ + 🙅🏼‍♀️ + 🙅🏽‍♀️ + 🙅🏾‍♀️ + 🙅🏿‍♀️ + 🙅 + 🙅🏻 + 🙅🏼 + 🙅🏽 + 🙅🏾 + 🙅🏿 + 🙅‍♂️ + 🙅🏻‍♂️ + 🙅🏼‍♂️ + 🙅🏽‍♂️ + 🙅🏾‍♂️ + 🙅🏿‍♂️ + 🙆‍♀️ + 🙆🏻‍♀️ + 🙆🏼‍♀️ + 🙆🏽‍♀️ + 🙆🏾‍♀️ + 🙆🏿‍♀️ + 🙆 + 🙆🏻 + 🙆🏼 + 🙆🏽 + 🙆🏾 + 🙆🏿 + 🙆‍♂️ + 🙆🏻‍♂️ + 🙆🏼‍♂️ + 🙆🏽‍♂️ + 🙆🏾‍♂️ + 🙆🏿‍♂️ + 🙋‍♀️ + 🙋🏻‍♀️ + 🙋🏼‍♀️ + 🙋🏽‍♀️ + 🙋🏾‍♀️ + 🙋🏿‍♀️ + 🙋 + 🙋🏻 + 🙋🏼 + 🙋🏽 + 🙋🏾 + 🙋🏿 + 🙋‍♂️ + 🙋🏻‍♂️ + 🙋🏼‍♂️ + 🙋🏽‍♂️ + 🙋🏾‍♂️ + 🙋🏿‍♂️ + 🧏‍♀️ + 🧏🏻‍♀️ + 🧏🏼‍♀️ + 🧏🏽‍♀️ + 🧏🏾‍♀️ + 🧏🏿‍♀️ + 🧏 + 🧏🏻 + 🧏🏼 + 🧏🏽 + 🧏🏾 + 🧏🏿 + 🧏‍♂️ + 🧏🏻‍♂️ + 🧏🏼‍♂️ + 🧏🏽‍♂️ + 🧏🏾‍♂️ + 🧏🏿‍♂️ + 🤦‍♀️ + 🤦🏻‍♀️ + 🤦🏼‍♀️ + 🤦🏽‍♀️ + 🤦🏾‍♀️ + 🤦🏿‍♀️ + 🤦 + 🤦🏻 + 🤦🏼 + 🤦🏽 + 🤦🏾 + 🤦🏿 + 🤦‍♂️ + 🤦🏻‍♂️ + 🤦🏼‍♂️ + 🤦🏽‍♂️ + 🤦🏾‍♂️ + 🤦🏿‍♂️ + 🤷‍♀️ + 🤷🏻‍♀️ + 🤷🏼‍♀️ + 🤷🏽‍♀️ + 🤷🏾‍♀️ + 🤷🏿‍♀️ + 🤷 + 🤷🏻 + 🤷🏼 + 🤷🏽 + 🤷🏾 + 🤷🏿 + 🤷‍♂️ + 🤷🏻‍♂️ + 🤷🏼‍♂️ + 🤷🏽‍♂️ + 🤷🏾‍♂️ + 🤷🏿‍♂️ + 🙎‍♀️ + 🙎🏻‍♀️ + 🙎🏼‍♀️ + 🙎🏽‍♀️ + 🙎🏾‍♀️ + 🙎🏿‍♀️ + 🙎 + 🙎🏻 + 🙎🏼 + 🙎🏽 + 🙎🏾 + 🙎🏿 + 🙎‍♂️ + 🙎🏻‍♂️ + 🙎🏼‍♂️ + 🙎🏽‍♂️ + 🙎🏾‍♂️ + 🙎🏿‍♂️ + 🙍‍♀️ + 🙍🏻‍♀️ + 🙍🏼‍♀️ + 🙍🏽‍♀️ + 🙍🏾‍♀️ + 🙍🏿‍♀️ + 🙍 + 🙍🏻 + 🙍🏼 + 🙍🏽 + 🙍🏾 + 🙍🏿 + 🙍‍♂️ + 🙍🏻‍♂️ + 🙍🏼‍♂️ + 🙍🏽‍♂️ + 🙍🏾‍♂️ + 🙍🏿‍♂️ + 💇‍♀️ + 💇🏻‍♀️ + 💇🏼‍♀️ + 💇🏽‍♀️ + 💇🏾‍♀️ + 💇🏿‍♀️ + 💇 + 💇🏻 + 💇🏼 + 💇🏽 + 💇🏾 + 💇🏿 + 💇‍♂️ + 💇🏻‍♂️ + 💇🏼‍♂️ + 💇🏽‍♂️ + 💇🏾‍♂️ + 💇🏿‍♂️ + 💆‍♀️ + 💆🏻‍♀️ + 💆🏼‍♀️ + 💆🏽‍♀️ + 💆🏾‍♀️ + 💆🏿‍♀️ + 💆 + 💆🏻 + 💆🏼 + 💆🏽 + 💆🏾 + 💆🏿 + 💆‍♂️ + 💆🏻‍♂️ + 💆🏼‍♂️ + 💆🏽‍♂️ + 💆🏾‍♂️ + 💆🏿‍♂️ + 🧖‍♀️ + 🧖🏻‍♀️ + 🧖🏼‍♀️ + 🧖🏽‍♀️ + 🧖🏾‍♀️ + 🧖🏿‍♀️ + 🧖 + 🧖🏻 + 🧖🏼 + 🧖🏽 + 🧖🏾 + 🧖🏿 + 🧖‍♂️ + 🧖🏻‍♂️ + 🧖🏼‍♂️ + 🧖🏽‍♂️ + 🧖🏾‍♂️ + 🧖🏿‍♂️ + 💅 + 💅🏻 + 💅🏼 + 💅🏽 + 💅🏾 + 💅🏿 + 🤳 + 🤳🏻 + 🤳🏼 + 🤳🏽 + 🤳🏾 + 🤳🏿 + 💃 + 💃🏻 + 💃🏼 + 💃🏽 + 💃🏾 + 💃🏿 + 🕺 + 🕺🏻 + 🕺🏼 + 🕺🏽 + 🕺🏾 + 🕺🏿 + 👯‍♀️ + 👯 + 👯‍♂️ + 🕴 + 🕴🏻 + 🕴🏼 + 🕴🏽 + 🕴🏾 + 🕴🏿 + 👩‍🦽 + 👩🏻‍🦽 + 👩🏼‍🦽 + 👩🏽‍🦽 + 👩🏾‍🦽 + 👩🏿‍🦽 + 🧑‍🦽 + 🧑🏻‍🦽 + 🧑🏼‍🦽 + 🧑🏽‍🦽 + 🧑🏾‍🦽 + 🧑🏿‍🦽 + 👨‍🦽 + 👨🏻‍🦽 + 👨🏼‍🦽 + 👨🏽‍🦽 + 👨🏾‍🦽 + 👨🏿‍🦽 + 👩‍🦼 + 👩🏻‍🦼 + 👩🏼‍🦼 + 👩🏽‍🦼 + 👩🏾‍🦼 + 👩🏿‍🦼 + 🧑‍🦼 + 🧑🏻‍🦼 + 🧑🏼‍🦼 + 🧑🏽‍🦼 + 🧑🏾‍🦼 + 🧑🏿‍🦼 + 👨‍🦼 + 👨🏻‍🦼 + 👨🏼‍🦼 + 👨🏽‍🦼 + 👨🏾‍🦼 + 👨🏿‍🦼 + 🚶‍♀️ + 🚶🏻‍♀️ + 🚶🏼‍♀️ + 🚶🏽‍♀️ + 🚶🏾‍♀️ + 🚶🏿‍♀️ + 🚶 + 🚶🏻 + 🚶🏼 + 🚶🏽 + 🚶🏾 + 🚶🏿 + 🚶‍♂️ + 🚶🏻‍♂️ + 🚶🏼‍♂️ + 🚶🏽‍♂️ + 🚶🏾‍♂️ + 🚶🏿‍♂️ + 👩‍🦯 + 👩🏻‍🦯 + 👩🏼‍🦯 + 👩🏽‍🦯 + 👩🏾‍🦯 + 👩🏿‍🦯 + 🧑‍🦯 + 🧑🏻‍🦯 + 🧑🏼‍🦯 + 🧑🏽‍🦯 + 🧑🏾‍🦯 + 🧑🏿‍🦯 + 👨‍🦯 + 👨🏻‍🦯 + 👨🏼‍🦯 + 👨🏽‍🦯 + 👨🏾‍🦯 + 👨🏿‍🦯 + 🧎‍♀️ + 🧎🏻‍♀️ + 🧎🏼‍♀️ + 🧎🏽‍♀️ + 🧎🏾‍♀️ + 🧎🏿‍♀️ + 🧎 + 🧎🏻 + 🧎🏼 + 🧎🏽 + 🧎🏾 + 🧎🏿 + 🧎‍♂️ + 🧎🏻‍♂️ + 🧎🏼‍♂️ + 🧎🏽‍♂️ + 🧎🏾‍♂️ + 🧎🏿‍♂️ + 🏃‍♀️ + 🏃🏻‍♀️ + 🏃🏼‍♀️ + 🏃🏽‍♀️ + 🏃🏾‍♀️ + 🏃🏿‍♀️ + 🏃 + 🏃🏻 + 🏃🏼 + 🏃🏽 + 🏃🏾 + 🏃🏿 + 🏃‍♂️ + 🏃🏻‍♂️ + 🏃🏼‍♂️ + 🏃🏽‍♂️ + 🏃🏾‍♂️ + 🏃🏿‍♂️ + 🧍‍♀️ + 🧍🏻‍♀️ + 🧍🏼‍♀️ + 🧍🏽‍♀️ + 🧍🏾‍♀️ + 🧍🏿‍♀️ + 🧍 + 🧍🏻 + 🧍🏼 + 🧍🏽 + 🧍🏾 + 🧍🏿 + 🧍‍♂️ + 🧍🏻‍♂️ + 🧍🏼‍♂️ + 🧍🏽‍♂️ + 🧍🏾‍♂️ + 🧍🏿‍♂️ + 👫 + 👩🏻‍🤝‍👨🏼 + 👩🏻‍🤝‍👨🏽 + 👩🏻‍🤝‍👨🏾 + 👩🏻‍🤝‍👨🏿 + 👩🏼‍🤝‍👨🏻 + 👭 + 👩🏻‍🤝‍👩🏼 + 👩🏻‍🤝‍👩🏽 + 👩🏻‍🤝‍👩🏾 + 👩🏻‍🤝‍👩🏿 + 👩🏼‍🤝‍👩🏻 + 👬 + 👨🏻‍🤝‍👨🏼 + 👨🏻‍🤝‍👨🏽 + 👨🏻‍🤝‍👨🏾 + 👨🏻‍🤝‍👨🏿 + 👨🏼‍🤝‍👨🏻 + 👩‍❤️‍👨 + 👩‍❤️‍👩 + 👨‍❤️‍👨 + 👩‍❤️‍💋‍👨 + 👩‍❤️‍💋‍👩 + 👨‍❤️‍💋‍👨 + 👨‍👩‍👦 + 👨‍👩‍👧 + 👨‍👩‍👧‍👦 + 👨‍👩‍👦‍👦 + 👨‍👩‍👧‍👧 + 👩‍👩‍👦 + 👩‍👩‍👧 + 👩‍👩‍👧‍👦 + 👩‍👩‍👦‍👦 + 👩‍👩‍👧‍👧 + 👨‍👨‍👦 + 👨‍👨‍👧 + 👨‍👨‍👧‍👦 + 👨‍👨‍👦‍👦 + 👨‍👨‍👧‍👧 + 👩‍👦 + 👩‍👧 + 👩‍👧‍👦 + 👩‍👦‍👦 + 👩‍👧‍👧 + 👨‍👦 + 👨‍👧 + 👨‍👧‍👦 + 👨‍👦‍👦 + 👨‍👧‍👧 + 🧶 + 🧵 + 🧥 + 🥼 + 🦺 + 👚 + 👕 + 👖 + 🩲 + 🩳 + 👔 + 👗 + 👙 + 👘 + 🥻 + 🩱 + 🥿 + 👠 + 👡 + 👢 + 👞 + 👟 + 🥾 + 🧦 + 🧤 + 🧣 + 🎩 + 🧢 + 👒 + 🎓 + + 👑 + 💍 + 👝 + 👛 + 👜 + 💼 + 🎒 + 🧳 + 👓 + 🕶 + 🥽 + 🌂 + + + + + Title + Animals & Nature + Emojis + + 🐶 + 🐱 + 🐭 + 🐹 + 🐰 + 🦊 + 🐻 + 🐼 + 🐨 + 🐯 + 🦁 + 🐮 + 🐷 + 🐽 + 🐸 + 🐵 + 🙈 + 🙉 + 🙊 + 🐒 + 🐔 + 🐧 + 🐦 + 🐤 + 🐣 + 🐥 + 🦆 + 🦅 + 🦉 + 🦇 + 🐺 + 🐗 + 🐴 + 🦄 + 🐝 + 🐛 + 🦋 + 🐌 + 🐞 + 🐜 + 🦟 + 🦗 + 🕷 + 🕸 + 🦂 + 🐢 + 🐍 + 🦎 + 🦖 + 🦕 + 🐙 + 🦑 + 🦐 + 🦞 + 🦀 + 🐡 + 🐠 + 🐟 + 🐬 + 🐳 + 🐋 + 🦈 + 🐊 + 🐅 + 🐆 + 🦓 + 🦍 + 🦧 + 🐘 + 🦛 + 🦏 + 🐪 + 🐫 + 🦒 + 🦘 + 🐃 + 🐂 + 🐄 + 🐎 + 🐖 + 🐏 + 🐑 + 🦙 + 🐐 + 🦌 + 🐕 + 🐩 + 🦮 + 🐕‍🦺 + 🐈 + 🐓 + 🦃 + 🦚 + 🦜 + 🦢 + 🦩 + 🕊 + 🐇 + 🦝 + 🦨 + 🦡 + 🦦 + 🦥 + 🐁 + 🐀 + 🐿 + 🦔 + 🐾 + 🐉 + 🐲 + 🌵 + 🎄 + 🌲 + 🌳 + 🌴 + 🌱 + 🌿 + ☘️ + 🍀 + 🎍 + 🎋 + 🍃 + 🍂 + 🍁 + 🍄 + 🐚 + 🌾 + 💐 + 🌷 + 🌹 + 🥀 + 🌺 + 🌸 + 🌼 + 🌻 + 🌞 + 🌝 + 🌛 + 🌜 + 🌚 + 🌕 + 🌖 + 🌗 + 🌘 + 🌑 + 🌒 + 🌓 + 🌔 + 🌙 + 🌎 + 🌍 + 🌏 + 🪐 + 💫 + ⭐️ + 🌟 + + ⚡️ + ☄️ + 💥 + 🔥 + 🌪 + 🌈 + ☀️ + 🌤 + ⛅️ + 🌥 + ☁️ + 🌦 + 🌧 + + 🌩 + 🌨 + ❄️ + ☃️ + ⛄️ + 🌬 + 💨 + 💧 + 💦 + ☔️ + ☂️ + 🌊 + 🌫 + + + + + Title + Food & Drink + Emojis + + 🍏 + 🍎 + 🍐 + 🍊 + 🍋 + 🍌 + 🍉 + 🍇 + 🍓 + 🍈 + 🍒 + 🍑 + 🥭 + 🍍 + 🥥 + 🥝 + 🍅 + 🍆 + 🥑 + 🥦 + 🥬 + 🥒 + 🌶 + 🌽 + 🥕 + 🧄 + 🧅 + 🥔 + 🍠 + 🥐 + 🥯 + 🍞 + 🥖 + 🥨 + 🧀 + 🥚 + 🍳 + 🧈 + 🥞 + 🧇 + 🥓 + 🥩 + 🍗 + 🍖 + 🦴 + 🌭 + 🍔 + 🍟 + 🍕 + 🥪 + 🥙 + 🧆 + 🌮 + 🌯 + 🥗 + 🥘 + 🥫 + 🍝 + 🍜 + 🍲 + 🍛 + 🍣 + 🍱 + 🥟 + 🦪 + 🍤 + 🍙 + 🍚 + 🍘 + 🍥 + 🥠 + 🥮 + 🍢 + 🍡 + 🍧 + 🍨 + 🍦 + 🥧 + 🧁 + 🍰 + 🎂 + 🍮 + 🍭 + 🍬 + 🍫 + 🍿 + 🍩 + 🍪 + 🌰 + 🥜 + 🍯 + 🥛 + 🍼 + ☕️ + 🍵 + 🧃 + 🥤 + 🍶 + 🍺 + 🍻 + 🥂 + 🍷 + 🥃 + 🍸 + 🍹 + 🧉 + 🍾 + 🧊 + 🥄 + 🍴 + 🍽 + 🥣 + 🥡 + 🥢 + 🧂 + + + + + Title + Activity + Emojis + + ⚽️ + 🏀 + 🏈 + ⚾️ + 🥎 + 🎾 + 🏐 + 🏉 + 🥏 + 🎱 + 🪀 + 🏓 + 🏸 + 🏒 + 🏑 + 🥍 + 🏏 + 🥅 + ⛳️ + 🪁 + 🏹 + 🎣 + 🤿 + 🥊 + 🥋 + 🎽 + 🛹 + 🛷 + + 🥌 + 🎿 + + 🏂 + 🪂 + 🏋️‍♀️ + 🏋🏻‍♀️ + 🏋🏼‍♀️ + 🏋🏽‍♀️ + 🏋🏾‍♀️ + 🏋🏿‍♀️ + 🏋️ + 🏋🏻 + 🏋🏼 + 🏋🏽 + 🏋🏾 + 🏋🏿 + 🏋️‍♂️ + 🏋🏻‍♂️ + 🏋🏼‍♂️ + 🏋🏽‍♂️ + 🏋🏾‍♂️ + 🏋🏿‍♂️ + 🤼‍♀️ + 🤼 + 🤼‍♂️ + 🤸‍♀️ + 🤸🏻‍♀️ + 🤸🏼‍♀️ + 🤸🏽‍♀️ + 🤸🏾‍♀️ + 🤸🏿‍♀️ + 🤸 + 🤸🏻 + 🤸🏼 + 🤸🏽 + 🤸🏾 + 🤸🏿 + 🤸‍♂️ + 🤸🏻‍♂️ + 🤸🏼‍♂️ + 🤸🏽‍♂️ + 🤸🏾‍♂️ + 🤸🏿‍♂️ + ⛹️‍♀️ + ⛹🏻‍♀️ + ⛹🏼‍♀️ + ⛹🏽‍♀️ + ⛹🏾‍♀️ + ⛹🏿‍♀️ + ⛹️ + ⛹🏻 + ⛹🏼 + ⛹🏽 + ⛹🏾 + ⛹🏿 + ⛹️‍♂️ + ⛹🏻‍♂️ + ⛹🏼‍♂️ + ⛹🏽‍♂️ + ⛹🏾‍♂️ + ⛹🏿‍♂️ + 🤺 + 🤾‍♀️ + 🤾🏻‍♀️ + 🤾🏼‍♀️ + 🤾🏽‍♀️ + 🤾🏾‍♀️ + 🤾🏿‍♀️ + 🤾 + 🤾🏻 + 🤾🏼 + 🤾🏽 + 🤾🏾 + 🤾🏿 + 🤾‍♂️ + 🤾🏻‍♂️ + 🤾🏼‍♂️ + 🤾🏽‍♂️ + 🤾🏾‍♂️ + 🤾🏿‍♂️ + 🏌️‍♀️ + 🏌🏻‍♀️ + 🏌🏼‍♀️ + 🏌🏽‍♀️ + 🏌🏾‍♀️ + 🏌🏿‍♀️ + 🏌️ + 🏌🏻 + 🏌🏼 + 🏌🏽 + 🏌🏾 + 🏌🏿 + 🏌️‍♂️ + 🏌🏻‍♂️ + 🏌🏼‍♂️ + 🏌🏽‍♂️ + 🏌🏾‍♂️ + 🏌🏿‍♂️ + 🏇 + 🏇🏻 + 🏇🏼 + 🏇🏽 + 🏇🏾 + 🏇🏿 + 🧘‍♀️ + 🧘🏻‍♀️ + 🧘🏼‍♀️ + 🧘🏽‍♀️ + 🧘🏾‍♀️ + 🧘🏿‍♀️ + 🧘 + 🧘🏻 + 🧘🏼 + 🧘🏽 + 🧘🏾 + 🧘🏿 + 🧘‍♂️ + 🧘🏻‍♂️ + 🧘🏼‍♂️ + 🧘🏽‍♂️ + 🧘🏾‍♂️ + 🧘🏿‍♂️ + 🏄‍♀️ + 🏄🏻‍♀️ + 🏄🏼‍♀️ + 🏄🏽‍♀️ + 🏄🏾‍♀️ + 🏄🏿‍♀️ + 🏄 + 🏄🏻 + 🏄🏼 + 🏄🏽 + 🏄🏾 + 🏄🏿 + 🏄‍♂️ + 🏄🏻‍♂️ + 🏄🏼‍♂️ + 🏄🏽‍♂️ + 🏄🏾‍♂️ + 🏄🏿‍♂️ + 🏊‍♀️ + 🏊🏻‍♀️ + 🏊🏼‍♀️ + 🏊🏽‍♀️ + 🏊🏾‍♀️ + 🏊🏿‍♀️ + 🏊 + 🏊🏻 + 🏊🏼 + 🏊🏽 + 🏊🏾 + 🏊🏿 + 🏊‍♂️ + 🏊🏻‍♂️ + 🏊🏼‍♂️ + 🏊🏽‍♂️ + 🏊🏾‍♂️ + 🏊🏿‍♂️ + 🤽‍♀️ + 🤽🏻‍♀️ + 🤽🏼‍♀️ + 🤽🏽‍♀️ + 🤽🏾‍♀️ + 🤽🏿‍♀️ + 🤽 + 🤽🏻 + 🤽🏼 + 🤽🏽 + 🤽🏾 + 🤽🏿 + 🤽‍♂️ + 🤽🏻‍♂️ + 🤽🏼‍♂️ + 🤽🏽‍♂️ + 🤽🏾‍♂️ + 🤽🏿‍♂️ + 🚣‍♀️ + 🚣🏻‍♀️ + 🚣🏼‍♀️ + 🚣🏽‍♀️ + 🚣🏾‍♀️ + 🚣🏿‍♀️ + 🚣 + 🚣🏻 + 🚣🏼 + 🚣🏽 + 🚣🏾 + 🚣🏿 + 🚣‍♂️ + 🚣🏻‍♂️ + 🚣🏼‍♂️ + 🚣🏽‍♂️ + 🚣🏾‍♂️ + 🚣🏿‍♂️ + 🧗‍♀️ + 🧗🏻‍♀️ + 🧗🏼‍♀️ + 🧗🏽‍♀️ + 🧗🏾‍♀️ + 🧗🏿‍♀️ + 🧗 + 🧗🏻 + 🧗🏼 + 🧗🏽 + 🧗🏾 + 🧗🏿 + 🧗‍♂️ + 🧗🏻‍♂️ + 🧗🏼‍♂️ + 🧗🏽‍♂️ + 🧗🏾‍♂️ + 🧗🏿‍♂️ + 🚵‍♀️ + 🚵🏻‍♀️ + 🚵🏼‍♀️ + 🚵🏽‍♀️ + 🚵🏾‍♀️ + 🚵🏿‍♀️ + 🚵 + 🚵🏻 + 🚵🏼 + 🚵🏽 + 🚵🏾 + 🚵🏿 + 🚵‍♂️ + 🚵🏻‍♂️ + 🚵🏼‍♂️ + 🚵🏽‍♂️ + 🚵🏾‍♂️ + 🚵🏿‍♂️ + 🚴‍♀️ + 🚴🏻‍♀️ + 🚴🏼‍♀️ + 🚴🏽‍♀️ + 🚴🏾‍♀️ + 🚴🏿‍♀️ + 🚴 + 🚴🏻 + 🚴🏼 + 🚴🏽 + 🚴🏾 + 🚴🏿 + 🚴‍♂️ + 🚴🏻‍♂️ + 🚴🏼‍♂️ + 🚴🏽‍♂️ + 🚴🏾‍♂️ + 🚴🏿‍♂️ + 🏆 + 🥇 + 🥈 + 🥉 + 🏅 + 🎖 + 🏵 + 🎗 + 🎫 + 🎟 + 🎪 + 🤹‍♀️ + 🤹🏻‍♀️ + 🤹🏼‍♀️ + 🤹🏽‍♀️ + 🤹🏾‍♀️ + 🤹🏿‍♀️ + 🤹 + 🤹🏻 + 🤹🏼 + 🤹🏽 + 🤹🏾 + 🤹🏿 + 🤹‍♂️ + 🤹🏻‍♂️ + 🤹🏼‍♂️ + 🤹🏽‍♂️ + 🤹🏾‍♂️ + 🤹🏿‍♂️ + 🎭 + 🩰 + 🎨 + 🎬 + 🎤 + 🎧 + 🎼 + 🎹 + 🥁 + 🎷 + 🎺 + 🎸 + 🪕 + 🎻 + 🎲 + + 🎯 + 🎳 + 🎮 + 🎰 + 🧩 + + + + + Title + Travel & Places + Emojis + + 🚗 + 🚕 + 🚙 + 🚌 + 🚎 + 🏎 + 🚓 + 🚑 + 🚒 + 🚐 + 🚚 + 🚛 + 🚜 + 🦯 + 🦽 + 🦼 + 🛴 + 🚲 + 🛵 + 🏍 + 🛺 + 🚨 + 🚔 + 🚍 + 🚘 + 🚖 + 🚡 + 🚠 + 🚟 + 🚃 + 🚋 + 🚞 + 🚝 + 🚄 + 🚅 + 🚈 + 🚂 + 🚆 + 🚇 + 🚊 + 🚉 + ✈️ + 🛫 + 🛬 + 🛩 + 💺 + 🛰 + 🚀 + 🛸 + 🚁 + 🛶 + ⛵️ + 🚤 + 🛥 + 🛳 + + 🚢 + ⚓️ + ⛽️ + 🚧 + 🚦 + 🚥 + 🚏 + 🗺 + 🗿 + 🗽 + 🗼 + 🏰 + 🏯 + 🏟 + 🎡 + 🎢 + 🎠 + ⛲️ + + 🏖 + 🏝 + 🏜 + 🌋 + + 🏔 + 🗻 + 🏕 + ⛺️ + 🏠 + 🏡 + 🏘 + 🏚 + 🏗 + 🏭 + 🏢 + 🏬 + 🏣 + 🏤 + 🏥 + 🏦 + 🏨 + 🏪 + 🏫 + 🏩 + 💒 + 🏛 + ⛪️ + 🕌 + 🕍 + 🛕 + 🕋 + + 🛤 + 🛣 + 🗾 + 🎑 + 🏞 + 🌅 + 🌄 + 🌠 + 🎇 + 🎆 + 🌇 + 🌆 + 🏙 + 🌃 + 🌌 + 🌉 + 🌁 + + + + + Title + Objects + Emojis + + ⌚️ + 📱 + 📲 + 💻 + ⌨️ + 🖥 + 🖨 + 🖱 + 🖲 + 🕹 + 🗜 + 💽 + 💾 + 💿 + 📀 + 📼 + 📷 + 📸 + 📹 + 🎥 + 📽 + 🎞 + 📞 + ☎️ + 📟 + 📠 + 📺 + 📻 + 🎙 + 🎚 + 🎛 + 🧭 + + + + 🕰 + ⌛️ + + 📡 + 🔋 + 🔌 + 💡 + 🔦 + 🕯 + 🪔 + 🧯 + 🛢 + 💸 + 💵 + 💴 + 💶 + 💷 + 💰 + 💳 + 💎 + ⚖️ + 🧰 + 🔧 + 🔨 + + 🛠 + + 🔩 + ⚙️ + 🧱 + + 🧲 + 🔫 + 💣 + 🧨 + 🪓 + 🔪 + 🗡 + ⚔️ + 🛡 + 🚬 + ⚰️ + ⚱️ + 🏺 + 🔮 + 📿 + 🧿 + 💈 + ⚗️ + 🔭 + 🔬 + 🕳 + 🩹 + 🩺 + 💊 + 💉 + 🩸 + 🧬 + 🦠 + 🧫 + 🧪 + 🌡 + 🧹 + 🧺 + 🧻 + 🚽 + 🚰 + 🚿 + 🛁 + 🛀 + 🛀🏻 + 🛀🏼 + 🛀🏽 + 🛀🏾 + 🛀🏿 + 🧼 + 🪒 + 🧽 + 🧴 + 🛎 + 🔑 + 🗝 + 🚪 + 🪑 + 🛋 + 🛏 + 🛌 + 🧸 + 🖼 + 🛍 + 🛒 + 🎁 + 🎈 + 🎏 + 🎀 + 🎊 + 🎉 + 🎎 + 🏮 + 🎐 + 🧧 + ✉️ + 📩 + 📨 + 📧 + 💌 + 📥 + 📤 + 📦 + 🏷 + 📪 + 📫 + 📬 + 📭 + 📮 + 📯 + 📜 + 📃 + 📄 + 📑 + 🧾 + 📊 + 📈 + 📉 + 🗒 + 🗓 + 📆 + 📅 + 🗑 + 📇 + 🗃 + 🗳 + 🗄 + 📋 + 📁 + 📂 + 🗂 + 🗞 + 📰 + 📓 + 📔 + 📒 + 📕 + 📗 + 📘 + 📙 + 📚 + 📖 + 🔖 + 🧷 + 🔗 + 📎 + 🖇 + 📐 + 📏 + 🧮 + 📌 + 📍 + ✂️ + 🖊 + 🖋 + ✒️ + 🖌 + 🖍 + 📝 + ✏️ + 🔍 + 🔎 + 🔏 + 🔐 + 🔒 + 🔓 + + + + + Title + Symbols + Emojis + + ❤️ + 🧡 + 💛 + 💚 + 💙 + 💜 + 🖤 + 🤍 + 🤎 + 💔 + ❣️ + 💕 + 💞 + 💓 + 💗 + 💖 + 💘 + 💝 + 💟 + ☮️ + ✝️ + ☪️ + 🕉 + ☸️ + ✡️ + 🔯 + 🕎 + ☯️ + ☦️ + 🛐 + + ♈️ + ♉️ + ♊️ + ♋️ + ♌️ + ♍️ + ♎️ + ♏️ + ♐️ + ♑️ + ♒️ + ♓️ + 🆔 + ⚛️ + 🉑 + ☢️ + ☣️ + 📴 + 📳 + 🈶 + 🈚️ + 🈸 + 🈺 + 🈷️ + ✴️ + 🆚 + 💮 + 🉐 + ㊙️ + ㊗️ + 🈴 + 🈵 + 🈹 + 🈲 + 🅰️ + 🅱️ + 🆎 + 🆑 + 🅾️ + 🆘 + + ⭕️ + 🛑 + ⛔️ + 📛 + 🚫 + 💯 + 💢 + ♨️ + 🚷 + 🚯 + 🚳 + 🚱 + 🔞 + 📵 + 🚭 + ❗️ + + + + ‼️ + ⁉️ + 🔅 + 🔆 + 〽️ + ⚠️ + 🚸 + 🔱 + ⚜️ + 🔰 + ♻️ + + 🈯️ + 💹 + ❇️ + ✳️ + + 🌐 + 💠 + Ⓜ️ + 🌀 + 💤 + 🏧 + 🚾 + ♿️ + 🅿️ + 🈳 + 🈂️ + 🛂 + 🛃 + 🛄 + 🛅 + 🚹 + 🚺 + 🚼 + 🚻 + 🚮 + 🎦 + 📶 + 🈁 + 🔣 + ℹ️ + 🔤 + 🔡 + 🔠 + 🆖 + 🆗 + 🆙 + 🆒 + 🆕 + 🆓 + 0️⃣ + 1️⃣ + 2️⃣ + 3️⃣ + 4️⃣ + 5️⃣ + 6️⃣ + 7️⃣ + 8️⃣ + 9️⃣ + 🔟 + 🔢 + #️⃣ + *️⃣ + ⏏️ + ▶️ + + + + + + + + + + + ◀️ + 🔼 + 🔽 + ➡️ + ⬅️ + ⬆️ + ⬇️ + ↗️ + ↘️ + ↙️ + ↖️ + ↕️ + ↔️ + ↪️ + ↩️ + ⤴️ + ⤵️ + 🔀 + 🔁 + 🔂 + 🔄 + 🔃 + 🎵 + 🎶 + + + + ✖️ + + 💲 + 💱 + ™️ + ©️ + ®️ + 👁‍🗨 + 🔚 + 🔙 + 🔛 + 🔝 + 🔜 + 〰️ + + + ✔️ + ☑️ + 🔘 + 🔴 + 🟠 + 🟡 + 🟢 + 🔵 + 🟣 + ⚫️ + ⚪️ + 🟤 + 🔺 + 🔻 + 🔸 + 🔹 + 🔶 + 🔷 + 🔳 + 🔲 + ▪️ + ▫️ + ◾️ + ◽️ + ◼️ + ◻️ + 🟥 + 🟧 + 🟨 + 🟩 + 🟦 + 🟪 + ⬛️ + ⬜️ + 🟫 + 🔈 + 🔇 + 🔉 + 🔊 + 🔔 + 🔕 + 📣 + 📢 + 💬 + 💭 + 🗯 + ♠️ + ♣️ + ♥️ + ♦️ + 🃏 + 🎴 + 🀄️ + 🕐 + 🕑 + 🕒 + 🕓 + 🕔 + 🕕 + 🕖 + 🕗 + 🕘 + 🕙 + 🕚 + 🕛 + 🕜 + 🕝 + 🕞 + 🕟 + 🕠 + 🕡 + 🕢 + 🕣 + 🕤 + 🕥 + 🕦 + 🕧 + + + + + Title + Flags + Emojis + + 🏳️ + 🏴 + 🏴‍☠️ + 🏁 + 🚩 + 🏳️‍🌈 + 🇺🇳 + 🇦🇫 + 🇦🇽 + 🇦🇱 + 🇩🇿 + 🇦🇸 + 🇦🇩 + 🇦🇴 + 🇦🇮 + 🇦🇶 + 🇦🇬 + 🇦🇷 + 🇦🇲 + 🇦🇼 + 🇦🇺 + 🇦🇹 + 🇦🇿 + 🇧🇸 + 🇧🇭 + 🇧🇩 + 🇧🇧 + 🇧🇾 + 🇧🇪 + 🇧🇿 + 🇧🇯 + 🇧🇲 + 🇧🇹 + 🇧🇴 + 🇧🇦 + 🇧🇼 + 🇧🇷 + 🇮🇴 + 🇻🇬 + 🇧🇳 + 🇧🇬 + 🇧🇫 + 🇧🇮 + 🇰🇭 + 🇨🇲 + 🇨🇦 + 🇮🇨 + 🇨🇻 + 🇧🇶 + 🇰🇾 + 🇨🇫 + 🇹🇩 + 🇨🇱 + 🇨🇳 + 🇨🇽 + 🇨🇨 + 🇨🇴 + 🇰🇲 + 🇨🇬 + 🇨🇩 + 🇨🇰 + 🇨🇷 + 🇨🇮 + 🇭🇷 + 🇨🇺 + 🇨🇼 + 🇨🇾 + 🇨🇿 + 🇩🇰 + 🇩🇯 + 🇩🇲 + 🇩🇴 + 🇪🇨 + 🇪🇬 + 🇸🇻 + 🇬🇶 + 🇪🇷 + 🇪🇪 + 🇸🇿 + 🇪🇹 + 🇪🇺 + 🇫🇰 + 🇫🇴 + 🇫🇯 + 🇫🇮 + 🇫🇷 + 🇬🇫 + 🇵🇫 + 🇹🇫 + 🇬🇦 + 🇬🇲 + 🇬🇪 + 🇩🇪 + 🇬🇭 + 🇬🇮 + 🇬🇷 + 🇬🇱 + 🇬🇩 + 🇬🇵 + 🇬🇺 + 🇬🇹 + 🇬🇬 + 🇬🇳 + 🇬🇼 + 🇬🇾 + 🇭🇹 + 🇭🇳 + 🇭🇰 + 🇭🇺 + 🇮🇸 + 🇮🇳 + 🇮🇩 + 🇮🇷 + 🇮🇶 + 🇮🇪 + 🇮🇲 + 🇮🇱 + 🇮🇹 + 🇯🇲 + 🇯🇵 + 🎌 + 🇯🇪 + 🇯🇴 + 🇰🇿 + 🇰🇪 + 🇰🇮 + 🇽🇰 + 🇰🇼 + 🇰🇬 + 🇱🇦 + 🇱🇻 + 🇱🇧 + 🇱🇸 + 🇱🇷 + 🇱🇾 + 🇱🇮 + 🇱🇹 + 🇱🇺 + 🇲🇴 + 🇲🇬 + 🇲🇼 + 🇲🇾 + 🇲🇻 + 🇲🇱 + 🇲🇹 + 🇲🇭 + 🇲🇶 + 🇲🇷 + 🇲🇺 + 🇾🇹 + 🇲🇽 + 🇫🇲 + 🇲🇩 + 🇲🇨 + 🇲🇳 + 🇲🇪 + 🇲🇸 + 🇲🇦 + 🇲🇿 + 🇲🇲 + 🇳🇦 + 🇳🇷 + 🇳🇵 + 🇳🇱 + 🇳🇨 + 🇳🇿 + 🇳🇮 + 🇳🇪 + 🇳🇬 + 🇳🇺 + 🇳🇫 + 🇰🇵 + 🇲🇰 + 🇲🇵 + 🇳🇴 + 🇴🇲 + 🇵🇰 + 🇵🇼 + 🇵🇸 + 🇵🇦 + 🇵🇬 + 🇵🇾 + 🇵🇪 + 🇵🇭 + 🇵🇳 + 🇵🇱 + 🇵🇹 + 🇵🇷 + 🇶🇦 + 🇷🇪 + 🇷🇴 + 🇷🇺 + 🇷🇼 + 🇼🇸 + 🇸🇲 + 🇸🇹 + 🇸🇦 + 🇸🇳 + 🇷🇸 + 🇸🇨 + 🇸🇱 + 🇸🇬 + 🇸🇽 + 🇸🇰 + 🇸🇮 + 🇬🇸 + 🇸🇧 + 🇸🇴 + 🇿🇦 + 🇰🇷 + 🇸🇸 + 🇪🇸 + 🇱🇰 + 🇧🇱 + 🇸🇭 + 🇰🇳 + 🇱🇨 + 🇵🇲 + 🇻🇨 + 🇸🇩 + 🇸🇷 + 🇸🇪 + 🇨🇭 + 🇸🇾 + 🇹🇼 + 🇹🇯 + 🇹🇿 + 🇹🇭 + 🇹🇱 + 🇹🇬 + 🇹🇰 + 🇹🇴 + 🇹🇹 + 🇹🇳 + 🇹🇷 + 🇹🇲 + 🇹🇨 + 🇹🇻 + 🇺🇬 + 🇺🇦 + 🇦🇪 + 🇬🇧 + 🏴󠁧󠁢󠁥󠁮󠁧󠁿 + 🏴󠁧󠁢󠁳󠁣󠁴󠁿 + 🏴󠁧󠁢󠁷󠁬󠁳󠁿 + 🇺🇸 + 🇺🇾 + 🇻🇮 + 🇺🇿 + 🇻🇺 + 🇻🇦 + 🇻🇪 + 🇻🇳 + 🇼🇫 + 🇪🇭 + 🇾🇪 + 🇿🇲 + 🇿🇼 + + + + + diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/appearance-dark@3x.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/appearance-dark@3x.png new file mode 100644 index 0000000..8348619 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/appearance-dark@3x.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/appearance-dynamic@3x.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/appearance-dynamic@3x.png new file mode 100644 index 0000000..4764af1 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/appearance-dynamic@3x.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/appearance-light@3x.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/appearance-light@3x.png new file mode 100644 index 0000000..eeab5c2 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/appearance-light@3x.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/banner@3x.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/banner@3x.png new file mode 100644 index 0000000..b4960fa Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/banner@3x.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/capsule@3x.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/capsule@3x.png new file mode 100644 index 0000000..7186855 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Appearance/capsule@3x.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/bug.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/bug.png new file mode 100644 index 0000000..7ce8e74 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/bug.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/file.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/file.png new file mode 100644 index 0000000..4c0ec06 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/file.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/image.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/image.png new file mode 100644 index 0000000..626a370 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/image.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/url-link.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/url-link.png new file mode 100644 index 0000000..d98c3bf Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Bug Report/url-link.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/appearance.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/appearance.png new file mode 100644 index 0000000..c499d39 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/appearance.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/applist.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/applist.png new file mode 100644 index 0000000..5da2782 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/applist.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png new file mode 100644 index 0000000..e273377 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/bug.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/button.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/button.png new file mode 100644 index 0000000..f25dfac Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/button.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/changlog.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/changlog.png new file mode 100644 index 0000000..795c964 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/changlog.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/colour.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/colour.png new file mode 100644 index 0000000..12ca198 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/colour.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/compose.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/compose.png new file mode 100644 index 0000000..e6318dd Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/compose.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/date.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/date.png new file mode 100644 index 0000000..2e15bff Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/date.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/disabled.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/disabled.png new file mode 100644 index 0000000..8898b0e Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/disabled.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/edit.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/edit.png new file mode 100644 index 0000000..066e9ee Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/edit.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/enabled.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/enabled.png new file mode 100644 index 0000000..c2dab50 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/enabled.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/file.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/file.png new file mode 100644 index 0000000..e234de9 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/file.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/font.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/font.png new file mode 100644 index 0000000..785ed4d Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/font.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/image.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/image.png new file mode 100644 index 0000000..10dd16b Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/image.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/link.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/link.png new file mode 100644 index 0000000..e67364e Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/link.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/list.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/list.png new file mode 100644 index 0000000..9e66591 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/list.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/misc.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/misc.png new file mode 100644 index 0000000..65e1820 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/misc.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/photo.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/photo.png new file mode 100644 index 0000000..b9d38ac Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/photo.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/profile.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/profile.png new file mode 100644 index 0000000..bb7ce60 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/profile.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/purchase.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/purchase.png new file mode 100644 index 0000000..6f07b0b Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/purchase.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/question.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/question.png new file mode 100644 index 0000000..2ee8169 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/question.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/review.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/review.png new file mode 100644 index 0000000..627969a Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/review.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/square-grid.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/square-grid.png new file mode 100644 index 0000000..100c9f1 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/square-grid.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/star.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/star.png new file mode 100644 index 0000000..633f449 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/star.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/stepper.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/stepper.png new file mode 100644 index 0000000..0b3e14c Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/stepper.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/switch.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/switch.png new file mode 100644 index 0000000..38a3d08 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/switch.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/textview.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/textview.png new file mode 100644 index 0000000..99abda1 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/textview.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/tutorial.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/tutorial.png new file mode 100644 index 0000000..636401d Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/tutorial.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/update.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/update.png new file mode 100644 index 0000000..84a8606 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/update.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/url-link.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/url-link.png new file mode 100644 index 0000000..060fadc Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Cells/url-link.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/bug-fix.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/bug-fix.png new file mode 100644 index 0000000..7c0acd4 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/bug-fix.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/improvements.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/improvements.png new file mode 100644 index 0000000..9d54c2a Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/improvements.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/initial-release.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/initial-release.png new file mode 100644 index 0000000..a0138f6 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/initial-release.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/new-features.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/new-features.png new file mode 100644 index 0000000..192388b Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Changelog/new-features.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Confetti/diamond.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Confetti/diamond.png new file mode 100644 index 0000000..5ae5484 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Confetti/diamond.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/backup-restore.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/backup-restore.png new file mode 100644 index 0000000..78689e1 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/backup-restore.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/changelog.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/changelog.png new file mode 100644 index 0000000..90f70be Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/changelog.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/colour-wheel.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/colour-wheel.png new file mode 100644 index 0000000..6cee7ad Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/colour-wheel.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/crew-mask.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/crew-mask.png new file mode 100644 index 0000000..84bdda6 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/crew-mask.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/crew.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/crew.png new file mode 100644 index 0000000..29fa7ab Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/crew.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/dob.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/dob.png new file mode 100644 index 0000000..020633f Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/dob.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/drawer-menu.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/drawer-menu.png new file mode 100644 index 0000000..7d61f13 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/drawer-menu.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/link.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/link.png new file mode 100644 index 0000000..e955a8c Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/link.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/profile.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/profile.png new file mode 100644 index 0000000..a86a206 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/profile.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/restore.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/restore.png new file mode 100644 index 0000000..985d626 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/restore.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/social.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/social.png new file mode 100644 index 0000000..e1b4cb2 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/social.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/themes.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/themes.png new file mode 100644 index 0000000..a82bfd1 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/themes.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/tweak.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/tweak.png new file mode 100644 index 0000000..b2da553 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/tweak.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/tweaks.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/tweaks.png new file mode 100644 index 0000000..989dd9c Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/tweaks.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/twitter.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/twitter.png new file mode 100644 index 0000000..e98c03e Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Drawer/twitter.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/birthday.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/birthday.png new file mode 100644 index 0000000..e038170 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/birthday.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/christmas.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/christmas.png new file mode 100644 index 0000000..ef3a25c Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/christmas.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/fourth-july.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/fourth-july.png new file mode 100644 index 0000000..5bc2a6e Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/fourth-july.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/halloween.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/halloween.png new file mode 100644 index 0000000..cf4bdd2 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/halloween.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/nyd.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/nyd.png new file mode 100644 index 0000000..3428a12 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/nyd.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/nye.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/nye.png new file mode 100644 index 0000000..c49acae Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Events/nye.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Icons/bug.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Icons/bug.png new file mode 100644 index 0000000..6e03f79 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Icons/bug.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Icons/tutorial.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Icons/tutorial.png new file mode 100644 index 0000000..57b9761 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Icons/tutorial.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/blackhat-avatar.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/blackhat-avatar.png new file mode 100644 index 0000000..fed33cb Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/blackhat-avatar.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/blackhat-banner.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/blackhat-banner.png new file mode 100644 index 0000000..a7953ae Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/blackhat-banner.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/sgwc-avatar.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/sgwc-avatar.png new file mode 100644 index 0000000..4fcaa7c Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/sgwc-avatar.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/sgwc-banner.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/sgwc-banner.png new file mode 100644 index 0000000..8578213 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/Images/sgwc-banner.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/crew.plist b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/crew.plist new file mode 100644 index 0000000..24b443e --- /dev/null +++ b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Crew/crew.plist @@ -0,0 +1,33 @@ + + + + + + + banner + sgwc-banner.png + avatar + sgwc-avatar.png + name + SouthernGirlWhoCode + role + iOS front-end developer + url + https://twitter.com/SouthGalWhoCode + + + + banner + blackhat-banner.png + avatar + blackhat-avatar.png + name + MeBlackHat + role + iOS back-end developer + url + https://twitter.com/Mr_BlackHat_7 + + + + diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/avatar.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/avatar.png new file mode 100644 index 0000000..4987ca9 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/avatar.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/discord.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/discord.png new file mode 100644 index 0000000..ce889ba Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/discord.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/instagram.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/instagram.png new file mode 100644 index 0000000..7b2cb6b Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/instagram.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/patreon.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/patreon.png new file mode 100644 index 0000000..4f5ddae Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/patreon.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/paypal.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/paypal.png new file mode 100644 index 0000000..4caa455 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/paypal.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/reddit.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/reddit.png new file mode 100644 index 0000000..8cd94c6 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/reddit.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/twitter.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/twitter.png new file mode 100644 index 0000000..7d6b05e Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/twitter.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/website.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/website.png new file mode 100644 index 0000000..ff36445 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/website.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/youtube.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/youtube.png new file mode 100644 index 0000000..c139455 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/Icons/youtube.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/social.plist b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/social.plist new file mode 100644 index 0000000..53b88cd --- /dev/null +++ b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Social/social.plist @@ -0,0 +1,84 @@ + + + + + + + title + Patreon + subtitle + Become a patron + url + https://www.patreon.com/TitanD3v + icon + patreon.png + + + + title + Discord + subtitle + Chat with us + url + https://discord.gg/Kk4KYpZ528 + icon + discord.png + + + + title + Reddit + subtitle + Follow me on Reddit + url + https://www.reddit.com/user/TitanD3v + icon + reddit.png + + + + title + Instagram + subtitle + Follow me on Instagram + url + https://www.instagram.com//?hl=en + icon + instagram.png + + + + title + YouTube + subtitle + Subscribe me on YouTube + url + https://www.youtube.com/channel/UCGvKt2TBsA8UBweIO0qF69A/featured?view_as=subscriber + icon + youtube.png + + + + title + PayPal + subtitle + Any donation is greatly appreciated + url + https://paypal.me/southerngirlwhocode + icon + paypal.png + + + + title + TitanD3v + subtitle + Website + url + https://titand3v.com/ + icon + website.png + + + + diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/avatar.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/avatar.png new file mode 100644 index 0000000..6fcccd5 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/avatar.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/breezy.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/breezy.png new file mode 100644 index 0000000..5425265 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/breezy.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/colourmydock.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/colourmydock.png new file mode 100644 index 0000000..8539ea9 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/colourmydock.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/digitnetic.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/digitnetic.png new file mode 100644 index 0000000..7533249 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/digitnetic.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/flowing.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/flowing.png new file mode 100644 index 0000000..b94b950 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/flowing.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/idevices.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/idevices.png new file mode 100644 index 0000000..c117cdd Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/idevices.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/jarvis.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/jarvis.png new file mode 100644 index 0000000..31181ec Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/jarvis.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/luv.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/luv.png new file mode 100644 index 0000000..91d7ffb Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/luv.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/nova.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/nova.png new file mode 100644 index 0000000..5db2ee5 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/nova.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/palette.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/palette.png new file mode 100644 index 0000000..7d642fc Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/palette.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/paradise.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/paradise.png new file mode 100644 index 0000000..3d0c42b Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/paradise.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/phoenix.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/phoenix.png new file mode 100644 index 0000000..dc93e14 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/phoenix.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/restriction.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/restriction.png new file mode 100644 index 0000000..3a3cdce Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/restriction.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/speedy.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/speedy.png new file mode 100644 index 0000000..03919f9 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/speedy.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/substia.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/substia.png new file mode 100644 index 0000000..4b10c88 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/substia.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/surge.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/surge.png new file mode 100644 index 0000000..4d2d024 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/surge.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/unique.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/unique.png new file mode 100644 index 0000000..5cbbdf4 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/Icons/unique.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/tweak.plist b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/tweak.plist new file mode 100644 index 0000000..1e83154 --- /dev/null +++ b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Info/Tweak/tweak.plist @@ -0,0 +1,262 @@ + + + + + + + name + Jarvis + price + $3.00 + compatibility + iOS 13+ + description + Powerful multi-center with control center, notification center, app launcher, clipboard manager, tweak list and music. + icon + jarvis.png + url + https://repo.twickd.com/package/com.twickd.southerngirlwhocode.jarvis + + + + name + Restriction + price + $2.50 + compatibility + iOS 13+ + description + Unlimited guest mode for your iOS device, you can log into unlimited accounts if you lend your phone to your friends or family. + icon + restriction.png + url + https://repo.twickd.com/package/com.twickd.southerngirlwhocode.restriction + + + + name + ColourMyDock + price + FREE + compatibility + iOS 14 + description + Colour your dock with iOS 14 colour picker, very simple to use, double tap on the dock, choose your colour then your dock are colouring! + icon + colourmydock.png + url + https://titand3v.github.io/depictions/colourmydock/index.html + + + + name + Nova + price + $2.50 + compatibility + iOS 14 + description + Send schedule messages with attachments for Messages app + icon + nova.png + url + https://titand3v.github.io/depictions/nova/index.html + + + + name + Luv + price + FREE + compatibility + iOS 14 + description + Floating button for Spotify to like or dislike the song and added to Liked Songs + icon + luv.png + url + https://titand3v.github.io/depictions/luv/index.html + + + + name + Paradise + price + $3.00 + compatibility + iOS 14 + description + Icon editor for springboard apps, style apps label, widgets and app library + icon + paradise.png + url + https://titand3v.github.io/depictions/paradise/index.html + + + + name + Breezy + price + FREE + compatibility + iOS 14 + description + Invoke fake notifications with custom title, message and app of your choice from anywhere + icon + breezy.png + url + https://titand3v.github.io/depictions/breezy/index.html + + + + name + Speedy + price + FREE + compatibility + iOS 14 + description + Batch uninstall applications on SpringBoard via 3D Touch Menu + icon + speedy.png + url + https://titand3v.github.io/depictions/speedy/index.html + + + + name + Substia + price + FREE + compatibility + iOS 14 + description + Text replacemnet + icon + substia.png + url + https://titand3v.github.io/depictions/substia/index.html + + + + name + Surge + price + $0.99 + compatibility + iOS 14 + description + Low power alert and quick way to enable LPM from the status bar + icon + surge.png + url + https://titand3v.github.io/depictions/surge/index.html + + + + name + Digitnetic + price + $0.99 + compatibility + iOS 14 + description + Floating phone keypad and calculator + icon + digitnetic.png + url + https://titand3v.github.io/depictions/digitnetic/index.html + + + + name + Unique + price + FREE + compatibility + iOS 14 + description + Swipe up on the keyboard to paste your device's UDID + icon + unique.png + url + https://titand3v.github.io/depictions/unique/index.html + + + + name + Palette + price + FREE + compatibility + iOS 14 + description + Add colours to your collection + icon + palette.png + url + https://titand3v.github.io/depictions/palette/index.html + + + + name + Flowing + price + FREE + compatibility + iOS 14 + description + Disable paging scrolling on SpringBoard + icon + flowing.png + url + https://titand3v.github.io/depictions/flowing/index.html + + + + name + Avatar + price + $2.50 + compatibility + iOS 14 + description + Avatar studio for Memoji and Animoji + icon + avatar.png + url + https://titand3v.github.io/depictions/avatar/index.html + + + + name + Phoenix + price + $2.00 + compatibility + iOS 14 + description + A redesign of the contact list for the Phone app + icon + phoenix.png + url + https://titand3v.github.io/depictions/phoenix/index.html + + + + name + iDevices + price + $2.00 + compatibility + iOS 14 + description + Devices Information + icon + idevices.png + url + https://titand3v.github.io/depictions/idevices/index.html + + + + \ No newline at end of file diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Licence/owned.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Licence/owned.png new file mode 100644 index 0000000..6f30c8b Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Licence/owned.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Licence/trial.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Licence/trial.png new file mode 100644 index 0000000..4034ec8 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Licence/trial.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Licence/unowned.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Licence/unowned.png new file mode 100644 index 0000000..188f333 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Licence/unowned.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/PayPal.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/PayPal.png new file mode 100644 index 0000000..a6848fe Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/PayPal.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/Stripe.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/Stripe.png new file mode 100644 index 0000000..60d27da Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/Stripe.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/payment-help.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/payment-help.png new file mode 100644 index 0000000..fc55db2 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/payment-help.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/purchase-banner.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/purchase-banner.png new file mode 100644 index 0000000..d5ab36a Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Payment/purchase-banner.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Terms&Conditions/terms-and-conditions.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Terms&Conditions/terms-and-conditions.png new file mode 100644 index 0000000..c2a515f Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Terms&Conditions/terms-and-conditions.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Terms&Conditions/titand3v.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Terms&Conditions/titand3v.png new file mode 100644 index 0000000..ab223ae Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Terms&Conditions/titand3v.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Tips/airplane.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Tips/airplane.png new file mode 100644 index 0000000..98d38ce Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Tips/airplane.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Tips/tips.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Tips/tips.png new file mode 100644 index 0000000..2eb7704 Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Tips/tips.png differ diff --git a/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Tips/update.png b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Tips/update.png new file mode 100644 index 0000000..29c6b9b Binary files /dev/null and b/libTitanD3vUniversal/layout/usr/lib/TitanD3v/TitanD3v.bundle/Tips/update.png differ