From 311312930b48c72d3e6464578c87838db81eda8e Mon Sep 17 00:00:00 2001 From: chinosk <2248589280@qq.com> Date: Sat, 21 Mar 2026 00:15:18 +0800 Subject: [PATCH] Add EN support. Fixed window. --- GakumasLocalify/GakumasLocalify/Hook.cpp | 6 +- Makefile | 29 +- control | 2 +- includes/SCLAlertView/LICENSE | 19 + includes/SCLAlertView/SCLAlertView.h | 585 +++++ includes/SCLAlertView/SCLAlertView.m | 2019 +++++++++++++++++ includes/SCLAlertView/SCLAlertViewResponder.h | 30 + includes/SCLAlertView/SCLAlertViewResponder.m | 45 + includes/SCLAlertView/SCLAlertViewStyleKit.h | 105 + includes/SCLAlertView/SCLAlertViewStyleKit.m | 380 ++++ includes/SCLAlertView/SCLButton.h | 109 + includes/SCLAlertView/SCLButton.m | 167 ++ includes/SCLAlertView/SCLMacros.h | 27 + includes/SCLAlertView/SCLSwitchView.h | 23 + includes/SCLAlertView/SCLSwitchView.m | 140 ++ includes/SCLAlertView/SCLTextView.h | 17 + includes/SCLAlertView/SCLTextView.m | 56 + includes/SCLAlertView/SCLTimerDisplay.h | 39 + includes/SCLAlertView/SCLTimerDisplay.m | 133 ++ includes/SCLAlertView/UIImage+ImageEffects.h | 115 + includes/SCLAlertView/UIImage+ImageEffects.m | 324 +++ src/Entry.mm | 4 +- src/UpdateChecker.mm | 359 +-- src/platformDefine.hpp | 2 +- 24 files changed, 4560 insertions(+), 175 deletions(-) create mode 100644 includes/SCLAlertView/LICENSE create mode 100644 includes/SCLAlertView/SCLAlertView.h create mode 100644 includes/SCLAlertView/SCLAlertView.m create mode 100644 includes/SCLAlertView/SCLAlertViewResponder.h create mode 100644 includes/SCLAlertView/SCLAlertViewResponder.m create mode 100644 includes/SCLAlertView/SCLAlertViewStyleKit.h create mode 100644 includes/SCLAlertView/SCLAlertViewStyleKit.m create mode 100644 includes/SCLAlertView/SCLButton.h create mode 100644 includes/SCLAlertView/SCLButton.m create mode 100644 includes/SCLAlertView/SCLMacros.h create mode 100644 includes/SCLAlertView/SCLSwitchView.h create mode 100644 includes/SCLAlertView/SCLSwitchView.m create mode 100644 includes/SCLAlertView/SCLTextView.h create mode 100644 includes/SCLAlertView/SCLTextView.m create mode 100644 includes/SCLAlertView/SCLTimerDisplay.h create mode 100644 includes/SCLAlertView/SCLTimerDisplay.m create mode 100644 includes/SCLAlertView/UIImage+ImageEffects.h create mode 100644 includes/SCLAlertView/UIImage+ImageEffects.m diff --git a/GakumasLocalify/GakumasLocalify/Hook.cpp b/GakumasLocalify/GakumasLocalify/Hook.cpp index bb6e09c..f917290 100644 --- a/GakumasLocalify/GakumasLocalify/Hook.cpp +++ b/GakumasLocalify/GakumasLocalify/Hook.cpp @@ -586,7 +586,11 @@ namespace GakumasLocal::HookMain { MasterLocal::LoadData(); Log::Info("Plugin init finished."); - Log::ShowToastFmt("插件加载完成 / Plugin loaded: %s", PLUGIN_VERSION); +#if LOCALIFY_SCN + Log::ShowToastFmt("插件加载完成: %s", PLUGIN_VERSION); +#else + Log::ShowToastFmt("Plugin loaded: %s", PLUGIN_VERSION); +#endif } diff --git a/Makefile b/Makefile index 642f644..776ab36 100644 --- a/Makefile +++ b/Makefile @@ -7,12 +7,24 @@ THEOS = /home/chinosk/theos include $(THEOS)/makefiles/common.mk -LIBRARY_NAME = GakumasLocalifyIOS +# LOCALIFY_LANG: SCN or EN +LOCALIFY_LANG ?= SCN + +ifeq ($(LOCALIFY_LANG),EN) +LOCALIFY_LANG_DEFINES := -DLOCALIFY_SCN=0 -DLOCALIFY_EN=1 +else ifeq ($(LOCALIFY_LANG),SCN) +LOCALIFY_LANG_DEFINES := -DLOCALIFY_SCN=1 -DLOCALIFY_EN=0 +else +$(error LOCALIFY_LANG must be SCN or EN) +endif + +LIBRARY_NAME_BASE = GakumasLocalifyIOS +LIBRARY_NAME = $(LIBRARY_NAME_BASE)_$(LOCALIFY_LANG) #ALL_MINIZIP_C = $(wildcard includes/SSZipArchive/minizip/*.c) #MINIZIP_FILES = $(filter-out %mz_crypt.c %mz_crypt_apple.c %mz_os_win32.c %mz_strm_win32.c, $(ALL_MINIZIP_C)) -GakumasLocalifyIOS_FILES = \ +$(LIBRARY_NAME)_FILES = \ src/Entry.mm \ src/UpdateChecker.mm \ src/Plugin.cpp \ @@ -26,34 +38,35 @@ GakumasLocalifyIOS_FILES = \ GakumasLocalify/GakumasLocalify/config/Config.cpp \ GakumasLocalify/GakumasLocalify/string_parser/StringParser.cpp \ GakumasLocalify/il2cpp_dump/Il2cppJson.cpp \ + $(wildcard includes/SCLAlertView/*.m) \ $(wildcard includes/SSZipArchive/SSZipArchive.m) \ $(wildcard includes/SSZipArchive/minizip/*.c) ZIP_ARCHIVE_DEFINES = -DHAVE_INTTYPES_H -DHAVE_PKCRYPT -DHAVE_STDINT_H -DHAVE_WZAES -DHAVE_ZLIB -GakumasLocalifyIOS_CFLAGS += -fobjc-arc -Wno-error -Wno-unused-function $(ZIP_ARCHIVE_DEFINES) +$(LIBRARY_NAME)_CFLAGS += -fobjc-arc -Wno-error -Wno-unused-function $(ZIP_ARCHIVE_DEFINES) $(LOCALIFY_LANG_DEFINES) COMMON_CCFLAGS = -DFMT_HEADER_ONLY -Wno-c++11-narrowing -Wno-unused-function -Wno-deprecated-declarations -fdeclspec -Wno-error \ -IGakumasLocalify/deps \ -IGakumasLocalify/deps/fmt-11.0.2/include \ -IGakumasLocalify/il2cpp_dump -GakumasLocalifyIOS_CCFLAGS += -std=c++20 $(COMMON_CCFLAGS) +$(LIBRARY_NAME)_CCFLAGS += -std=c++20 $(COMMON_CCFLAGS) $(LOCALIFY_LANG_DEFINES) #src/UpdateChecker.mm_CCFLAGS = -std=c++11 $(COMMON_CCFLAGS) #src/Entry.mm_CCFLAGS = -std=c++11 $(COMMON_CCFLAGS) #src/IOSHookInstaller.mm_CCFLAGS = -std=c++11 $(COMMON_CCFLAGS) -GakumasLocalifyIOS_OBJCCFLAGS += -std=c++17 -Wno-error -Wno-unused-function +$(LIBRARY_NAME)_OBJCCFLAGS += -std=c++17 -Wno-error -Wno-unused-function $(LOCALIFY_LANG_DEFINES) -GakumasLocalifyIOS_INCLUDE_PATHS += \ +$(LIBRARY_NAME)_INCLUDE_PATHS += \ GakumasLocalify \ GakumasLocalify/deps \ GakumasLocalify/deps/fmt-11.0.2/include \ GakumasLocalify/il2cpp_dump -GakumasLocalifyIOS_FRAMEWORKS += Foundation UIKit -GakumasLocalifyIOS_LDFLAGS += -ldl -lz -Wl,-undefined,dynamic_lookup +$(LIBRARY_NAME)_FRAMEWORKS += Foundation UIKit +$(LIBRARY_NAME)_LDFLAGS += -ldl -lz -Wl,-undefined,dynamic_lookup include $(THEOS_MAKE_PATH)/library.mk diff --git a/control b/control index 5310001..baf8301 100644 --- a/control +++ b/control @@ -1,6 +1,6 @@ Package: io.github.chinosk.gkms-localify Name: Gakumas Localify -Version: 3.2.0 Beta 1 +Version: 3.2.0 Beta 2 Architecture: iphoneos-arm Description: Gakumas localization plugin Maintainer: chinosk diff --git a/includes/SCLAlertView/LICENSE b/includes/SCLAlertView/LICENSE new file mode 100644 index 0000000..cb4203d --- /dev/null +++ b/includes/SCLAlertView/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2014 SCLAlertView-Objective-C by Diogo Autilio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/includes/SCLAlertView/SCLAlertView.h b/includes/SCLAlertView/SCLAlertView.h new file mode 100644 index 0000000..33ec029 --- /dev/null +++ b/includes/SCLAlertView/SCLAlertView.h @@ -0,0 +1,585 @@ +// +// SCLAlertView.h +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// + +#if defined(__has_feature) && __has_feature(modules) +@import UIKit; +#else +#import +#endif +#import "SCLButton.h" +#import "SCLTextView.h" +#import "SCLSwitchView.h" + +typedef NSAttributedString* (^SCLAttributedFormatBlock)(NSString *value); +typedef void (^SCLDismissBlock)(void); +typedef void (^SCLDismissAnimationCompletionBlock)(void); +typedef void (^SCLShowAnimationCompletionBlock)(void); +typedef void (^SCLForceHideBlock)(void); + +@interface SCLAlertView : UIViewController + +/** Alert Styles + * + * Set SCLAlertView Style + */ +typedef NS_ENUM(NSInteger, SCLAlertViewStyle) +{ + SCLAlertViewStyleSuccess, + SCLAlertViewStyleError, + SCLAlertViewStyleNotice, + SCLAlertViewStyleWarning, + SCLAlertViewStyleInfo, + SCLAlertViewStyleEdit, + SCLAlertViewStyleWaiting, + SCLAlertViewStyleQuestion, + SCLAlertViewStyleCustom +}; + +/** Alert hide animation styles + * + * Set SCLAlertView hide animation type. + */ +typedef NS_ENUM(NSInteger, SCLAlertViewHideAnimation) +{ + SCLAlertViewHideAnimationFadeOut, + SCLAlertViewHideAnimationSlideOutToBottom, + SCLAlertViewHideAnimationSlideOutToTop, + SCLAlertViewHideAnimationSlideOutToLeft, + SCLAlertViewHideAnimationSlideOutToRight, + SCLAlertViewHideAnimationSlideOutToCenter, + SCLAlertViewHideAnimationSlideOutFromCenter, + SCLAlertViewHideAnimationSimplyDisappear +}; + +/** Alert show animation styles + * + * Set SCLAlertView show animation type. + */ +typedef NS_ENUM(NSInteger, SCLAlertViewShowAnimation) +{ + SCLAlertViewShowAnimationFadeIn, + SCLAlertViewShowAnimationSlideInFromBottom, + SCLAlertViewShowAnimationSlideInFromTop, + SCLAlertViewShowAnimationSlideInFromLeft, + SCLAlertViewShowAnimationSlideInFromRight, + SCLAlertViewShowAnimationSlideInFromCenter, + SCLAlertViewShowAnimationSlideInToCenter, + SCLAlertViewShowAnimationSimplyAppear +}; + +/** Alert background styles + * + * Set SCLAlertView background type. + */ +typedef NS_ENUM(NSInteger, SCLAlertViewBackground) +{ + SCLAlertViewBackgroundShadow, + SCLAlertViewBackgroundBlur, + SCLAlertViewBackgroundTransparent +}; + +/** Content view corner radius + * + * A float value that replaces the standard content viuew corner radius. + */ +@property CGFloat cornerRadius; + +/** Tint top circle + * + * A boolean value that determines whether to tint the SCLAlertView top circle. + * (Default: YES) + */ +@property (assign, nonatomic) BOOL tintTopCircle; + +/** Use larger icon + * + * A boolean value that determines whether to make the SCLAlertView top circle icon larger. + * (Default: NO) + */ +@property (assign, nonatomic) BOOL useLargerIcon; + +/** Title Label + * + * The text displayed as title. + */ +@property (strong, nonatomic) UILabel *labelTitle; + +/** Text view with the body message + * + * Holds the textview. + */ +@property (strong, nonatomic) UITextView *viewText; + +/** Activity Indicator + * + * Holds the activityIndicator. + */ +@property (strong, nonatomic) UIActivityIndicatorView *activityIndicatorView; + +/** Dismiss on tap outside + * + * A boolean value that determines whether to dismiss when tapping outside the SCLAlertView. + * (Default: NO) + */ +@property (assign, nonatomic) BOOL shouldDismissOnTapOutside; + +/** Sound URL + * + * Holds the sound NSURL path. + */ +@property (strong, nonatomic) NSURL *soundURL; + +/** Set text attributed format block + * + * Holds the attributed string. + */ +@property (copy, nonatomic) SCLAttributedFormatBlock attributedFormatBlock; + +/** Set Complete button format block. + * + * Holds the button format block. + * Support keys : backgroundColor, borderWidth, borderColor, textColor + */ +@property (copy, nonatomic) CompleteButtonFormatBlock completeButtonFormatBlock; + +/** Set button format block. + * + * Holds the button format block. + * Support keys : backgroundColor, borderWidth, borderColor, textColor + */ +@property (copy, nonatomic) ButtonFormatBlock buttonFormatBlock; + +/** Set force hide block. + * + * When set force hideview method invocation. + */ +@property (copy, nonatomic) SCLForceHideBlock forceHideBlock; + +/** Hide animation type + * + * Holds the hide animation type. + * (Default: FadeOut) + */ +@property (nonatomic) SCLAlertViewHideAnimation hideAnimationType; + +/** Show animation type + * + * Holds the show animation type. + * (Default: SlideInFromTop) + */ +@property (nonatomic) SCLAlertViewShowAnimation showAnimationType; + +/** Set SCLAlertView background type. + * + * SCLAlertView background type. + * (Default: Shadow) + */ +@property (nonatomic) SCLAlertViewBackground backgroundType; + +/** Set custom color to SCLAlertView. + * + * SCLAlertView custom color. + * (Buttons, top circle and borders) + */ +@property (strong, nonatomic) UIColor *customViewColor; + +/** Set custom color to SCLAlertView background. + * + * SCLAlertView background custom color. + */ +@property (strong, nonatomic) UIColor *backgroundViewColor; + +/** Set custom tint color for icon image. + * + * SCLAlertView icon tint color + */ +@property (strong, nonatomic) UIColor *iconTintColor; + +/** Set custom circle icon height. + * + * Circle icon height + */ +@property (nonatomic) CGFloat circleIconHeight; + +/** Set SCLAlertView extension bounds. + * + * Set new bounds (EXTENSION ONLY) + */ +@property (nonatomic) CGRect extensionBounds; + +/** Set status bar hidden. + * + * Status bar hidden + */ +@property (nonatomic) BOOL statusBarHidden; + +/** Set status bar style. + * + * Status bar style + */ +@property (nonatomic) UIStatusBarStyle statusBarStyle; + +/** Set horizontal alignment for buttons + * + * Horizontal aligment instead of vertically if YES + */ +@property (nonatomic) BOOL horizontalButtons; + +/** Initialize SCLAlertView using a new window. + * + * Init with new window + */ +- (instancetype)initWithNewWindow; + +/** Initialize SCLAlertView using a new window. + * + * Init with new window with custom width + */ +- (instancetype)initWithNewWindowWidth:(CGFloat)windowWidth; + +/** Warns that alerts is gone + * + * Warns that alerts is gone using block + */ +- (void)alertIsDismissed:(SCLDismissBlock)dismissBlock; + +/** Warns that alerts dismiss animation is completed + * + * Warns that alerts dismiss animation is completed + */ +- (void)alertDismissAnimationIsCompleted:(SCLDismissAnimationCompletionBlock)dismissAnimationCompletionBlock; + +/** Warns that alerts show animation is completed + * + * Warns that alerts show animation is completed + */ +- (void)alertShowAnimationIsCompleted:(SCLShowAnimationCompletionBlock)showAnimationCompletionBlock; + +/** Hide SCLAlertView + * + * Hide SCLAlertView using animation and removing from super view. + */ + +- (void)hideView; + +/** SCLAlertView visibility + * + * Returns if the alert is visible or not. + */ +- (BOOL)isVisible; + +/** Remove Top Circle + * + * Remove top circle from SCLAlertView. + */ +- (void)removeTopCircle; + +/** Add a custom UIView + * + * @param customView UIView object to be added above the first SCLButton. + */ +- (UIView *)addCustomView:(UIView *)customView; + +/** Add Text Field + * + * @param title The text displayed on the textfield. + */ +- (SCLTextView *)addTextField:(NSString *)title setDefaultText:(NSString *)defaultText; + +/** Add a custom Text Field + * + * @param textField The custom textfield provided by the programmer. + */ +- (void)addCustomTextField:(UITextField *)textField; + +/** Add a switch view + * + * @param label The label displayed for the switch. + */ +- (SCLSwitchView *)addSwitchViewWithLabel:(NSString *)label; + +/** Add Timer Display + * + * @param buttonIndex The index of the button to add the timer display to. + * @param reverse Convert timer to countdown. + */ +- (void)addTimerToButtonIndex:(NSInteger)buttonIndex reverse:(BOOL)reverse; + +/** Set Title font family and size + * + * @param titleFontFamily The family name used to displayed the title. + * @param size Font size. + */ +- (void)setTitleFontFamily:(NSString *)titleFontFamily withSize:(CGFloat)size; + +/** Set Text field font family and size + * + * @param bodyTextFontFamily The family name used to displayed the text field. + * @param size Font size. + */ +- (void)setBodyTextFontFamily:(NSString *)bodyTextFontFamily withSize:(CGFloat)size; + +/** Set Buttons font family and size + * + * @param buttonsFontFamily The family name used to displayed the buttons. + * @param size Font size. + */ +- (void)setButtonsTextFontFamily:(NSString *)buttonsFontFamily withSize:(CGFloat)size; + +/** Add a Button with a title and a block to handle when the button is pressed. + * + * @param title The text displayed on the button. + * @param action A block of code to be executed when the button is pressed. + */ +- (SCLButton *)addButton:(NSString *)title actionBlock:(SCLActionBlock)action; + +/** Add a Button with a title, a block to handle validation, and a block to handle when the button is pressed and validation succeeds. + * + * @param title The text displayed on the button. + * @param validationBlock A block of code that will allow you to validate fields or do any other logic you may want to do to determine if the alert should be dismissed or not. Inside of this block, return a BOOL indicating whether or not the action block should be called and the alert dismissed. + * @param action A block of code to be executed when the button is pressed and validation passes. + */ +- (SCLButton *)addButton:(NSString *)title validationBlock:(SCLValidationBlock)validationBlock actionBlock:(SCLActionBlock)action; + +/** Add a Button with a title, a target and a selector to handle when the button is pressed. + * + * @param title The text displayed on the button. + * @param target Add target for particular event. + * @param selector A method to be executed when the button is pressed. + */ +- (SCLButton *)addButton:(NSString *)title target:(id)target selector:(SEL)selector; + +/** Show Success SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showSuccess:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showSuccess:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Error SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showError:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showError:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Notice SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showNotice:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showNotice:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Warning SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showWarning:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showWarning:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Info SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showInfo:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showInfo:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Edit SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showEdit:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showEdit:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Title SCLAlertView using a predefined type + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param style One of predefined SCLAlertView styles. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showTitle:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showTitle:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Shows a custom SCLAlertView without using a predefined type, allowing for a custom image and color to be specified. + * + * @param vc The view controller the alert view will be displayed in. + * @param image A UIImage object to be used as the icon for the alert view. + * @param color A UIColor object to be used to tint the background of the icon circle and the buttons. + * @param title The title text of the alert view. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showCustom:(UIViewController *)vc image:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showCustom:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Waiting SCLAlertView with UIActityIndicator. + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showWaiting:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showWaiting:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** Show Question SCLAlertView + * + * @param vc The view controller the alert view will be displayed in. + * @param title The text displayed on the button. + * @param subTitle The subtitle text of the alert view. + * @param closeButtonTitle The text for the close button. + * @param duration The amount of time the alert will remain on screen until it is automatically dismissed. If automatic dismissal is not desired, set to 0. + */ +- (void)showQuestion:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showQuestion:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +@end + +@protocol SCLItemsBuilder__Protocol__Fluent +- (void)setupFluent; +@end + +@interface SCLAlertViewBuilder__WithFluent: NSObject @end + +@interface SCLAlertViewShowBuilder : SCLAlertViewBuilder__WithFluent + +@property(weak, nonatomic, readonly) UIViewController *parameterViewController; +@property(copy, nonatomic, readonly) UIImage *parameterImage; +@property(copy, nonatomic, readonly) UIColor *parameterColor; +@property(copy, nonatomic, readonly) NSString *parameterTitle; +@property(copy, nonatomic, readonly) NSString *parameterSubTitle; +@property(copy, nonatomic, readonly) NSString *parameterCompleteText; +@property(copy, nonatomic, readonly) NSString *parameterCloseButtonTitle; +@property(assign, nonatomic, readonly) SCLAlertViewStyle parameterStyle; +@property(assign, nonatomic, readonly) NSTimeInterval parameterDuration; + +#pragma mark - Setters +@property(copy, nonatomic, readonly) SCLAlertViewShowBuilder *(^viewController)(UIViewController *viewController); +@property(copy, nonatomic, readonly) SCLAlertViewShowBuilder *(^image)(UIImage *image); +@property(copy, nonatomic, readonly) SCLAlertViewShowBuilder *(^color)(UIColor *color); +@property(copy, nonatomic, readonly) SCLAlertViewShowBuilder *(^title)(NSString *title); +@property(copy, nonatomic, readonly) SCLAlertViewShowBuilder *(^subTitle)(NSString *subTitle); +@property(copy, nonatomic, readonly) SCLAlertViewShowBuilder *(^completeText)(NSString *completeText); +@property(copy, nonatomic, readonly) SCLAlertViewShowBuilder *(^style)(SCLAlertViewStyle style); +@property(copy, nonatomic, readonly) SCLAlertViewShowBuilder *(^closeButtonTitle)(NSString *closeButtonTitle); +@property(copy, nonatomic, readonly) SCLAlertViewShowBuilder *(^duration)(NSTimeInterval duration); + +- (void)showAlertView:(SCLAlertView *)alertView; +- (void)showAlertView:(SCLAlertView *)alertView onViewController:(UIViewController *)controller; +@property(copy, nonatomic, readonly) void (^show)(SCLAlertView *view, UIViewController *controller); +@end + +@interface SCLALertViewTextFieldBuilder : SCLAlertViewBuilder__WithFluent + +#pragma mark - Available later after adding +@property(weak, nonatomic, readonly) SCLTextView *textField; + +#pragma mark - Setters +@property(copy, nonatomic, readonly) SCLALertViewTextFieldBuilder *(^title) (NSString *title); + +@end + +@interface SCLALertViewButtonBuilder : SCLAlertViewBuilder__WithFluent + +#pragma mark - Available later after adding +@property(weak, nonatomic, readonly) SCLButton *button; + +#pragma mark - Setters +@property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^title) (NSString *title); +@property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^target) (id target); +@property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^selector) (SEL selector); +@property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^actionBlock) (void(^actionBlock)(void)); +@property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^validationBlock) (BOOL(^validationBlock)(void)); + +@end + +@interface SCLAlertViewBuilder : SCLAlertViewBuilder__WithFluent + +#pragma mark - Parameters +@property (strong, nonatomic, readonly) SCLAlertView *alertView; + +#pragma mark - Init +- (instancetype)init; +- (instancetype)initWithNewWindow; +- (instancetype)initWithNewWindowWidth:(CGFloat)width; + +#pragma mark - Properties +@property(copy, nonatomic) SCLAlertViewBuilder *(^cornerRadius) (CGFloat cornerRadius); +@property(copy, nonatomic) SCLAlertViewBuilder *(^tintTopCircle) (BOOL tintTopCircle); +@property(copy, nonatomic) SCLAlertViewBuilder *(^useLargerIcon) (BOOL useLargerIcon); +@property(copy, nonatomic) SCLAlertViewBuilder *(^labelTitle) (UILabel *labelTitle); +@property(copy, nonatomic) SCLAlertViewBuilder *(^viewText) (UITextView *viewText); +@property(copy, nonatomic) SCLAlertViewBuilder *(^activityIndicatorView) (UIActivityIndicatorView *activityIndicatorView); +@property(copy, nonatomic) SCLAlertViewBuilder *(^shouldDismissOnTapOutside) (BOOL shouldDismissOnTapOutside); +@property(copy, nonatomic) SCLAlertViewBuilder *(^soundURL) (NSURL *soundURL); +@property(copy, nonatomic) SCLAlertViewBuilder *(^attributedFormatBlock) (SCLAttributedFormatBlock attributedFormatBlock); +@property(copy, nonatomic) SCLAlertViewBuilder *(^completeButtonFormatBlock) (CompleteButtonFormatBlock completeButtonFormatBlock); +@property(copy, nonatomic) SCLAlertViewBuilder *(^buttonFormatBlock) (ButtonFormatBlock buttonFormatBlock); +@property(copy, nonatomic) SCLAlertViewBuilder *(^forceHideBlock) (SCLForceHideBlock forceHideBlock); +@property(copy, nonatomic) SCLAlertViewBuilder *(^hideAnimationType) (SCLAlertViewHideAnimation hideAnimationType); +@property(copy, nonatomic) SCLAlertViewBuilder *(^showAnimationType) (SCLAlertViewShowAnimation showAnimationType); +@property(copy, nonatomic) SCLAlertViewBuilder *(^backgroundType) (SCLAlertViewBackground backgroundType); +@property(copy, nonatomic) SCLAlertViewBuilder *(^customViewColor) (UIColor *customViewColor); +@property(copy, nonatomic) SCLAlertViewBuilder *(^backgroundViewColor) (UIColor *backgroundViewColor); +@property(copy, nonatomic) SCLAlertViewBuilder *(^iconTintColor) (UIColor *iconTintColor); +@property(copy, nonatomic) SCLAlertViewBuilder *(^circleIconHeight) (CGFloat circleIconHeight); +@property(copy, nonatomic) SCLAlertViewBuilder *(^extensionBounds) (CGRect extensionBounds); +@property(copy, nonatomic) SCLAlertViewBuilder *(^statusBarHidden) (BOOL statusBarHidden); +@property(copy, nonatomic) SCLAlertViewBuilder *(^statusBarStyle) (UIStatusBarStyle statusBarStyle); + +#pragma mark - Custom Setters +@property(copy, nonatomic) SCLAlertViewBuilder *(^alertIsDismissed) (SCLDismissBlock dismissBlock); +@property(copy, nonatomic) SCLAlertViewBuilder *(^alertDismissAnimationIsCompleted) (SCLDismissAnimationCompletionBlock dismissAnimationCompletionBlock); +@property(copy, nonatomic) SCLAlertViewBuilder *(^alertShowAnimationIsCompleted) (SCLShowAnimationCompletionBlock showAnimationCompletionBlock); +@property(copy, nonatomic) SCLAlertViewBuilder *(^removeTopCircle)(void); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addCustomView)(UIView *view); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addTextField)(NSString *title, NSString *defaultText); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addCustomTextField)(UITextField *textField); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addSwitchViewWithLabelTitle)(NSString *title); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addTimerToButtonIndex)(NSInteger buttonIndex, BOOL reverse); +@property(copy, nonatomic) SCLAlertViewBuilder *(^setTitleFontFamily)(NSString *titleFontFamily, CGFloat size); +@property(copy, nonatomic) SCLAlertViewBuilder *(^setBodyTextFontFamily)(NSString *bodyTextFontFamily, CGFloat size); +@property(copy, nonatomic) SCLAlertViewBuilder *(^setButtonsTextFontFamily)(NSString *buttonsFontFamily, CGFloat size); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addButtonWithActionBlock)(NSString *title, SCLActionBlock action); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addButtonWithValidationBlock)(NSString *title, SCLValidationBlock validationBlock, SCLActionBlock action); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addButtonWithTarget)(NSString *title, id target, SEL selector); + +#pragma mark - Builders +@property(copy, nonatomic) SCLAlertViewBuilder *(^addButtonWithBuilder)(SCLALertViewButtonBuilder *builder); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addTextFieldWithBuilder)(SCLALertViewTextFieldBuilder *builder); + +@end diff --git a/includes/SCLAlertView/SCLAlertView.m b/includes/SCLAlertView/SCLAlertView.m new file mode 100644 index 0000000..20a22dc --- /dev/null +++ b/includes/SCLAlertView/SCLAlertView.m @@ -0,0 +1,2019 @@ +// +// SCLAlertView.m +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertView.h" +#import "SCLAlertViewResponder.h" +#import "SCLAlertViewStyleKit.h" +#import "UIImage+ImageEffects.h" +#import "SCLTimerDisplay.h" +#import "SCLMacros.h" + +#if defined(__has_feature) && __has_feature(modules) +@import AVFoundation; +@import AudioToolbox; +#else +#import +#import +#endif + +#define KEYBOARD_HEIGHT 80 +#define PREDICTION_BAR_HEIGHT 40 +#define ADD_BUTTON_PADDING 10.0f +#define DEFAULT_WINDOW_WIDTH 240 + +@interface SCLAlertView () + +@property (strong, nonatomic) NSMutableArray *inputs; +@property (strong, nonatomic) NSMutableArray *customViews; +@property (strong, nonatomic) NSMutableArray *buttons; +@property (strong, nonatomic) UIImageView *circleIconImageView; +@property (strong, nonatomic) UIView *circleView; +@property (strong, nonatomic) UIView *circleViewBackground; +@property (strong, nonatomic) UIView *contentView; +@property (strong, nonatomic) UIImageView *backgroundView; +@property (strong, nonatomic) UITapGestureRecognizer *gestureRecognizer; +@property (strong, nonatomic) NSString *titleFontFamily; +@property (strong, nonatomic) NSString *bodyTextFontFamily; +@property (strong, nonatomic) NSString *buttonsFontFamily; +@property (strong, nonatomic) UIWindow *previousWindow; +@property (strong, nonatomic) UIWindow *SCLAlertWindow; +@property (copy, nonatomic) SCLDismissBlock dismissBlock; +@property (copy, nonatomic) SCLDismissAnimationCompletionBlock dismissAnimationCompletionBlock; +@property (copy, nonatomic) SCLShowAnimationCompletionBlock showAnimationCompletionBlock; +@property (weak, nonatomic) UIViewController *rootViewController; +@property (weak, nonatomic) id restoreInteractivePopGestureDelegate; +@property (assign, nonatomic) SystemSoundID soundID; +@property (assign, nonatomic) BOOL canAddObservers; +@property (assign, nonatomic) BOOL keyboardIsVisible; +@property (assign, nonatomic) BOOL usingNewWindow; +@property (assign, nonatomic) BOOL restoreInteractivePopGestureEnabled; +@property (nonatomic) CGFloat backgroundOpacity; +@property (nonatomic) CGFloat titleFontSize; +@property (nonatomic) CGFloat bodyFontSize; +@property (nonatomic) CGFloat buttonsFontSize; +@property (nonatomic) CGFloat windowHeight; +@property (nonatomic) CGFloat windowWidth; +@property (nonatomic) CGFloat titleHeight; +@property (nonatomic) CGFloat subTitleHeight; +@property (nonatomic) CGFloat subTitleY; + +@end + +@implementation SCLAlertView + +CGFloat kCircleHeight; +CGFloat kCircleTopPosition; +CGFloat kCircleBackgroundTopPosition; +CGFloat kCircleHeightBackground; +CGFloat kActivityIndicatorHeight; +CGFloat kTitleTop; + +// Timer +NSTimer *durationTimer; +SCLTimerDisplay *buttonTimer; + +#pragma mark - Initialization + +- (instancetype)initWithCoder:(NSCoder *)aDecoder +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"NSCoding not supported" + userInfo:nil]; +} + +- (instancetype)init +{ + self = [super init]; + if (self) + { + [self setupViewWindowWidth:DEFAULT_WINDOW_WIDTH]; + } + return self; +} + +- (instancetype)initWithWindowWidth:(CGFloat)windowWidth +{ + self = [super init]; + if (self) + { + [self setupViewWindowWidth:windowWidth]; + } + return self; +} + +- (instancetype)initWithNewWindow +{ + self = [self initWithWindowWidth:DEFAULT_WINDOW_WIDTH]; + if(self) + { + [self setupNewWindow]; + } + return self; +} + +- (instancetype)initWithNewWindowWidth:(CGFloat)windowWidth +{ + self = [self initWithWindowWidth:windowWidth]; + if(self) + { + [self setupNewWindow]; + } + return self; +} + +- (void)dealloc +{ + [self removeObservers]; + [self restoreInteractivePopGesture]; +} + +- (void)addObservers +{ + if(_canAddObservers) + { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; + _canAddObservers = NO; + } +} + +- (void)removeObservers +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; +} + +#pragma mark - Setup view + +- (void)setupViewWindowWidth:(CGFloat)windowWidth +{ + // Default values + kCircleBackgroundTopPosition = -15.0f; + kCircleHeight = 56.0f; + kCircleHeightBackground = 62.0f; + kActivityIndicatorHeight = 40.0f; + kTitleTop = 30.0f; + self.titleHeight = 40.0f; + self.subTitleY = 70.0f; + self.subTitleHeight = 90.0f; + self.circleIconHeight = 20.0f; + self.windowWidth = windowWidth; + self.windowHeight = 178.0f; + self.shouldDismissOnTapOutside = NO; + self.usingNewWindow = NO; + self.canAddObservers = YES; + self.keyboardIsVisible = NO; + self.hideAnimationType = SCLAlertViewHideAnimationFadeOut; + self.showAnimationType = SCLAlertViewShowAnimationSlideInFromTop; + self.backgroundType = SCLAlertViewBackgroundShadow; + self.tintTopCircle = YES; + + // Font + _titleFontFamily = @"HelveticaNeue"; + _bodyTextFontFamily = @"HelveticaNeue"; + _buttonsFontFamily = @"HelveticaNeue-Bold"; + _titleFontSize = 20.0f; + _bodyFontSize = 14.0f; + _buttonsFontSize = 14.0f; + + // Init + _labelTitle = [[UILabel alloc] init]; + _viewText = [[UITextView alloc] init]; + _viewText.accessibilityTraits = UIAccessibilityTraitStaticText; + _contentView = [[UIView alloc] init]; + _circleView = [[UIView alloc] init]; + _circleViewBackground = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, kCircleHeightBackground, kCircleHeightBackground)]; + _circleIconImageView = [[UIImageView alloc] init]; + _backgroundView = [[UIImageView alloc] initWithFrame:[self mainScreenFrame]]; + _buttons = [[NSMutableArray alloc] init]; + _inputs = [[NSMutableArray alloc] init]; + _customViews = [[NSMutableArray alloc] init]; + self.view.accessibilityViewIsModal = YES; + + // Add Subviews + [self.view addSubview:_contentView]; + [self.view addSubview:_circleViewBackground]; + + // Circle View + CGFloat x = (kCircleHeightBackground - kCircleHeight) / 2; + _circleView.frame = CGRectMake(x, x, kCircleHeight, kCircleHeight); + _circleView.layer.cornerRadius = _circleView.frame.size.height / 2; + + // Circle Background View + _circleViewBackground.backgroundColor = [UIColor whiteColor]; + _circleViewBackground.layer.cornerRadius = _circleViewBackground.frame.size.height / 2; + x = (kCircleHeight - _circleIconHeight) / 2; + + // Circle Image View + _circleIconImageView.frame = CGRectMake(x, x, _circleIconHeight, _circleIconHeight); + _circleIconImageView.contentMode = UIViewContentModeScaleAspectFill; + + [_circleViewBackground addSubview:_circleView]; + [_circleView addSubview:_circleIconImageView]; + + // Background View + _backgroundView.userInteractionEnabled = YES; + + // Title + _labelTitle.numberOfLines = 2; + _labelTitle.lineBreakMode = NSLineBreakByWordWrapping; + _labelTitle.textAlignment = NSTextAlignmentCenter; + _labelTitle.font = [UIFont fontWithName:_titleFontFamily size:_titleFontSize]; + _labelTitle.frame = CGRectMake(12.0f, kTitleTop, _windowWidth - 24.0f, _titleHeight); + + // View text + _viewText.editable = NO; + _viewText.allowsEditingTextAttributes = YES; + _viewText.textAlignment = NSTextAlignmentCenter; + _viewText.font = [UIFont fontWithName:_bodyTextFontFamily size:_bodyFontSize]; + _viewText.frame = CGRectMake(12.0f, _subTitleY, _windowWidth - 24.0f, _subTitleHeight); + _viewText.textContainerInset = UIEdgeInsetsZero; + _viewText.textContainer.lineFragmentPadding = 0; + self.automaticallyAdjustsScrollViewInsets = NO; + + // Content View + _contentView.backgroundColor = [UIColor whiteColor]; + _contentView.layer.cornerRadius = 5.0f; + _contentView.layer.masksToBounds = YES; + _contentView.layer.borderWidth = 0.5f; + [_contentView addSubview:_viewText]; + [_contentView addSubview:_labelTitle]; + + // Colors + self.backgroundViewColor = [UIColor whiteColor]; + _labelTitle.textColor = UIColorFromHEX(0x4D4D4D); //Dark Grey + _viewText.textColor = UIColorFromHEX(0x4D4D4D); //Dark Grey + _contentView.layer.borderColor = UIColorFromHEX(0xCCCCCC).CGColor; //Light Grey +} + +- (void)setupNewWindow { + // Save previous window + self.previousWindow = [UIApplication sharedApplication].keyWindow; + + // Create a new one to show the alert + UIWindow *alertWindow = [[UIWindow alloc] initWithFrame:[self mainScreenFrame]]; + alertWindow.windowLevel = UIWindowLevelAlert; + alertWindow.backgroundColor = [UIColor clearColor]; + alertWindow.rootViewController = [UIViewController new]; + alertWindow.accessibilityViewIsModal = YES; + self.SCLAlertWindow = alertWindow; + self.usingNewWindow = YES; +} + +#pragma mark - Modal Validation + +- (BOOL)isModal { + return (_rootViewController != nil && _rootViewController.presentingViewController); +} + +#pragma mark - View Cycle + +- (void)viewWillLayoutSubviews +{ + [super viewWillLayoutSubviews]; + + CGSize sz = [self mainScreenFrame].size; + + // Check for larger top circle icon flag + if (_useLargerIcon) { + // Adjust icon + _circleIconHeight = 70.0f; + + // Adjust coordinate variables for larger sized top circle + kCircleBackgroundTopPosition = -61.0f; + kCircleHeight = 106.0f; + kCircleHeightBackground = 122.0f; + + // Reposition inner circle appropriately + CGFloat x = (kCircleHeightBackground - kCircleHeight) / 2; + _circleView.frame = CGRectMake(x, x, kCircleHeight, kCircleHeight); + if (_labelTitle.text == nil) { + kTitleTop = kCircleHeightBackground / 2; + } + } else { + kCircleBackgroundTopPosition = -(kCircleHeightBackground / 2); + } + + // Check if the rootViewController is modal, if so we need to get the modal size not the main screen size + if ([self isModal] && !_usingNewWindow) { + sz = _rootViewController.view.frame.size; + } + + // Set new main frame + CGRect r; + if (self.view.superview != nil) { + // View is showing, position at center of screen + r = CGRectMake((sz.width-_windowWidth)/2, (sz.height-_windowHeight)/2, _windowWidth, _windowHeight); + } else { + // View is not visible, position outside screen bounds + r = CGRectMake((sz.width-_windowWidth)/2, -_windowHeight, _windowWidth, _windowHeight); + } + self.view.frame = r; + + // Set new background frame + CGRect newBackgroundFrame = self.backgroundView.frame; + newBackgroundFrame.size = sz; + self.backgroundView.frame = newBackgroundFrame; + + // Set frames + _contentView.frame = CGRectMake(0.0f, 0.0f, _windowWidth, _windowHeight); + _circleViewBackground.frame = CGRectMake(_windowWidth / 2 - kCircleHeightBackground / 2, kCircleBackgroundTopPosition, kCircleHeightBackground, kCircleHeightBackground); + _circleViewBackground.layer.cornerRadius = _circleViewBackground.frame.size.height / 2; + _circleView.layer.cornerRadius = _circleView.frame.size.height / 2; + _circleIconImageView.frame = CGRectMake(kCircleHeight / 2 - _circleIconHeight / 2, kCircleHeight / 2 - _circleIconHeight / 2, _circleIconHeight, _circleIconHeight); + _labelTitle.frame = CGRectMake(12.0f, kTitleTop, _windowWidth - 24.0f, _titleHeight); + + // Text fields + CGFloat y = (_labelTitle.text == nil) ? kTitleTop : (_titleHeight - 10.0f) + _labelTitle.frame.size.height; + _viewText.frame = CGRectMake(12.0f, y, _windowWidth - 24.0f, _subTitleHeight); + + if (!_labelTitle && !_viewText) { + y = 0.0f; + } + + y += _subTitleHeight + 14.0f; + for (SCLTextView *textField in _inputs) { + textField.frame = CGRectMake(12.0f, y, _windowWidth - 24.0f, textField.frame.size.height); + textField.layer.cornerRadius = 3.0f; + y += textField.frame.size.height + 10.0f; + } + + // Custom views + for (UIView *view in _customViews) { + view.frame = CGRectMake(12.0f, y, view.frame.size.width, view.frame.size.height); + y += view.frame.size.height + 10.0f; + } + + // Buttons + CGFloat x = 12.0f; + for (SCLButton *btn in _buttons) { + btn.frame = CGRectMake(x, y, btn.frame.size.width, btn.frame.size.height); + + // Add horizontal or vertical offset acording on _horizontalButtons parameter + if (_horizontalButtons) { + x += btn.frame.size.width + 10.0f; + } else { + y += btn.frame.size.height + 10.0f; + } + } + + // Adapt window height according to icon size + self.windowHeight = _useLargerIcon ? y : self.windowHeight; + _contentView.frame = CGRectMake(_contentView.frame.origin.x, _contentView.frame.origin.y, _windowWidth, _windowHeight); + + // Adjust corner radius, if a value has been passed + _contentView.layer.cornerRadius = self.cornerRadius ? self.cornerRadius : 5.0f; +} + +#pragma mark - UIViewController + +- (BOOL)prefersStatusBarHidden +{ + return self.statusBarHidden; +} + +- (UIStatusBarStyle)preferredStatusBarStyle +{ + return self.statusBarStyle; +} + +#pragma mark - Handle gesture + +- (void)handleTap:(UITapGestureRecognizer *)gesture +{ + if (_shouldDismissOnTapOutside) + { + BOOL hide = _shouldDismissOnTapOutside; + + for(SCLTextView *txt in _inputs) + { + // Check if there is any keyboard on screen and dismiss + if (txt.editing) + { + [txt resignFirstResponder]; + hide = NO; + } + } + if(hide) + { + [self hideView]; + } + } +} + +- (void)setShouldDismissOnTapOutside:(BOOL)shouldDismissOnTapOutside +{ + _shouldDismissOnTapOutside = shouldDismissOnTapOutside; + + if(_shouldDismissOnTapOutside) + { + self.gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; + [_backgroundView addGestureRecognizer:_gestureRecognizer]; + } +} + +- (void)disableInteractivePopGesture +{ + UINavigationController *navigationController; + + if([_rootViewController isKindOfClass:[UINavigationController class]]) + { + navigationController = ((UINavigationController*)_rootViewController); + } + else + { + navigationController = _rootViewController.navigationController; + } + + // Disable iOS 7 back gesture + if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) + { + _restoreInteractivePopGestureEnabled = navigationController.interactivePopGestureRecognizer.enabled; + _restoreInteractivePopGestureDelegate = navigationController.interactivePopGestureRecognizer.delegate; + navigationController.interactivePopGestureRecognizer.enabled = NO; + navigationController.interactivePopGestureRecognizer.delegate = self; + } +} + +- (void)restoreInteractivePopGesture +{ + UINavigationController *navigationController; + + if([_rootViewController isKindOfClass:[UINavigationController class]]) + { + navigationController = ((UINavigationController*)_rootViewController); + } + else + { + navigationController = _rootViewController.navigationController; + } + + // Restore iOS 7 back gesture + if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) + { + navigationController.interactivePopGestureRecognizer.enabled = _restoreInteractivePopGestureEnabled; + navigationController.interactivePopGestureRecognizer.delegate = _restoreInteractivePopGestureDelegate; + } +} + +#pragma mark - Custom Fonts + +- (void)setTitleFontFamily:(NSString *)titleFontFamily withSize:(CGFloat)size +{ + self.titleFontFamily = titleFontFamily; + self.titleFontSize = size; + self.labelTitle.font = [UIFont fontWithName:_titleFontFamily size:_titleFontSize]; +} + +- (void)setBodyTextFontFamily:(NSString *)bodyTextFontFamily withSize:(CGFloat)size +{ + self.bodyTextFontFamily = bodyTextFontFamily; + self.bodyFontSize = size; + self.viewText.font = [UIFont fontWithName:_bodyTextFontFamily size:_bodyFontSize]; +} + +- (void)setButtonsTextFontFamily:(NSString *)buttonsFontFamily withSize:(CGFloat)size +{ + self.buttonsFontFamily = buttonsFontFamily; + self.buttonsFontSize = size; +} + +#pragma mark - Background Color + +- (void)setBackgroundViewColor:(UIColor *)backgroundViewColor +{ + _backgroundViewColor = backgroundViewColor; + _circleViewBackground.backgroundColor = _backgroundViewColor; + _contentView.backgroundColor = _backgroundViewColor; + _viewText.backgroundColor = _backgroundViewColor; +} + +#pragma mark - Sound + +- (void)setSoundURL:(NSURL *)soundURL +{ + _soundURL = soundURL; + + //DisposeSound + AudioServicesDisposeSystemSoundID(_soundID); + + AudioServicesCreateSystemSoundID((__bridge CFURLRef)_soundURL, &_soundID); + + //PlaySound + AudioServicesPlaySystemSound(_soundID); +} + +#pragma mark - Subtitle Height + +- (void)setSubTitleHeight:(CGFloat)value +{ + _subTitleHeight = value; +} + +#pragma mark - ActivityIndicator + +- (void)addActivityIndicatorView +{ + // Add UIActivityIndicatorView + _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + _activityIndicatorView.frame = CGRectMake(kCircleHeight / 2 - kActivityIndicatorHeight / 2, kCircleHeight / 2 - kActivityIndicatorHeight / 2, kActivityIndicatorHeight, kActivityIndicatorHeight); + [_circleView addSubview:_activityIndicatorView]; +} + +#pragma mark - UICustomView + +- (UIView *)addCustomView:(UIView *)customView +{ + // Update view height + self.windowHeight += customView.bounds.size.height + 10.0f; + + [_contentView addSubview:customView]; + [_customViews addObject:customView]; + + return customView; +} + +#pragma mark - SwitchView + +- (SCLSwitchView *)addSwitchViewWithLabel:(NSString *)label +{ + // Add switch view + SCLSwitchView *switchView = [[SCLSwitchView alloc] initWithFrame:CGRectMake(0, 0, self.windowWidth, 31.0f)]; + + // Update view height + self.windowHeight += switchView.bounds.size.height + 10.0f; + + if (label != nil) + { + switchView.labelText = label; + } + + [_contentView addSubview:switchView]; + [_inputs addObject:switchView]; + + return switchView; +} + +#pragma mark - TextField + +- (SCLTextView *)addTextField:(NSString *)title setDefaultText:(NSString *)defaultText +{ + [self addObservers]; + + // Add text field + SCLTextView *txt = [[SCLTextView alloc] init]; + txt.font = [UIFont fontWithName:_bodyTextFontFamily size:_bodyFontSize]; + txt.delegate = self; + + // Update view height + self.windowHeight += txt.bounds.size.height + 10.0f; + + if (title != nil) + { + txt.placeholder = title; + } + if (defaultText != nil) + { + txt.text = defaultText; + } + + [_contentView addSubview:txt]; + [_inputs addObject:txt]; + + // If there are other fields in the inputs array, get the previous field and set the + // return key type on that to next. + if (_inputs.count > 1) + { + NSUInteger indexOfCurrentField = [_inputs indexOfObject:txt]; + SCLTextView *priorField = _inputs[indexOfCurrentField - 1]; + priorField.returnKeyType = UIReturnKeyNext; + } + return txt; +} + +- (void)addCustomTextField:(UITextField *)textField +{ + // Update view height + self.windowHeight += textField.bounds.size.height + 10.0f; + + [_contentView addSubview:textField]; + [_inputs addObject:textField]; + + // If there are other fields in the inputs array, get the previous field and set the + // return key type on that to next. + if (_inputs.count > 1) + { + NSUInteger indexOfCurrentField = [_inputs indexOfObject:textField]; + UITextField *priorField = _inputs[indexOfCurrentField - 1]; + priorField.returnKeyType = UIReturnKeyNext; + } +} + +# pragma mark - UITextFieldDelegate + +- (BOOL)textFieldShouldReturn:(UITextField *)textField +{ + // If this is the last object in the inputs array, resign first responder + // as the form is at the end. + if (textField == _inputs.lastObject) + { + [textField resignFirstResponder]; + } + else // Otherwise find the next field and make it first responder. + { + NSUInteger indexOfCurrentField = [_inputs indexOfObject:textField]; + UITextField *nextField = _inputs[indexOfCurrentField + 1]; + [nextField becomeFirstResponder]; + } + return NO; +} + +- (void)keyboardWillShow:(NSNotification *)notification +{ + if(_keyboardIsVisible) return; + + [UIView animateWithDuration:0.2f animations:^{ + CGRect f = self.view.frame; + f.origin.y -= KEYBOARD_HEIGHT + PREDICTION_BAR_HEIGHT; + self.view.frame = f; + }]; + _keyboardIsVisible = YES; +} + +- (void)keyboardWillHide:(NSNotification *)notification +{ + if(!_keyboardIsVisible) return; + + [UIView animateWithDuration:0.2f animations:^{ + CGRect f = self.view.frame; + f.origin.y += KEYBOARD_HEIGHT + PREDICTION_BAR_HEIGHT; + self.view.frame = f; + }]; + _keyboardIsVisible = NO; +} + +#pragma mark - Buttons + +- (SCLButton *)addButton:(NSString *)title +{ + // Add button + SCLButton *btn = [[SCLButton alloc] initWithWindowWidth:self.windowWidth]; + btn.layer.masksToBounds = YES; + [btn setTitle:title forState:UIControlStateNormal]; + btn.titleLabel.font = [UIFont fontWithName:_buttonsFontFamily size:_buttonsFontSize]; + + [_contentView addSubview:btn]; + [_buttons addObject:btn]; + + if (_horizontalButtons) { + // Update buttons width according to the number of buttons + for (SCLButton *bttn in _buttons) { + [bttn adjustWidthWithWindowWidth:self.windowWidth numberOfButtons:[_buttons count]]; + } + + // Update view height + if (!([_buttons count] > 1)) { + self.windowHeight += (btn.frame.size.height + ADD_BUTTON_PADDING); + } + } else { + // Update view height + self.windowHeight += (btn.frame.size.height + ADD_BUTTON_PADDING); + } + + return btn; +} + +- (SCLButton *)addDoneButtonWithTitle:(NSString *)title +{ + SCLButton *btn = [self addButton:title]; + + if (_completeButtonFormatBlock != nil) + { + btn.completeButtonFormatBlock = _completeButtonFormatBlock; + } + + [btn addTarget:self action:@selector(hideView) forControlEvents:UIControlEventTouchUpInside]; + + return btn; +} + +- (SCLButton *)addButton:(NSString *)title actionBlock:(SCLActionBlock)action +{ + SCLButton *btn = [self addButton:title]; + + if (_buttonFormatBlock != nil) + { + btn.buttonFormatBlock = _buttonFormatBlock; + } + + btn.actionType = SCLBlock; + btn.actionBlock = action; + [btn addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; + + return btn; +} + +- (SCLButton *)addButton:(NSString *)title validationBlock:(SCLValidationBlock)validationBlock actionBlock:(SCLActionBlock)action +{ + SCLButton *btn = [self addButton:title actionBlock:action]; + btn.validationBlock = validationBlock; + + return btn; +} + +- (SCLButton *)addButton:(NSString *)title target:(id)target selector:(SEL)selector +{ + SCLButton *btn = [self addButton:title]; + btn.actionType = SCLSelector; + btn.target = target; + btn.selector = selector; + [btn addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; + + return btn; +} + +- (void)buttonTapped:(SCLButton *)btn +{ + // Cancel Countdown timer + [buttonTimer cancelTimer]; + + // If the button has a validation block, and the validation block returns NO, validation + // failed, so we should bail. + if (btn.validationBlock && !btn.validationBlock()) { + return; + } + + if (btn.actionType == SCLBlock) + { + if (btn.actionBlock) + btn.actionBlock(); + } + else if (btn.actionType == SCLSelector) + { + UIControl *ctrl = [[UIControl alloc] init]; + [ctrl sendAction:btn.selector to:btn.target forEvent:nil]; + } + else + { + NSLog(@"Unknown action type for button"); + } + + if([self isVisible]) + { + [self hideView]; + } +} + +#pragma mark - Button Timer + +- (void)addTimerToButtonIndex:(NSInteger)buttonIndex reverse:(BOOL)reverse +{ + buttonIndex = MAX(buttonIndex, 0); + buttonIndex = MIN(buttonIndex, [_buttons count]); + + buttonTimer = [[SCLTimerDisplay alloc] initWithOrigin:CGPointMake(5, 5) radius:13 lineWidth:4]; + buttonTimer.buttonIndex = buttonIndex; + buttonTimer.reverse = reverse; +} + +#pragma mark - Show Alert + +- (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle duration:(NSTimeInterval)duration completeText:(NSString *)completeText style:(SCLAlertViewStyle)style +{ + if(_usingNewWindow) { + + self.backgroundView.frame = _SCLAlertWindow.bounds; + + // Add window subview + [_SCLAlertWindow.rootViewController addChildViewController:self]; + [_SCLAlertWindow.rootViewController.view addSubview:_backgroundView]; + [_SCLAlertWindow.rootViewController.view addSubview:self.view]; + } else { + _rootViewController = vc; + + [self disableInteractivePopGesture]; + + self.backgroundView.frame = vc.view.bounds; + + // Add view controller subviews + [_rootViewController addChildViewController:self]; + [_rootViewController.view addSubview:_backgroundView]; + [_rootViewController.view addSubview:self.view]; + } + + self.view.alpha = 0.0f; + [self setBackground]; + + // Alert color/icon + UIColor *viewColor; + UIImage *iconImage; + + // Icon style + switch (style) + { + case SCLAlertViewStyleSuccess: + viewColor = UIColorFromHEX(0x22B573); + iconImage = SCLAlertViewStyleKit.imageOfCheckmark; + break; + + case SCLAlertViewStyleError: + viewColor = UIColorFromHEX(0xC1272D); + iconImage = SCLAlertViewStyleKit.imageOfCross; + break; + + case SCLAlertViewStyleNotice: + viewColor = UIColorFromHEX(0x727375); + iconImage = SCLAlertViewStyleKit.imageOfNotice; + break; + + case SCLAlertViewStyleWarning: + viewColor = UIColorFromHEX(0xFFD110); + iconImage = SCLAlertViewStyleKit.imageOfWarning; + break; + + case SCLAlertViewStyleInfo: + viewColor = UIColorFromHEX(0x2866BF); + iconImage = SCLAlertViewStyleKit.imageOfInfo; + break; + + case SCLAlertViewStyleEdit: + viewColor = UIColorFromHEX(0xA429FF); + iconImage = SCLAlertViewStyleKit.imageOfEdit; + break; + + case SCLAlertViewStyleWaiting: + viewColor = UIColorFromHEX(0x6c125d); + break; + + case SCLAlertViewStyleQuestion: + viewColor = UIColorFromHEX(0x727375); + iconImage = SCLAlertViewStyleKit.imageOfQuestion; + break; + + case SCLAlertViewStyleCustom: + viewColor = color; + iconImage = image; + self.circleIconHeight *= 2.0f; + break; + } + + // Custom Alert color + if(_customViewColor) + { + viewColor = _customViewColor; + } + + // Title + if ([title stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length > 0) { + self.labelTitle.text = title; + + // Adjust text view size, if necessary + CGSize sz = CGSizeMake(_windowWidth - 24.0f, CGFLOAT_MAX); + + CGSize size = [_labelTitle sizeThatFits:sz]; + + CGFloat ht = ceilf(size.height); + if (ht > _titleHeight) { + self.windowHeight += (ht - _titleHeight); + self.titleHeight = ht; + self.subTitleY += 20; + } + } else { + // Title is nil, we can move the body message to center and remove it from superView + self.windowHeight -= _labelTitle.frame.size.height; + [_labelTitle removeFromSuperview]; + _labelTitle = nil; + + _subTitleY = kCircleHeight - 20; + } + + // Subtitle + if ([subTitle stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length > 0) { + + // No custom text + if (_attributedFormatBlock == nil) { + _viewText.text = subTitle; + } else { + self.viewText.font = [UIFont fontWithName:_bodyTextFontFamily size:_bodyFontSize]; + _viewText.attributedText = self.attributedFormatBlock(subTitle); + } + + // Adjust text view size, if necessary + CGSize sz = CGSizeMake(_windowWidth - 24.0f, CGFLOAT_MAX); + + CGSize size = [_viewText sizeThatFits:sz]; + + CGFloat ht = ceilf(size.height); + if (ht < _subTitleHeight) { + self.windowHeight -= (_subTitleHeight - ht); + self.subTitleHeight = ht; + } else { + self.windowHeight += (ht - _subTitleHeight); + self.subTitleHeight = ht; + } + } else { + // Subtitle is nil, we can move the title to center and remove it from superView + self.subTitleHeight = 0.0f; + self.windowHeight -= _viewText.frame.size.height; + [_viewText removeFromSuperview]; + _viewText = nil; + + // Move up + _labelTitle.frame = CGRectMake(12.0f, 37.0f, _windowWidth - 24.0f, _titleHeight); + } + + if (!_labelTitle && !_viewText) { + self.windowHeight -= kTitleTop; + } + + // Add button, if necessary + if(completeText != nil) + { + [self addDoneButtonWithTitle:completeText]; + } + + // Alert view color and images + self.circleView.backgroundColor = self.tintTopCircle ? viewColor : _backgroundViewColor; + + if (style == SCLAlertViewStyleWaiting) + { + [self.activityIndicatorView startAnimating]; + } + else + { + if (self.iconTintColor) { + self.circleIconImageView.tintColor = self.iconTintColor; + iconImage = [iconImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } + self.circleIconImageView.image = iconImage; + } + + for (SCLTextView *textField in _inputs) + { + textField.layer.borderColor = viewColor.CGColor; + } + + for (SCLButton *btn in _buttons) + { + if (style == SCLAlertViewStyleWarning) + { + [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + } + + if (!btn.defaultBackgroundColor) { + btn.defaultBackgroundColor = viewColor; + } + + if (btn.completeButtonFormatBlock != nil) + { + [btn parseConfig:btn.completeButtonFormatBlock()]; + } + else if (btn.buttonFormatBlock != nil) + { + [btn parseConfig:btn.buttonFormatBlock()]; + } + } + + // Adding duration + if (duration > 0) + { + [durationTimer invalidate]; + + if (buttonTimer && _buttons.count > 0) + { + SCLButton *btn = _buttons[buttonTimer.buttonIndex]; + btn.timer = buttonTimer; + __weak __typeof(self) weakSelf = self; + [buttonTimer startTimerWithTimeLimit:duration completed:^{ + [weakSelf buttonTapped:btn]; + }]; + } + else + { + durationTimer = [NSTimer scheduledTimerWithTimeInterval:duration + target:self + selector:@selector(hideView) + userInfo:nil + repeats:NO]; + } + } + + if(_usingNewWindow) + { + [_SCLAlertWindow makeKeyAndVisible]; + } + + // Show the alert view + [self showView]; + + // Chainable objects + return [[SCLAlertViewResponder alloc] init:self]; +} + +#pragma mark - Show using UIViewController + +- (void)showSuccess:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleSuccess]; +} + +- (void)showError:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleError]; +} + +- (void)showNotice:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleNotice]; +} + +- (void)showWarning:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleWarning]; +} + +- (void)showInfo:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleInfo]; +} + +- (void)showEdit:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleEdit]; +} + +- (void)showTitle:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:style]; +} + +- (void)showCustom:(UIViewController *)vc image:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:image color:color title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleCustom]; +} + +- (void)showWaiting:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self addActivityIndicatorView]; + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleWaiting]; +} + +- (void)showQuestion:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:vc image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleQuestion]; +} + + +#pragma mark - Show using new window + +- (void)showSuccess:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleSuccess]; +} + +- (void)showError:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleError]; +} + +- (void)showNotice:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleNotice]; +} + +- (void)showWarning:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleWarning]; +} + +- (void)showInfo:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleInfo]; +} + +- (void)showEdit:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleEdit]; +} + +- (void)showTitle:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:style]; +} + +- (void)showCustom:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:nil image:image color:color title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleCustom]; +} + +- (void)showWaiting:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self addActivityIndicatorView]; + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleWaiting]; +} + +- (void)showQuestion:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(NSString *)closeButtonTitle duration:(NSTimeInterval)duration +{ + [self showTitle:nil image:nil color:nil title:title subTitle:subTitle duration:duration completeText:closeButtonTitle style:SCLAlertViewStyleQuestion]; +} + +#pragma mark - Visibility + +- (void)removeTopCircle +{ + [_circleViewBackground removeFromSuperview]; + [_circleView removeFromSuperview]; +} + +- (BOOL)isVisible +{ + return (self.view.alpha); +} + +- (void)alertIsDismissed:(SCLDismissBlock)dismissBlock +{ + self.dismissBlock = dismissBlock; +} + +- (void)alertDismissAnimationIsCompleted:(SCLDismissAnimationCompletionBlock)dismissAnimationCompletionBlock{ + self.dismissAnimationCompletionBlock = dismissAnimationCompletionBlock; +} + +- (void)alertShowAnimationIsCompleted:(SCLShowAnimationCompletionBlock)showAnimationCompletionBlock{ + self.showAnimationCompletionBlock = showAnimationCompletionBlock; +} + +- (SCLForceHideBlock)forceHideBlock:(SCLForceHideBlock)forceHideBlock +{ + _forceHideBlock = forceHideBlock; + + if (_forceHideBlock) + { + [self hideView]; + } + return _forceHideBlock; +} + +- (CGRect)mainScreenFrame +{ + return [self isAppExtension] ? _extensionBounds : [UIApplication sharedApplication].keyWindow.bounds; +} + +- (BOOL)isAppExtension +{ + return [[NSBundle mainBundle].executablePath rangeOfString:@".appex/"].location != NSNotFound; +} + +#pragma mark - Background Effects + +- (void)makeShadowBackground +{ + _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + _backgroundView.backgroundColor = [UIColor blackColor]; + _backgroundView.alpha = 0.7f; + _backgroundOpacity = 0.7f; +} + +- (void)makeBlurBackground +{ + UIView *appView = (_usingNewWindow) ? [UIApplication sharedApplication].keyWindow.subviews.lastObject : _rootViewController.view; + UIImage *image = [UIImage convertViewToImage:appView]; + UIImage *blurSnapshotImage = [image applyBlurWithRadius:5.0f + tintColor:[UIColor colorWithWhite:0.2f + alpha:0.7f] + saturationDeltaFactor:1.8f + maskImage:nil]; + + _backgroundView.image = blurSnapshotImage; + _backgroundView.alpha = 0.0f; + _backgroundOpacity = 1.0f; +} + +- (void)makeTransparentBackground +{ + _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + _backgroundView.backgroundColor = [UIColor clearColor]; + _backgroundView.alpha = 0.0f; + _backgroundOpacity = 1.0f; +} + +- (void)setBackground +{ + switch (_backgroundType) + { + case SCLAlertViewBackgroundShadow: + [self makeShadowBackground]; + break; + + case SCLAlertViewBackgroundBlur: + [self makeBlurBackground]; + break; + + case SCLAlertViewBackgroundTransparent: + [self makeTransparentBackground]; + break; + } +} + +#pragma mark - Show Alert + +- (void)showView +{ + switch (_showAnimationType) + { + case SCLAlertViewShowAnimationFadeIn: + [self fadeIn]; + break; + + case SCLAlertViewShowAnimationSlideInFromBottom: + [self slideInFromBottom]; + break; + + case SCLAlertViewShowAnimationSlideInFromTop: + [self slideInFromTop]; + break; + + case SCLAlertViewShowAnimationSlideInFromLeft: + [self slideInFromLeft]; + break; + + case SCLAlertViewShowAnimationSlideInFromRight: + [self slideInFromRight]; + break; + + case SCLAlertViewShowAnimationSlideInFromCenter: + [self slideInFromCenter]; + break; + + case SCLAlertViewShowAnimationSlideInToCenter: + [self slideInToCenter]; + break; + + case SCLAlertViewShowAnimationSimplyAppear: + [self simplyAppear]; + break; + } +} + +#pragma mark - Hide Alert + +- (void)hideView +{ + switch (_hideAnimationType) + { + case SCLAlertViewHideAnimationFadeOut: + [self fadeOut]; + break; + + case SCLAlertViewHideAnimationSlideOutToBottom: + [self slideOutToBottom]; + break; + + case SCLAlertViewHideAnimationSlideOutToTop: + [self slideOutToTop]; + break; + + case SCLAlertViewHideAnimationSlideOutToLeft: + [self slideOutToLeft]; + break; + + case SCLAlertViewHideAnimationSlideOutToRight: + [self slideOutToRight]; + break; + + case SCLAlertViewHideAnimationSlideOutToCenter: + [self slideOutToCenter]; + break; + + case SCLAlertViewHideAnimationSlideOutFromCenter: + [self slideOutFromCenter]; + break; + + case SCLAlertViewHideAnimationSimplyDisappear: + [self simplyDisappear]; + break; + } + + if (_activityIndicatorView) + { + [_activityIndicatorView stopAnimating]; + } + + if (durationTimer) + { + [durationTimer invalidate]; + } + + if (self.dismissBlock) + { + self.dismissBlock(); + } + + if (_usingNewWindow) + { + // Restore previous window + [self.previousWindow makeKeyAndVisible]; + self.previousWindow = nil; + } + + for (SCLButton *btn in _buttons) + { + btn.actionBlock = nil; + btn.target = nil; + btn.selector = nil; + } +} + +#pragma mark - Hide Animations + +- (void)fadeOut +{ + [self fadeOutWithDuration:0.3f]; +} + +- (void)fadeOutWithDuration:(NSTimeInterval)duration +{ + [UIView animateWithDuration:duration animations:^{ + self.backgroundView.alpha = 0.0f; + self.view.alpha = 0.0f; + } completion:^(BOOL completed) { + [self.backgroundView removeFromSuperview]; + [self.view removeFromSuperview]; + [self removeFromParentViewController]; + + if (self.usingNewWindow) { + // Remove current window + [self.SCLAlertWindow setHidden:YES]; + self.SCLAlertWindow = nil; + } + if ( self.dismissAnimationCompletionBlock ){ + self.dismissAnimationCompletionBlock(); + } + }]; +} + +- (void)slideOutToBottom +{ + [UIView animateWithDuration:0.3f animations:^{ + CGRect frame = self.view.frame; + frame.origin.y += self.backgroundView.frame.size.height; + self.view.frame = frame; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +- (void)slideOutToTop +{ + [UIView animateWithDuration:0.3f animations:^{ + CGRect frame = self.view.frame; + frame.origin.y -= self.backgroundView.frame.size.height; + self.view.frame = frame; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +- (void)slideOutToLeft +{ + [UIView animateWithDuration:0.3f animations:^{ + CGRect frame = self.view.frame; + frame.origin.x -= self.backgroundView.frame.size.width; + self.view.frame = frame; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +- (void)slideOutToRight +{ + [UIView animateWithDuration:0.3f animations:^{ + CGRect frame = self.view.frame; + frame.origin.x += self.backgroundView.frame.size.width; + self.view.frame = frame; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +- (void)slideOutToCenter +{ + [UIView animateWithDuration:0.3f animations:^{ + self.view.transform = + CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(0.1f, 0.1f)); + self.view.alpha = 0.0f; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +- (void)slideOutFromCenter +{ + [UIView animateWithDuration:0.3f animations:^{ + self.view.transform = + CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(3.0f, 3.0f)); + self.view.alpha = 0.0f; + } completion:^(BOOL completed) { + [self fadeOut]; + }]; +} + +- (void)simplyDisappear +{ + self.backgroundView.alpha = self.backgroundOpacity; + self.view.alpha = 1.0f; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self fadeOutWithDuration:0]; + }); +} + + +#pragma mark - Show Animations + +- (void)fadeIn +{ + self.backgroundView.alpha = 0.0f; + self.view.alpha = 0.0f; + + [UIView animateWithDuration:0.3f + delay:0.0f + options:UIViewAnimationOptionCurveEaseIn + animations:^{ + self.backgroundView.alpha = self.backgroundOpacity; + self.view.alpha = 1.0f; + } + completion:^(BOOL finished) { + if ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } + }]; +} + +- (void)slideInFromTop +{ + //From Frame + CGRect frame = self.backgroundView.frame; + frame.origin.y = -self.backgroundView.frame.size.height; + self.view.frame = frame; + + [UIView animateWithDuration:0.5f delay:0.0f usingSpringWithDamping:0.6f initialSpringVelocity:0.5f options:0 animations:^{ + self.backgroundView.alpha = self.backgroundOpacity; + + //To Frame + CGRect frame = self.backgroundView.frame; + frame.origin.y = 0.0f; + self.view.frame = frame; + + self.view.alpha = 1.0f; + } completion:^(BOOL finished) { + if ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } + }]; +} + +- (void)slideInFromBottom +{ + //From Frame + CGRect frame = self.backgroundView.frame; + frame.origin.y = self.backgroundView.frame.size.height; + self.view.frame = frame; + + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = self.backgroundOpacity; + + //To Frame + CGRect frame = self.backgroundView.frame; + frame.origin.y = 0.0f; + self.view.frame = frame; + + self.view.alpha = 1.0f; + } completion:^(BOOL completed) { + [UIView animateWithDuration:0.2f animations:^{ + self.view.center = self.backgroundView.center; + } completion:^(BOOL finished) { + if ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } + }]; + }]; +} + +- (void)slideInFromLeft +{ + //From Frame + CGRect frame = self.backgroundView.frame; + frame.origin.x = -self.backgroundView.frame.size.width; + self.view.frame = frame; + + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = self.backgroundOpacity; + + //To Frame + CGRect frame = self.backgroundView.frame; + frame.origin.x = 0.0f; + self.view.frame = frame; + + self.view.alpha = 1.0f; + } completion:^(BOOL completed) { + [UIView animateWithDuration:0.2f animations:^{ + self.view.center = self.backgroundView.center; + } completion:^(BOOL finished) { + if ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } + }]; + }]; +} + +- (void)slideInFromRight +{ + //From Frame + CGRect frame = self.backgroundView.frame; + frame.origin.x = self.backgroundView.frame.size.width; + self.view.frame = frame; + + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = self.backgroundOpacity; + + //To Frame + CGRect frame = self.backgroundView.frame; + frame.origin.x = 0.0f; + self.view.frame = frame; + + self.view.alpha = 1.0f; + } completion:^(BOOL completed) { + [UIView animateWithDuration:0.2f animations:^{ + self.view.center = self.backgroundView.center; + } completion:^(BOOL finished) { + if ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } + }]; + }]; +} + +- (void)slideInFromCenter +{ + //From Frame + self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(3.0f, 3.0f)); + self.view.alpha = 0.0f; + + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = self.backgroundOpacity; + + //To Frame + self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(1.0f, 1.0f)); + self.view.alpha = 1.0f; + } completion:^(BOOL completed) { + [UIView animateWithDuration:0.2f animations:^{ + self.view.center = self.backgroundView.center; + } completion:^(BOOL finished) { + if ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } + }]; + }]; +} + +- (void)slideInToCenter +{ + //From Frame + self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(0.1f, 0.1f)); + self.view.alpha = 0.0f; + + [UIView animateWithDuration:0.3f animations:^{ + self.backgroundView.alpha = self.backgroundOpacity; + + //To Frame + self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, + CGAffineTransformMakeScale(1.0f, 1.0f)); + self.view.alpha = 1.0f; + } completion:^(BOOL completed) { + [UIView animateWithDuration:0.2f animations:^{ + self.view.center = self.backgroundView.center; + } completion:^(BOOL finished) { + if ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } + }]; + }]; +} + +- (void)simplyAppear +{ + self.backgroundView.alpha = 0.0f; + self.view.alpha = 0.0f; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + self.backgroundView.alpha = self.backgroundOpacity; + self.view.alpha = 1.0f; + if ( self.showAnimationCompletionBlock ){ + self.showAnimationCompletionBlock(); + } + }); +} + + +@end + +@implementation SCLAlertViewBuilder__WithFluent +- (instancetype)init { + if (self = [super init]) { + [self setupFluent]; + } + return self; +} +- (void)setupFluent {} +@end + +@interface SCLALertViewTextFieldBuilder() +#pragma mark - Parameters +@property(copy, nonatomic) NSString *parameterTitle; +@property(copy, nonatomic) NSString *parameterDefaultText; + +#pragma mark - Available later after adding +@property(weak, nonatomic) SCLTextView *textField; + +#pragma mark - Setters +@property(copy, nonatomic) SCLALertViewTextFieldBuilder *(^title) (NSString *title); +@property(copy, nonatomic) SCLALertViewTextFieldBuilder *(^defaultText) (NSString *defaultText); +@end + +@implementation SCLALertViewTextFieldBuilder +- (void)setupFluent { + __weak __auto_type weakSelf = self; + self.title = ^(NSString *title){ + weakSelf.parameterTitle = title; + return weakSelf; + }; + self.defaultText = ^(NSString *defaultText){ + weakSelf.parameterDefaultText = defaultText; + return weakSelf; + }; +} +@end + +@interface SCLALertViewButtonBuilder() + +#pragma mark - Parameters +@property(copy, nonatomic) NSString *parameterTitle; +@property(copy, nonatomic) NSString *parameterDefaultText; +@property(weak, nonatomic) id parameterTarget; +@property(assign, nonatomic) SEL parameterSelector; +@property(copy, nonatomic) void(^parameterActionBlock)(void); +@property(copy, nonatomic) BOOL(^parameterValidationBlock)(void); + +#pragma mark - Available later after adding +@property(weak, nonatomic) SCLButton *button; + +#pragma mark - Setters +@property(copy, nonatomic) SCLALertViewButtonBuilder *(^title) (NSString *title); +@property(copy, nonatomic) SCLALertViewButtonBuilder *(^defaultText) (NSString *defaultText); +@property(copy, nonatomic) SCLALertViewButtonBuilder *(^target) (id target); +@property(copy, nonatomic) SCLALertViewButtonBuilder *(^selector) (SEL selector); +@property(copy, nonatomic) SCLALertViewButtonBuilder *(^actionBlock) (void(^actionBlock)(void)); +@property(copy, nonatomic) SCLALertViewButtonBuilder *(^validationBlock) (BOOL(^validationBlock)(void)); + +@end + +@implementation SCLALertViewButtonBuilder +- (void)setupFluent { + __weak __auto_type weakSelf = self; + self.title = ^(NSString *title){ + weakSelf.parameterTitle = title; + return weakSelf; + }; + self.defaultText = ^(NSString *defaultText){ + weakSelf.parameterDefaultText = defaultText; + return weakSelf; + }; + self.target = ^(id target){ + weakSelf.parameterTarget = target; + return weakSelf; + }; + self.selector = ^(SEL selector){ + weakSelf.parameterSelector = selector; + return weakSelf; + }; + self.actionBlock = ^(void(^actionBlock)(void)){ + weakSelf.parameterActionBlock = actionBlock; + return weakSelf; + }; + self.validationBlock = ^(BOOL(^validationBlock)(void)){ + weakSelf.parameterValidationBlock = validationBlock; + return weakSelf; + }; +} + +@end + + +@interface SCLAlertViewBuilder() + +@property (strong, nonatomic) SCLAlertView *alertView; + +@end + +@implementation SCLAlertViewBuilder + +- (void)setupFluent { + __weak __auto_type weakSelf = self; + self.cornerRadius = ^(CGFloat cornerRadius) { + weakSelf.alertView.cornerRadius = cornerRadius; + return weakSelf; + }; + self.tintTopCircle = ^(BOOL tintTopCircle) { + weakSelf.alertView.tintTopCircle = tintTopCircle; + return weakSelf; + }; + self.useLargerIcon = ^(BOOL useLargerIcon) { + weakSelf.alertView.useLargerIcon = useLargerIcon; + return weakSelf; + }; + self.labelTitle = ^(UILabel *labelTitle) { + weakSelf.alertView.labelTitle = labelTitle; + return weakSelf; + }; + self.viewText = ^(UITextView *viewText) { + weakSelf.alertView.viewText = viewText; + return weakSelf; + }; + self.activityIndicatorView = ^(UIActivityIndicatorView *activityIndicatorView) { + weakSelf.alertView.activityIndicatorView = activityIndicatorView; + return weakSelf; + }; + self.shouldDismissOnTapOutside = ^(BOOL shouldDismissOnTapOutside) { + weakSelf.alertView.shouldDismissOnTapOutside = shouldDismissOnTapOutside; + return weakSelf; + }; + self.soundURL = ^(NSURL *soundURL) { + weakSelf.alertView.soundURL = soundURL; + return weakSelf; + }; + self.attributedFormatBlock = ^(SCLAttributedFormatBlock attributedFormatBlock) { + weakSelf.alertView.attributedFormatBlock = attributedFormatBlock; + return weakSelf; + }; + self.completeButtonFormatBlock = ^(CompleteButtonFormatBlock completeButtonFormatBlock) { + weakSelf.alertView.completeButtonFormatBlock = completeButtonFormatBlock; + return weakSelf; + }; + self.buttonFormatBlock = ^(ButtonFormatBlock buttonFormatBlock) { + weakSelf.alertView.buttonFormatBlock = buttonFormatBlock; + return weakSelf; + }; + self.forceHideBlock = ^(SCLForceHideBlock forceHideBlock) { + weakSelf.alertView.forceHideBlock = forceHideBlock; + return weakSelf; + }; + self.hideAnimationType = ^(SCLAlertViewHideAnimation hideAnimationType) { + weakSelf.alertView.hideAnimationType = hideAnimationType; + return weakSelf; + }; + self.showAnimationType = ^(SCLAlertViewShowAnimation showAnimationType) { + weakSelf.alertView.showAnimationType = showAnimationType; + return weakSelf; + }; + self.backgroundType = ^(SCLAlertViewBackground backgroundType) { + weakSelf.alertView.backgroundType = backgroundType; + return weakSelf; + }; + self.customViewColor = ^(UIColor *customViewColor) { + weakSelf.alertView.customViewColor = customViewColor; + return weakSelf; + }; + self.backgroundViewColor = ^(UIColor *backgroundViewColor) { + weakSelf.alertView.backgroundViewColor = backgroundViewColor; + return weakSelf; + }; + self.iconTintColor = ^(UIColor *iconTintColor) { + weakSelf.alertView.iconTintColor = iconTintColor; + return weakSelf; + }; + self.circleIconHeight = ^(CGFloat circleIconHeight) { + weakSelf.alertView.circleIconHeight = circleIconHeight; + return weakSelf; + }; + self.extensionBounds = ^(CGRect extensionBounds) { + weakSelf.alertView.extensionBounds = extensionBounds; + return weakSelf; + }; + self.statusBarHidden = ^(BOOL statusBarHidden) { + weakSelf.alertView.statusBarHidden = statusBarHidden; + return weakSelf; + }; + self.statusBarStyle = ^(UIStatusBarStyle statusBarStyle) { + weakSelf.alertView.statusBarStyle = statusBarStyle; + return weakSelf; + }; + self.alertIsDismissed = ^(SCLDismissBlock dismissBlock) { + [weakSelf.alertView alertIsDismissed:dismissBlock]; + return weakSelf; + }; + self.alertDismissAnimationIsCompleted = ^(SCLDismissAnimationCompletionBlock dismissAnimationCompletionBlock) { + [weakSelf.alertView alertDismissAnimationIsCompleted:dismissAnimationCompletionBlock]; + return weakSelf; + }; + self.alertShowAnimationIsCompleted = ^(SCLShowAnimationCompletionBlock showAnimationCompletionBlock) { + [weakSelf.alertView alertShowAnimationIsCompleted:showAnimationCompletionBlock]; + return weakSelf; + }; + self.removeTopCircle = ^(void) { + [weakSelf.alertView removeTopCircle]; + return weakSelf; + }; + self.addCustomView = ^(UIView *view) { + [weakSelf.alertView addCustomView:view]; + return weakSelf; + }; + self.addTextField = ^(NSString *title, NSString *defaultText) { + [weakSelf.alertView addTextField:title setDefaultText:defaultText]; + return weakSelf; + }; + self.addCustomTextField = ^(UITextField *textField) { + [weakSelf.alertView addCustomTextField:textField]; + return weakSelf; + }; + self.addSwitchViewWithLabelTitle = ^(NSString *title) { + [weakSelf.alertView addSwitchViewWithLabel:title]; + return weakSelf; + }; + self.addTimerToButtonIndex = ^(NSInteger buttonIndex, BOOL reverse) { + [weakSelf.alertView addTimerToButtonIndex:buttonIndex reverse:reverse]; + return weakSelf; + }; + self.setTitleFontFamily = ^(NSString *titleFontFamily, CGFloat size) { + [weakSelf.alertView setTitleFontFamily:titleFontFamily withSize:size]; + return weakSelf; + }; + self.setBodyTextFontFamily = ^(NSString *bodyTextFontFamily, CGFloat size) { + [weakSelf.alertView setBodyTextFontFamily:bodyTextFontFamily withSize:size]; + return weakSelf; + }; + self.setButtonsTextFontFamily = ^(NSString *buttonsFontFamily, CGFloat size) { + [weakSelf.alertView setButtonsTextFontFamily:buttonsFontFamily withSize:size]; + return weakSelf; + }; + self.addButtonWithActionBlock = ^(NSString *title, SCLActionBlock action) { + [weakSelf.alertView addButton:title actionBlock:action]; + return weakSelf; + }; + self.addButtonWithValidationBlock = ^(NSString *title, SCLValidationBlock validationBlock, SCLActionBlock action) { + [weakSelf.alertView addButton:title validationBlock:validationBlock actionBlock:action]; + return weakSelf; + }; + self.addButtonWithTarget = ^(NSString *title, id target, SEL selector) { + [weakSelf.alertView addButton:title target:target selector:selector]; + return weakSelf; + }; + + self.addButtonWithBuilder = ^(SCLALertViewButtonBuilder *builder){ + SCLButton *button = nil; + if (builder.parameterTarget && builder.parameterSelector) { + button = [weakSelf.alertView addButton:builder.parameterTitle target:builder.parameterTarget selector:builder.parameterSelector]; + } + else if (builder.parameterValidationBlock && builder.parameterActionBlock) { + button = [weakSelf.alertView addButton:builder.parameterTitle validationBlock:builder.parameterValidationBlock actionBlock:builder.parameterActionBlock]; + } + else if (builder.parameterActionBlock) { + button = [weakSelf.alertView addButton:builder.parameterTitle actionBlock:builder.parameterActionBlock]; + } + builder.button = button; + return weakSelf; + }; + + self.addTextFieldWithBuilder = ^(SCLALertViewTextFieldBuilder *builder){ + builder.textField = [weakSelf.alertView addTextField:builder.parameterTitle setDefaultText:builder.parameterDefaultText]; + return weakSelf; + }; +} + +#pragma mark - Init + +- (instancetype)init { + self = [super init]; + if (self) { + self.alertView = [[SCLAlertView alloc] init]; + } + return self; +} +- (instancetype)initWithNewWindow { + self = [super init]; + if (self) { + self.alertView = [[SCLAlertView alloc] initWithNewWindow]; + } + return self; +} + +- (instancetype)initWithNewWindowWidth:(CGFloat)width { + self = [super init]; + if (self) { + self.alertView = [[SCLAlertView alloc] initWithNewWindowWidth:width]; + } + return self; +} +@end + +@interface SCLAlertViewShowBuilder() + +@property(weak, nonatomic) UIViewController *parameterViewController; +@property(copy, nonatomic) UIImage *parameterImage; +@property(copy, nonatomic) UIColor *parameterColor; +@property(copy, nonatomic) NSString *parameterTitle; +@property(copy, nonatomic) NSString *parameterDefaultText; +@property(copy, nonatomic) NSString *parameterSubTitle; +@property(copy, nonatomic) NSString *parameterCompleteText; +@property(copy, nonatomic) NSString *parameterCloseButtonTitle; +@property(assign, nonatomic) SCLAlertViewStyle parameterStyle; +@property(assign, nonatomic) NSTimeInterval parameterDuration; + +#pragma mark - Setters +@property(copy, nonatomic) SCLAlertViewShowBuilder *(^viewController)(UIViewController *viewController); +@property(copy, nonatomic) SCLAlertViewShowBuilder *(^image)(UIImage *image); +@property(copy, nonatomic) SCLAlertViewShowBuilder *(^color)(UIColor *color); +@property(copy, nonatomic) SCLAlertViewShowBuilder *(^title)(NSString *title); +@property(copy, nonatomic) SCLAlertViewShowBuilder *(^subTitle)(NSString *subTitle); +@property(copy, nonatomic) SCLAlertViewShowBuilder *(^completeText)(NSString *completeText); +@property(copy, nonatomic) SCLAlertViewShowBuilder *(^style)(SCLAlertViewStyle style); +@property(copy, nonatomic) SCLAlertViewShowBuilder *(^closeButtonTitle)(NSString *closeButtonTitle); +@property(copy, nonatomic) SCLAlertViewShowBuilder *(^duration)(NSTimeInterval duration); + +#pragma mark - Show +@property(copy, nonatomic) void (^show)(SCLAlertView *view, UIViewController *controller); +@end + +@implementation SCLAlertViewShowBuilder + +- (void)setupFluent { + __weak __auto_type weakSelf = self; + self.viewController = ^(UIViewController *viewController){ + weakSelf.parameterViewController = viewController; + return weakSelf; + }; + self.image = ^(UIImage *image) { + weakSelf.parameterImage = image; + return weakSelf; + }; + self.color = ^(UIColor *color) { + weakSelf.parameterColor = color; + return weakSelf; + }; + self.title = ^(NSString *title){ + weakSelf.parameterTitle = title; + return weakSelf; + }; + self.subTitle = ^(NSString *subTitle){ + weakSelf.parameterSubTitle = subTitle; + return weakSelf; + }; + self.completeText = ^(NSString *completeText){ + weakSelf.parameterCompleteText = completeText; + return weakSelf; + }; + self.style = ^(SCLAlertViewStyle style){ + weakSelf.parameterStyle = style; + return weakSelf; + }; + self.closeButtonTitle = ^(NSString *closeButtonTitle){ + weakSelf.parameterCloseButtonTitle = closeButtonTitle; + return weakSelf; + }; + self.duration = ^(NSTimeInterval duration){ + weakSelf.parameterDuration = duration; + return weakSelf; + }; + self.show = ^(SCLAlertView *view, UIViewController *controller) { + [weakSelf showAlertView:view onViewController:controller]; + }; +} + +#pragma mark - Setters + +- (void)showAlertView:(SCLAlertView *)alertView { + [self showAlertView:alertView onViewController:self.parameterViewController]; +} + +- (void)showAlertView:(SCLAlertView *)alertView onViewController:(UIViewController *)controller { + UIViewController *targetController = controller ? controller : self.parameterViewController; + + if (self.parameterImage || self.parameterColor) { + [alertView showTitle:targetController image:self.parameterImage color:self.parameterColor title:self.parameterTitle subTitle:self.parameterSubTitle duration:self.parameterDuration completeText:self.parameterCloseButtonTitle style:self.parameterStyle]; + } + else { + [alertView showTitle:targetController title:self.parameterTitle subTitle:self.parameterSubTitle style:self.parameterStyle closeButtonTitle:self.parameterCloseButtonTitle duration:self.parameterDuration]; + } +} + +@end diff --git a/includes/SCLAlertView/SCLAlertViewResponder.h b/includes/SCLAlertView/SCLAlertViewResponder.h new file mode 100644 index 0000000..0dfb77b --- /dev/null +++ b/includes/SCLAlertView/SCLAlertViewResponder.h @@ -0,0 +1,30 @@ +// +// SCLAlertViewResponder.h +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// + +#if defined(__has_feature) && __has_feature(modules) +@import Foundation; +#else +#import +#endif +#import "SCLAlertView.h" + +@interface SCLAlertViewResponder : NSObject + +/** TODO + * + * TODO + */ +- (instancetype)init:(SCLAlertView *)alertview; + +/** TODO + * + * TODO + */ +- (void)close; + +@end diff --git a/includes/SCLAlertView/SCLAlertViewResponder.m b/includes/SCLAlertView/SCLAlertViewResponder.m new file mode 100644 index 0000000..847ed9d --- /dev/null +++ b/includes/SCLAlertView/SCLAlertViewResponder.m @@ -0,0 +1,45 @@ +// +// SCLAlertViewResponder.m +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewResponder.h" + +@interface SCLAlertViewResponder () + +@property SCLAlertView *alertview; + +@end + +@implementation SCLAlertViewResponder + +// +//// Allow alerts to be closed/renamed in a chainable manner +//// Example: SCLAlertView().showSuccess(self, title: "Test", subTitle: "Value").close() + +// Initialisation and Title/Subtitle/Close functions +- (instancetype)init:(SCLAlertView *)alertview +{ + self.alertview = alertview; + return self; +} + +- (void)setTitletitle:(NSString *)title +{ + self.alertview.labelTitle.text = title; +} + +- (void)setSubTitle:(NSString *)subTitle +{ + self.alertview.viewText.text = subTitle; +} + +- (void)close +{ + [self.alertview hideView]; +} + +@end diff --git a/includes/SCLAlertView/SCLAlertViewStyleKit.h b/includes/SCLAlertView/SCLAlertViewStyleKit.h new file mode 100644 index 0000000..9d7cc05 --- /dev/null +++ b/includes/SCLAlertView/SCLAlertViewStyleKit.h @@ -0,0 +1,105 @@ +// +// SCLAlertViewStyleKit.h +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// + +#if defined(__has_feature) && __has_feature(modules) +@import Foundation; +@import UIKit; +#else +#import +#import +#endif +#import "SCLButton.h" + +@interface SCLAlertViewStyleKit : NSObject + +// Images +/** TODO + * + * TODO + */ ++ (UIImage *)imageOfCheckmark; + +/** TODO + * + * TODO + */ ++ (UIImage *)imageOfCross; + +/** TODO + * + * TODO + */ ++ (UIImage *)imageOfNotice; + +/** TODO + * + * TODO + */ ++ (UIImage *)imageOfWarning; + +/** TODO + * + * TODO + */ ++ (UIImage *)imageOfInfo; + +/** TODO + * + * TODO + */ ++ (UIImage *)imageOfEdit; + +/** TODO + * + * TODO + */ ++ (UIImage *)imageOfQuestion; + +/** TODO + * + * TODO + */ ++ (void)drawCheckmark; + +/** TODO + * + * TODO + */ ++ (void)drawCross; + +/** TODO + * + * TODO + */ ++ (void)drawNotice; + +/** TODO + * + * TODO + */ ++ (void)drawWarning; + +/** TODO + * + * TODO + */ ++ (void)drawInfo; + +/** TODO + * + * TODO + */ ++ (void)drawEdit; + +/** TODO + * + * TODO + */ ++ (void)drawQuestion; + +@end diff --git a/includes/SCLAlertView/SCLAlertViewStyleKit.m b/includes/SCLAlertView/SCLAlertViewStyleKit.m new file mode 100644 index 0000000..f467f47 --- /dev/null +++ b/includes/SCLAlertView/SCLAlertViewStyleKit.m @@ -0,0 +1,380 @@ +// +// SCLAlertViewStyleKit.m +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewStyleKit.h" + +// ------------------------------------ +// Icon drawing +// Code generated by PaintCode +// ------------------------------------ +@implementation SCLAlertViewStyleKit + +#pragma mark - Cache + +static UIImage *imageOfCheckmark = nil; +static UIImage *imageOfCross = nil; +static UIImage *imageOfNotice = nil; +static UIImage *imageOfWarning = nil; +static UIImage *imageOfInfo = nil; +static UIImage *imageOfEdit = nil; +static UIImage *imageOfQuestion = nil; + +#pragma mark - Initialization + ++ (void)initialize +{ + // Do something +} + +#pragma mark - Drawing Methods + ++ (void)drawCheckmark +{ + // Checkmark Shape Drawing + UIBezierPath *checkmarkShapePath = [[UIBezierPath alloc] init]; + [checkmarkShapePath moveToPoint:CGPointMake(73.25, 14.05)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(64.51, 13.86) controlPoint1: CGPointMake(70.98, 11.44) controlPoint2: CGPointMake(66.78, 11.26)]; + [checkmarkShapePath addLineToPoint:CGPointMake(27.46, 52)]; + [checkmarkShapePath addLineToPoint:CGPointMake(15.75, 39.54)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(6.84, 39.54) controlPoint1: CGPointMake(13.48, 36.93) controlPoint2: CGPointMake(9.28, 36.93)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(6.84, 49.02) controlPoint1: CGPointMake(4.39, 42.14) controlPoint2: CGPointMake(4.39, 46.42)]; + [checkmarkShapePath addLineToPoint:CGPointMake(22.91, 66.14)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(27.28, 68) controlPoint1: CGPointMake(24.14, 67.44) controlPoint2: CGPointMake(25.71, 68)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(31.65, 66.14) controlPoint1: CGPointMake(28.86, 68) controlPoint2: CGPointMake(30.43, 67.26)]; + [checkmarkShapePath addLineToPoint:CGPointMake(73.08, 23.35)]; + [checkmarkShapePath addCurveToPoint:CGPointMake(73.25, 14.05) controlPoint1: CGPointMake(75.52, 20.75) controlPoint2: CGPointMake(75.7, 16.65)]; + [checkmarkShapePath closePath]; + checkmarkShapePath.miterLimit = 4; + + [[UIColor whiteColor] setFill]; + [checkmarkShapePath fill]; +} + ++ (void)drawCross +{ + // Cross Shape Drawing + UIBezierPath *crossShapePath = [[UIBezierPath alloc] init]; + [crossShapePath moveToPoint:CGPointMake(10, 70)]; + [crossShapePath addLineToPoint:CGPointMake(70, 10)]; + [crossShapePath moveToPoint:CGPointMake(10, 10)]; + [crossShapePath addLineToPoint:CGPointMake(70, 70)]; + + crossShapePath.lineCapStyle = kCGLineCapRound; + crossShapePath.lineJoinStyle = kCGLineJoinRound; + + [[UIColor whiteColor] setStroke]; + crossShapePath.lineWidth = 14; + [crossShapePath stroke]; +} + ++ (void)drawNotice +{ + // Notice Shape Drawing + UIBezierPath *noticeShapePath = [[UIBezierPath alloc] init]; + [noticeShapePath moveToPoint:CGPointMake(72, 48.54)]; + [noticeShapePath addLineToPoint:CGPointMake(72, 39.9)]; + [noticeShapePath addCurveToPoint:CGPointMake(66.38, 34.01) controlPoint1: CGPointMake(72, 36.76) controlPoint2: CGPointMake(69.48, 34.01)]; + [noticeShapePath addCurveToPoint:CGPointMake(61.53, 35.97) controlPoint1: CGPointMake(64.82, 34.01) controlPoint2: CGPointMake(62.69, 34.8)]; + [noticeShapePath addCurveToPoint:CGPointMake(60.36, 35.78) controlPoint1: CGPointMake(61.33, 35.97) controlPoint2: CGPointMake(62.3, 35.78)]; + [noticeShapePath addLineToPoint:CGPointMake(60.36, 33.22)]; + [noticeShapePath addCurveToPoint:CGPointMake(54.16, 26.16) controlPoint1: CGPointMake(60.36, 29.3) controlPoint2: CGPointMake(57.65, 26.16)]; + [noticeShapePath addCurveToPoint:CGPointMake(48.73, 29.89) controlPoint1: CGPointMake(51.64, 26.16) controlPoint2: CGPointMake(50.67, 27.73)]; + [noticeShapePath addLineToPoint:CGPointMake(48.73, 28.71)]; + [noticeShapePath addCurveToPoint:CGPointMake(43.49, 21.64) controlPoint1: CGPointMake(48.73, 24.78) controlPoint2: CGPointMake(46.98, 21.64)]; + [noticeShapePath addCurveToPoint:CGPointMake(39.03, 25.37) controlPoint1: CGPointMake(40.97, 21.64) controlPoint2: CGPointMake(39.03, 23.01)]; + [noticeShapePath addLineToPoint:CGPointMake(39.03, 9.07)]; + [noticeShapePath addCurveToPoint:CGPointMake(32.24, 2) controlPoint1: CGPointMake(39.03, 5.14) controlPoint2: CGPointMake(35.73, 2)]; + [noticeShapePath addCurveToPoint:CGPointMake(25.45, 9.07) controlPoint1: CGPointMake(28.56, 2) controlPoint2: CGPointMake(25.45, 5.14)]; + [noticeShapePath addLineToPoint:CGPointMake(25.45, 41.47)]; + [noticeShapePath addCurveToPoint:CGPointMake(24.29, 43.44) controlPoint1: CGPointMake(25.45, 42.45) controlPoint2: CGPointMake(24.68, 43.04)]; + [noticeShapePath addCurveToPoint:CGPointMake(9.55, 43.04) controlPoint1: CGPointMake(16.73, 40.88) controlPoint2: CGPointMake(11.88, 40.69)]; + [noticeShapePath addCurveToPoint:CGPointMake(8, 46.58) controlPoint1: CGPointMake(8.58, 43.83) controlPoint2: CGPointMake(8, 45.2)]; + [noticeShapePath addCurveToPoint:CGPointMake(14.4, 55.81) controlPoint1: CGPointMake(8.19, 50.31) controlPoint2: CGPointMake(12.07, 53.84)]; + [noticeShapePath addLineToPoint:CGPointMake(27.2, 69.56)]; + [noticeShapePath addCurveToPoint:CGPointMake(42.91, 77.8) controlPoint1: CGPointMake(30.5, 74.47) controlPoint2: CGPointMake(35.73, 77.21)]; + [noticeShapePath addCurveToPoint:CGPointMake(43.88, 77.8) controlPoint1: CGPointMake(43.3, 77.8) controlPoint2: CGPointMake(43.68, 77.8)]; + [noticeShapePath addCurveToPoint:CGPointMake(47.18, 78) controlPoint1: CGPointMake(45.04, 77.8) controlPoint2: CGPointMake(46.01, 78)]; + [noticeShapePath addLineToPoint:CGPointMake(48.34, 78)]; + [noticeShapePath addLineToPoint:CGPointMake(48.34, 78)]; + [noticeShapePath addCurveToPoint:CGPointMake(71.61, 52.08) controlPoint1: CGPointMake(56.48, 78) controlPoint2: CGPointMake(69.87, 75.05)]; + [noticeShapePath addCurveToPoint:CGPointMake(72, 48.54) controlPoint1: CGPointMake(71.81, 51.29) controlPoint2: CGPointMake(72, 49.72)]; + [noticeShapePath closePath]; + noticeShapePath.miterLimit = 4; + + [[UIColor whiteColor] setFill]; + [noticeShapePath fill]; +} + ++ (void)drawWarning +{ + // Color Declarations + UIColor *greyColor = [UIColor colorWithRed:0.236 green:0.236 blue:0.236 alpha:1.000]; + + // Warning Group + // Warning Circle Drawing + UIBezierPath *warningCirclePath = [[UIBezierPath alloc] init]; + [warningCirclePath moveToPoint:CGPointMake(40.94, 63.39)]; + [warningCirclePath addCurveToPoint:CGPointMake(36.03, 65.55) controlPoint1: CGPointMake(39.06, 63.39) controlPoint2: CGPointMake(37.36, 64.18)]; + [warningCirclePath addCurveToPoint:CGPointMake(34.14, 70.45) controlPoint1: CGPointMake(34.9, 66.92) controlPoint2: CGPointMake(34.14, 68.49)]; + [warningCirclePath addCurveToPoint:CGPointMake(36.22, 75.54) controlPoint1: CGPointMake(34.14, 72.41) controlPoint2: CGPointMake(34.9, 74.17)]; + [warningCirclePath addCurveToPoint:CGPointMake(40.94, 77.5) controlPoint1: CGPointMake(37.54, 76.91) controlPoint2: CGPointMake(39.06, 77.5)]; + [warningCirclePath addCurveToPoint:CGPointMake(45.86, 75.35) controlPoint1: CGPointMake(42.83, 77.5) controlPoint2: CGPointMake(44.53, 76.72)]; + [warningCirclePath addCurveToPoint:CGPointMake(47.93, 70.45) controlPoint1: CGPointMake(47.18, 74.17) controlPoint2: CGPointMake(47.93, 72.41)]; + [warningCirclePath addCurveToPoint:CGPointMake(45.86, 65.35) controlPoint1: CGPointMake(47.93, 68.49) controlPoint2: CGPointMake(47.18, 66.72)]; + [warningCirclePath addCurveToPoint:CGPointMake(40.94, 63.39) controlPoint1: CGPointMake(44.53, 64.18) controlPoint2: CGPointMake(42.83, 63.39)]; + [warningCirclePath closePath]; + warningCirclePath.miterLimit = 4; + + [greyColor setFill]; + [warningCirclePath fill]; + + + //// Warning Shape Drawing + UIBezierPath *warningShapePath = [[UIBezierPath alloc] init]; + [warningShapePath moveToPoint:CGPointMake(46.23, 4.26)]; + [warningShapePath addCurveToPoint:CGPointMake(40.94, 2.5) controlPoint1: CGPointMake(44.91, 3.09) controlPoint2: CGPointMake(43.02, 2.5)]; + [warningShapePath addCurveToPoint:CGPointMake(34.71, 4.26) controlPoint1: CGPointMake(38.68, 2.5) controlPoint2: CGPointMake(36.03, 3.09)]; + [warningShapePath addCurveToPoint:CGPointMake(31.5, 8.77) controlPoint1: CGPointMake(33.01, 5.44) controlPoint2: CGPointMake(31.5, 7.01)]; + [warningShapePath addLineToPoint:CGPointMake(31.5, 19.36)]; + [warningShapePath addLineToPoint:CGPointMake(34.71, 54.44)]; + [warningShapePath addCurveToPoint:CGPointMake(40.38, 58.16) controlPoint1: CGPointMake(34.9, 56.2) controlPoint2: CGPointMake(36.41, 58.16)]; + [warningShapePath addCurveToPoint:CGPointMake(45.67, 54.44) controlPoint1: CGPointMake(44.34, 58.16) controlPoint2: CGPointMake(45.67, 56.01)]; + [warningShapePath addLineToPoint:CGPointMake(48.5, 19.36)]; + [warningShapePath addLineToPoint:CGPointMake(48.5, 8.77)]; + [warningShapePath addCurveToPoint:CGPointMake(46.23, 4.26) controlPoint1: CGPointMake(48.5, 7.01) controlPoint2: CGPointMake(47.74, 5.44)]; + [warningShapePath closePath]; + warningShapePath.miterLimit = 4; + + [greyColor setFill]; + [warningShapePath fill]; +} + ++ (void)drawInfo +{ + // Color Declarations + UIColor *color0 = [UIColor colorWithRed:1.000 green:1.000 blue:1.000 alpha:1.000]; + + // Info Shape Drawing + UIBezierPath *infoShapePath = [[UIBezierPath alloc] init]; + [infoShapePath moveToPoint:CGPointMake(45.66, 15.96)]; + [infoShapePath addCurveToPoint:CGPointMake(45.66, 5.22) controlPoint1: CGPointMake(48.78, 12.99) controlPoint2: CGPointMake(48.78, 8.19)]; + [infoShapePath addCurveToPoint:CGPointMake(34.34, 5.22) controlPoint1: CGPointMake(42.53, 2.26) controlPoint2: CGPointMake(37.47, 2.26)]; + [infoShapePath addCurveToPoint:CGPointMake(34.34, 15.96) controlPoint1: CGPointMake(31.22, 8.19) controlPoint2: CGPointMake(31.22, 12.99)]; + [infoShapePath addCurveToPoint:CGPointMake(45.66, 15.96) controlPoint1: CGPointMake(37.47, 18.92) controlPoint2: CGPointMake(42.53, 18.92)]; + [infoShapePath closePath]; + + [infoShapePath moveToPoint:CGPointMake(48, 69.41)]; + [infoShapePath addCurveToPoint:CGPointMake(40, 77) controlPoint1: CGPointMake(48, 73.58) controlPoint2: CGPointMake(44.4, 77)]; + [infoShapePath addLineToPoint:CGPointMake(40, 77)]; + [infoShapePath addCurveToPoint:CGPointMake(32, 69.41) controlPoint1: CGPointMake(35.6, 77) controlPoint2: CGPointMake(32, 73.58)]; + [infoShapePath addLineToPoint:CGPointMake(32, 35.26)]; + [infoShapePath addCurveToPoint:CGPointMake(40, 27.67) controlPoint1: CGPointMake(32, 31.08) controlPoint2: CGPointMake(35.6, 27.67)]; + [infoShapePath addLineToPoint:CGPointMake(40, 27.67)]; + [infoShapePath addCurveToPoint:CGPointMake(48, 35.26) controlPoint1: CGPointMake(44.4, 27.67) controlPoint2: CGPointMake(48, 31.08)]; + [infoShapePath addLineToPoint:CGPointMake(48, 69.41)]; + [infoShapePath closePath]; + + [color0 setFill]; + [infoShapePath fill]; +} + ++ (void)drawEdit +{ + // Color Declarations + UIColor *color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; + + // Edit shape Drawing + UIBezierPath *editPathPath = [[UIBezierPath alloc] init]; + [editPathPath moveToPoint:CGPointMake(71, 2.7)]; + [editPathPath addCurveToPoint:CGPointMake(71.9, 15.2) controlPoint1:CGPointMake(74.7, 5.9) controlPoint2:CGPointMake(75.1, 11.6)]; + [editPathPath addLineToPoint:CGPointMake(64.5, 23.7)]; + [editPathPath addLineToPoint:CGPointMake(49.9, 11.1)]; + [editPathPath addLineToPoint:CGPointMake(57.3, 2.6)]; + [editPathPath addCurveToPoint:CGPointMake(69.7, 1.7) controlPoint1:CGPointMake(60.4, -1.1) controlPoint2:CGPointMake(66.1, -1.5)]; + [editPathPath addLineToPoint:CGPointMake(71, 2.7)]; + [editPathPath addLineToPoint:CGPointMake(71, 2.7)]; + [editPathPath closePath]; + + [editPathPath moveToPoint:CGPointMake(47.8, 13.5)]; + [editPathPath addLineToPoint:CGPointMake(13.4, 53.1)]; + [editPathPath addLineToPoint:CGPointMake(15.7, 55.1)]; + [editPathPath addLineToPoint:CGPointMake(50.1, 15.5)]; + [editPathPath addLineToPoint:CGPointMake(47.8, 13.5)]; + [editPathPath addLineToPoint:CGPointMake(47.8, 13.5)]; + [editPathPath closePath]; + + [editPathPath moveToPoint:CGPointMake(17.7, 56.7)]; + [editPathPath addLineToPoint:CGPointMake(23.8, 62.2)]; + [editPathPath addLineToPoint:CGPointMake(58.2, 22.6)]; + [editPathPath addLineToPoint:CGPointMake(52, 17.1)]; + [editPathPath addLineToPoint:CGPointMake(17.7, 56.7)]; + [editPathPath addLineToPoint:CGPointMake(17.7, 56.7)]; + [editPathPath closePath]; + + [editPathPath moveToPoint:CGPointMake(25.8, 63.8)]; + [editPathPath addLineToPoint:CGPointMake(60.1, 24.2)]; + [editPathPath addLineToPoint:CGPointMake(62.3, 26.1)]; + [editPathPath addLineToPoint:CGPointMake(28.1, 65.7)]; + [editPathPath addLineToPoint:CGPointMake(25.8, 63.8)]; + [editPathPath addLineToPoint:CGPointMake(25.8, 63.8)]; + [editPathPath closePath]; + + [editPathPath moveToPoint:CGPointMake(25.9, 68.1)]; + [editPathPath addLineToPoint:CGPointMake(4.2, 79.5)]; + [editPathPath addLineToPoint:CGPointMake(11.3, 55.5)]; + [editPathPath addLineToPoint:CGPointMake(25.9, 68.1)]; + [editPathPath closePath]; + + editPathPath.miterLimit = 4; + editPathPath.usesEvenOddFillRule = YES; + [color setFill]; + [editPathPath fill]; +} + ++ (void)drawQuestion +{ + // Color Declarations + UIColor *color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; + + // Questionmark Shape Drawing + UIBezierPath *questionShapePath = [[UIBezierPath alloc] init]; + [questionShapePath moveToPoint: CGPointMake(33.75, 54.1)]; + [questionShapePath addLineToPoint: CGPointMake(44.15, 54.1)]; + [questionShapePath addLineToPoint: CGPointMake(44.15, 47.5)]; + [questionShapePath addCurveToPoint: CGPointMake(51.85, 37.2) controlPoint1: CGPointMake(44.15, 42.9) controlPoint2: CGPointMake(46.75, 41.2)]; + [questionShapePath addCurveToPoint: CGPointMake(61.95, 19.9) controlPoint1: CGPointMake(59.05, 31.6) controlPoint2: CGPointMake(61.95, 28.5)]; + [questionShapePath addCurveToPoint: CGPointMake(41.45, 2.8) controlPoint1: CGPointMake(61.95, 7.6) controlPoint2: CGPointMake(52.85, 2.8)]; + [questionShapePath addCurveToPoint: CGPointMake(25.05, 5.8) controlPoint1: CGPointMake(34.75, 2.8) controlPoint2: CGPointMake(29.65, 3.8)]; + [questionShapePath addLineToPoint: CGPointMake(25.05, 14.4)]; + [questionShapePath addCurveToPoint: CGPointMake(38.15, 12.3) controlPoint1: CGPointMake(29.15, 13.2) controlPoint2: CGPointMake(32.35, 12.3)]; + [questionShapePath addCurveToPoint: CGPointMake(49.65, 20.8) controlPoint1: CGPointMake(45.65, 12.3) controlPoint2: CGPointMake(49.65, 14.4)]; + [questionShapePath addCurveToPoint: CGPointMake(43.65, 31.7) controlPoint1: CGPointMake(49.65, 26) controlPoint2: CGPointMake(47.95, 28.4)]; + [questionShapePath addCurveToPoint: CGPointMake(33.75, 46.6) controlPoint1: CGPointMake(37.15, 36.9) controlPoint2: CGPointMake(33.75, 39.7)]; + [questionShapePath addLineToPoint: CGPointMake(33.75, 54.1)]; + [questionShapePath closePath]; + + [questionShapePath moveToPoint: CGPointMake(33.15, 75.4)]; + [questionShapePath addLineToPoint: CGPointMake(45.35, 75.4)]; + [questionShapePath addLineToPoint: CGPointMake(45.35, 63.7)]; + [questionShapePath addLineToPoint: CGPointMake(33.15, 63.7)]; + [questionShapePath addLineToPoint: CGPointMake(33.15, 75.4)]; + [questionShapePath closePath]; + + [color setFill]; + [questionShapePath fill]; +} + +#pragma mark - Images + ++ (UIImage*)imageOfCheckmark +{ + if (imageOfCheckmark != nil) + { + return imageOfCheckmark; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawCheckmark]; + imageOfCheckmark = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfCheckmark; +} + + ++ (UIImage*)imageOfCross +{ + if (imageOfCross != nil) + { + return imageOfCross; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawCross]; + imageOfCross = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfCross; +} + ++ (UIImage*)imageOfNotice +{ + if (imageOfNotice != nil) + { + return imageOfNotice; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawNotice]; + imageOfNotice = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfNotice; +} + ++ (UIImage*)imageOfWarning +{ + if (imageOfWarning != nil) + { + return imageOfWarning; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawWarning]; + imageOfWarning = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfWarning; +} + ++ (UIImage*)imageOfInfo +{ + if (imageOfInfo != nil) + { + return imageOfInfo; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawInfo]; + imageOfInfo = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfInfo; +} + ++ (UIImage*)imageOfEdit +{ + if (imageOfEdit != nil) + { + return imageOfEdit; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawEdit]; + imageOfEdit = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfEdit; +} + ++ (UIImage*)imageOfQuestion +{ + if (imageOfQuestion != nil) + { + return imageOfQuestion; + } + + UIGraphicsBeginImageContextWithOptions(CGSizeMake(80, 80), NO, 0); + [SCLAlertViewStyleKit drawQuestion]; + imageOfQuestion = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return imageOfQuestion; +} + +@end diff --git a/includes/SCLAlertView/SCLButton.h b/includes/SCLAlertView/SCLButton.h new file mode 100644 index 0000000..a1fb3a5 --- /dev/null +++ b/includes/SCLAlertView/SCLButton.h @@ -0,0 +1,109 @@ +// +// SCLButton.h +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// + +#if defined(__has_feature) && __has_feature(modules) +@import UIKit; +#else +#import +#endif + +@class SCLTimerDisplay; + +@interface SCLButton : UIButton + +typedef void (^SCLActionBlock)(void); +typedef BOOL (^SCLValidationBlock)(void); +typedef NSDictionary* (^CompleteButtonFormatBlock)(void); +typedef NSDictionary* (^ButtonFormatBlock)(void); + +// Action Types +typedef NS_ENUM(NSInteger, SCLActionType) +{ + SCLNone, + SCLSelector, + SCLBlock +}; + +/** Set button action type. + * + * Holds the button action type. + */ +@property SCLActionType actionType; + +/** Set action button block. + * + * TODO + */ +@property (copy, nonatomic) SCLActionBlock actionBlock; + +/** Set Validation button block. + * + * Set one kind of validation and keeps the alert visible until the validation is successful + */ +@property (copy, nonatomic) SCLValidationBlock validationBlock; + +/** Set Complete button format block. + * + * Holds the complete button format block. + * Support keys : backgroundColor, borderWidth, borderColor, textColor + */ +@property (copy, nonatomic) CompleteButtonFormatBlock completeButtonFormatBlock; + +/** Set button format block. + * + * Holds the button format block. + * Support keys : backgroundColor, borderWidth, borderColor, textColor + */ +@property (copy, nonatomic) ButtonFormatBlock buttonFormatBlock; + +/** Set SCLButton color. + * + * Set SCLButton color. + */ +@property (strong, nonatomic) UIColor *defaultBackgroundColor UI_APPEARANCE_SELECTOR; + +/** Set Target object. + * + * Target is an object that holds the information necessary to send a message to another object when an event occurs. + */ +@property id target; + +/** Set selector id. + * + * A selector is the name used to select a method to execute for an object, + * or the unique identifier that replaces the name when the source code is compiled. + */ +@property SEL selector; + +/** Parse button configuration + * + * Parse ButtonFormatBlock and CompleteButtonFormatBlock setting custom configuration. + * Set keys : backgroundColor, borderWidth, borderColor, textColor + */ +- (void)parseConfig:(NSDictionary *)buttonConfig; + +/** Set button timer. + * + * Holds the button timer, if present. + */ +@property (strong, nonatomic) SCLTimerDisplay *timer; + +/** Init method + * + */ +- (instancetype)initWithWindowWidth:(CGFloat)windowWidth; + +/** Adjust width of the button according to the width of the alert and + * the number of buttons. Only used when buttons are horizontally aligned. + * + * @param windowWidth The width of the alert. + * @param numberOfButtons The number of buttons in the alert. + */ +- (void)adjustWidthWithWindowWidth:(CGFloat)windowWidth numberOfButtons:(NSUInteger)numberOfButtons; + +@end diff --git a/includes/SCLAlertView/SCLButton.m b/includes/SCLAlertView/SCLButton.m new file mode 100644 index 0000000..056ce0c --- /dev/null +++ b/includes/SCLAlertView/SCLButton.m @@ -0,0 +1,167 @@ +// +// SCLButton.m +// SCLAlertView +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// + +#import "SCLButton.h" +#import "SCLTimerDisplay.h" + +#define MARGIN_BUTTON 12.0f +#define DEFAULT_WINDOW_WIDTH 240 +#define MIN_HEIGHT 35.0f + +@implementation SCLButton + +- (instancetype)init +{ + self = [super init]; + if (self) + { + [self setupWithWindowWidth:DEFAULT_WINDOW_WIDTH]; + } + return self; +} + +- (instancetype)initWithWindowWidth:(CGFloat)windowWidth +{ + self = [super init]; + if (self) + { + [self setupWithWindowWidth:windowWidth]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if(self) + { + [self setupWithWindowWidth:DEFAULT_WINDOW_WIDTH]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) + { + [self setupWithWindowWidth:DEFAULT_WINDOW_WIDTH]; + } + return self; +} + +- (void)setupWithWindowWidth:(CGFloat)windowWidth +{ + self.frame = CGRectMake(0.0f, 0.0f, windowWidth - (MARGIN_BUTTON * 2), MIN_HEIGHT); + self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping; + self.titleLabel.textAlignment = NSTextAlignmentCenter; + self.layer.cornerRadius = 3.0f; +} + +- (void)adjustWidthWithWindowWidth:(CGFloat)windowWidth numberOfButtons:(NSUInteger)numberOfButtons +{ + CGFloat allButtonsWidth = windowWidth - (MARGIN_BUTTON * 2); + CGFloat buttonWidth = (allButtonsWidth - ((numberOfButtons - 1) * 10)) / numberOfButtons; + + self.frame = CGRectMake(0.0f, 0.0f, buttonWidth, MIN_HEIGHT); +} + +- (void)setTitle:(NSString *)title forState:(UIControlState)state +{ + [super setTitle:title forState:state]; + self.titleLabel.numberOfLines = 0; + + // Update title frame. + [self.titleLabel sizeToFit]; + + // Update button frame + [self layoutIfNeeded]; + + // Get height needed to display title label completely + CGFloat buttonHeight = MAX(self.titleLabel.frame.size.height, MIN_HEIGHT); + + // Update button frame + self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, buttonHeight); +} + +- (void)setHighlighted:(BOOL)highlighted +{ + self.backgroundColor = (highlighted) ? [self darkerColorForColor:_defaultBackgroundColor] : _defaultBackgroundColor; + [super setHighlighted:highlighted]; +} + +- (void)setDefaultBackgroundColor:(UIColor *)defaultBackgroundColor +{ + self.backgroundColor = _defaultBackgroundColor = defaultBackgroundColor; +} + +- (void)setTimer:(SCLTimerDisplay *)timer +{ + _timer = timer; + [self addSubview:timer]; + [timer updateFrame:self.frame.size]; + timer.color = self.titleLabel.textColor; +} + +#pragma mark - Button Apperance + +- (void)parseConfig:(NSDictionary *)buttonConfig +{ + if (buttonConfig[@"backgroundColor"]) + { + self.defaultBackgroundColor = buttonConfig[@"backgroundColor"]; + } + if (buttonConfig[@"textColor"]) + { + [self setTitleColor:buttonConfig[@"textColor"] forState:UIControlStateNormal]; + } + if (buttonConfig[@"cornerRadius"]) + { + self.layer.cornerRadius = [buttonConfig[@"cornerRadius"] floatValue]; + } + if ((buttonConfig[@"borderColor"]) && (buttonConfig[@"borderWidth"])) + { + self.layer.borderColor = ((UIColor*)buttonConfig[@"borderColor"]).CGColor; + self.layer.borderWidth = [buttonConfig[@"borderWidth"] floatValue]; + } + else if (buttonConfig[@"borderWidth"]) + { + self.layer.borderWidth = [buttonConfig[@"borderWidth"] floatValue]; + } + + // Add Button custom font with buttonConfig parameters + if (buttonConfig[@"font"]) { + self.titleLabel.font = buttonConfig[@"font"]; + } +} + +#pragma mark - Helpers + +- (UIColor *)darkerColorForColor:(UIColor *)color +{ + CGFloat r, g, b, a; + if ([color getRed:&r green:&g blue:&b alpha:&a]) + return [UIColor colorWithRed:MAX(r - 0.2f, 0.0f) + green:MAX(g - 0.2f, 0.0f) + blue:MAX(b - 0.2f, 0.0f) + alpha:a]; + return nil; +} + +- (UIColor *)lighterColorForColor:(UIColor *)color +{ + CGFloat r, g, b, a; + if ([color getRed:&r green:&g blue:&b alpha:&a]) + return [UIColor colorWithRed:MIN(r + 0.2f, 1.0f) + green:MIN(g + 0.2f, 1.0f) + blue:MIN(b + 0.2f, 1.0f) + alpha:a]; + return nil; +} + +@end diff --git a/includes/SCLAlertView/SCLMacros.h b/includes/SCLAlertView/SCLMacros.h new file mode 100644 index 0000000..1fec837 --- /dev/null +++ b/includes/SCLAlertView/SCLMacros.h @@ -0,0 +1,27 @@ +// +// SCLMacros.h +// SCLAlertView +// +// Created by Diogo Autilio on 10/03/15. +// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. +// + +#ifndef SCL_MACROS_H +#define SCL_MACROS_H + +#define UIColorFromHEX(rgbValue) [UIColor \ +colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \ +green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \ +blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] + +#define DEGREES_TO_RADIANS(degrees) ((M_PI * degrees)/ 180) +#define TIMER_STEP .01 +#define START_DEGREE_OFFSET -90 + +#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) +#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) +#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) +#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) +#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) + +#endif diff --git a/includes/SCLAlertView/SCLSwitchView.h b/includes/SCLAlertView/SCLSwitchView.h new file mode 100644 index 0000000..ecc4d6c --- /dev/null +++ b/includes/SCLAlertView/SCLSwitchView.h @@ -0,0 +1,23 @@ +// +// SCLSwitchView.h +// SCLAlertView +// +// Created by André Felipe Santos on 27/01/16. +// Copyright (c) 2016-2017 AnyKey Entertainment. All rights reserved. +// + +#if defined(__has_feature) && __has_feature(modules) +@import UIKit; +#else +#import +#endif + +@interface SCLSwitchView : UIView + +@property (strong, nonatomic) UIColor *tintColor UI_APPEARANCE_SELECTOR; +@property (strong, nonatomic) UIColor *labelColor UI_APPEARANCE_SELECTOR; +@property (strong, nonatomic) UIFont *labelFont UI_APPEARANCE_SELECTOR; +@property (strong, nonatomic) NSString *labelText UI_APPEARANCE_SELECTOR; +@property (nonatomic, getter=isSelected) BOOL selected; + +@end diff --git a/includes/SCLAlertView/SCLSwitchView.m b/includes/SCLAlertView/SCLSwitchView.m new file mode 100644 index 0000000..93662ac --- /dev/null +++ b/includes/SCLAlertView/SCLSwitchView.m @@ -0,0 +1,140 @@ +// +// SCLSwitchView.m +// SCLAlertView +// +// Created by André Felipe Santos on 27/01/16. +// Copyright (c) 2016-2017 AnyKey Entertainment. All rights reserved. +// + +#import "SCLSwitchView.h" +#import "SCLMacros.h" + +@interface SCLSwitchView () + +@property (strong, nonatomic) UISwitch *switchKnob; +@property (strong, nonatomic) UILabel *switchLabel; + +@end + +#pragma mark + +@implementation SCLSwitchView + +#pragma mark - Constructors + +- (instancetype)init +{ + self = [super init]; + if (self) + { + [self setup]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if(self) + { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) + { + [self setup]; + } + return self; +} + +#pragma mark - Initialization + +- (void)setup +{ + // Add switch knob + self.switchKnob = [[UISwitch alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.f)]; + [self addSubview:self.switchKnob]; + + // Add switch label + CGFloat x, width, height; + x = self.switchKnob.frame.size.width + 8.0f; + width = self.frame.size.width - self.switchKnob.frame.size.width - 8.0f; + height = self.switchKnob.frame.size.height; + + self.switchLabel = [[UILabel alloc] initWithFrame:CGRectMake(x, 0.0f, width, height)]; + + NSString *switchFontFamily = @"HelveticaNeue-Bold"; + CGFloat switchFontSize = 12.0f; + + self.switchLabel.numberOfLines = 1; + self.switchLabel.textAlignment = NSTextAlignmentLeft; + self.switchLabel.lineBreakMode = NSLineBreakByTruncatingTail; + self.switchLabel.adjustsFontSizeToFitWidth = YES; + self.switchLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; + self.switchLabel.minimumScaleFactor = 0.5f; + self.switchLabel.font = [UIFont fontWithName:switchFontFamily size:switchFontSize]; + self.switchLabel.textColor = UIColorFromHEX(0x4D4D4D); + + [self addSubview:self.switchLabel]; +} + +#pragma mark - Getters + +- (UIColor *)tintColor +{ + return self.switchKnob.tintColor; +} + +- (UIColor *)labelColor +{ + return self.switchLabel.textColor; +} + +- (UIFont *)labelFont +{ + return self.switchLabel.font; +} + +- (NSString *)labelText +{ + return self.switchLabel.text; +} + +- (BOOL)isSelected +{ + return self.switchKnob.isOn; +} + +#pragma mark - Setters + +- (void)setTintColor:(UIColor *)tintColor +{ + self.switchKnob.onTintColor = tintColor; +} + +- (void)setLabelColor:(UIColor *)labelColor +{ + self.switchLabel.textColor = labelColor; +} + +- (void)setLabelFont:(UIFont *)labelFont +{ + self.switchLabel.font = labelFont; +} + +- (void)setLabelText:(NSString *)labelText +{ + self.switchLabel.text = labelText; +} + +- (void)setSelected:(BOOL)selected +{ + self.switchKnob.on = selected; +} + +@end diff --git a/includes/SCLAlertView/SCLTextView.h b/includes/SCLAlertView/SCLTextView.h new file mode 100644 index 0000000..e691ef8 --- /dev/null +++ b/includes/SCLAlertView/SCLTextView.h @@ -0,0 +1,17 @@ +// +// SCLTextView.h +// SCLAlertView +// +// Created by Diogo Autilio on 9/18/15. +// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. +// + +#if defined(__has_feature) && __has_feature(modules) +@import UIKit; +#else +#import +#endif + +@interface SCLTextView : UITextField + +@end diff --git a/includes/SCLAlertView/SCLTextView.m b/includes/SCLAlertView/SCLTextView.m new file mode 100644 index 0000000..c508359 --- /dev/null +++ b/includes/SCLAlertView/SCLTextView.m @@ -0,0 +1,56 @@ +// +// SCLTextView.m +// SCLAlertView +// +// Created by Diogo Autilio on 9/18/15. +// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. +// + +#import "SCLTextView.h" + +#define MIN_HEIGHT 30.0f + +@implementation SCLTextView + +- (instancetype)init +{ + self = [super init]; + if (self) + { + [self setup]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if(self) + { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) + { + [self setup]; + } + return self; +} + +- (void)setup +{ + self.frame = CGRectMake(0.0f, 0.0f, 0.0f, MIN_HEIGHT); + self.returnKeyType = UIReturnKeyDone; + self.borderStyle = UITextBorderStyleRoundedRect; + self.autocapitalizationType = UITextAutocapitalizationTypeSentences; + self.clearButtonMode = UITextFieldViewModeWhileEditing; + self.layer.masksToBounds = YES; + self.layer.borderWidth = 1.0f; +} + +@end diff --git a/includes/SCLAlertView/SCLTimerDisplay.h b/includes/SCLAlertView/SCLTimerDisplay.h new file mode 100644 index 0000000..2f9bc18 --- /dev/null +++ b/includes/SCLAlertView/SCLTimerDisplay.h @@ -0,0 +1,39 @@ +// +// SCLTimerDisplay.h +// SCLAlertView +// +// Created by Taylor Ryan on 8/18/15. +// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. +// +// Taken from https://stackoverflow.com/questions/11783439/uibutton-with-timer + +#if defined(__has_feature) && __has_feature(modules) +@import UIKit; +#else +#import +#endif +#import "SCLButton.h" + +@interface SCLTimerDisplay : UIView { + CGFloat currentAngle; + CGFloat currentTime; + CGFloat timerLimit; + CGFloat radius; + CGFloat lineWidth; + NSTimer *timer; + SCLActionBlock completedBlock; +} + +@property CGFloat currentAngle; +@property NSInteger buttonIndex; +@property (strong, nonatomic) UIColor *color; +@property (assign, nonatomic) BOOL reverse; + +- (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r; +- (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r lineWidth:(CGFloat)width; +- (void)updateFrame:(CGSize)size; +- (void)cancelTimer; +- (void)stopTimer; +- (void)startTimerWithTimeLimit:(int)tl completed:(SCLActionBlock)completed; + +@end diff --git a/includes/SCLAlertView/SCLTimerDisplay.m b/includes/SCLAlertView/SCLTimerDisplay.m new file mode 100644 index 0000000..6921e81 --- /dev/null +++ b/includes/SCLAlertView/SCLTimerDisplay.m @@ -0,0 +1,133 @@ +// +// SCLTimerDisplay.m +// SCLAlertView +// +// Created by Taylor Ryan on 8/18/15. +// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. +// + +#import "SCLTimerDisplay.h" +#import "SCLMacros.h" + +@interface SCLTimerDisplay () + +@property (strong, nonatomic) UILabel *countLabel; + +@end + +@implementation SCLTimerDisplay + +@synthesize currentAngle; + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) + { + self.backgroundColor = [UIColor clearColor]; + currentAngle = 0.0f; + } + return self; +} + +- (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r +{ + return [self initWithOrigin:(CGPoint)origin radius:r lineWidth:5.0f]; +} + +- (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r lineWidth:(CGFloat)width +{ + self = [super initWithFrame:CGRectMake(origin.x, origin.y, r*2, r*2)]; + if (self) { + self.backgroundColor = [UIColor clearColor]; + currentAngle = START_DEGREE_OFFSET; + radius = r-(width/2); + lineWidth = width; + self.color = [UIColor whiteColor]; + self.userInteractionEnabled = NO; + + // Add count label + _countLabel = [[UILabel alloc] init]; + _countLabel.textColor = [UIColor whiteColor]; + _countLabel.backgroundColor = [UIColor clearColor]; + _countLabel.font = [UIFont fontWithName: @"HelveticaNeue-Bold" size:12.0f]; + _countLabel.textAlignment = NSTextAlignmentCenter; + _countLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; + [self addSubview:_countLabel]; + } + return self; +} + +- (void)updateFrame:(CGSize)size +{ + CGFloat r = radius+(lineWidth/2); + + CGFloat originX = size.width - (2*r) - 5; + CGFloat originY = (size.height - (2*r))/2; + + self.frame = CGRectMake(originX, originY, r*2, r*2); + self.countLabel.frame = CGRectMake(0, 0, r*2, r*2); +} + +- (void)drawRect:(CGRect)rect +{ + UIBezierPath* aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(radius+(lineWidth/2), radius+(lineWidth/2)) + radius:radius + startAngle:DEGREES_TO_RADIANS(START_DEGREE_OFFSET) + endAngle:DEGREES_TO_RADIANS(currentAngle) + clockwise:YES]; + [self.color setStroke]; + aPath.lineWidth = lineWidth; + [aPath stroke]; + + _countLabel.text = [NSString stringWithFormat:@"%d", (int)currentTime]; +} + +- (void)startTimerWithTimeLimit:(int)tl completed:(SCLActionBlock)completed +{ + if (_reverse) + { + currentTime = tl; + } + timerLimit = tl; + timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_STEP target:self selector:@selector(updateTimerButton:) userInfo:nil repeats:YES]; + completedBlock = completed; + _countLabel.textColor = _color; +} + +- (void)cancelTimer +{ + [timer invalidate]; +} + +- (void)stopTimer +{ + [timer invalidate]; + if (completedBlock != nil) { + completedBlock(); + } +} + +- (void)updateTimerButton:(NSTimer *)timer +{ + if (_reverse) + { + currentTime -= TIMER_STEP; + currentAngle = (currentTime/timerLimit) * 360 + START_DEGREE_OFFSET; + + if(currentTime <= 0) { + [self stopTimer]; + } + } + else { + currentTime += TIMER_STEP; + currentAngle = (currentTime/timerLimit) * 360 + START_DEGREE_OFFSET; + + if(currentAngle >= (360 + START_DEGREE_OFFSET)) { + [self stopTimer]; + } + } + [self setNeedsDisplay]; +} + +@end diff --git a/includes/SCLAlertView/UIImage+ImageEffects.h b/includes/SCLAlertView/UIImage+ImageEffects.h new file mode 100644 index 0000000..e5fd509 --- /dev/null +++ b/includes/SCLAlertView/UIImage+ImageEffects.h @@ -0,0 +1,115 @@ +/* + File: UIImage+ImageEffects.h + Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur. + Version: 1.0 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2013 Apple Inc. All Rights Reserved. + + + Copyright © 2013 Apple Inc. All rights reserved. + WWDC 2013 License + + NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013 + Session. Please refer to the applicable WWDC 2013 Session for further + information. + + IMPORTANT: This Apple software is supplied to you by Apple Inc. + ("Apple") in consideration of your agreement to the following terms, and + your use, installation, modification or redistribution of this Apple + software constitutes acceptance of these terms. If you do not agree with + these terms, please do not use, install, modify or redistribute this + Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a non-exclusive license, under + Apple's copyrights in this original Apple software (the "Apple + Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES + NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE + IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + EA1002 + 5/3/2013 + */ + +#if defined(__has_feature) && __has_feature(modules) +@import UIKit; +#else +#import +#endif + +@interface UIImage (ImageEffects) + +- (UIImage *)applyLightEffect; +- (UIImage *)applyExtraLightEffect; +- (UIImage *)applyDarkEffect; +- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor; + +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage; + ++ (UIImage *)imageWithColor:(UIColor *)color; ++ (UIImage *)convertViewToImage; ++ (UIImage *)convertViewToImage:(UIView *)view; + +@end diff --git a/includes/SCLAlertView/UIImage+ImageEffects.m b/includes/SCLAlertView/UIImage+ImageEffects.m new file mode 100644 index 0000000..121e0e6 --- /dev/null +++ b/includes/SCLAlertView/UIImage+ImageEffects.m @@ -0,0 +1,324 @@ +/* + File: UIImage+ImageEffects.m + Abstract: This is a category of UIImage that adds methods to apply blur and tint effects to an image. This is the code you’ll want to look out to find out how to use vImage to efficiently calculate a blur. + Version: 1.0 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple + Inc. ("Apple") in consideration of your agreement to the following + terms, and your use, installation, modification or redistribution of + this Apple software constitutes acceptance of these terms. If you do + not agree with these terms, please do not use, install, modify or + redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a personal, non-exclusive + license, under Apple's copyrights in this original Apple software (the + "Apple Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE + MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2013 Apple Inc. All Rights Reserved. + + + Copyright © 2013 Apple Inc. All rights reserved. + WWDC 2013 License + + NOTE: This Apple Software was supplied by Apple as part of a WWDC 2013 + Session. Please refer to the applicable WWDC 2013 Session for further + information. + + IMPORTANT: This Apple software is supplied to you by Apple Inc. + ("Apple") in consideration of your agreement to the following terms, and + your use, installation, modification or redistribution of this Apple + software constitutes acceptance of these terms. If you do not agree with + these terms, please do not use, install, modify or redistribute this + Apple software. + + In consideration of your agreement to abide by the following terms, and + subject to these terms, Apple grants you a non-exclusive license, under + Apple's copyrights in this original Apple software (the "Apple + Software"), to use, reproduce, modify and redistribute the Apple + Software, with or without modifications, in source and/or binary forms; + provided that if you redistribute the Apple Software in its entirety and + without modifications, you must retain this notice and the following + text and disclaimers in all such redistributions of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may + be used to endorse or promote products derived from the Apple Software + without specific prior written permission from Apple. Except as + expressly stated in this notice, no other rights or licenses, express or + implied, are granted by Apple herein, including but not limited to any + patent rights that may be infringed by your derivative works or by other + works in which the Apple Software may be incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES + NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE + IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + EA1002 + 5/3/2013 + */ + +#import "UIImage+ImageEffects.h" +#import "SCLMacros.h" + +#if defined(__has_feature) && __has_feature(modules) +@import Accelerate; +#else +#import +#endif +#import + + +@implementation UIImage (ImageEffects) + + +- (UIImage *)applyLightEffect +{ + UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3]; + return [self applyBlurWithRadius:30 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +- (UIImage *)applyExtraLightEffect +{ + UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82]; + return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +- (UIImage *)applyDarkEffect +{ + UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73]; + return [self applyBlurWithRadius:20 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil]; +} + + +- (UIImage *)applyTintEffectWithColor:(UIColor *)tintColor +{ + const CGFloat EffectColorAlpha = 0.6; + UIColor *effectColor = tintColor; + NSUInteger componentCount = CGColorGetNumberOfComponents(tintColor.CGColor); + if (componentCount == 2) { + CGFloat b; + if ([tintColor getWhite:&b alpha:NULL]) { + effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha]; + } + } + else { + CGFloat r, g, b; + if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) { + effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha]; + } + } + return [self applyBlurWithRadius:10 tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil]; +} + + +- (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage +{ + // Check pre-conditions. + if (self.size.width < 1 || self.size.height < 1) { + NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self); + return nil; + } + if (!self.CGImage) { + NSLog (@"*** error: image must be backed by a CGImage: %@", self); + return nil; + } + if (maskImage && !maskImage.CGImage) { + NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage); + return nil; + } + + CGRect imageRect = { CGPointZero, self.size }; + UIImage *effectImage = self; + + BOOL hasBlur = blurRadius > __FLT_EPSILON__; + BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; + if (hasBlur || hasSaturationChange) { + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef effectInContext = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(effectInContext, 1.0, -1.0); + CGContextTranslateCTM(effectInContext, 0, -self.size.height); + CGContextDrawImage(effectInContext, imageRect, self.CGImage); + + vImage_Buffer effectInBuffer; + effectInBuffer.data = CGBitmapContextGetData(effectInContext); + effectInBuffer.width = CGBitmapContextGetWidth(effectInContext); + effectInBuffer.height = CGBitmapContextGetHeight(effectInContext); + effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext); + + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef effectOutContext = UIGraphicsGetCurrentContext(); + vImage_Buffer effectOutBuffer; + effectOutBuffer.data = CGBitmapContextGetData(effectOutContext); + effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext); + effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); + effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); + + if (hasBlur) { + // A description of how to compute the box kernel width from the Gaussian + // radius (aka standard deviation) appears in the SVG spec: + // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement + // + // For larger values of 's' (s >= 2.0), an approximation can be used: Three + // successive box-blurs build a piece-wise quadratic convolution kernel, which + // approximates the Gaussian kernel to within roughly 3%. + // + // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5) + // + // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel. + // + CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale]; + uint32_t radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5); + if (radius % 2 != 1) { + radius += 1; // force radius to be odd so that the three box-blur methodology works. + } + vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); + vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); + vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); + } + BOOL effectImageBuffersAreSwapped = NO; + if (hasSaturationChange) { + CGFloat s = saturationDeltaFactor; + CGFloat floatingPointSaturationMatrix[] = { + 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0, + 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0, + 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0, + 0, 0, 0, 1, + }; + const int32_t divisor = 256; + NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]); + int16_t saturationMatrix[matrixSize]; + for (NSUInteger i = 0; i < matrixSize; ++i) { + saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); + } + if (hasBlur) { + vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); + effectImageBuffersAreSwapped = YES; + } + else { + vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); + } + } + if (!effectImageBuffersAreSwapped) + effectImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + if (effectImageBuffersAreSwapped) + effectImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + } + + // Set up output context. + UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]); + CGContextRef outputContext = UIGraphicsGetCurrentContext(); + CGContextScaleCTM(outputContext, 1.0, -1.0); + CGContextTranslateCTM(outputContext, 0, -self.size.height); + + // Draw base image. + CGContextDrawImage(outputContext, imageRect, self.CGImage); + + // Draw effect image. + if (hasBlur) { + CGContextSaveGState(outputContext); + if (maskImage) { + CGContextClipToMask(outputContext, imageRect, maskImage.CGImage); + } + CGContextDrawImage(outputContext, imageRect, effectImage.CGImage); + CGContextRestoreGState(outputContext); + } + + // Add in color tint. + if (tintColor) { + CGContextSaveGState(outputContext); + CGContextSetFillColorWithColor(outputContext, tintColor.CGColor); + CGContextFillRect(outputContext, imageRect); + CGContextRestoreGState(outputContext); + } + + // Output image is ready. + UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return outputImage; +} + ++ (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; +} + ++ (UIImage *)convertViewToImage +{ + UIWindow *keyWindow = [[UIApplication sharedApplication]keyWindow]; + CGRect rect = [keyWindow bounds]; + UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0.0f); + CGContextRef context = UIGraphicsGetCurrentContext(); + [keyWindow.layer renderInContext:context]; + UIImage *capturedScreen = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return capturedScreen; +} + ++ (UIImage *)convertViewToImage:(UIView *)view +{ + CGFloat scale = [UIScreen mainScreen].scale; + UIImage *capturedScreen; + + //Optimized/fast method for rendering a UIView as image on iOS 7 and later versions. + UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, scale); + [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO]; + capturedScreen = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return capturedScreen; +} + +@end diff --git a/src/Entry.mm b/src/Entry.mm index c06a762..93b9259 100644 --- a/src/Entry.mm +++ b/src/Entry.mm @@ -95,6 +95,7 @@ void* OpenUnityFramework() { NSString* const frameworkName = @"UnityFramework.framework/UnityFramework"; NSString* const frameworkFullPath = [frameworkPath stringByAppendingPathComponent:frameworkName]; const char* const frameworkFullPathCString = [frameworkFullPath UTF8String]; + g_unityFrameworkPath = frameworkFullPathCString; return dlopen(frameworkFullPathCString, RTLD_LAZY); } @@ -163,9 +164,10 @@ void StartInitMyPlugin() configJson.c_str(), baseDir.string().c_str()); } +/* static void OnAppDidFinishLaunching(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { StartInitMyPlugin(); -} +}*/ __attribute__((constructor)) static void GakumasLocalifyIOSInit() { dispatch_async(dispatch_get_main_queue(), ^{ diff --git a/src/UpdateChecker.mm b/src/UpdateChecker.mm index 9a9276e..526ddd1 100644 --- a/src/UpdateChecker.mm +++ b/src/UpdateChecker.mm @@ -9,17 +9,32 @@ #include #include #import "includes/SSZipArchive/SSZipArchive.h" +#import "includes/SCLAlertView/SCLAlertView.h" std::atomic g_updateCheckDone{false}; #pragma mark - Configuration -// TODO: fill in GitHub repo paths (e.g., "owner/repo") +#if LOCALIFY_SCN static NSString * const kIl2cppRepo = @"https://uma.chinosk6.cn/api/gkms_ios_maps"; static NSString * const kTransRepo = @"https://uma.chinosk6.cn/api/gkms_trans_data"; +#elif LOCALIFY_EN +static NSString * const kIl2cppRepo = @"https://api.github.com/repos/chinosk6/G-I-Map/releases?per_page=100"; +static NSString * const kTransRepo = @"https://api.github.com/repos/NatsumeLS/Gakumas-Translation-Data-EN/releases/latest"; +#else +#error "Exactly one of LOCALIFY must be set to 1." +#endif #pragma mark - Utility Functions +static NSString* LocalifyText(NSString *scn, NSString *en) { +#if LOCALIFY_EN + return en ?: scn ?: @""; +#else + return scn ?: en ?: @""; +#endif +} + static NSString* TrimString(NSString *str) { if (!str) return nil; return [str stringByTrimmingCharactersInSet: @@ -47,18 +62,6 @@ static NSString* FormatBytes(int64_t bytes) { return [NSString stringWithFormat:@"%.2f MB", bytes / 1048576.0]; } -static NSString* MakeProgressBar(float progress) { - const int kWidth = 20; - int filled = (int)(progress * kWidth); - filled = MAX(0, MIN(kWidth, filled)); - NSMutableString *bar = [NSMutableString stringWithCapacity:kWidth + 2]; - [bar appendString:@"["]; - for (int i = 0; i < kWidth; i++) - [bar appendString:(i < filled) ? @"█" : @"░"]; - [bar appendString:@"]"]; - return bar; -} - static void PumpRunLoop(NSTimeInterval seconds) { CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, YES); } @@ -77,82 +80,90 @@ static void PerformOnMainWait(void(^block)(void)) { dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); } -#pragma mark - Passthrough Window +#pragma mark - Alert Management (SCLAlertView) -@interface GKMSAlertWindow : UIWindow -@end +static SCLAlertView *g_currentSCLAlert = nil; +static UIProgressView *g_progressView = nil; -@implementation GKMSAlertWindow +static void EnsureViewText(SCLAlertView *alert) { + if (alert.viewText) return; -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { - if (!self.rootViewController.presentedViewController) { - return NO; - } - return [super pointInside:point withEvent:event]; + UIView *contentView = [alert valueForKey:@"contentView"]; + if (!contentView) return; + + CGFloat ww = [[alert valueForKey:@"windowWidth"] floatValue]; + if (ww <= 0) ww = 240.0f; + + UITextView *vt = [[UITextView alloc] init]; + vt.editable = NO; + vt.textAlignment = NSTextAlignmentCenter; + vt.font = [UIFont fontWithName:@"HelveticaNeue" size:14.0f]; + vt.backgroundColor = contentView.backgroundColor ?: [UIColor whiteColor]; + vt.textColor = [UIColor colorWithRed:0.302f green:0.302f + blue:0.302f alpha:1.0f]; + vt.textContainerInset = UIEdgeInsetsZero; + vt.textContainer.lineFragmentPadding = 0; + vt.frame = CGRectMake(12.0f, 70.0f, ww - 24.0f, 0.0f); + [contentView addSubview:vt]; + alert.viewText = vt; + [alert setValue:@(0.0f) forKey:@"subTitleHeight"]; } -@end +static void ResizeSCLAlertSubtitle(SCLAlertView *alert, NSString *text) { + if (!alert) return; + EnsureViewText(alert); + if (!alert.viewText) return; -#pragma mark - Alert Window Management + alert.viewText.text = text; -static GKMSAlertWindow *g_alertWindow = nil; -static UIAlertController *g_currentAlert = nil; + CGFloat textWidth = alert.viewText.frame.size.width; + if (textWidth <= 0) return; -static UIViewController* EnsureAlertVC() { - if (!g_alertWindow) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - g_alertWindow = [[GKMSAlertWindow alloc] initWithFrame: - [[UIScreen mainScreen] bounds]]; -#pragma clang diagnostic pop - g_alertWindow.rootViewController = [[UIViewController alloc] init]; - g_alertWindow.windowLevel = UIWindowLevelAlert + 1; - g_alertWindow.backgroundColor = [UIColor clearColor]; - g_alertWindow.hidden = NO; - } - return g_alertWindow.rootViewController; -} + CGSize fitSize = [alert.viewText sizeThatFits: + CGSizeMake(textWidth, CGFLOAT_MAX)]; + CGFloat newHeight = MAX(ceilf(fitSize.height), 1.0f); -static void DismissCurrentAlert() { - UIViewController *vc = EnsureAlertVC(); - if (vc.presentedViewController) { - __block BOOL dismissed = NO; - [vc dismissViewControllerAnimated:NO completion:^{ dismissed = YES; }]; - NSDate *deadline = [NSDate dateWithTimeIntervalSinceNow:3.0]; - while (!dismissed && - [[NSDate date] compare:deadline] == NSOrderedAscending) { - PumpRunLoop(0.05); - } - if (!dismissed) { - os_log(OS_LOG_DEFAULT, - "GakumasLocalify: Dismiss completion not fired, forcing cleanup"); - } - } - g_currentAlert = nil; + CGFloat oldHeight = [[alert valueForKey:@"subTitleHeight"] floatValue]; + CGFloat winHeight = [[alert valueForKey:@"windowHeight"] floatValue]; + + [alert setValue:@(newHeight) forKey:@"subTitleHeight"]; + [alert setValue:@(winHeight + (newHeight - oldHeight)) + forKey:@"windowHeight"]; + + [alert.view setNeedsLayout]; + [alert.view layoutIfNeeded]; } static void ShowStatusAlert(NSString *title, NSString *message) { PerformOnMainWait(^{ - if (g_currentAlert) { - g_currentAlert.title = title; - g_currentAlert.message = message; + if (g_currentSCLAlert) { + g_currentSCLAlert.labelTitle.text = title; + ResizeSCLAlertSubtitle(g_currentSCLAlert, message ?: @""); return; } - UIViewController *vc = EnsureAlertVC(); - g_currentAlert = [UIAlertController alertControllerWithTitle:title - message:message preferredStyle:UIAlertControllerStyleAlert]; - [vc presentViewController:g_currentAlert animated:NO completion:nil]; + g_currentSCLAlert = [[SCLAlertView alloc] initWithNewWindow]; + g_currentSCLAlert.shouldDismissOnTapOutside = NO; + g_currentSCLAlert.showAnimationType = SCLAlertViewShowAnimationFadeIn; + g_currentSCLAlert.hideAnimationType = SCLAlertViewHideAnimationFadeOut; + g_currentSCLAlert.backgroundType = SCLAlertViewBackgroundShadow; + NSString *subtitle = message; + if ([message stringByTrimmingCharactersInSet: + [NSCharacterSet whitespaceAndNewlineCharacterSet]].length == 0) { + subtitle = @"..."; + } + [g_currentSCLAlert showWaiting:title subTitle:subtitle + closeButtonTitle:nil duration:0]; }); } static NSInteger ShowChoiceAlert(NSString *title, NSString *message, NSArray *buttons) { PerformOnMainWait(^{ - UIViewController *vc = EnsureAlertVC(); - if (vc.presentedViewController) { - [vc dismissViewControllerAnimated:NO completion:nil]; + if (g_currentSCLAlert) { + [g_currentSCLAlert hideView]; + g_currentSCLAlert = nil; + g_progressView = nil; } - g_currentAlert = nil; }); [NSThread sleepForTimeInterval:0.15]; @@ -161,24 +172,22 @@ static NSInteger ShowChoiceAlert(NSString *title, NSString *message, dispatch_semaphore_t sem = dispatch_semaphore_create(0); PerformOnMainWait(^{ - UIViewController *vc = EnsureAlertVC(); - - UIAlertController *alert = - [UIAlertController alertControllerWithTitle:title - message:message - preferredStyle:UIAlertControllerStyleAlert]; + SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; + alert.shouldDismissOnTapOutside = NO; + alert.showAnimationType = SCLAlertViewShowAnimationFadeIn; + alert.hideAnimationType = SCLAlertViewHideAnimationFadeOut; + alert.backgroundType = SCLAlertViewBackgroundShadow; for (NSUInteger i = 0; i < buttons.count; i++) { NSInteger idx = (NSInteger)i; - [alert addAction:[UIAlertAction actionWithTitle:buttons[i] - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *__unused a) { - selected = idx; - dispatch_semaphore_signal(sem); - }]]; + [alert addButton:buttons[i] actionBlock:^{ + selected = idx; + dispatch_semaphore_signal(sem); + }]; } - [vc presentViewController:alert animated:NO completion:nil]; + [alert showInfo:title subTitle:message + closeButtonTitle:nil duration:0]; }); dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); @@ -186,15 +195,10 @@ static NSInteger ShowChoiceAlert(NSString *title, NSString *message, } static void CleanupAlertWindow() { - if (g_alertWindow) { - if (g_alertWindow.rootViewController.presentedViewController) { - [g_alertWindow.rootViewController - dismissViewControllerAnimated:NO completion:nil]; - } - g_currentAlert = nil; - g_alertWindow.rootViewController = nil; - g_alertWindow.hidden = YES; - g_alertWindow = nil; + if (g_currentSCLAlert) { + [g_currentSCLAlert hideView]; + g_currentSCLAlert = nil; + g_progressView = nil; } } @@ -393,17 +397,35 @@ static BOOL ExtractZipToDirectory(NSData *zipData, NSString *destDir) { static void UpdateDownloadProgress(NSString *displayName, float progress, int64_t received, int64_t total) { - if (!g_currentAlert) return; + if (!g_currentSCLAlert) return; + + if (!g_progressView) { + g_progressView = [[UIProgressView alloc] + initWithProgressViewStyle:UIProgressViewStyleDefault]; + CGFloat ww = [[g_currentSCLAlert valueForKey:@"windowWidth"] floatValue]; + if (ww <= 0) ww = 240.0f; + g_progressView.frame = CGRectMake(0, 0, ww - 24.0f, 4); + g_progressView.trackTintColor = + [UIColor colorWithWhite:0.85 alpha:1.0]; + g_progressView.progressTintColor = + [UIColor colorWithRed:0.0 green:0.478 blue:1.0 alpha:1.0]; + [g_currentSCLAlert addCustomView:g_progressView]; + } + NSMutableString *msg = [NSMutableString string]; - [msg appendFormat:@"正在下载 / Downloading\n%@\n\n", displayName]; + [msg appendFormat:@"%@\n%@\n", + LocalifyText(@"正在下载", @"Downloading"), displayName]; if (progress >= 0) { - [msg appendFormat:@"%@ %.0f%%\n%@ / %@", - MakeProgressBar(progress), progress * 100.0f, + g_progressView.progress = progress; + [msg appendFormat:@"%.0f%% %@ / %@", + progress * 100.0f, FormatBytes(received), FormatBytes(total)]; } else { - [msg appendFormat:@"⏳ 已下载 / Downloaded: %@", FormatBytes(received)]; + g_progressView.progress = 0; + [msg appendFormat:@"⏳ %@: %@", + LocalifyText(@"已下载", @"Downloaded"), FormatBytes(received)]; } - g_currentAlert.message = msg; + ResizeSCLAlertSubtitle(g_currentSCLAlert, msg); } #pragma mark - Game Version Check @@ -428,8 +450,8 @@ static void CheckGameVersion(NSString *baseDir) { if (stored && [stored isEqualToString:gameVersion]) return; - ShowStatusAlert(@"检查更新 / Checking for Updates", - @"正在检查游戏版本适配...\nChecking game version compatibility..."); + ShowStatusAlert(LocalifyText(@"检查更新", @"Checking for Updates"), + LocalifyText(@"正在检查游戏版本适配...", @"Checking game version compatibility...")); NSString *apiURL = kIl2cppRepo; os_log(OS_LOG_DEFAULT, @@ -441,10 +463,10 @@ static void CheckGameVersion(NSString *baseDir) { if (!releases || ![releases isKindOfClass:[NSArray class]]) { ShowChoiceAlert( - @"检查失败 / Check Failed", - @"无法获取版本信息,请检查网络连接。\n" - @"Failed to fetch version info. Please check your network.", - @[@"OK"]); + LocalifyText(@"检查失败", @"Check Failed"), + LocalifyText(@"无法获取版本信息,请检查网络连接。", + @"Failed to fetch version info. Please check your network."), + @[LocalifyText(@"确定", @"OK")]); return; } @@ -458,13 +480,13 @@ static void CheckGameVersion(NSString *baseDir) { if (!matched) { NSInteger choice = ShowChoiceAlert( - @"版本未适配 / Version Not Supported", + LocalifyText(@"版本未适配", @"Version Not Supported"), [NSString stringWithFormat: - @"插件暂未适配当前游戏版本 (%@),请耐心等待更新。\n" - @"The plugin does not yet support game version %@. " - @"Please wait for an update.", + LocalifyText(@"插件暂未适配当前游戏版本 (%@),请耐心等待更新。", + @"The plugin does not yet support game version %@. Please wait for an update."), gameVersion, gameVersion], - @[@"退出游戏 / Exit Game", @"强制继续 / Continue Anyway"]); + @[LocalifyText(@"退出游戏", @"Exit Game"), + LocalifyText(@"强制继续", @"Continue Anyway")]); if (choice == 0) exit(0); return; } @@ -482,40 +504,46 @@ static void CheckGameVersion(NSString *baseDir) { if (!binURL || !mapURL) { ShowChoiceAlert( - @"文件缺失 / Files Missing", - @"Release 中缺少必要文件 (il2cpp.bin / il2cpp_map.json)。\n" - @"Required files are missing from the release.", - @[@"OK"]); + LocalifyText(@"文件缺失", @"Files Missing"), + LocalifyText(@"Release 中缺少必要文件 (il2cpp.bin / il2cpp_map.json)。", + @"Required files are missing from the release."), + @[LocalifyText(@"确定", @"OK")]); return; } - ShowStatusAlert(@"下载中 / Downloading", @""); - - NSData *binData = SyncDownload(binURL, ^(float p, int64_t r, int64_t t) { - UpdateDownloadProgress(@"il2cpp.bin", p, r, t); - }); - if (!binData) { - ShowChoiceAlert( - @"下载失败 / Download Failed", - @"下载 il2cpp.bin 失败,请检查网络连接。\n" - @"Failed to download il2cpp.bin. Please check your network.", - @[@"OK"]); - return; + NSData *binData = nil; + for (;;) { + ShowStatusAlert(LocalifyText(@"下载中", @"Downloading"), @""); + if (g_progressView) g_progressView.progress = 0; + binData = SyncDownload(binURL, ^(float p, int64_t r, int64_t t) { + UpdateDownloadProgress(@"il2cpp.bin", p, r, t); + }); + if (binData) break; + NSInteger choice = ShowChoiceAlert( + LocalifyText(@"下载失败", @"Download Failed"), + LocalifyText(@"下载 il2cpp.bin 失败,请检查网络连接。", + @"Failed to download il2cpp.bin. Please check your network."), + @[LocalifyText(@"重试", @"Retry"), LocalifyText(@"取消", @"Cancel")]); + if (choice != 0) return; } NSString *binPath = [baseDir stringByAppendingPathComponent:@"il2cpp.bin"]; [binData writeToFile:binPath atomically:YES]; - NSData *mapData = SyncDownload(mapURL, ^(float p, int64_t r, int64_t t) { - UpdateDownloadProgress(@"il2cpp_map.json", p, r, t); - }); - if (!mapData) { - ShowChoiceAlert( - @"下载失败 / Download Failed", - @"下载 il2cpp_map.json 失败,请检查网络连接。\n" - @"Failed to download il2cpp_map.json. Please check your network.", - @[@"OK"]); - return; + NSData *mapData = nil; + for (;;) { + ShowStatusAlert(LocalifyText(@"下载中", @"Downloading"), @""); + if (g_progressView) g_progressView.progress = 0; + mapData = SyncDownload(mapURL, ^(float p, int64_t r, int64_t t) { + UpdateDownloadProgress(@"il2cpp_map.json", p, r, t); + }); + if (mapData) break; + NSInteger choice = ShowChoiceAlert( + LocalifyText(@"下载失败", @"Download Failed"), + LocalifyText(@"下载 il2cpp_map.json 失败,请检查网络连接。", + @"Failed to download il2cpp_map.json. Please check your network."), + @[LocalifyText(@"重试", @"Retry"), LocalifyText(@"取消", @"Cancel")]); + if (choice != 0) return; } NSString *mapPath = [baseDir stringByAppendingPathComponent:@"il2cpp_map.json"]; @@ -530,8 +558,8 @@ static void CheckGameVersion(NSString *baseDir) { #pragma mark - Translation Update Check static void CheckTranslationUpdate(NSString *baseDir) { - ShowStatusAlert(@"检查更新 / Checking for Updates", - @"正在检查翻译更新...\nChecking for translation updates..."); + ShowStatusAlert(LocalifyText(@"检查更新", @"Checking for Updates"), + LocalifyText(@"正在检查翻译更新...", @"Checking for translation updates...")); NSString *apiURL = kTransRepo; NSDictionary *latest = @@ -558,16 +586,17 @@ static void CheckTranslationUpdate(NSString *baseDir) { if (stored && [stored isEqualToString:latestTag]) return; NSString *currentDisplay = stored - ? stored : @"未安装 / Not installed"; + ? stored : LocalifyText(@"未安装", @"Not installed"); NSString *msg = [NSString stringWithFormat: - @"发现翻译文件更新 / Translation update available\n\n" - @"当前版本 / Current: %@\n" - @"最新版本 / Latest: %@\n\n%@", - currentDisplay, latestTag, body]; + @"%@\n\n%@: %@\n%@: %@\n\n%@", + LocalifyText(@"发现翻译文件更新", @"Translation update available"), + LocalifyText(@"当前版本", @"Current"), currentDisplay, + LocalifyText(@"最新版本", @"Latest"), latestTag, + body]; NSInteger choice = ShowChoiceAlert( - @"翻译更新 / Translation Update", msg, - @[@"更新 / Update", @"跳过 / Skip"]); + LocalifyText(@"翻译更新", @"Translation Update"), msg, + @[LocalifyText(@"更新", @"Update"), LocalifyText(@"跳过", @"Skip")]); if (choice != 0) return; NSURL *zipURL = nil; @@ -580,35 +609,39 @@ static void CheckTranslationUpdate(NSString *baseDir) { if (!zipURL) { ShowChoiceAlert( - @"更新失败 / Update Failed", - @"未找到更新文件。\nUpdate package not found in release.", - @[@"OK"]); + LocalifyText(@"更新失败", @"Update Failed"), + LocalifyText(@"未找到更新文件。", + @"Update package not found in release."), + @[LocalifyText(@"确定", @"OK")]); return; } - ShowStatusAlert(@"下载更新 / Downloading Update", @""); - NSData *zipData = SyncDownload(zipURL, ^(float p, int64_t r, int64_t t) { - UpdateDownloadProgress(@"translation update", p, r, t); - }); - - if (!zipData) { - ShowChoiceAlert( - @"下载失败 / Download Failed", - @"下载翻译更新失败,请检查网络连接。\n" - @"Failed to download translation update. Please check your network.", - @[@"OK"]); - return; + NSData *zipData = nil; + for (;;) { + ShowStatusAlert(LocalifyText(@"下载更新", @"Downloading Update"), @""); + if (g_progressView) g_progressView.progress = 0; + zipData = SyncDownload(zipURL, ^(float p, int64_t r, int64_t t) { + UpdateDownloadProgress(LocalifyText(@"翻译更新", @"translation update"), p, r, t); + }); + if (zipData) break; + NSInteger choice = ShowChoiceAlert( + LocalifyText(@"下载失败", @"Download Failed"), + LocalifyText(@"下载翻译更新失败,请检查网络连接。", + @"Failed to download translation update. Please check your network."), + @[LocalifyText(@"重试", @"Retry"), LocalifyText(@"取消", @"Cancel")]); + if (choice != 0) return; } - ShowStatusAlert(@"解压中 / Extracting", - @"正在解压翻译文件...\nExtracting translation files..."); + ShowStatusAlert(LocalifyText(@"解压中", @"Extracting"), + LocalifyText(@"正在解压翻译文件...", @"Extracting translation files...")); PumpRunLoop(0.1); if (!ExtractZipToDirectory(zipData, baseDir)) { ShowChoiceAlert( - @"解压失败 / Extraction Failed", - @"解压翻译文件失败。\nFailed to extract translation files.", - @[@"OK"]); + LocalifyText(@"解压失败", @"Extraction Failed"), + LocalifyText(@"解压翻译文件失败。", + @"Failed to extract translation files."), + @[LocalifyText(@"确定", @"OK")]); return; } @@ -625,8 +658,8 @@ void CheckForUpdates(const std::string& baseDir) { [[NSFileManager defaultManager] createDirectoryAtPath:dir withIntermediateDirectories:YES attributes:nil error:nil]; - ShowStatusAlert(@"检查更新 / Checking for Updates", - @"请稍候...\nPlease wait..."); + ShowStatusAlert(LocalifyText(@"检查更新", @"Checking for Updates"), + LocalifyText(@"请稍候...", @"Please wait...")); if (kIl2cppRepo.length > 0) { CheckGameVersion(dir); diff --git a/src/platformDefine.hpp b/src/platformDefine.hpp index c7f43f3..dde2c70 100644 --- a/src/platformDefine.hpp +++ b/src/platformDefine.hpp @@ -17,7 +17,7 @@ #define LogMinVersion ANDROID_LOG_DEBUG -#define PLUGIN_VERSION "3.2.0 Beta 1" +#define PLUGIN_VERSION "3.2.0 Beta 2" typedef enum MH_STATUS { MH_OK = 0,