From 7f5ce2cb88ec5ad5440f3b96cb3b28ec3e00b06e Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 5 Apr 2022 20:56:47 -0300 Subject: [PATCH 01/41] Update CocoaPods to 1.11.3 (was 1.10.2) --- Gemfile.lock | 60 +++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ed6b39b..979d6ac 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,23 +1,25 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.3) - activesupport (5.2.6) + CFPropertyList (3.0.5) + rexml + activesupport (6.1.5) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) atomos (0.1.3) - claide (1.0.3) - cocoapods (1.10.2) - addressable (~> 2.6) + claide (1.1.0) + cocoapods (1.11.3) + addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.10.2) + cocoapods-core (= 1.11.3) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 1.4.0, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -28,55 +30,54 @@ GEM escape (~> 0.0.4) fourflusher (>= 2.3.0, < 3.0) gh_inspector (~> 1.0) - molinillo (~> 0.6.6) + molinillo (~> 0.8.0) nap (~> 1.0) - ruby-macho (~> 1.4) - xcodeproj (>= 1.19.0, < 2.0) - cocoapods-core (1.10.2) - activesupport (> 5.0, < 6) - addressable (~> 2.6) + ruby-macho (>= 1.0, < 3.0) + xcodeproj (>= 1.21.0, < 2.0) + cocoapods-core (1.11.3) + activesupport (>= 5.0, < 7) + addressable (~> 2.8) algoliasearch (~> 1.0) concurrent-ruby (~> 1.1) fuzzy_match (~> 2.0.4) nap (~> 1.0) netrc (~> 0.11) - public_suffix + public_suffix (~> 4.0) typhoeus (~> 1.0) cocoapods-deintegrate (1.0.5) - cocoapods-downloader (1.4.0) + cocoapods-downloader (1.6.3) cocoapods-plugins (1.0.0) nap cocoapods-search (1.0.1) - cocoapods-trunk (1.5.0) + cocoapods-trunk (1.6.0) nap (>= 0.8, < 2.0) netrc (~> 0.11) cocoapods-try (1.2.0) colored2 (3.1.2) - concurrent-ruby (1.1.9) + concurrent-ruby (1.1.10) escape (0.0.4) - ethon (0.14.0) + ethon (0.15.0) ffi (>= 1.15.0) - ffi (1.15.3) + ffi (1.15.5) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) httpclient (2.8.3) - i18n (1.8.10) + i18n (1.10.0) concurrent-ruby (~> 1.0) - json (2.5.1) - minitest (5.14.4) - molinillo (0.6.6) + json (2.6.1) + minitest (5.15.0) + molinillo (0.8.0) nanaimo (0.3.0) nap (1.1.0) netrc (0.11.0) public_suffix (4.0.6) rexml (3.2.5) - ruby-macho (1.4.0) - thread_safe (0.3.6) + ruby-macho (2.5.1) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (1.2.9) - thread_safe (~> 0.1) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) xcodeproj (1.21.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) @@ -84,6 +85,7 @@ GEM colored2 (~> 3.1) nanaimo (~> 0.3.0) rexml (~> 3.2.4) + zeitwerk (2.5.4) PLATFORMS ruby From 09cb09292a405a61f45e2d501a94b766ad9ab3b5 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 5 Apr 2022 20:59:58 -0300 Subject: [PATCH 02/41] Update Build.yml --- .github/workflows/Build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 510aeaa..1633568 100755 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -7,10 +7,10 @@ jobs: runs-on: macOS-latest steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Xcode version - uses: maxim-lobanov/setup-xcode@v1.1 + uses: maxim-lobanov/setup-xcode@v1.41 with: - xcode-version: 12.0.0 + xcode-version: 13.2.1 - name: Building iOS app run: exec ./.github/scripts/build_app.sh From cba50880becd075632cbcc370e228772991236e5 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 5 Apr 2022 21:00:59 -0300 Subject: [PATCH 03/41] Update Build.yml --- .github/workflows/Build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 1633568..d89814b 100755 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -9,7 +9,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - name: Setup Xcode version - uses: maxim-lobanov/setup-xcode@v1.41 + uses: maxim-lobanov/setup-xcode@v1.4.1 with: xcode-version: 13.2.1 - name: Building iOS app From 09245fdcc5d699269fd18af4bd0eb4d471291c66 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 5 Apr 2022 21:02:53 -0300 Subject: [PATCH 04/41] Update build_app.sh --- .github/scripts/build_app.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/build_app.sh b/.github/scripts/build_app.sh index 41a9d56..746dab3 100755 --- a/.github/scripts/build_app.sh +++ b/.github/scripts/build_app.sh @@ -4,5 +4,5 @@ set -eo pipefail xcodebuild -project SCLAlertView.xcodeproj \ -scheme SCLAlertView \ - -destination platform=iOS\ Simulator,OS=14.0,name=iPhone\ 11 \ + -destination platform=iOS\ Simulator,OS=15.2,name=iPhone\ 11 \ clean build | xcpretty From c4505d41a15518f4c72f5fbe5a1cd6965038ad27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Mar 2023 05:44:49 +0000 Subject: [PATCH 05/41] Bump activesupport from 6.1.5 to 6.1.7.3 Bumps [activesupport](https://github.com/rails/rails) from 6.1.5 to 6.1.7.3. - [Release notes](https://github.com/rails/rails/releases) - [Changelog](https://github.com/rails/rails/blob/v7.0.4.3/activesupport/CHANGELOG.md) - [Commits](https://github.com/rails/rails/compare/v6.1.5...v6.1.7.3) --- updated-dependencies: - dependency-name: activesupport dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 979d6ac..b8495cb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,7 +3,7 @@ GEM specs: CFPropertyList (3.0.5) rexml - activesupport (6.1.5) + activesupport (6.1.7.3) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -54,7 +54,7 @@ GEM netrc (~> 0.11) cocoapods-try (1.2.0) colored2 (3.1.2) - concurrent-ruby (1.1.10) + concurrent-ruby (1.2.2) escape (0.0.4) ethon (0.15.0) ffi (>= 1.15.0) @@ -63,10 +63,10 @@ GEM fuzzy_match (2.0.4) gh_inspector (1.1.3) httpclient (2.8.3) - i18n (1.10.0) + i18n (1.12.0) concurrent-ruby (~> 1.0) json (2.6.1) - minitest (5.15.0) + minitest (5.18.0) molinillo (0.8.0) nanaimo (0.3.0) nap (1.1.0) @@ -76,7 +76,7 @@ GEM ruby-macho (2.5.1) typhoeus (1.4.0) ethon (>= 0.9.0) - tzinfo (2.0.4) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) xcodeproj (1.21.0) CFPropertyList (>= 2.3.3, < 4.0) @@ -85,7 +85,7 @@ GEM colored2 (~> 3.1) nanaimo (~> 0.3.0) rexml (~> 3.2.4) - zeitwerk (2.5.4) + zeitwerk (2.6.7) PLATFORMS ruby From adcecb29ee087e7e26cface97ff0500226e4f21e Mon Sep 17 00:00:00 2001 From: Fernando Reynoso Date: Thu, 8 Jun 2023 15:04:18 -0700 Subject: [PATCH 06/41] Add initWithWidth method for setting the width of the object. --- SCLAlertView/SCLAlertView.h | 6 ++++++ SCLAlertView/SCLAlertView.m | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/SCLAlertView/SCLAlertView.h b/SCLAlertView/SCLAlertView.h index 33ec029..1df8008 100755 --- a/SCLAlertView/SCLAlertView.h +++ b/SCLAlertView/SCLAlertView.h @@ -230,6 +230,12 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) */ @property (nonatomic) BOOL horizontalButtons; +/** Initialize SCLAlertView using specific width. + * + * Init instance + */ +- (instancetype)initWithWidth:(CGFloat)width; + /** Initialize SCLAlertView using a new window. * * Init with new window diff --git a/SCLAlertView/SCLAlertView.m b/SCLAlertView/SCLAlertView.m index 20a22dc..909b907 100755 --- a/SCLAlertView/SCLAlertView.m +++ b/SCLAlertView/SCLAlertView.m @@ -96,6 +96,16 @@ - (instancetype)init return self; } +- (instancetype)initWithWidth:(CGFloat)width +{ + self = [super init]; + if (self) + { + [self setupViewWindowWidth:width]; + } + return self; +} + - (instancetype)initWithWindowWidth:(CGFloat)windowWidth { self = [super init]; From 757534a89140489a6b4df6dadb83df831d188df2 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Sun, 15 Oct 2023 10:00:47 -0300 Subject: [PATCH 07/41] Update gems --- Gemfile.lock | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index b8495cb..18ef867 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,30 +1,30 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.5) + CFPropertyList (3.0.6) rexml - activesupport (6.1.7.3) + activesupport (6.1.7.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) zeitwerk (~> 2.3) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + addressable (2.8.5) + public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) atomos (0.1.3) claide (1.1.0) - cocoapods (1.11.3) + cocoapods (1.13.0) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.11.3) + cocoapods-core (= 1.13.0) cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.4.0, < 2.0) + cocoapods-downloader (>= 1.6.0, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.4.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) cocoapods-try (>= 1.1.0, < 2.0) colored2 (~> 3.1) escape (~> 0.0.4) @@ -32,10 +32,10 @@ GEM gh_inspector (~> 1.0) molinillo (~> 0.8.0) nap (~> 1.0) - ruby-macho (>= 1.0, < 3.0) - xcodeproj (>= 1.21.0, < 2.0) - cocoapods-core (1.11.3) - activesupport (>= 5.0, < 7) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.23.0, < 2.0) + cocoapods-core (1.13.0) + activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) concurrent-ruby (~> 1.1) @@ -56,36 +56,36 @@ GEM colored2 (3.1.2) concurrent-ruby (1.2.2) escape (0.0.4) - ethon (0.15.0) + ethon (0.16.0) ffi (>= 1.15.0) - ffi (1.15.5) + ffi (1.16.3) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) httpclient (2.8.3) - i18n (1.12.0) + i18n (1.14.1) concurrent-ruby (~> 1.0) - json (2.6.1) - minitest (5.18.0) + json (2.6.3) + minitest (5.20.0) molinillo (0.8.0) nanaimo (0.3.0) nap (1.1.0) netrc (0.11.0) - public_suffix (4.0.6) - rexml (3.2.5) + public_suffix (4.0.7) + rexml (3.2.6) ruby-macho (2.5.1) typhoeus (1.4.0) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - xcodeproj (1.21.0) + xcodeproj (1.23.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) rexml (~> 3.2.4) - zeitwerk (2.6.7) + zeitwerk (2.6.12) PLATFORMS ruby From 7d46070721870b91dcbe4b46b0ef961cec62038f Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 19 Dec 2023 21:04:04 -0300 Subject: [PATCH 08/41] Update Ruby to 3.1.2 (was 2.6.5) Update CocoaPods to 1.14.3 (was 1.13.0) --- .tool-versions | 1 + Gemfile | 4 ++-- Gemfile.lock | 38 ++++++++++++++++++++++++-------------- 3 files changed, 27 insertions(+), 16 deletions(-) create mode 100644 .tool-versions diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..0b2d858 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +ruby 3.1.2 diff --git a/Gemfile b/Gemfile index 2096226..5bc1f49 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ # frozen_string_literal: true - source "https://rubygems.org" -ruby "2.6.5" + +ruby "3.1.2" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } diff --git a/Gemfile.lock b/Gemfile.lock index 18ef867..b87ed7b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,25 +3,31 @@ GEM specs: CFPropertyList (3.0.6) rexml - activesupport (6.1.7.6) + activesupport (7.1.2) + base64 + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) minitest (>= 5.1) + mutex_m tzinfo (~> 2.0) - zeitwerk (~> 2.3) - addressable (2.8.5) + addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) atomos (0.1.3) + base64 (0.2.0) + bigdecimal (3.1.5) claide (1.1.0) - cocoapods (1.13.0) + cocoapods (1.14.3) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.13.0) + cocoapods-core (= 1.14.3) cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.6.0, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) cocoapods-trunk (>= 1.6.0, < 2.0) @@ -34,7 +40,7 @@ GEM nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.13.0) + cocoapods-core (1.14.3) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -45,7 +51,7 @@ GEM public_suffix (~> 4.0) typhoeus (~> 1.0) cocoapods-deintegrate (1.0.5) - cocoapods-downloader (1.6.3) + cocoapods-downloader (2.1) cocoapods-plugins (1.0.0) nap cocoapods-search (1.0.1) @@ -55,6 +61,9 @@ GEM cocoapods-try (1.2.0) colored2 (3.1.2) concurrent-ruby (1.2.2) + connection_pool (2.4.1) + drb (2.2.0) + ruby2_keywords escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) @@ -65,16 +74,18 @@ GEM httpclient (2.8.3) i18n (1.14.1) concurrent-ruby (~> 1.0) - json (2.6.3) + json (2.7.1) minitest (5.20.0) molinillo (0.8.0) + mutex_m (0.2.0) nanaimo (0.3.0) nap (1.1.0) netrc (0.11.0) public_suffix (4.0.7) rexml (3.2.6) ruby-macho (2.5.1) - typhoeus (1.4.0) + ruby2_keywords (0.0.5) + typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) @@ -85,16 +96,15 @@ GEM colored2 (~> 3.1) nanaimo (~> 0.3.0) rexml (~> 3.2.4) - zeitwerk (2.6.12) PLATFORMS - ruby + x86_64-darwin-23 DEPENDENCIES cocoapods RUBY VERSION - ruby 2.6.5p114 + ruby 3.1.2p20 BUNDLED WITH - 2.1.4 + 2.3.7 From f73760811dc3ead001e7ae15a28963b3d6e51175 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 19 Dec 2023 21:05:52 -0300 Subject: [PATCH 09/41] Bump version to 1.3.0 --- SCLAlertView-Objective-C.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SCLAlertView-Objective-C.podspec b/SCLAlertView-Objective-C.podspec index cfb5881..5e2f0a3 100644 --- a/SCLAlertView-Objective-C.podspec +++ b/SCLAlertView-Objective-C.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "SCLAlertView-Objective-C" - spec.version = "1.2.0" + spec.version = "1.3.0" spec.summary = "Beautiful animated Alert View. Written in Swift but ported to Objective-C" spec.homepage = "https://github.com/dogo/SCLAlertView" spec.screenshots = "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot.png", "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot2.png" From ba55241ac70ab8cc949ea3a1da4a992c7f144693 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 19 Dec 2023 21:26:34 -0300 Subject: [PATCH 10/41] Update LICENSE --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index cb4203d..740d024 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2014 SCLAlertView-Objective-C by Diogo Autilio +Copyright (c) 2013-2023 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 @@ -16,4 +16,4 @@ 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 +THE SOFTWARE. From 550686b31fd2a640ecec9ab883ff11677cf1efa4 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Wed, 20 Dec 2023 09:23:59 -0300 Subject: [PATCH 11/41] Update changelog --- CHANGELOG.md | 159 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 147 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2022b3b..9f668f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,79 @@ -# Change Log +# Changelog + +## [1.3.0](https://github.com/dogo/SCLAlertView/tree/1.3.0) (2023-12-20) + +[Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.2.0...1.3.0) + +**Closed issues:** + +- Android system can use it even better [\#307](https://github.com/dogo/SCLAlertView/issues/307) +- showCustom 的时候如何自定义 closeButton样式 [\#302](https://github.com/dogo/SCLAlertView/issues/302) +- Cannot find ChangesLog for version 1.2.0 [\#299](https://github.com/dogo/SCLAlertView/issues/299) +- Is this an SCLAlertView bug, or an Apple bug? [\#296](https://github.com/dogo/SCLAlertView/issues/296) +- SCLAlertView \*alert = \[\[SCLAlertView alloc\] initWithNewWindowWidth:300.0f\]; self.username = @"zaxo"; self.password = @"pass"; UITextField \*usernameTextField = \[alert addTextField:@"username"\]; UITextField \*passwordTextField = \[alert addTextField:@"password"\]; passwordTextField.secureTextEntry = YES; \[alert addButton:@"Login" actionBlock: ^\(void\){ BOOL isUsersEqual = \[self.username isEqualToString:\[self.usernameTextField text\]\]; BOOL isPasswordsEqual = \[self.password isEqualToString:\[self.passwordTextField text\]\]; if\(isUsersEqual && isPasswordsEqual\){ NSLog\(@"Successful"\); } else { NSLog\(@"frailer"\); } @@@@@@@@ Why I can't compile it I even have set the @Property \(nonatomic, strong\) NSString \*username; in SCLALertView.m but I still errors do im doing anthing please can you help Tweak.xm:350:1: error: use of undeclared identifier 'self' self.username = @"zaxo"; [\#293](https://github.com/dogo/SCLAlertView/issues/293) + +**Merged pull requests:** + +- Add initWithWidth method for setting the width of the object. [\#310](https://github.com/dogo/SCLAlertView/pull/310) ([FernandoReynoso](https://github.com/FernandoReynoso)) +- Bump activesupport from 6.1.5 to 6.1.7.3 [\#308](https://github.com/dogo/SCLAlertView/pull/308) ([dependabot[bot]](https://github.com/apps/dependabot)) +- default value for a textfield [\#295](https://github.com/dogo/SCLAlertView/pull/295) ([syto203](https://github.com/syto203)) + +## [1.2.0](https://github.com/dogo/SCLAlertView/tree/1.2.0) (2020-10-31) + +[Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.6...1.2.0) + +**Closed issues:** + +- alertView with textfield moves up twice\(too much\) when textfield become first responder and the keyboard shows [\#291](https://github.com/dogo/SCLAlertView/issues/291) +- 设置富文本后不居中显示了 变成了居左。 [\#288](https://github.com/dogo/SCLAlertView/issues/288) +- Good day, as you can implement the verification key which is located on the website .txt document? Roughly speaking to make check on a key if the key is correct, then there is a start. [\#286](https://github.com/dogo/SCLAlertView/issues/286) +- How to hidden top image with OC? [\#285](https://github.com/dogo/SCLAlertView/issues/285) + +**Merged pull requests:** + +- Fix: break a strong reference cycle [\#290](https://github.com/dogo/SCLAlertView/pull/290) ([kingste](https://github.com/kingste)) +- Merge [\#279](https://github.com/dogo/SCLAlertView/pull/279) ([dogo](https://github.com/dogo)) +- Add Stale config [\#275](https://github.com/dogo/SCLAlertView/pull/275) ([dogo](https://github.com/dogo)) + +## [1.1.6](https://github.com/dogo/SCLAlertView/tree/1.1.6) (2018-10-14) + +[Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.5...1.1.6) + +**Implemented enhancements:** + +- ButtonTimer: Enable button once timer elapsed [\#181](https://github.com/dogo/SCLAlertView/issues/181) + +**Fixed bugs:** + +- UIStatusBarStyle always appears as 'UIStatusBarStyleDefault' [\#274](https://github.com/dogo/SCLAlertView/issues/274) +- Alert view height problem when using it with long text in body [\#127](https://github.com/dogo/SCLAlertView/issues/127) + +**Closed issues:** + +- handleNavigationTransition Bug [\#276](https://github.com/dogo/SCLAlertView/issues/276) +- Could you release fixed version? [\#273](https://github.com/dogo/SCLAlertView/issues/273) +- Accessibility: implement - \(BOOL\)accessibilityPerformEscape [\#271](https://github.com/dogo/SCLAlertView/issues/271) +- How to solve the problem of overlapping multiple calls in a controller?(如何解决在一个控制器中,连续多次调用,会出现重叠的情况?) [\#267](https://github.com/dogo/SCLAlertView/issues/267) +- TextView height problem when text entered with the long body \(it need to expend it's height \) [\#258](https://github.com/dogo/SCLAlertView/issues/258) +- i need to add on the preloaded text in the text field before textfield Alert pop up [\#254](https://github.com/dogo/SCLAlertView/issues/254) +- Problem in increasing height of TextField & customize the Alert view colour & image & button [\#253](https://github.com/dogo/SCLAlertView/issues/253) +- Custom TextField not adding Keyboard Observers [\#250](https://github.com/dogo/SCLAlertView/issues/250) +- Portrait or Landscape fixed [\#201](https://github.com/dogo/SCLAlertView/issues/201) +- \[Bug\] when changing keyboard... [\#200](https://github.com/dogo/SCLAlertView/issues/200) +- If new alert is displayed before 1st waiting alert is closed by duration, then 1st alert will never automatically close [\#178](https://github.com/dogo/SCLAlertView/issues/178) +- Add support to show only one alert view at the same time. [\#141](https://github.com/dogo/SCLAlertView/issues/141) +- UITextField Return/Done Action \(UIControlEventEditingDidEndOnExit\) [\#123](https://github.com/dogo/SCLAlertView/issues/123) + +## [1.1.5](https://github.com/dogo/SCLAlertView/tree/1.1.5) (2018-06-22) + +[Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.4...1.1.5) + +**Merged pull requests:** + +- core: base builder with fluent has been added. [\#272](https://github.com/dogo/SCLAlertView/pull/272) ([lolgear](https://github.com/lolgear)) ## [1.1.4](https://github.com/dogo/SCLAlertView/tree/1.1.4) (2018-06-19) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.3...1.1.4) **Closed issues:** @@ -19,6 +92,7 @@ - Create CODE\_OF\_CONDUCT.md [\#264](https://github.com/dogo/SCLAlertView/pull/264) ([dogo](https://github.com/dogo)) ## [1.1.3](https://github.com/dogo/SCLAlertView/tree/1.1.3) (2018-01-17) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.2...1.1.3) **Fixed bugs:** @@ -43,6 +117,7 @@ - clerical error [\#249](https://github.com/dogo/SCLAlertView/pull/249) ([amisare](https://github.com/amisare)) ## [1.1.2](https://github.com/dogo/SCLAlertView/tree/1.1.2) (2017-04-11) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.1...1.1.2) **Closed issues:** @@ -56,6 +131,7 @@ - Command failed due to signal: Segmentation fault: 11 swift 3 [\#221](https://github.com/dogo/SCLAlertView/issues/221) ## [1.1.1](https://github.com/dogo/SCLAlertView/tree/1.1.1) (2017-02-16) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.1.0...1.1.1) **Closed issues:** @@ -72,6 +148,7 @@ - Dismiss Animation Completion Block [\#239](https://github.com/dogo/SCLAlertView/pull/239) ([hydr93](https://github.com/hydr93)) ## [1.1.0](https://github.com/dogo/SCLAlertView/tree/1.1.0) (2016-12-07) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.6...1.1.0) **Closed issues:** @@ -83,11 +160,12 @@ **Merged pull requests:** -- Add button custom font support when use buttonConfig block [\#232](https://github.com/dogo/SCLAlertView/pull/232) ([marcoslacerda](https://github.com/marcoslacerda)) +- Add button custom font support when use buttonConfig block [\#232](https://github.com/dogo/SCLAlertView/pull/232) ([maclacerda](https://github.com/maclacerda)) - fix the bug: dismiss SCLAlertViewHideAnimationSimplyDisappear hideAni… [\#230](https://github.com/dogo/SCLAlertView/pull/230) ([JoakimLiu](https://github.com/JoakimLiu)) - Change auto-capitalisation to sentence only [\#229](https://github.com/dogo/SCLAlertView/pull/229) ([idrougge](https://github.com/idrougge)) ## [1.0.6](https://github.com/dogo/SCLAlertView/tree/1.0.6) (2016-10-27) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.5...1.0.6) **Fixed bugs:** @@ -112,6 +190,7 @@ - Changed constants names to avoid name collision [\#224](https://github.com/dogo/SCLAlertView/pull/224) ([damarte](https://github.com/damarte)) ## [1.0.5](https://github.com/dogo/SCLAlertView/tree/1.0.5) (2016-09-13) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.4...1.0.5) **Closed issues:** @@ -123,11 +202,12 @@ **Merged pull requests:** -- Add umbrella header to exclude warnings during framework building [\#220](https://github.com/dogo/SCLAlertView/pull/220) ([alokard](https://github.com/alokard)) -- Add Carthage support [\#210](https://github.com/dogo/SCLAlertView/pull/210) ([alokard](https://github.com/alokard)) +- Add umbrella header to exclude warnings during framework building [\#220](https://github.com/dogo/SCLAlertView/pull/220) ([goncharik](https://github.com/goncharik)) +- Add Carthage support [\#210](https://github.com/dogo/SCLAlertView/pull/210) ([goncharik](https://github.com/goncharik)) - docs: nativescript integration mention [\#209](https://github.com/dogo/SCLAlertView/pull/209) ([NathanWalker](https://github.com/NathanWalker)) ## [1.0.4](https://github.com/dogo/SCLAlertView/tree/1.0.4) (2016-06-21) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.3...1.0.4) **Closed issues:** @@ -137,6 +217,7 @@ - ShowWaiting timer error [\#202](https://github.com/dogo/SCLAlertView/issues/202) ## [1.0.3](https://github.com/dogo/SCLAlertView/tree/1.0.3) (2016-05-03) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.2...1.0.3) **Closed issues:** @@ -151,12 +232,15 @@ - Adds show/hide AnimationTypes 'SimplyAppear' and 'SimplyDisappear' i.e., 'None' [\#198](https://github.com/dogo/SCLAlertView/pull/198) ([AmitaiB](https://github.com/AmitaiB)) ## [1.0.2](https://github.com/dogo/SCLAlertView/tree/1.0.2) (2016-03-16) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.1...1.0.2) ## [1.0.1](https://github.com/dogo/SCLAlertView/tree/1.0.1) (2016-03-08) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/1.0.0...1.0.1) ## [1.0.0](https://github.com/dogo/SCLAlertView/tree/1.0.0) (2016-03-07) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.9.3...1.0.0) **Closed issues:** @@ -174,6 +258,7 @@ - Fluent style support [\#189](https://github.com/dogo/SCLAlertView/pull/189) ([lolgear](https://github.com/lolgear)) ## [0.9.3](https://github.com/dogo/SCLAlertView/tree/0.9.3) (2016-03-03) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.9.2...0.9.3) **Implemented enhancements:** @@ -181,6 +266,7 @@ - Add bounce animation to all slides [\#116](https://github.com/dogo/SCLAlertView/issues/116) ## [0.9.2](https://github.com/dogo/SCLAlertView/tree/0.9.2) (2016-03-03) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.9.1...0.9.2) **Closed issues:** @@ -188,9 +274,11 @@ - Vertical spacing broken on 0.9.0 [\#183](https://github.com/dogo/SCLAlertView/issues/183) ## [0.9.1](https://github.com/dogo/SCLAlertView/tree/0.9.1) (2016-02-15) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.9.0...0.9.1) ## [0.9.0](https://github.com/dogo/SCLAlertView/tree/0.9.0) (2016-02-10) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.8.2...0.9.0) **Implemented enhancements:** @@ -212,6 +300,7 @@ - Change play sound class [\#171](https://github.com/dogo/SCLAlertView/pull/171) ([Liqiankun](https://github.com/Liqiankun)) ## [0.8.2](https://github.com/dogo/SCLAlertView/tree/0.8.2) (2016-01-22) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.8.1...0.8.2) **Closed issues:** @@ -219,6 +308,7 @@ - Memory leak using new window way to display [\#142](https://github.com/dogo/SCLAlertView/issues/142) ## [0.8.1](https://github.com/dogo/SCLAlertView/tree/0.8.1) (2016-01-21) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.8.0...0.8.1) **Fixed bugs:** @@ -232,6 +322,7 @@ - Multitasking Split Screen Bug [\#158](https://github.com/dogo/SCLAlertView/issues/158) ## [0.8.0](https://github.com/dogo/SCLAlertView/tree/0.8.0) (2015-12-29) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.9...0.8.0) **Fixed bugs:** @@ -255,9 +346,9 @@ - Develop [\#163](https://github.com/dogo/SCLAlertView/pull/163) ([jusefjames](https://github.com/jusefjames)) - Prevent viewText scrollable [\#154](https://github.com/dogo/SCLAlertView/pull/154) ([AzulesM](https://github.com/AzulesM)) - Fixing centering problem when used in iPad split view [\#153](https://github.com/dogo/SCLAlertView/pull/153) ([abbasmousavi](https://github.com/abbasmousavi)) -- To get the correct subtitle height [\#152](https://github.com/dogo/SCLAlertView/pull/152) ([AzulesM](https://github.com/AzulesM)) ## [0.7.9](https://github.com/dogo/SCLAlertView/tree/0.7.9) (2015-10-20) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.7...0.7.9) **Fixed bugs:** @@ -275,6 +366,7 @@ - Namespace SCLActionTypes to avoid conflicts [\#144](https://github.com/dogo/SCLAlertView/pull/144) ([mbelkin](https://github.com/mbelkin)) ## [0.7.7](https://github.com/dogo/SCLAlertView/tree/0.7.7) (2015-09-17) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.6...0.7.7) **Closed issues:** @@ -284,9 +376,11 @@ - Modules enabled but still getting disabled error [\#136](https://github.com/dogo/SCLAlertView/issues/136) ## [0.7.6](https://github.com/dogo/SCLAlertView/tree/0.7.6) (2015-09-15) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.5...0.7.6) ## [0.7.5](https://github.com/dogo/SCLAlertView/tree/0.7.5) (2015-09-02) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.4...0.7.5) **Closed issues:** @@ -299,6 +393,7 @@ - Dynamically set button height to allow for multiple lines of text. [\#139](https://github.com/dogo/SCLAlertView/pull/139) ([yatryan](https://github.com/yatryan)) ## [0.7.4](https://github.com/dogo/SCLAlertView/tree/0.7.4) (2015-07-29) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.3...0.7.4) **Closed issues:** @@ -321,6 +416,7 @@ - fix bug [\#134](https://github.com/dogo/SCLAlertView/pull/134) ([HuylensHu](https://github.com/HuylensHu)) ## [0.7.3](https://github.com/dogo/SCLAlertView/tree/0.7.3) (2015-06-10) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.2...0.7.3) **Closed issues:** @@ -328,6 +424,7 @@ - check TextField.text is empty. [\#122](https://github.com/dogo/SCLAlertView/issues/122) ## [0.7.2](https://github.com/dogo/SCLAlertView/tree/0.7.2) (2015-05-29) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.1...0.7.2) **Fixed bugs:** @@ -347,6 +444,7 @@ - If defaultBackgroundColor is preconfigured for button its not changed to... [\#109](https://github.com/dogo/SCLAlertView/pull/109) ([alex1704](https://github.com/alex1704)) ## [0.7.1](https://github.com/dogo/SCLAlertView/tree/0.7.1) (2015-05-04) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.7.0...0.7.1) **Fixed bugs:** @@ -368,6 +466,7 @@ - ignore depreceted inside SCLAlertView [\#103](https://github.com/dogo/SCLAlertView/pull/103) ([jcavar](https://github.com/jcavar)) ## [0.7.0](https://github.com/dogo/SCLAlertView/tree/0.7.0) (2015-04-01) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.6.1...0.7.0) **Fixed bugs:** @@ -385,25 +484,26 @@ - fix screen stutter glitch with blur background [\#96](https://github.com/dogo/SCLAlertView/pull/96) ([felix-dumit](https://github.com/felix-dumit)) - Fixes a bug where you could not set Font attributes on the attributed st... [\#88](https://github.com/dogo/SCLAlertView/pull/88) ([n1mda](https://github.com/n1mda)) +- Automatically add a borderWidth to the button if borderColor is defined [\#85](https://github.com/dogo/SCLAlertView/pull/85) ([jeremygrenier](https://github.com/jeremygrenier)) ## [0.6.1](https://github.com/dogo/SCLAlertView/tree/0.6.1) (2015-03-23) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.6.0...0.6.1) ## [0.6.0](https://github.com/dogo/SCLAlertView/tree/0.6.0) (2015-03-22) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.9...0.6.0) **Closed issues:** - new alert flick [\#83](https://github.com/dogo/SCLAlertView/issues/83) -**Merged pull requests:** - -- Automatically add a borderWidth to the button if borderColor is defined [\#85](https://github.com/dogo/SCLAlertView/pull/85) ([jeremygrenier](https://github.com/jeremygrenier)) - ## [0.5.9](https://github.com/dogo/SCLAlertView/tree/0.5.9) (2015-03-18) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.8...0.5.9) ## [0.5.8](https://github.com/dogo/SCLAlertView/tree/0.5.8) (2015-03-17) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.7...0.5.8) **Implemented enhancements:** @@ -411,6 +511,7 @@ - Custom button height feature request [\#71](https://github.com/dogo/SCLAlertView/issues/71) ## [0.5.7](https://github.com/dogo/SCLAlertView/tree/0.5.7) (2015-03-16) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.6...0.5.7) **Closed issues:** @@ -420,6 +521,7 @@ - BOOL visibility of alert needed [\#73](https://github.com/dogo/SCLAlertView/issues/73) ## [0.5.6](https://github.com/dogo/SCLAlertView/tree/0.5.6) (2015-03-05) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.5...0.5.6) **Fixed bugs:** @@ -427,6 +529,7 @@ - Latest Version Fails To Build [\#74](https://github.com/dogo/SCLAlertView/issues/74) ## [0.5.5](https://github.com/dogo/SCLAlertView/tree/0.5.5) (2015-02-22) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.4...0.5.5) **Closed issues:** @@ -438,6 +541,7 @@ - Minor icon and button customization fixes [\#70](https://github.com/dogo/SCLAlertView/pull/70) ([wzs](https://github.com/wzs)) ## [0.5.4](https://github.com/dogo/SCLAlertView/tree/0.5.4) (2015-02-13) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.3...0.5.4) **Implemented enhancements:** @@ -450,11 +554,10 @@ **Fixed bugs:** -- AlertView does not disable Interactive Pop Gesture [\#66](https://github.com/dogo/SCLAlertView/issues/66) -- Blur background is wrong when shown from "UIModalPresentationFormSheet" [\#65](https://github.com/dogo/SCLAlertView/issues/65) - The white background view is too long [\#53](https://github.com/dogo/SCLAlertView/issues/53) ## [0.5.3](https://github.com/dogo/SCLAlertView/tree/0.5.3) (2015-02-02) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.2...0.5.3) **Fixed bugs:** @@ -466,6 +569,7 @@ - textarea in alert [\#61](https://github.com/dogo/SCLAlertView/issues/61) ## [0.5.2](https://github.com/dogo/SCLAlertView/tree/0.5.2) (2015-01-27) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.1...0.5.2) **Implemented enhancements:** @@ -477,6 +581,7 @@ - ability to only show one alert [\#56](https://github.com/dogo/SCLAlertView/issues/56) ## [0.5.1](https://github.com/dogo/SCLAlertView/tree/0.5.1) (2015-01-26) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.5.0...0.5.1) **Implemented enhancements:** @@ -493,6 +598,7 @@ - Rotating with keyboard [\#36](https://github.com/dogo/SCLAlertView/issues/36) ## [0.5.0](https://github.com/dogo/SCLAlertView/tree/0.5.0) (2015-01-21) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.4.3...0.5.0) **Fixed bugs:** @@ -500,6 +606,7 @@ - Display in formsheet [\#50](https://github.com/dogo/SCLAlertView/issues/50) ## [0.4.3](https://github.com/dogo/SCLAlertView/tree/0.4.3) (2015-01-20) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.4.2...0.4.3) **Closed issues:** @@ -507,6 +614,7 @@ - Change Title Size [\#42](https://github.com/dogo/SCLAlertView/issues/42) ## [0.4.2](https://github.com/dogo/SCLAlertView/tree/0.4.2) (2015-01-20) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.4.1...0.4.2) **Closed issues:** @@ -515,6 +623,7 @@ - does not work with UIPIckview [\#26](https://github.com/dogo/SCLAlertView/issues/26) ## [0.4.1](https://github.com/dogo/SCLAlertView/tree/0.4.1) (2015-01-19) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.4.0...0.4.1) **Closed issues:** @@ -523,6 +632,7 @@ - Landscape not working on iPad [\#48](https://github.com/dogo/SCLAlertView/issues/48) ## [0.4.0](https://github.com/dogo/SCLAlertView/tree/0.4.0) (2015-01-19) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.9...0.4.0) **Fixed bugs:** @@ -539,9 +649,11 @@ - fix \#44 [\#47](https://github.com/dogo/SCLAlertView/pull/47) ([portwatcher](https://github.com/portwatcher)) ## [0.3.9](https://github.com/dogo/SCLAlertView/tree/0.3.9) (2015-01-15) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.8...0.3.9) ## [0.3.8](https://github.com/dogo/SCLAlertView/tree/0.3.8) (2015-01-12) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.7...0.3.8) **Implemented enhancements:** @@ -553,6 +665,7 @@ - alertview position issue [\#39](https://github.com/dogo/SCLAlertView/issues/39) ## [0.3.7](https://github.com/dogo/SCLAlertView/tree/0.3.7) (2014-12-13) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.6...0.3.7) **Closed issues:** @@ -566,6 +679,7 @@ - Subtitle Height Setting [\#34](https://github.com/dogo/SCLAlertView/pull/34) ([ancloid](https://github.com/ancloid)) ## [0.3.6](https://github.com/dogo/SCLAlertView/tree/0.3.6) (2014-12-09) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.5...0.3.6) **Closed issues:** @@ -579,6 +693,7 @@ - modified podspec file to support iOS6 [\#33](https://github.com/dogo/SCLAlertView/pull/33) ([shannonchou](https://github.com/shannonchou)) ## [0.3.5](https://github.com/dogo/SCLAlertView/tree/0.3.5) (2014-11-28) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.4...0.3.5) **Implemented enhancements:** @@ -591,6 +706,7 @@ - EXC\_BAD\_ACCESS \(code=1\) [\#28](https://github.com/dogo/SCLAlertView/issues/28) ## [0.3.4](https://github.com/dogo/SCLAlertView/tree/0.3.4) (2014-11-14) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.3...0.3.4) **Closed issues:** @@ -598,9 +714,11 @@ - Any way to show this from a UIView? [\#11](https://github.com/dogo/SCLAlertView/issues/11) ## [0.3.3](https://github.com/dogo/SCLAlertView/tree/0.3.3) (2014-11-11) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.2...0.3.3) ## [0.3.2](https://github.com/dogo/SCLAlertView/tree/0.3.2) (2014-11-05) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.1...0.3.2) **Fixed bugs:** @@ -612,9 +730,11 @@ - Any of the showAnimationType not working [\#22](https://github.com/dogo/SCLAlertView/issues/22) ## [0.3.1](https://github.com/dogo/SCLAlertView/tree/0.3.1) (2014-11-04) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.3.0...0.3.1) ## [0.3.0](https://github.com/dogo/SCLAlertView/tree/0.3.0) (2014-11-04) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.6...0.3.0) **Implemented enhancements:** @@ -638,18 +758,23 @@ - fix showAnimation bug [\#19](https://github.com/dogo/SCLAlertView/pull/19) ([sanshanchuns](https://github.com/sanshanchuns)) ## [0.2.6](https://github.com/dogo/SCLAlertView/tree/0.2.6) (2014-10-23) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.5...0.2.6) ## [0.2.5](https://github.com/dogo/SCLAlertView/tree/0.2.5) (2014-10-23) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.4...0.2.5) ## [0.2.4](https://github.com/dogo/SCLAlertView/tree/0.2.4) (2014-10-22) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.3...0.2.4) ## [0.2.3](https://github.com/dogo/SCLAlertView/tree/0.2.3) (2014-10-21) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.2...0.2.3) ## [0.2.2](https://github.com/dogo/SCLAlertView/tree/0.2.2) (2014-10-21) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.1...0.2.2) **Implemented enhancements:** @@ -657,6 +782,7 @@ - is possible button show touch down or touch up display? [\#10](https://github.com/dogo/SCLAlertView/issues/10) ## [0.2.1](https://github.com/dogo/SCLAlertView/tree/0.2.1) (2014-10-20) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.2.0...0.2.1) **Closed issues:** @@ -669,6 +795,7 @@ - Add validation block [\#9](https://github.com/dogo/SCLAlertView/pull/9) ([mamaral](https://github.com/mamaral)) ## [0.2.0](https://github.com/dogo/SCLAlertView/tree/0.2.0) (2014-10-18) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.1.2...0.2.0) **Implemented enhancements:** @@ -682,6 +809,7 @@ - Custom icon and color [\#6](https://github.com/dogo/SCLAlertView/pull/6) ([mamaral](https://github.com/mamaral)) ## [0.1.2](https://github.com/dogo/SCLAlertView/tree/0.1.2) (2014-10-13) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.1.1...0.1.2) **Closed issues:** @@ -690,18 +818,25 @@ - Issues with a side menu controller [\#1](https://github.com/dogo/SCLAlertView/issues/1) ## [0.1.1](https://github.com/dogo/SCLAlertView/tree/0.1.1) (2014-10-09) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.1.0...0.1.1) ## [0.1.0](https://github.com/dogo/SCLAlertView/tree/0.1.0) (2014-10-08) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.0.3...0.1.0) ## [0.0.3](https://github.com/dogo/SCLAlertView/tree/0.0.3) (2014-10-03) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.0.2...0.0.3) ## [0.0.2](https://github.com/dogo/SCLAlertView/tree/0.0.2) (2014-09-29) + [Full Changelog](https://github.com/dogo/SCLAlertView/compare/0.0.1...0.0.2) ## [0.0.1](https://github.com/dogo/SCLAlertView/tree/0.0.1) (2014-09-29) +[Full Changelog](https://github.com/dogo/SCLAlertView/compare/49477fbc62f611ec0dd04590afa3d29972b60d22...0.0.1) + + -\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file +\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* From ba85bbad0d1a828fb19f32897f40bcbe24d48d8c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 May 2024 21:48:17 +0000 Subject: [PATCH 12/41] Bump rexml from 3.2.6 to 3.2.8 Bumps [rexml](https://github.com/ruby/rexml) from 3.2.6 to 3.2.8. - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.2.6...v3.2.8) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index b87ed7b..4b57bda 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -82,9 +82,11 @@ GEM nap (1.1.0) netrc (0.11.0) public_suffix (4.0.7) - rexml (3.2.6) + rexml (3.2.8) + strscan (>= 3.0.9) ruby-macho (2.5.1) ruby2_keywords (0.0.5) + strscan (3.1.0) typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) @@ -99,6 +101,7 @@ GEM PLATFORMS x86_64-darwin-23 + x86_64-linux DEPENDENCIES cocoapods From 5e7e2e897e091011ffec32cc83d948c512e79e11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:28:21 +0000 Subject: [PATCH 13/41] Bump rexml from 3.2.8 to 3.3.9 Bumps [rexml](https://github.com/ruby/rexml) from 3.2.8 to 3.3.9. - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.2.8...v3.3.9) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4b57bda..573df91 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -82,22 +82,20 @@ GEM nap (1.1.0) netrc (0.11.0) public_suffix (4.0.7) - rexml (3.2.8) - strscan (>= 3.0.9) + rexml (3.3.9) ruby-macho (2.5.1) ruby2_keywords (0.0.5) - strscan (3.1.0) typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - xcodeproj (1.23.0) + xcodeproj (1.25.1) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (~> 3.2.4) + rexml (>= 3.3.6, < 4.0) PLATFORMS x86_64-darwin-23 From 8d24b4263771792fce872e61b3b768bce250d7a3 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 15 Apr 2025 12:15:23 +0000 Subject: [PATCH 14/41] Update Build.yml --- .github/workflows/Build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index d89814b..d55e0a1 100755 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -4,13 +4,13 @@ on: [push, pull_request] jobs: build: name: Building SCLAlertView - runs-on: macOS-latest + runs-on: macos-13 steps: - name: Checkout repository uses: actions/checkout@v3 - name: Setup Xcode version - uses: maxim-lobanov/setup-xcode@v1.4.1 + uses: maxim-lobanov/setup-xcode@v1.6.0 with: - xcode-version: 13.2.1 + xcode-version: 15.0.1 - name: Building iOS app run: exec ./.github/scripts/build_app.sh From 4e9a4a7d52fa16c22ced8e55d6f93c135b2260f3 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 15 Apr 2025 12:17:26 +0000 Subject: [PATCH 15/41] Update build_app.sh --- .github/scripts/build_app.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/build_app.sh b/.github/scripts/build_app.sh index 746dab3..14ce85d 100755 --- a/.github/scripts/build_app.sh +++ b/.github/scripts/build_app.sh @@ -4,5 +4,5 @@ set -eo pipefail xcodebuild -project SCLAlertView.xcodeproj \ -scheme SCLAlertView \ - -destination platform=iOS\ Simulator,OS=15.2,name=iPhone\ 11 \ + -destination platform=iOS\ Simulator,OS=17.2,name=iPhone\ 15 \ clean build | xcpretty From 5f7ef783fcb845606800bf8da40269d611451734 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 15 Apr 2025 12:19:09 +0000 Subject: [PATCH 16/41] Update .ruby-version --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index 57cf282..ef538c2 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.6.5 +3.1.2 From 67a329c750e2b5194afc524234d947b5fd776997 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 18:39:47 +0000 Subject: [PATCH 17/41] Bump rexml from 3.3.9 to 3.4.2 Bumps [rexml](https://github.com/ruby/rexml) from 3.3.9 to 3.4.2. - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.3.9...v3.4.2) --- updated-dependencies: - dependency-name: rexml dependency-version: 3.4.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 573df91..a088a51 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -82,7 +82,7 @@ GEM nap (1.1.0) netrc (0.11.0) public_suffix (4.0.7) - rexml (3.3.9) + rexml (3.4.2) ruby-macho (2.5.1) ruby2_keywords (0.0.5) typhoeus (1.4.1) From eb527918a825eb7b93ff89132b1079ad74c43cef Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 7 Oct 2025 10:02:19 -0300 Subject: [PATCH 18/41] Update CocoaPods to 1.16.2 (was 1.14.3) --- Gemfile.lock | 70 ++++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a088a51..fe58e35 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,31 +1,36 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.6) + CFPropertyList (3.0.7) + base64 + nkf rexml - activesupport (7.1.2) + activesupport (7.2.2.2) base64 + benchmark (>= 0.3) bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) atomos (0.1.3) - base64 (0.2.0) - bigdecimal (3.1.5) + base64 (0.3.0) + benchmark (0.4.1) + bigdecimal (3.3.0) claide (1.1.0) - cocoapods (1.14.3) + cocoapods (1.16.2) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.14.3) + cocoapods-core (= 1.16.2) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -39,8 +44,8 @@ GEM molinillo (~> 0.8.0) nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) - xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.14.3) + xcodeproj (>= 1.27.0, < 2.0) + cocoapods-core (1.16.2) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -60,46 +65,47 @@ GEM netrc (~> 0.11) cocoapods-try (1.2.0) colored2 (3.1.2) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - drb (2.2.0) - ruby2_keywords + concurrent-ruby (1.3.5) + connection_pool (2.5.4) + drb (2.2.3) escape (0.0.4) - ethon (0.16.0) + ethon (0.15.0) ffi (>= 1.15.0) - ffi (1.16.3) + ffi (1.17.2-x86_64-darwin) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - httpclient (2.8.3) - i18n (1.14.1) + httpclient (2.9.0) + mutex_m + i18n (1.14.7) concurrent-ruby (~> 1.0) - json (2.7.1) - minitest (5.20.0) + json (2.15.1) + logger (1.7.0) + minitest (5.25.5) molinillo (0.8.0) - mutex_m (0.2.0) - nanaimo (0.3.0) + mutex_m (0.3.0) + nanaimo (0.4.0) nap (1.1.0) netrc (0.11.0) + nkf (0.2.0) public_suffix (4.0.7) - rexml (3.4.2) + rexml (3.4.4) ruby-macho (2.5.1) - ruby2_keywords (0.0.5) - typhoeus (1.4.1) - ethon (>= 0.9.0) + securerandom (0.4.1) + typhoeus (1.5.0) + ethon (>= 0.9.0, < 0.16.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - xcodeproj (1.25.1) + xcodeproj (1.27.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) - nanaimo (~> 0.3.0) + nanaimo (~> 0.4.0) rexml (>= 3.3.6, < 4.0) PLATFORMS x86_64-darwin-23 - x86_64-linux DEPENDENCIES cocoapods From 788e0b859ef6ff44e0be4c3c7acec7e6d69495f0 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 7 Oct 2025 10:50:34 -0300 Subject: [PATCH 19/41] feat(alert): improve background blur capture for iOS 13+ scenes and iOS 26 safety Added SCLAlertView+WindowResolver category to resolve the active window via UIScene, replacing deprecated keyWindow. Updated makeBlurBackground to use new resolver and call layoutIfNeeded before snapshot. Replaced legacy snapshot code with UIGraphicsImageRenderer to prevent CGBitmapContext size={0,0} crash on iOS 26. --- SCLAlertView.xcodeproj/project.pbxproj | 26 ++++++++---- SCLAlertView/SCLAlertView+WindowResolver.h | 24 +++++++++++ SCLAlertView/SCLAlertView+WindowResolver.m | 45 ++++++++++++++++++++ SCLAlertView/SCLAlertView.m | 32 ++++++++++---- SCLAlertView/UIImage+ImageEffects.m | 49 ++++++++++++++++------ 5 files changed, 147 insertions(+), 29 deletions(-) create mode 100644 SCLAlertView/SCLAlertView+WindowResolver.h create mode 100644 SCLAlertView/SCLAlertView+WindowResolver.m diff --git a/SCLAlertView.xcodeproj/project.pbxproj b/SCLAlertView.xcodeproj/project.pbxproj index 1d41bc0..cc28820 100644 --- a/SCLAlertView.xcodeproj/project.pbxproj +++ b/SCLAlertView.xcodeproj/project.pbxproj @@ -21,6 +21,9 @@ DD2E172A19FA84B800CBAEC3 /* UIImage+ImageEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = DD2E172919FA84B800CBAEC3 /* UIImage+ImageEffects.m */; }; DD4B77E41D8C580B00CF97C7 /* SCLAlertViewFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 44E430DB1D889255002FE849 /* SCLAlertViewFramework.h */; settings = {ATTRIBUTES = (Public, ); }; }; DD4BA9C119DED8EF008D73EB /* right_answer.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = DD4BA9C019DED8EF008D73EB /* right_answer.mp3 */; }; + DD5F3E112E954CB700E91C60 /* SCLAlertView+WindowResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = DD5F3E102E954CB400E91C60 /* SCLAlertView+WindowResolver.h */; }; + DD5F3E132E954D3100E91C60 /* SCLAlertView+WindowResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = DD5F3E122E954D2F00E91C60 /* SCLAlertView+WindowResolver.m */; }; + DD5F3E142E954D3100E91C60 /* SCLAlertView+WindowResolver.m in Sources */ = {isa = PBXBuildFile; fileRef = DD5F3E122E954D2F00E91C60 /* SCLAlertView+WindowResolver.m */; }; DD7282B919D6087C00077F54 /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DD7282B719D6087C00077F54 /* Storyboard.storyboard */; }; DDAD0113254DEABA00270C67 /* UIViewController+Alert.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAD0111254DEABA00270C67 /* UIViewController+Alert.m */; }; DDAD011D254DEAEC00270C67 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAD0119254DEAEC00270C67 /* AppDelegate.m */; }; @@ -73,6 +76,8 @@ DD2F03171AAFA4E0007BC507 /* SCLMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCLMacros.h; sourceTree = ""; }; DD4BA9C019DED8EF008D73EB /* right_answer.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = right_answer.mp3; sourceTree = ""; }; DD4BA9C219DEDD8E008D73EB /* SCLAlertView-Objective-C-prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SCLAlertView-Objective-C-prefix.pch"; path = "SCLAlertViewExample/SCLAlertView-Objective-C-prefix.pch"; sourceTree = SOURCE_ROOT; }; + DD5F3E102E954CB400E91C60 /* SCLAlertView+WindowResolver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SCLAlertView+WindowResolver.h"; sourceTree = ""; }; + DD5F3E122E954D2F00E91C60 /* SCLAlertView+WindowResolver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SCLAlertView+WindowResolver.m"; sourceTree = ""; }; DD7282B819D6087C00077F54 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = SCLAlertViewExample/Base.lproj/Storyboard.storyboard; sourceTree = SOURCE_ROOT; }; DDAD0111254DEABA00270C67 /* UIViewController+Alert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+Alert.m"; sourceTree = ""; }; DDAD0112254DEABA00270C67 /* UIViewController+Alert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Alert.h"; sourceTree = ""; }; @@ -248,23 +253,25 @@ DDB15FD519D5B96500173158 /* SCLAlertView */ = { isa = PBXGroup; children = ( - DD2E172819FA84B800CBAEC3 /* UIImage+ImageEffects.h */, - DD2E172919FA84B800CBAEC3 /* UIImage+ImageEffects.m */, DDB15FD819D5B98800173158 /* SCLAlertView.h */, DDB15FD619D5B96500173158 /* SCLAlertView.m */, - DDB15FD919D5BAA000173158 /* SCLButton.h */, - DDB15FDA19D5BAA000173158 /* SCLButton.m */, + DD5F3E102E954CB400E91C60 /* SCLAlertView+WindowResolver.h */, + DD5F3E122E954D2F00E91C60 /* SCLAlertView+WindowResolver.m */, DDB15FDC19D5BCF400173158 /* SCLAlertViewResponder.h */, DDB15FDD19D5BCF400173158 /* SCLAlertViewResponder.m */, DDB15FDF19D5D85B00173158 /* SCLAlertViewStyleKit.h */, DDB15FE019D5D85B00173158 /* SCLAlertViewStyleKit.m */, + DDB15FD919D5BAA000173158 /* SCLButton.h */, + DDB15FDA19D5BAA000173158 /* SCLButton.m */, DD2F03171AAFA4E0007BC507 /* SCLMacros.h */, - 572BB1451B8383B3002DEE38 /* SCLTimerDisplay.h */, - 572BB1461B8383B3002DEE38 /* SCLTimerDisplay.m */, - DD24453A1BAC383600892117 /* SCLTextView.h */, - DD24453B1BAC383600892117 /* SCLTextView.m */, CF6FB1221C5926FC009715F3 /* SCLSwitchView.h */, CF6FB1231C5926FC009715F3 /* SCLSwitchView.m */, + DD24453A1BAC383600892117 /* SCLTextView.h */, + DD24453B1BAC383600892117 /* SCLTextView.m */, + 572BB1451B8383B3002DEE38 /* SCLTimerDisplay.h */, + 572BB1461B8383B3002DEE38 /* SCLTimerDisplay.m */, + DD2E172819FA84B800CBAEC3 /* UIImage+ImageEffects.h */, + DD2E172919FA84B800CBAEC3 /* UIImage+ImageEffects.m */, ); path = SCLAlertView; sourceTree = ""; @@ -299,6 +306,7 @@ 726C8FA81EF805620060F33B /* SCLTextView.h in Headers */, 726C8FA71EF805520060F33B /* SCLButton.h in Headers */, DD4B77E41D8C580B00CF97C7 /* SCLAlertViewFramework.h in Headers */, + DD5F3E112E954CB700E91C60 /* SCLAlertView+WindowResolver.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -443,6 +451,7 @@ DD24453C1BAC383600892117 /* SCLTextView.m in Sources */, 572BB1471B8383B3002DEE38 /* SCLTimerDisplay.m in Sources */, DDB15FD719D5B96500173158 /* SCLAlertView.m in Sources */, + DD5F3E132E954D3100E91C60 /* SCLAlertView+WindowResolver.m in Sources */, DDB15FDB19D5BAA000173158 /* SCLButton.m in Sources */, DDB15FDE19D5BCF400173158 /* SCLAlertViewResponder.m in Sources */, ); @@ -462,6 +471,7 @@ files = ( EF994B191D47AB4A00619DFF /* SCLAlertViewStyleKit.m in Sources */, EF994B1C1D47AB4A00619DFF /* SCLSwitchView.m in Sources */, + DD5F3E142E954D3100E91C60 /* SCLAlertView+WindowResolver.m in Sources */, EF994B1A1D47AB4A00619DFF /* SCLTimerDisplay.m in Sources */, EF994B161D47AB4A00619DFF /* SCLAlertView.m in Sources */, EF994B181D47AB4A00619DFF /* SCLAlertViewResponder.m in Sources */, diff --git a/SCLAlertView/SCLAlertView+WindowResolver.h b/SCLAlertView/SCLAlertView+WindowResolver.h new file mode 100644 index 0000000..ade6576 --- /dev/null +++ b/SCLAlertView/SCLAlertView+WindowResolver.h @@ -0,0 +1,24 @@ +// +// SCLAlertView+WindowResolver.h +// SCLAlertView +// +// Created by Diogo Autilio on 07/10/25. +// Copyright (c) 2025 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertView.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface SCLAlertView (WindowResolver) + +/// Active window (iOS 13+ compatible with UIScene) ++ (nullable UIWindow *)scl_currentKeyWindow; + +/// Resolves the best app view for snapshot/blur. +/// If there is no valid window, returns the provided `fallback`. ++ (nullable UIView *)scl_resolveAppViewWithFallback:(nullable UIView *)fallback; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertView/SCLAlertView+WindowResolver.m b/SCLAlertView/SCLAlertView+WindowResolver.m new file mode 100644 index 0000000..ede91a7 --- /dev/null +++ b/SCLAlertView/SCLAlertView+WindowResolver.m @@ -0,0 +1,45 @@ +// +// SCLAlertView+WindowResolver.m +// SCLAlertView +// +// Created by Diogo Autilio on 07/10/25. +// Copyright (c) 2025 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertView+WindowResolver.h" +#import + +@implementation SCLAlertView (WindowResolver) + ++ (UIWindow *)scl_currentKeyWindow { + UIApplication *app = UIApplication.sharedApplication; + if (@available(iOS 13.0, *)) { + for (UIScene *scene in app.connectedScenes) { + if (scene.activationState == UISceneActivationStateForegroundActive && + [scene isKindOfClass:[UIWindowScene class]]) { + UIWindowScene *ws = (UIWindowScene *)scene; + for (UIWindow *w in ws.windows) { + if (w.isKeyWindow) return w; + } + if (ws.windows.firstObject) return ws.windows.firstObject; + } + } + for (UIScene *scene in app.connectedScenes) { + if ([scene isKindOfClass:[UIWindowScene class]]) { + UIWindowScene *ws = (UIWindowScene *)scene; + if (ws.windows.firstObject) return ws.windows.firstObject; + } + } + return nil; + } else { + return app.keyWindow; + } +} + ++ (UIView *)scl_resolveAppViewWithFallback:(UIView *)fallback { + UIWindow *key = [self scl_currentKeyWindow]; + if (key) return key; + return fallback; +} + +@end diff --git a/SCLAlertView/SCLAlertView.m b/SCLAlertView/SCLAlertView.m index 909b907..7a9689c 100755 --- a/SCLAlertView/SCLAlertView.m +++ b/SCLAlertView/SCLAlertView.m @@ -10,6 +10,7 @@ #import "SCLAlertViewResponder.h" #import "SCLAlertViewStyleKit.h" #import "UIImage+ImageEffects.h" +#import "SCLAlertView+WindowResolver.h" #import "SCLTimerDisplay.h" #import "SCLMacros.h" @@ -1191,15 +1192,29 @@ - (void)makeShadowBackground - (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]; + UIView *fallbackView = _rootViewController.view; + UIView *appView = _usingNewWindow ? (UIView *)[SCLAlertView scl_currentKeyWindow] : fallbackView; - _backgroundView.image = blurSnapshotImage; + // final fallback in case it still comes as nil + if (!appView) { + appView = [SCLAlertView scl_resolveAppViewWithFallback:fallbackView]; + } + + [appView layoutIfNeeded]; + + UIImage *snapshot = [UIImage convertViewToImage:appView]; + if (snapshot) { + UIImage *blurSnapshotImage = [snapshot applyBlurWithRadius:5.0f + tintColor:[UIColor colorWithWhite:0.2f + alpha:0.7f] + saturationDeltaFactor:1.8f + maskImage:nil]; + + _backgroundView.image = blurSnapshotImage; + } else { + _backgroundView.image = nil; + _backgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.4f]; + } _backgroundView.alpha = 0.0f; _backgroundOpacity = 1.0f; } @@ -2027,3 +2042,4 @@ - (void)showAlertView:(SCLAlertView *)alertView onViewController:(UIViewControll } @end + diff --git a/SCLAlertView/UIImage+ImageEffects.m b/SCLAlertView/UIImage+ImageEffects.m index 121e0e6..7c27fbb 100755 --- a/SCLAlertView/UIImage+ImageEffects.m +++ b/SCLAlertView/UIImage+ImageEffects.m @@ -102,7 +102,7 @@ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF #import #endif #import - +#import @implementation UIImage (ImageEffects) @@ -307,18 +307,41 @@ + (UIImage *)convertViewToImage 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; ++ (UIImage *)convertViewToImage:(UIView *)view { + if (!view) { return nil; } + + [view layoutIfNeeded]; + + CGSize size = view.bounds.size; + if (size.width <= 0.0 || size.height <= 0.0) { + return nil; + } + + CGFloat scale = UIScreen.mainScreen.scale; + + if (@available(iOS 10.0, *)) { + UIGraphicsImageRendererFormat *fmt = [UIGraphicsImageRendererFormat defaultFormat]; + fmt.scale = scale; + fmt.opaque = YES; + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size format:fmt]; + return [renderer imageWithActions:^(__kindof UIGraphicsImageRendererContext * _Nonnull context) { + BOOL ok = [view drawViewHierarchyInRect:(CGRect){.origin = CGPointZero, .size = size} + afterScreenUpdates:NO]; + if (!ok) { + [view.layer renderInContext:context.CGContext]; + } + }]; + } else { + UIGraphicsBeginImageContextWithOptions(size, YES, scale); + BOOL ok = [view drawViewHierarchyInRect:(CGRect){.origin = CGPointZero, .size = size} + afterScreenUpdates:NO]; + if (!ok) { + [view.layer renderInContext:UIGraphicsGetCurrentContext()]; + } + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return image; + } } @end From 1aeb76792da54bce73b79799b2757dbc905f3f1d Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 7 Oct 2025 10:51:30 -0300 Subject: [PATCH 20/41] Bump version to 1.3.1 --- SCLAlertView-Objective-C.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SCLAlertView-Objective-C.podspec b/SCLAlertView-Objective-C.podspec index 5e2f0a3..67c3b1a 100644 --- a/SCLAlertView-Objective-C.podspec +++ b/SCLAlertView-Objective-C.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "SCLAlertView-Objective-C" - spec.version = "1.3.0" + spec.version = "1.3.1" spec.summary = "Beautiful animated Alert View. Written in Swift but ported to Objective-C" spec.homepage = "https://github.com/dogo/SCLAlertView" spec.screenshots = "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot.png", "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot2.png" From db869afcf85590f9fe8f79a7f1e71f8c9855791c Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 7 Oct 2025 11:38:46 -0300 Subject: [PATCH 21/41] chore: bump minimum iOS deployment target from 9.0 to 12.0 Xcode 16 no longer supports deployment targets below iOS 12. --- SCLAlertView-Objective-C.podspec | 2 +- SCLAlertView.xcodeproj/project.pbxproj | 16 +++++++++------- .../xcshareddata/xcschemes/SCLAlertView.xcscheme | 2 +- .../xcschemes/SCLAlertViewFramework.xcscheme | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/SCLAlertView-Objective-C.podspec b/SCLAlertView-Objective-C.podspec index 67c3b1a..deda426 100644 --- a/SCLAlertView-Objective-C.podspec +++ b/SCLAlertView-Objective-C.podspec @@ -10,7 +10,7 @@ Pod::Spec.new do |spec| spec.social_media_url = "http://twitter.com/di_autilio" spec.platform = :ios spec.frameworks = "UIKit", "AudioToolbox", "Accelerate", "CoreGraphics" - spec.ios.deployment_target = '9.0' + spec.ios.deployment_target = '12.0' spec.source = { :git => "https://github.com/dogo/SCLAlertView.git", :tag => spec.version.to_s } spec.source_files = "SCLAlertView/*" spec.requires_arc = true diff --git a/SCLAlertView.xcodeproj/project.pbxproj b/SCLAlertView.xcodeproj/project.pbxproj index cc28820..fa74768 100644 --- a/SCLAlertView.xcodeproj/project.pbxproj +++ b/SCLAlertView.xcodeproj/project.pbxproj @@ -372,7 +372,7 @@ DDB15F9519D5B7C600173158 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1200; + LastUpgradeCheck = 2600; ORGANIZATIONNAME = "AnyKey Entertainment"; TargetAttributes = { DDB15F9C19D5B7C600173158 = { @@ -550,7 +550,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -598,7 +598,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -613,7 +613,7 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = "$(SRCROOT)/SCLAlertViewExample/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "br.com.anykey.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -629,7 +629,7 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = "$(SRCROOT)/SCLAlertViewExample/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "br.com.anykey.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -650,6 +650,7 @@ "$(inherited)", ); INFOPLIST_FILE = SCLAlertViewTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "br.com.anykey.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -666,6 +667,7 @@ "$(inherited)", ); INFOPLIST_FILE = SCLAlertViewTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "br.com.anykey.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -687,7 +689,7 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SCLAlertViewFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = br.com.anykey.SCLAlertViewFramework; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -714,7 +716,7 @@ GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SCLAlertViewFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = br.com.anykey.SCLAlertViewFramework; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme b/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme index aafb128..5e094fc 100644 --- a/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme +++ b/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme @@ -1,6 +1,6 @@ Date: Tue, 7 Oct 2025 13:12:04 -0300 Subject: [PATCH 22/41] chore: project modernization --- SCLAlertView/SCLAlertView.h | 608 ++++++++---------- SCLAlertView/SCLAlertView.m | 162 +++-- SCLAlertView/SCLAlertViewResponder.h | 20 +- SCLAlertView/SCLAlertViewResponder.m | 19 +- SCLAlertView/SCLAlertViewStyleKit.m | 30 +- SCLAlertView/SCLButton.h | 138 ++-- SCLAlertView/SCLButton.m | 14 +- SCLAlertView/SCLMacros.h | 9 +- SCLAlertView/SCLSwitchView.h | 30 +- SCLAlertView/SCLSwitchView.m | 57 +- SCLAlertView/SCLTextView.h | 14 +- SCLAlertView/SCLTextView.m | 72 ++- SCLAlertView/SCLTimerDisplay.h | 65 +- SCLAlertView/SCLTimerDisplay.m | 159 ++++- .../Category/UIViewController+Alert.m | 4 +- .../ViewController/ViewController.m | 92 ++- SCLAlertViewFramework/SCLAlertViewFramework.h | 2 +- 17 files changed, 873 insertions(+), 622 deletions(-) diff --git a/SCLAlertView/SCLAlertView.h b/SCLAlertView/SCLAlertView.h index 1df8008..084fd1f 100755 --- a/SCLAlertView/SCLAlertView.h +++ b/SCLAlertView/SCLAlertView.h @@ -3,30 +3,25 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2025 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); +NS_ASSUME_NONNULL_BEGIN + +typedef NSAttributedString* _Nonnull (^SCLAttributedFormatBlock)(NSString *value); typedef void (^SCLDismissBlock)(void); typedef void (^SCLDismissAnimationCompletionBlock)(void); typedef void (^SCLShowAnimationCompletionBlock)(void); typedef void (^SCLForceHideBlock)(void); -@interface SCLAlertView : UIViewController +@interface SCLAlertView : UIViewController -/** Alert Styles - * - * Set SCLAlertView Style - */ +/** Predefined alert styles. */ typedef NS_ENUM(NSInteger, SCLAlertViewStyle) { SCLAlertViewStyleSuccess, @@ -40,10 +35,7 @@ typedef NS_ENUM(NSInteger, SCLAlertViewStyle) SCLAlertViewStyleCustom }; -/** Alert hide animation styles - * - * Set SCLAlertView hide animation type. - */ +/** Hide animation styles. */ typedef NS_ENUM(NSInteger, SCLAlertViewHideAnimation) { SCLAlertViewHideAnimationFadeOut, @@ -56,10 +48,7 @@ typedef NS_ENUM(NSInteger, SCLAlertViewHideAnimation) SCLAlertViewHideAnimationSimplyDisappear }; -/** Alert show animation styles - * - * Set SCLAlertView show animation type. - */ +/** Show animation styles. */ typedef NS_ENUM(NSInteger, SCLAlertViewShowAnimation) { SCLAlertViewShowAnimationFadeIn, @@ -72,10 +61,7 @@ typedef NS_ENUM(NSInteger, SCLAlertViewShowAnimation) SCLAlertViewShowAnimationSimplyAppear }; -/** Alert background styles - * - * Set SCLAlertView background type. - */ +/** Background styles. */ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) { SCLAlertViewBackgroundShadow, @@ -83,395 +69,369 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) SCLAlertViewBackgroundTransparent }; -/** Content view corner radius - * - * A float value that replaces the standard content viuew corner radius. - */ +/// Overrides the content view corner radius. @property CGFloat cornerRadius; -/** Tint top circle - * - * A boolean value that determines whether to tint the SCLAlertView top circle. - * (Default: YES) - */ +/// Whether the top circle is tinted with the alert color. (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) - */ +/// Whether to use a larger icon in the top circle. (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; +/// Title label displayed at the top of the alert. +@property (strong, nonatomic, nullable) UILabel *labelTitle; -/** Activity Indicator - * - * Holds the activityIndicator. - */ -@property (strong, nonatomic) UIActivityIndicatorView *activityIndicatorView; +/// Text view containing the message body. +@property (strong, nonatomic, nullable) UITextView *viewText; -/** Dismiss on tap outside - * - * A boolean value that determines whether to dismiss when tapping outside the SCLAlertView. - * (Default: NO) - */ +/// Activity indicator used for Waiting style. +@property (strong, nonatomic, nullable) UIActivityIndicatorView *activityIndicatorView; + +/// If YES, tapping outside the alert dismisses it. (Default: NO) @property (assign, nonatomic) BOOL shouldDismissOnTapOutside; -/** Sound URL - * - * Holds the sound NSURL path. - */ -@property (strong, nonatomic) NSURL *soundURL; +/// URL of the sound to play. +@property (strong, nonatomic, nullable) NSURL *soundURL; -/** Set text attributed format block - * - * Holds the attributed string. - */ -@property (copy, nonatomic) SCLAttributedFormatBlock attributedFormatBlock; +/// Provides an attributed string for the body text. +@property (copy, nonatomic, nullable) SCLAttributedFormatBlock attributedFormatBlock; -/** Set Complete button format block. - * - * Holds the button format block. - * Support keys : backgroundColor, borderWidth, borderColor, textColor - */ -@property (copy, nonatomic) CompleteButtonFormatBlock completeButtonFormatBlock; +/// Provides full button styling (backgroundColor, borderWidth, borderColor, textColor). +@property (copy, nonatomic, nullable) CompleteButtonFormatBlock completeButtonFormatBlock; -/** Set button format block. - * - * Holds the button format block. - * Support keys : backgroundColor, borderWidth, borderColor, textColor - */ -@property (copy, nonatomic) ButtonFormatBlock buttonFormatBlock; +/// Provides button styling (backgroundColor, borderWidth, borderColor, textColor). +@property (copy, nonatomic, nullable) ButtonFormatBlock buttonFormatBlock; -/** Set force hide block. - * - * When set force hideview method invocation. - */ -@property (copy, nonatomic) SCLForceHideBlock forceHideBlock; +/// If set, calling this property triggers hideView. +@property (copy, nonatomic, nullable) SCLForceHideBlock forceHideBlock; -/** Hide animation type - * - * Holds the hide animation type. - * (Default: FadeOut) - */ +/// Hide animation type. (Default: FadeOut) @property (nonatomic) SCLAlertViewHideAnimation hideAnimationType; -/** Show animation type - * - * Holds the show animation type. - * (Default: SlideInFromTop) - */ +/// Show animation type. (Default: SlideInFromTop) @property (nonatomic) SCLAlertViewShowAnimation showAnimationType; -/** Set SCLAlertView background type. - * - * SCLAlertView background type. - * (Default: Shadow) - */ +/// Background effect behind the alert. (Default: Shadow) @property (nonatomic) SCLAlertViewBackground backgroundType; -/** Set custom color to SCLAlertView. - * - * SCLAlertView custom color. - * (Buttons, top circle and borders) - */ -@property (strong, nonatomic) UIColor *customViewColor; +/// Custom alert color (buttons, top circle, borders). +@property (strong, nonatomic, nullable) UIColor *customViewColor; -/** Set custom color to SCLAlertView background. - * - * SCLAlertView background custom color. - */ -@property (strong, nonatomic) UIColor *backgroundViewColor; +/// Custom background view color. +@property (strong, nonatomic, nullable) UIColor *backgroundViewColor; -/** Set custom tint color for icon image. - * - * SCLAlertView icon tint color - */ -@property (strong, nonatomic) UIColor *iconTintColor; +/// Tint color for the icon image. +@property (strong, nonatomic, nullable) UIColor *iconTintColor; -/** Set custom circle icon height. - * - * Circle icon height - */ +/// Custom size for the icon inside the top circle. @property (nonatomic) CGFloat circleIconHeight; -/** Set SCLAlertView extension bounds. - * - * Set new bounds (EXTENSION ONLY) - */ +/// New bounds to use when running as an app extension only. @property (nonatomic) CGRect extensionBounds; -/** Set status bar hidden. - * - * Status bar hidden - */ +/// Status bar hidden state. @property (nonatomic) BOOL statusBarHidden; -/** Set status bar style. - * - * Status bar style - */ +/// Status bar style. @property (nonatomic) UIStatusBarStyle statusBarStyle; -/** Set horizontal alignment for buttons - * - * Horizontal aligment instead of vertically if YES - */ +/// If YES, buttons are laid out horizontally instead of vertically. @property (nonatomic) BOOL horizontalButtons; -/** Initialize SCLAlertView using specific width. - * - * Init instance +#pragma mark - Initializers + +/** + Initializes an alert with a specific width. + + @param width The desired alert width. + @return An initialized SCLAlertView instance. */ - (instancetype)initWithWidth:(CGFloat)width; -/** Initialize SCLAlertView using a new window. - * - * Init with new window +/** + Initializes an alert presented in a new UIWindow. + + @return An initialized SCLAlertView instance. */ - (instancetype)initWithNewWindow; -/** Initialize SCLAlertView using a new window. - * - * Init with new window with custom width +/** + Initializes an alert presented in a new UIWindow with custom width. + + @param windowWidth The desired alert width. + @return An initialized SCLAlertView instance. */ - (instancetype)initWithNewWindowWidth:(CGFloat)windowWidth; -/** Warns that alerts is gone - * - * Warns that alerts is gone using block +#pragma mark - Callbacks + +/** + Sets a block to be called when the alert is dismissed. + + @param dismissBlock The block executed upon dismissal. */ - (void)alertIsDismissed:(SCLDismissBlock)dismissBlock; -/** Warns that alerts dismiss animation is completed - * - * Warns that alerts dismiss animation is completed +/** + Sets a block to be called when the dismiss animation completes. + + @param dismissAnimationCompletionBlock The completion block. */ - (void)alertDismissAnimationIsCompleted:(SCLDismissAnimationCompletionBlock)dismissAnimationCompletionBlock; -/** Warns that alerts show animation is completed - * - * Warns that alerts show animation is completed +/** + Sets a block to be called when the show animation completes. + + @param showAnimationCompletionBlock The completion block. */ - (void)alertShowAnimationIsCompleted:(SCLShowAnimationCompletionBlock)showAnimationCompletionBlock; -/** Hide SCLAlertView - * - * Hide SCLAlertView using animation and removing from super view. - */ +#pragma mark - Visibility +/** + Hides the alert with animation and removes it from the view hierarchy. + */ - (void)hideView; -/** SCLAlertView visibility - * - * Returns if the alert is visible or not. +/** + Returns whether the alert is visible. + + @return YES if visible; otherwise NO. */ - (BOOL)isVisible; -/** Remove Top Circle - * - * Remove top circle from SCLAlertView. +/** + Removes the top circle from the alert. */ - (void)removeTopCircle; -/** Add a custom UIView - * - * @param customView UIView object to be added above the first SCLButton. +#pragma mark - Content + +/** + Adds a custom view above the first button. + + @param customView The UIView to add. + @return The same customView for chaining. */ - (UIView *)addCustomView:(UIView *)customView; -/** Add Text Field - * - * @param title The text displayed on the textfield. +/** + Adds a text field with optional default text. + + @param title The placeholder text for the text field. + @param defaultText Optional default text. + @return The created SCLTextView. */ -- (SCLTextView *)addTextField:(NSString *)title setDefaultText:(NSString *)defaultText; +- (SCLTextView *)addTextField:(NSString *)title setDefaultText:(nullable NSString *)defaultText; + +/** + Adds a custom text field. -/** Add a custom Text Field - * - * @param textField The custom textfield provided by the programmer. + @param textField The custom UITextField instance. */ - (void)addCustomTextField:(UITextField *)textField; -/** Add a switch view - * - * @param label The label displayed for the switch. +/** + Adds a switch view with an optional label. + + @param label The label text for the switch. + @return The created SCLSwitchView. */ -- (SCLSwitchView *)addSwitchViewWithLabel:(NSString *)label; +- (SCLSwitchView *)addSwitchViewWithLabel:(nullable NSString *)label; + +#pragma mark - Timer + +/** + Adds a circular timer to a button. -/** Add Timer Display - * - * @param buttonIndex The index of the button to add the timer display to. - * @param reverse Convert timer to countdown. + @param buttonIndex Index of the button to attach the timer to. + @param reverse If YES, shows a 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. +#pragma mark - Fonts + +/** + Sets the title font family and size. + + @param titleFontFamily The font family name. + @param size The 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. +/** + Sets the body text font family and size. + + @param bodyTextFontFamily The font family name. + @param size The 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. +/** + Sets the buttons font family and size. + + @param buttonsFontFamily The font family name. + @param size The 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. +#pragma mark - Buttons + +/** + Adds a button with a title and action block. + + @param title The button title. + @param action The block executed when the button is tapped. + @return The created SCLButton. */ - (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. +/** + Adds a button with validation and action blocks. + + @param title The button title. + @param validationBlock A block returning YES to proceed and dismiss, NO to keep the alert. + @param action The block executed when validation passes and the button is tapped. + @return The created SCLButton. */ - (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. +/** + Adds a button with a target and selector. + + @param title The button title. + @param target The target object for the selector. + @param selector The selector to invoke on tap. + @return The created SCLButton. */ - (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. +#pragma mark - Show (predefined styles) + +/** + Shows a Success alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (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)showSuccess:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showSuccess:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows an Error alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (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)showError:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showError:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows a Notice alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (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)showNotice:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showNotice:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows a Warning alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (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)showWarning:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showWarning:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows an Info alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (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)showInfo:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showInfo:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows an Edit alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (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)showEdit:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showEdit:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +#pragma mark - Show (custom) + +/** + Shows a predefined style alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param style The predefined style. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (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)showTitle:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showTitle:(NSString *)title subTitle:(NSString *)subTitle style:(SCLAlertViewStyle)style closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows a custom alert with custom image and color. + + @param vc The presenting view controller. + @param image The icon image. + @param color The primary color (buttons, top circle, borders). + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (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)showCustom:(UIViewController *)vc image:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showCustom:(UIImage *)image color:(UIColor *)color title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows a Waiting alert with UIActivityIndicator. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (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)showWaiting:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showWaiting:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; + +/** + Shows a Question alert. + + @param vc The presenting view controller. + @param title The alert title. + @param subTitle The alert subtitle. + @param closeButtonTitle The close button title (optional). + @param duration Automatic dismissal after this duration; set 0 to disable. */ -- (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; +- (void)showQuestion:(UIViewController *)vc title:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; +- (void)showQuestion:(NSString *)title subTitle:(NSString *)subTitle closeButtonTitle:(nullable NSString *)closeButtonTitle duration:(NSTimeInterval)duration; @end @@ -483,13 +443,13 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) @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(weak, nonatomic, readonly, nullable) UIViewController *parameterViewController; +@property(copy, nonatomic, readonly, nullable) UIImage *parameterImage; +@property(copy, nonatomic, readonly, nullable) UIColor *parameterColor; +@property(copy, nonatomic, readonly, nullable) NSString *parameterTitle; +@property(copy, nonatomic, readonly, nullable) NSString *parameterSubTitle; +@property(copy, nonatomic, readonly, nullable) NSString *parameterCompleteText; +@property(copy, nonatomic, readonly, nullable) NSString *parameterCloseButtonTitle; @property(assign, nonatomic, readonly) SCLAlertViewStyle parameterStyle; @property(assign, nonatomic, readonly) NSTimeInterval parameterDuration; @@ -505,14 +465,14 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) @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); +- (void)showAlertView:(SCLAlertView *)alertView onViewController:(UIViewController * _Nullable)controller; +@property(copy, nonatomic, readonly) void (^show)(SCLAlertView *view, UIViewController * _Nullable controller); @end @interface SCLALertViewTextFieldBuilder : SCLAlertViewBuilder__WithFluent #pragma mark - Available later after adding -@property(weak, nonatomic, readonly) SCLTextView *textField; +@property(weak, nonatomic, readonly, nullable) SCLTextView *textField; #pragma mark - Setters @property(copy, nonatomic, readonly) SCLALertViewTextFieldBuilder *(^title) (NSString *title); @@ -522,7 +482,7 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) @interface SCLALertViewButtonBuilder : SCLAlertViewBuilder__WithFluent #pragma mark - Available later after adding -@property(weak, nonatomic, readonly) SCLButton *button; +@property(weak, nonatomic, readonly, nullable) SCLButton *button; #pragma mark - Setters @property(copy, nonatomic, readonly) SCLALertViewButtonBuilder *(^title) (NSString *title); @@ -573,9 +533,9 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) @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 *(^addTextField)(NSString *title, NSString * _Nullable defaultText); @property(copy, nonatomic) SCLAlertViewBuilder *(^addCustomTextField)(UITextField *textField); -@property(copy, nonatomic) SCLAlertViewBuilder *(^addSwitchViewWithLabelTitle)(NSString *title); +@property(copy, nonatomic) SCLAlertViewBuilder *(^addSwitchViewWithLabelTitle)(NSString * _Nullable 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); @@ -589,3 +549,5 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) @property(copy, nonatomic) SCLAlertViewBuilder *(^addTextFieldWithBuilder)(SCLALertViewTextFieldBuilder *builder); @end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertView/SCLAlertView.m b/SCLAlertView/SCLAlertView.m index 7a9689c..409d956 100755 --- a/SCLAlertView/SCLAlertView.m +++ b/SCLAlertView/SCLAlertView.m @@ -3,7 +3,7 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2025 AnyKey Entertainment. All rights reserved. // #import "SCLAlertView.h" @@ -14,13 +14,8 @@ #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 @@ -143,6 +138,8 @@ - (void)dealloc [self restoreInteractivePopGesture]; } +#pragma mark - Observers + - (void)addObservers { if(_canAddObservers) @@ -159,7 +156,7 @@ - (void)removeObservers [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } -#pragma mark - Setup view +#pragma mark - Setup View - (void)setupViewWindowWidth:(CGFloat)windowWidth { @@ -184,7 +181,7 @@ - (void)setupViewWindowWidth:(CGFloat)windowWidth self.backgroundType = SCLAlertViewBackgroundShadow; self.tintTopCircle = YES; - // Font + // Fonts _titleFontFamily = @"HelveticaNeue"; _bodyTextFontFamily = @"HelveticaNeue"; _buttonsFontFamily = @"HelveticaNeue-Bold"; @@ -206,28 +203,28 @@ - (void)setupViewWindowWidth:(CGFloat)windowWidth _customViews = [[NSMutableArray alloc] init]; self.view.accessibilityViewIsModal = YES; - // Add Subviews + // Add subviews [self.view addSubview:_contentView]; [self.view addSubview:_circleViewBackground]; - // Circle View + // 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 + // Circle background view _circleViewBackground.backgroundColor = [UIColor whiteColor]; _circleViewBackground.layer.cornerRadius = _circleViewBackground.frame.size.height / 2; x = (kCircleHeight - _circleIconHeight) / 2; - // Circle Image View + // Circle image view _circleIconImageView.frame = CGRectMake(x, x, _circleIconHeight, _circleIconHeight); _circleIconImageView.contentMode = UIViewContentModeScaleAspectFill; [_circleViewBackground addSubview:_circleView]; [_circleView addSubview:_circleIconImageView]; - // Background View + // Background view _backgroundView.userInteractionEnabled = YES; // Title @@ -237,7 +234,7 @@ - (void)setupViewWindowWidth:(CGFloat)windowWidth _labelTitle.font = [UIFont fontWithName:_titleFontFamily size:_titleFontSize]; _labelTitle.frame = CGRectMake(12.0f, kTitleTop, _windowWidth - 24.0f, _titleHeight); - // View text + // Body text _viewText.editable = NO; _viewText.allowsEditingTextAttributes = YES; _viewText.textAlignment = NSTextAlignmentCenter; @@ -245,26 +242,27 @@ - (void)setupViewWindowWidth:(CGFloat)windowWidth _viewText.frame = CGRectMake(12.0f, _subTitleY, _windowWidth - 24.0f, _subTitleHeight); _viewText.textContainerInset = UIEdgeInsetsZero; _viewText.textContainer.lineFragmentPadding = 0; - self.automaticallyAdjustsScrollViewInsets = NO; + _viewText.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; - // Content View + // 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:_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 + _labelTitle.textColor = UIColorFromHEX(0x4D4D4D); // Dark gray + _viewText.textColor = UIColorFromHEX(0x4D4D4D); // Dark gray + _contentView.layer.borderColor = UIColorFromHEX(0xCCCCCC).CGColor; // Light gray } -- (void)setupNewWindow { +- (void)setupNewWindow +{ // Save previous window - self.previousWindow = [UIApplication sharedApplication].keyWindow; + self.previousWindow = [SCLAlertView scl_currentKeyWindow]; // Create a new one to show the alert UIWindow *alertWindow = [[UIWindow alloc] initWithFrame:[self mainScreenFrame]]; @@ -282,7 +280,7 @@ - (BOOL)isModal { return (_rootViewController != nil && _rootViewController.presentingViewController); } -#pragma mark - View Cycle +#pragma mark - View Lifecycle - (void)viewWillLayoutSubviews { @@ -310,12 +308,12 @@ - (void)viewWillLayoutSubviews kCircleBackgroundTopPosition = -(kCircleHeightBackground / 2); } - // Check if the rootViewController is modal, if so we need to get the modal size not the main screen size + // Use modal size if presented modally (and not using a new window) if ([self isModal] && !_usingNewWindow) { sz = _rootViewController.view.frame.size; } - // Set new main frame + // Set main frame CGRect r; if (self.view.superview != nil) { // View is showing, position at center of screen @@ -326,12 +324,12 @@ - (void)viewWillLayoutSubviews } self.view.frame = r; - // Set new background frame + // Background frame CGRect newBackgroundFrame = self.backgroundView.frame; newBackgroundFrame.size = sz; self.backgroundView.frame = newBackgroundFrame; - // Set frames + // 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; @@ -365,7 +363,7 @@ - (void)viewWillLayoutSubviews 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 + // Add horizontal or vertical offset according to _horizontalButtons if (_horizontalButtons) { x += btn.frame.size.width + 10.0f; } else { @@ -377,11 +375,11 @@ - (void)viewWillLayoutSubviews 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 + // Adjust corner radius (if a value has been passed) _contentView.layer.cornerRadius = self.cornerRadius ? self.cornerRadius : 5.0f; } -#pragma mark - UIViewController +#pragma mark - Status Bar - (BOOL)prefersStatusBarHidden { @@ -393,7 +391,7 @@ - (UIStatusBarStyle)preferredStatusBarStyle return self.statusBarStyle; } -#pragma mark - Handle gesture +#pragma mark - Gesture Handling - (void)handleTap:(UITapGestureRecognizer *)gesture { @@ -403,7 +401,7 @@ - (void)handleTap:(UITapGestureRecognizer *)gesture for(SCLTextView *txt in _inputs) { - // Check if there is any keyboard on screen and dismiss + // Dismiss keyboard if any input is editing if (txt.editing) { [txt resignFirstResponder]; @@ -428,6 +426,8 @@ - (void)setShouldDismissOnTapOutside:(BOOL)shouldDismissOnTapOutside } } +#pragma mark - Navigation Gesture + - (void)disableInteractivePopGesture { UINavigationController *navigationController; @@ -441,7 +441,7 @@ - (void)disableInteractivePopGesture navigationController = _rootViewController.navigationController; } - // Disable iOS 7 back gesture + // Disable back gesture if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { _restoreInteractivePopGestureEnabled = navigationController.interactivePopGestureRecognizer.enabled; @@ -464,7 +464,7 @@ - (void)restoreInteractivePopGesture navigationController = _rootViewController.navigationController; } - // Restore iOS 7 back gesture + // Restore back gesture if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { navigationController.interactivePopGestureRecognizer.enabled = _restoreInteractivePopGestureEnabled; @@ -510,12 +510,12 @@ - (void)setSoundURL:(NSURL *)soundURL { _soundURL = soundURL; - //DisposeSound + // Dispose previous sound AudioServicesDisposeSystemSoundID(_soundID); AudioServicesCreateSystemSoundID((__bridge CFURLRef)_soundURL, &_soundID); - //PlaySound + // Play new sound AudioServicesPlaySystemSound(_soundID); } @@ -526,7 +526,7 @@ - (void)setSubTitleHeight:(CGFloat)value _subTitleHeight = value; } -#pragma mark - ActivityIndicator +#pragma mark - Activity Indicator - (void)addActivityIndicatorView { @@ -536,7 +536,7 @@ - (void)addActivityIndicatorView [_circleView addSubview:_activityIndicatorView]; } -#pragma mark - UICustomView +#pragma mark - Custom View - (UIView *)addCustomView:(UIView *)customView { @@ -549,7 +549,7 @@ - (UIView *)addCustomView:(UIView *)customView return customView; } -#pragma mark - SwitchView +#pragma mark - Switch View - (SCLSwitchView *)addSwitchViewWithLabel:(NSString *)label { @@ -570,7 +570,7 @@ - (SCLSwitchView *)addSwitchViewWithLabel:(NSString *)label return switchView; } -#pragma mark - TextField +#pragma mark - Text Field - (SCLTextView *)addTextField:(NSString *)title setDefaultText:(NSString *)defaultText { @@ -596,8 +596,7 @@ - (SCLTextView *)addTextField:(NSString *)title setDefaultText:(NSString *)defau [_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 there are other fields in the inputs array, set the previous field return key to Next if (_inputs.count > 1) { NSUInteger indexOfCurrentField = [_inputs indexOfObject:txt]; @@ -615,8 +614,7 @@ - (void)addCustomTextField:(UITextField *)textField [_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 there are other fields in the inputs array, set the previous field return key to Next if (_inputs.count > 1) { NSUInteger indexOfCurrentField = [_inputs indexOfObject:textField]; @@ -630,12 +628,11 @@ - (void)addCustomTextField:(UITextField *)textField - (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. + else // Otherwise find the next field and make it first responder { NSUInteger indexOfCurrentField = [_inputs indexOfObject:textField]; UITextField *nextField = _inputs[indexOfCurrentField + 1]; @@ -644,6 +641,8 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField return NO; } +#pragma mark - Keyboard + - (void)keyboardWillShow:(NSNotification *)notification { if(_keyboardIsVisible) return; @@ -750,11 +749,10 @@ - (SCLButton *)addButton:(NSString *)title target:(id)target selector:(SEL)selec - (void)buttonTapped:(SCLButton *)btn { - // Cancel Countdown timer + // Cancel countdown timer [buttonTimer cancelTimer]; - // If the button has a validation block, and the validation block returns NO, validation - // failed, so we should bail. + // Validate if needed if (btn.validationBlock && !btn.validationBlock()) { return; } @@ -792,7 +790,7 @@ - (void)addTimerToButtonIndex:(NSInteger)buttonIndex reverse:(BOOL)reverse buttonTimer.reverse = reverse; } -#pragma mark - Show Alert +#pragma mark - Show Alert (Core) - (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 { @@ -873,7 +871,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima break; } - // Custom Alert color + // Custom alert color override if(_customViewColor) { viewColor = _customViewColor; @@ -883,11 +881,9 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima if ([title stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length > 0) { self.labelTitle.text = title; - // Adjust text view size, if necessary + // 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); @@ -895,18 +891,15 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima self.subTitleY += 20; } } else { - // Title is nil, we can move the body message to center and remove it from superView + // No title: center body and remove title view 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 { @@ -914,11 +907,9 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima _viewText.attributedText = self.attributedFormatBlock(subTitle); } - // Adjust text view size, if necessary + // 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); @@ -928,7 +919,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima self.subTitleHeight = ht; } } else { - // Subtitle is nil, we can move the title to center and remove it from superView + // No subtitle: center title and remove body view self.subTitleHeight = 0.0f; self.windowHeight -= _viewText.frame.size.height; [_viewText removeFromSuperview]; @@ -942,7 +933,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima self.windowHeight -= kTitleTop; } - // Add button, if necessary + // Add button if needed if(completeText != nil) { [self addDoneButtonWithTitle:completeText]; @@ -990,7 +981,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima } } - // Adding duration + // Duration if (duration > 0) { [durationTimer invalidate]; @@ -1022,7 +1013,7 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima // Show the alert view [self showView]; - // Chainable objects + // Chainable responder return [[SCLAlertViewResponder alloc] init:self]; } @@ -1079,7 +1070,6 @@ - (void)showQuestion:(UIViewController *)vc title:(NSString *)title subTitle:(NS [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 @@ -1151,11 +1141,13 @@ - (void)alertIsDismissed:(SCLDismissBlock)dismissBlock self.dismissBlock = dismissBlock; } -- (void)alertDismissAnimationIsCompleted:(SCLDismissAnimationCompletionBlock)dismissAnimationCompletionBlock{ +- (void)alertDismissAnimationIsCompleted:(SCLDismissAnimationCompletionBlock)dismissAnimationCompletionBlock +{ self.dismissAnimationCompletionBlock = dismissAnimationCompletionBlock; } -- (void)alertShowAnimationIsCompleted:(SCLShowAnimationCompletionBlock)showAnimationCompletionBlock{ +- (void)alertShowAnimationIsCompleted:(SCLShowAnimationCompletionBlock)showAnimationCompletionBlock +{ self.showAnimationCompletionBlock = showAnimationCompletionBlock; } @@ -1172,7 +1164,7 @@ - (SCLForceHideBlock)forceHideBlock:(SCLForceHideBlock)forceHideBlock - (CGRect)mainScreenFrame { - return [self isAppExtension] ? _extensionBounds : [UIApplication sharedApplication].keyWindow.bounds; + return [self isAppExtension] ? _extensionBounds : [SCLAlertView scl_currentKeyWindow].bounds; } - (BOOL)isAppExtension @@ -1195,7 +1187,7 @@ - (void)makeBlurBackground UIView *fallbackView = _rootViewController.view; UIView *appView = _usingNewWindow ? (UIView *)[SCLAlertView scl_currentKeyWindow] : fallbackView; - // final fallback in case it still comes as nil + // Final fallback in case it still comes as nil if (!appView) { appView = [SCLAlertView scl_resolveAppViewWithFallback:fallbackView]; } @@ -1245,7 +1237,7 @@ - (void)setBackground } } -#pragma mark - Show Alert +#pragma mark - Show Alert (Animations) - (void)showView { @@ -1285,7 +1277,7 @@ - (void)showView } } -#pragma mark - Hide Alert +#pragma mark - Hide Alert (Animations) - (void)hideView { @@ -1460,7 +1452,6 @@ - (void)simplyDisappear }); } - #pragma mark - Show Animations - (void)fadeIn @@ -1484,7 +1475,7 @@ - (void)fadeIn - (void)slideInFromTop { - //From Frame + // From frame CGRect frame = self.backgroundView.frame; frame.origin.y = -self.backgroundView.frame.size.height; self.view.frame = frame; @@ -1492,7 +1483,7 @@ - (void)slideInFromTop [UIView animateWithDuration:0.5f delay:0.0f usingSpringWithDamping:0.6f initialSpringVelocity:0.5f options:0 animations:^{ self.backgroundView.alpha = self.backgroundOpacity; - //To Frame + // To frame CGRect frame = self.backgroundView.frame; frame.origin.y = 0.0f; self.view.frame = frame; @@ -1507,7 +1498,7 @@ - (void)slideInFromTop - (void)slideInFromBottom { - //From Frame + // From frame CGRect frame = self.backgroundView.frame; frame.origin.y = self.backgroundView.frame.size.height; self.view.frame = frame; @@ -1515,7 +1506,7 @@ - (void)slideInFromBottom [UIView animateWithDuration:0.3f animations:^{ self.backgroundView.alpha = self.backgroundOpacity; - //To Frame + // To frame CGRect frame = self.backgroundView.frame; frame.origin.y = 0.0f; self.view.frame = frame; @@ -1534,7 +1525,7 @@ - (void)slideInFromBottom - (void)slideInFromLeft { - //From Frame + // From frame CGRect frame = self.backgroundView.frame; frame.origin.x = -self.backgroundView.frame.size.width; self.view.frame = frame; @@ -1542,7 +1533,7 @@ - (void)slideInFromLeft [UIView animateWithDuration:0.3f animations:^{ self.backgroundView.alpha = self.backgroundOpacity; - //To Frame + // To frame CGRect frame = self.backgroundView.frame; frame.origin.x = 0.0f; self.view.frame = frame; @@ -1561,7 +1552,7 @@ - (void)slideInFromLeft - (void)slideInFromRight { - //From Frame + // From frame CGRect frame = self.backgroundView.frame; frame.origin.x = self.backgroundView.frame.size.width; self.view.frame = frame; @@ -1569,7 +1560,7 @@ - (void)slideInFromRight [UIView animateWithDuration:0.3f animations:^{ self.backgroundView.alpha = self.backgroundOpacity; - //To Frame + // To frame CGRect frame = self.backgroundView.frame; frame.origin.x = 0.0f; self.view.frame = frame; @@ -1588,7 +1579,7 @@ - (void)slideInFromRight - (void)slideInFromCenter { - //From Frame + // From frame self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, CGAffineTransformMakeScale(3.0f, 3.0f)); self.view.alpha = 0.0f; @@ -1596,7 +1587,7 @@ - (void)slideInFromCenter [UIView animateWithDuration:0.3f animations:^{ self.backgroundView.alpha = self.backgroundOpacity; - //To Frame + // To frame self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, CGAffineTransformMakeScale(1.0f, 1.0f)); self.view.alpha = 1.0f; @@ -1613,7 +1604,7 @@ - (void)slideInFromCenter - (void)slideInToCenter { - //From Frame + // From frame self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, CGAffineTransformMakeScale(0.1f, 0.1f)); self.view.alpha = 0.0f; @@ -1621,7 +1612,7 @@ - (void)slideInToCenter [UIView animateWithDuration:0.3f animations:^{ self.backgroundView.alpha = self.backgroundOpacity; - //To Frame + // To frame self.view.transform = CGAffineTransformConcat(CGAffineTransformIdentity, CGAffineTransformMakeScale(1.0f, 1.0f)); self.view.alpha = 1.0f; @@ -1650,7 +1641,6 @@ - (void)simplyAppear }); } - @end @implementation SCLAlertViewBuilder__WithFluent diff --git a/SCLAlertView/SCLAlertViewResponder.h b/SCLAlertView/SCLAlertViewResponder.h index 0dfb77b..31c438b 100644 --- a/SCLAlertView/SCLAlertViewResponder.h +++ b/SCLAlertView/SCLAlertViewResponder.h @@ -6,25 +6,21 @@ // 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 - */ +/// Inicializa o responder vinculado a uma instância de SCLAlertView. - (instancetype)init:(SCLAlertView *)alertview; -/** TODO - * - * TODO - */ +/// Atualiza o título do alerta. +- (void)setTitle:(NSString *)title; + +/// Atualiza o subtítulo/texto do corpo do alerta. +- (void)setSubTitle:(NSString *)subTitle; + +/// Fecha o alerta. - (void)close; @end diff --git a/SCLAlertView/SCLAlertViewResponder.m b/SCLAlertView/SCLAlertViewResponder.m index 847ed9d..2318c53 100644 --- a/SCLAlertView/SCLAlertViewResponder.m +++ b/SCLAlertView/SCLAlertViewResponder.m @@ -10,33 +10,36 @@ @interface SCLAlertViewResponder () -@property SCLAlertView *alertview; +// Weak reference to the alert to avoid retain cycles. Valid while the alert is alive. +@property (weak, nonatomic) 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 +// Binds the responder to a presented alert, enabling title/subtitle updates and dismissal. - (instancetype)init:(SCLAlertView *)alertview { - self.alertview = alertview; + self = [super init]; + if (self) { + self.alertview = alertview; + } return self; } -- (void)setTitletitle:(NSString *)title +// Updates the alert title (useful for async state changes). +- (void)setTitle:(NSString *)title { self.alertview.labelTitle.text = title; } +// Updates the alert subtitle/body text. - (void)setSubTitle:(NSString *)subTitle { self.alertview.viewText.text = subTitle; } +// Dismisses the alert using its configured animation. - (void)close { [self.alertview hideView]; diff --git a/SCLAlertView/SCLAlertViewStyleKit.m b/SCLAlertView/SCLAlertViewStyleKit.m index f467f47..45b982e 100644 --- a/SCLAlertView/SCLAlertViewStyleKit.m +++ b/SCLAlertView/SCLAlertViewStyleKit.m @@ -3,7 +3,7 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2025 AnyKey Entertainment. All rights reserved. // #import "SCLAlertViewStyleKit.h" @@ -28,14 +28,14 @@ @implementation SCLAlertViewStyleKit + (void)initialize { - // Do something + // Reserved for future initialization. } #pragma mark - Drawing Methods + (void)drawCheckmark { - // Checkmark Shape Drawing + // 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)]; @@ -57,7 +57,7 @@ + (void)drawCheckmark + (void)drawCross { - // Cross Shape Drawing + // Cross shape drawing UIBezierPath *crossShapePath = [[UIBezierPath alloc] init]; [crossShapePath moveToPoint:CGPointMake(10, 70)]; [crossShapePath addLineToPoint:CGPointMake(70, 10)]; @@ -74,7 +74,7 @@ + (void)drawCross + (void)drawNotice { - // Notice Shape Drawing + // Notice shape drawing UIBezierPath *noticeShapePath = [[UIBezierPath alloc] init]; [noticeShapePath moveToPoint:CGPointMake(72, 48.54)]; [noticeShapePath addLineToPoint:CGPointMake(72, 39.9)]; @@ -112,11 +112,11 @@ + (void)drawNotice + (void)drawWarning { - // Color Declarations + // Color declarations UIColor *greyColor = [UIColor colorWithRed:0.236 green:0.236 blue:0.236 alpha:1.000]; - // Warning Group - // Warning Circle Drawing + // 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)]; @@ -134,7 +134,7 @@ + (void)drawWarning [warningCirclePath fill]; - //// Warning Shape Drawing + // 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)]; @@ -156,10 +156,10 @@ + (void)drawWarning + (void)drawInfo { - // Color Declarations + // Color declarations UIColor *color0 = [UIColor colorWithRed:1.000 green:1.000 blue:1.000 alpha:1.000]; - // Info Shape Drawing + // 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)]; @@ -185,10 +185,10 @@ + (void)drawInfo + (void)drawEdit { - // Color Declarations + // Color declarations UIColor *color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; - // Edit shape Drawing + // 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)]; @@ -238,10 +238,10 @@ + (void)drawEdit + (void)drawQuestion { - // Color Declarations + // Color declarations UIColor *color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; - // Questionmark Shape Drawing + // Question mark shape drawing UIBezierPath *questionShapePath = [[UIBezierPath alloc] init]; [questionShapePath moveToPoint: CGPointMake(33.75, 54.1)]; [questionShapePath addLineToPoint: CGPointMake(44.15, 54.1)]; diff --git a/SCLAlertView/SCLButton.h b/SCLAlertView/SCLButton.h index a1fb3a5..33ebf92 100755 --- a/SCLAlertView/SCLButton.h +++ b/SCLAlertView/SCLButton.h @@ -3,14 +3,12 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2025 AnyKey Entertainment. All rights reserved. // -#if defined(__has_feature) && __has_feature(modules) -@import UIKit; -#else #import -#endif + +NS_ASSUME_NONNULL_BEGIN @class SCLTimerDisplay; @@ -18,8 +16,8 @@ typedef void (^SCLActionBlock)(void); typedef BOOL (^SCLValidationBlock)(void); -typedef NSDictionary* (^CompleteButtonFormatBlock)(void); -typedef NSDictionary* (^ButtonFormatBlock)(void); +typedef NSDictionary * _Nonnull (^CompleteButtonFormatBlock)(void); +typedef NSDictionary * _Nonnull (^ButtonFormatBlock)(void); // Action Types typedef NS_ENUM(NSInteger, SCLActionType) @@ -29,81 +27,109 @@ typedef NS_ENUM(NSInteger, SCLActionType) SCLBlock }; -/** Set button action type. - * - * Holds the button action type. +/** + Button action type. + + Indicates how the button should handle taps (selector-based or block-based). */ @property SCLActionType actionType; -/** Set action button block. - * - * TODO +/** + Action block executed when the button is tapped. + + @note Used when actionType == SCLBlock. */ -@property (copy, nonatomic) SCLActionBlock actionBlock; +@property (copy, nonatomic, nullable) SCLActionBlock actionBlock; + +/** + Validation block executed before the action. + + Return YES to allow dismissal and call the action block; NO to keep the alert visible. -/** Set Validation button block. - * - * Set one kind of validation and keeps the alert visible until the validation is successful + @note If provided and returns NO, the action is not executed and the alert remains visible. */ -@property (copy, nonatomic) SCLValidationBlock validationBlock; +@property (copy, nonatomic, nullable) SCLValidationBlock validationBlock; -/** Set Complete button format block. - * - * Holds the complete button format block. - * Support keys : backgroundColor, borderWidth, borderColor, textColor +/** + Complete button format block. + + Provides full button styling. + + Supported keys: + - backgroundColor (UIColor) + - borderWidth (NSNumber/CGFloat) + - borderColor (UIColor) + - textColor (UIColor) */ -@property (copy, nonatomic) CompleteButtonFormatBlock completeButtonFormatBlock; +@property (copy, nonatomic, nullable) CompleteButtonFormatBlock completeButtonFormatBlock; + +/** + Button format block. + + Provides button styling. -/** Set button format block. - * - * Holds the button format block. - * Support keys : backgroundColor, borderWidth, borderColor, textColor + Supported keys: + - backgroundColor (UIColor) + - borderWidth (NSNumber/CGFloat) + - borderColor (UIColor) + - textColor (UIColor) */ -@property (copy, nonatomic) ButtonFormatBlock buttonFormatBlock; +@property (copy, nonatomic, nullable) ButtonFormatBlock buttonFormatBlock; -/** Set SCLButton color. - * - * Set SCLButton color. +/** + Default background color for the button. + + @note UI_APPEARANCE_SELECTOR is supported. */ -@property (strong, nonatomic) UIColor *defaultBackgroundColor UI_APPEARANCE_SELECTOR; +@property (strong, nonatomic, nullable) UIColor *defaultBackgroundColor UI_APPEARANCE_SELECTOR; + +/** + Target for selector-based actions. -/** Set Target object. - * - * Target is an object that holds the information necessary to send a message to another object when an event occurs. + @note Used when actionType == SCLSelector. */ -@property id target; +@property (nullable) id target; + +/** + Selector to invoke on the target for selector-based actions. -/** 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. + @note Used when actionType == SCLSelector. */ -@property SEL selector; +@property (nullable) SEL selector; -/** Parse button configuration - * - * Parse ButtonFormatBlock and CompleteButtonFormatBlock setting custom configuration. - * Set keys : backgroundColor, borderWidth, borderColor, textColor +/** + Applies configuration returned by a format block. + + @param buttonConfig The configuration dictionary. + @discussion Supported keys: backgroundColor, borderWidth, borderColor, textColor. */ - (void)parseConfig:(NSDictionary *)buttonConfig; -/** Set button timer. - * - * Holds the button timer, if present. +/** + Button timer (if present). + + Used to show countdown/progress on the button. */ -@property (strong, nonatomic) SCLTimerDisplay *timer; +@property (strong, nonatomic, nullable) SCLTimerDisplay *timer; -/** Init method - * +/** + Designated initializer for SCLButton. + + @param windowWidth The width of the alert window used to size the button. + @return An initialized SCLButton instance. */ - (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. +/** + Adjusts the button width based on alert width and number of buttons. + + Only used when buttons are horizontally aligned. + + @param windowWidth The alert window width. + @param numberOfButtons Total number of buttons in the alert. */ - (void)adjustWidthWithWindowWidth:(CGFloat)windowWidth numberOfButtons:(NSUInteger)numberOfButtons; @end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertView/SCLButton.m b/SCLAlertView/SCLButton.m index 056ce0c..b4a966d 100755 --- a/SCLAlertView/SCLButton.m +++ b/SCLAlertView/SCLButton.m @@ -103,7 +103,9 @@ - (void)setDefaultBackgroundColor:(UIColor *)defaultBackgroundColor - (void)setTimer:(SCLTimerDisplay *)timer { _timer = timer; - [self addSubview:timer]; + if (!timer.superview) { + [self addSubview:timer]; + } [timer updateFrame:self.frame.size]; timer.color = self.titleLabel.textColor; } @@ -145,23 +147,25 @@ - (void)parseConfig:(NSDictionary *)buttonConfig - (UIColor *)darkerColorForColor:(UIColor *)color { CGFloat r, g, b, a; - if ([color getRed:&r green:&g blue:&b alpha:&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; + } + return color; } - (UIColor *)lighterColorForColor:(UIColor *)color { CGFloat r, g, b, a; - if ([color getRed:&r green:&g blue:&b alpha:&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; + } + return color; } @end diff --git a/SCLAlertView/SCLMacros.h b/SCLAlertView/SCLMacros.h index 1fec837..5d6be5d 100644 --- a/SCLAlertView/SCLMacros.h +++ b/SCLAlertView/SCLMacros.h @@ -3,21 +3,28 @@ // SCLAlertView // // Created by Diogo Autilio on 10/03/15. -// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2015-2025 AnyKey Entertainment. All rights reserved. // #ifndef SCL_MACROS_H #define SCL_MACROS_H +// Create a UIColor from a 0xRRGGBB hex value (alpha is 1.0) #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] +// Convert degrees to radians #define DEGREES_TO_RADIANS(degrees) ((M_PI * degrees)/ 180) + +// Timer granularity (seconds) used by internal animations/timers #define TIMER_STEP .01 + +// Starting angle offset (degrees) for circular drawings (e.g., timers) #define START_DEGREE_OFFSET -90 +// iOS version comparison helpers (string-based, e.g., @"14.0") #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) diff --git a/SCLAlertView/SCLSwitchView.h b/SCLAlertView/SCLSwitchView.h index ecc4d6c..469624b 100644 --- a/SCLAlertView/SCLSwitchView.h +++ b/SCLAlertView/SCLSwitchView.h @@ -3,21 +3,33 @@ // SCLAlertView // // Created by André Felipe Santos on 27/01/16. -// Copyright (c) 2016-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2016-2025 AnyKey Entertainment. All rights reserved. // -#if defined(__has_feature) && __has_feature(modules) -@import UIKit; -#else #import -#endif +NS_ASSUME_NONNULL_BEGIN + +/** + A simple switch view with an optional label, configurable via UIAppearance. + */ @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; +/// Tint color for the switch (UIAppearance). +@property (strong, nonatomic, nullable) UIColor *tintColor UI_APPEARANCE_SELECTOR; + +/// Label color (UIAppearance). +@property (strong, nonatomic, nullable) UIColor *labelColor UI_APPEARANCE_SELECTOR; + +/// Label font (UIAppearance). +@property (strong, nonatomic, nullable) UIFont *labelFont UI_APPEARANCE_SELECTOR; + +/// Label text (UIAppearance). +@property (strong, nonatomic, nullable) NSString *labelText UI_APPEARANCE_SELECTOR; + +/// Selection state. @property (nonatomic, getter=isSelected) BOOL selected; @end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertView/SCLSwitchView.m b/SCLAlertView/SCLSwitchView.m index 93662ac..50addfc 100644 --- a/SCLAlertView/SCLSwitchView.m +++ b/SCLAlertView/SCLSwitchView.m @@ -9,6 +9,8 @@ #import "SCLSwitchView.h" #import "SCLMacros.h" +static const CGFloat kSpacing = 8.0f; + @interface SCLSwitchView () @property (strong, nonatomic) UISwitch *switchKnob; @@ -16,8 +18,6 @@ @interface SCLSwitchView () @end -#pragma mark - @implementation SCLSwitchView #pragma mark - Constructors @@ -56,38 +56,62 @@ - (instancetype)initWithFrame:(CGRect)frame - (void)setup { + self.backgroundColor = UIColor.clearColor; + // Add switch knob - self.switchKnob = [[UISwitch alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, 0.f)]; + self.switchKnob = [[UISwitch alloc] initWithFrame:CGRectZero]; [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 = [[UILabel alloc] initWithFrame:CGRectZero]; 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.font = [UIFont fontWithName:@"HelveticaNeue-Bold" size:12.0f]; self.switchLabel.textColor = UIColorFromHEX(0x4D4D4D); [self addSubview:self.switchLabel]; } +#pragma mark - Layout + +- (CGSize)sizeThatFits:(CGSize)size { + CGSize switchSize = self.switchKnob.intrinsicContentSize; + CGFloat availableWidth = (size.width > 0 ? size.width : (switchSize.width + kSpacing + 120.0f)); // fallback width + CGFloat labelWidth = MAX(0, availableWidth - switchSize.width - kSpacing); + CGSize labelSize = [self.switchLabel sizeThatFits:CGSizeMake(labelWidth, CGFLOAT_MAX)]; + CGFloat height = MAX(labelSize.height, switchSize.height); + return CGSizeMake(availableWidth, height); +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + CGSize boundsSize = self.bounds.size; + CGSize switchSize = self.switchKnob.intrinsicContentSize; + + // Place switch at leading (x=0) + CGFloat switchX = 0.0f; + CGFloat switchY = (boundsSize.height - switchSize.height) / 2.0f; + self.switchKnob.frame = CGRectMake(switchX, switchY, switchSize.width, switchSize.height); + + // Label fills remaining space after switch + spacing + CGFloat labelX = CGRectGetMaxX(self.switchKnob.frame) + kSpacing; + CGFloat labelWidth = MAX(0, boundsSize.width - labelX); + CGSize labelFit = [self.switchLabel sizeThatFits:CGSizeMake(labelWidth, CGFLOAT_MAX)]; + CGFloat labelHeight = MIN(labelFit.height, boundsSize.height); + CGFloat labelY = (boundsSize.height - labelHeight) / 2.0f; + self.switchLabel.frame = CGRectMake(labelX, labelY, labelWidth, labelHeight); +} + #pragma mark - Getters - (UIColor *)tintColor { - return self.switchKnob.tintColor; + return self.switchKnob.onTintColor; } - (UIColor *)labelColor @@ -114,6 +138,7 @@ - (BOOL)isSelected - (void)setTintColor:(UIColor *)tintColor { + [super setTintColor:tintColor]; self.switchKnob.onTintColor = tintColor; } @@ -125,11 +150,13 @@ - (void)setLabelColor:(UIColor *)labelColor - (void)setLabelFont:(UIFont *)labelFont { self.switchLabel.font = labelFont; + [self setNeedsLayout]; } - (void)setLabelText:(NSString *)labelText { self.switchLabel.text = labelText; + [self setNeedsLayout]; } - (void)setSelected:(BOOL)selected diff --git a/SCLAlertView/SCLTextView.h b/SCLAlertView/SCLTextView.h index e691ef8..4cb4b65 100644 --- a/SCLAlertView/SCLTextView.h +++ b/SCLAlertView/SCLTextView.h @@ -3,15 +3,17 @@ // SCLAlertView // // Created by Diogo Autilio on 9/18/15. -// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2015-2025 AnyKey Entertainment. All rights reserved. // -#if defined(__has_feature) && __has_feature(modules) -@import UIKit; -#else #import -#endif -@interface SCLTextView : UITextField +NS_ASSUME_NONNULL_BEGIN +/** + A UITextField subclass used by SCLAlertView for consistent styling and behavior. + */ +@interface SCLTextView : UITextField @end + +NS_ASSUME_NONNULL_END diff --git a/SCLAlertView/SCLTextView.m b/SCLAlertView/SCLTextView.m index c508359..067e1b6 100644 --- a/SCLAlertView/SCLTextView.m +++ b/SCLAlertView/SCLTextView.m @@ -8,49 +8,77 @@ #import "SCLTextView.h" -#define MIN_HEIGHT 30.0f +static const CGFloat kSCLTextViewHeight = 35.0f; +static const CGFloat kSCLTextViewHorizontalPadding = 8.0f; @implementation SCLTextView -- (instancetype)init -{ +- (instancetype)init { self = [super init]; - if (self) - { + if (self) { [self setup]; } return self; } -- (instancetype)initWithCoder:(NSCoder *)aDecoder -{ - self = [super initWithCoder:aDecoder]; - if(self) - { +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { [self setup]; } return self; } -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self) - { +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (self) { [self setup]; } return self; } -- (void)setup -{ - self.frame = CGRectMake(0.0f, 0.0f, 0.0f, MIN_HEIGHT); - self.returnKeyType = UIReturnKeyDone; +- (void)setup { + self.backgroundColor = [UIColor whiteColor]; + self.textColor = [UIColor darkTextColor]; self.borderStyle = UITextBorderStyleRoundedRect; - self.autocapitalizationType = UITextAutocapitalizationTypeSentences; self.clearButtonMode = UITextFieldViewModeWhileEditing; - self.layer.masksToBounds = YES; - self.layer.borderWidth = 1.0f; + self.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; + self.autocorrectionType = UITextAutocorrectionTypeDefault; + self.autocapitalizationType = UITextAutocapitalizationTypeSentences; + self.returnKeyType = UIReturnKeyDone; + + // Padding interno via left/right views + UIView *leftPad = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kSCLTextViewHorizontalPadding, 1)]; + UIView *rightPad = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kSCLTextViewHorizontalPadding, 1)]; + self.leftView = leftPad; + self.leftViewMode = UITextFieldViewModeAlways; + self.rightView = rightPad; + self.rightViewMode = UITextFieldViewModeAlways; + + // Altura mínima padrão + CGRect f = self.frame; + if (CGRectIsEmpty(f)) { + f = CGRectMake(0, 0, 0, kSCLTextViewHeight); + } else { + f.size.height = MAX(f.size.height, kSCLTextViewHeight); + } + self.frame = f; +} + +- (CGSize)intrinsicContentSize { + CGSize base = [super intrinsicContentSize]; + if (base.height <= 0) { + base.height = kSCLTextViewHeight; + } else { + base.height = MAX(base.height, kSCLTextViewHeight); + } + return base; +} + +- (CGSize)sizeThatFits:(CGSize)size { + CGSize fit = [super sizeThatFits:size]; + fit.height = MAX(fit.height, kSCLTextViewHeight); + return fit; } @end diff --git a/SCLAlertView/SCLTimerDisplay.h b/SCLAlertView/SCLTimerDisplay.h index 2f9bc18..0f90f60 100644 --- a/SCLAlertView/SCLTimerDisplay.h +++ b/SCLAlertView/SCLTimerDisplay.h @@ -3,7 +3,7 @@ // SCLAlertView // // Created by Taylor Ryan on 8/18/15. -// Copyright (c) 2015-2017 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2015-2025 AnyKey Entertainment. All rights reserved. // // Taken from https://stackoverflow.com/questions/11783439/uibutton-with-timer @@ -22,18 +22,81 @@ CGFloat lineWidth; NSTimer *timer; SCLActionBlock completedBlock; + + // Precision/state + CFTimeInterval startTime; + CFTimeInterval pausedElapsed; + BOOL running; } +/// Current angle (in degrees or radians depending on implementation). @property CGFloat currentAngle; + +/// Index of the button this timer is attached to. @property NSInteger buttonIndex; + +/// Stroke color for the circular timer. @property (strong, nonatomic) UIColor *color; + +/// If YES, timer runs in reverse (countdown). @property (assign, nonatomic) BOOL reverse; +/** + Initializes a circular timer view. + + @param origin The origin point for the view. + @param r The radius of the circular timer. + @return An initialized SCLTimerDisplay instance. + */ - (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r; + +/** + Initializes a circular timer view with custom line width. + + @param origin The origin point for the view. + @param r The radius of the circular timer. + @param width The stroke line width. + @return An initialized SCLTimerDisplay instance. + */ - (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r lineWidth:(CGFloat)width; + +/** + Updates the frame/layout of the timer to fit a given size. + + @param size The new size to fit. + */ - (void)updateFrame:(CGSize)size; + +/** + Cancels and removes the timer, preventing completion from firing. + */ - (void)cancelTimer; + +/** + Stops the timer without removing the view. + */ - (void)stopTimer; + +/** + Starts the timer with a time limit. + + @param tl The time limit in seconds. + @param completed A block called when the timer completes. + */ - (void)startTimerWithTimeLimit:(int)tl completed:(SCLActionBlock)completed; +/** + Pauses the timer. + + @note Kept for API compatibility; optional usage. + */ +- (void)pauseTimer; + +/** + Resumes the timer after a pause. + + @note Kept for API compatibility; optional usage. + */ +- (void)resumeTimer; + @end diff --git a/SCLAlertView/SCLTimerDisplay.m b/SCLAlertView/SCLTimerDisplay.m index 6921e81..47a99c2 100644 --- a/SCLAlertView/SCLTimerDisplay.m +++ b/SCLAlertView/SCLTimerDisplay.m @@ -11,6 +11,8 @@ @interface SCLTimerDisplay () +// Centered numeric readout for elapsed/remaining seconds. +// Kept as a subview to benefit from UILabel accessibility and text rendering. @property (strong, nonatomic) UILabel *countLabel; @end @@ -26,6 +28,9 @@ - (instancetype)initWithFrame:(CGRect)frame { self.backgroundColor = [UIColor clearColor]; currentAngle = 0.0f; + _color = [UIColor whiteColor]; + running = NO; + pausedElapsed = 0; } return self; } @@ -41,25 +46,50 @@ - (instancetype)initWithOrigin:(CGPoint)origin radius:(CGFloat)r lineWidth:(CGFl if (self) { self.backgroundColor = [UIColor clearColor]; currentAngle = START_DEGREE_OFFSET; + // Draw from the center of the stroke; subtract half line width from the radius to avoid clipping radius = r-(width/2); lineWidth = width; self.color = [UIColor whiteColor]; self.userInteractionEnabled = NO; - // Add count label + // Lightweight numeric HUD in the middle of the ring _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; + _countLabel.isAccessibilityElement = YES; + _countLabel.accessibilityTraits = UIAccessibilityTraitUpdatesFrequently; [self addSubview:_countLabel]; } return self; } +- (void)dealloc +{ + [self cancelTimer]; +} + +- (void)willMoveToSuperview:(UIView *)newSuperview +{ + if (newSuperview == nil) { + // Prevent orphaned timers when the view leaves the hierarchy + [self cancelTimer]; + } + [super willMoveToSuperview:newSuperview]; +} + +- (void)setColor:(UIColor *)color +{ + _color = color ?: [UIColor whiteColor]; + _countLabel.textColor = _color; + [self setNeedsDisplay]; +} + - (void)updateFrame:(CGSize)size { + // Position the ring in the trailing edge with a small inset; keep label centered CGFloat r = radius+(lineWidth/2); CGFloat originX = size.width - (2*r) - 5; @@ -71,6 +101,7 @@ - (void)updateFrame:(CGSize)size - (void)drawRect:(CGRect)rect { + // Draw progress ring from START_DEGREE_OFFSET to currentAngle UIBezierPath* aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(radius+(lineWidth/2), radius+(lineWidth/2)) radius:radius startAngle:DEGREES_TO_RADIANS(START_DEGREE_OFFSET) @@ -80,54 +111,126 @@ - (void)drawRect:(CGRect)rect aPath.lineWidth = lineWidth; [aPath stroke]; - _countLabel.text = [NSString stringWithFormat:@"%d", (int)currentTime]; + // Keep the numeric text aligned with the mode: + // - reverse: countdown shows remaining seconds + // - forward: count-up shows elapsed seconds + if (_reverse) { + int remaining = MAX((int)ceil(timerLimit - currentTime), 0); + _countLabel.text = [NSString stringWithFormat:@"%d", remaining]; + _countLabel.accessibilityLabel = [NSString stringWithFormat:@"%d seconds remaining", remaining]; + } else { + int elapsed = MIN((int)floor(currentTime), (int)ceil(timerLimit)); + _countLabel.text = [NSString stringWithFormat:@"%d", elapsed]; + _countLabel.accessibilityLabel = [NSString stringWithFormat:@"%d seconds elapsed", elapsed]; + } } - (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; + [self cancelTimer]; // Reset prior state and invalidate any running NSTimer + + timerLimit = MAX(0, tl); + // Use a single notion of time for simplicity: currentTime is "elapsed" regardless of mode + currentTime = 0.0; + currentAngle = START_DEGREE_OFFSET; + completedBlock = [completed copy]; _countLabel.textColor = _color; + + pausedElapsed = 0; + startTime = CACurrentMediaTime(); + running = YES; + + __weak typeof(self) weakSelf = self; + // Block-based NSTimer avoids needing a selector and reduces boilerplate; weakSelf prevents retain cycles + timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_STEP repeats:YES block:^(NSTimer * _Nonnull t) { + [weakSelf updateTimerTick]; + }]; + // Common run loop modes keep the ring responsive while the UI is interacting (e.g., scrolling) + [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; + + [self setNeedsDisplay]; +} + +- (void)updateTimerTick +{ + if (!running) { return; } + + CFTimeInterval now = CACurrentMediaTime(); + CFTimeInterval elapsedSinceStart = now - startTime + pausedElapsed; + + // Clamp elapsed to the limit to stabilize the label at the end boundary + currentTime = MIN(elapsedSinceStart, timerLimit); + + if (_reverse) { + // Countdown visualization: arc shrinks from full circle to zero + CGFloat timeRemaining = MAX(timerLimit - elapsedSinceStart, 0.0); + CGFloat fractionRemaining = (timerLimit <= 0.0) ? 0.0 : (timeRemaining / timerLimit); + fractionRemaining = MIN(MAX(fractionRemaining, 0.0), 1.0); + // Map remaining fraction to end angle so the visible arc length is proportional to remaining time + currentAngle = (fractionRemaining * 360.0) + START_DEGREE_OFFSET; + } else { + // Count-up visualization: arc grows from zero to full circle + CGFloat fractionDone = (timerLimit <= 0.0) ? 1.0 : (elapsedSinceStart / timerLimit); + fractionDone = MIN(MAX(fractionDone, 0.0), 1.0); + currentAngle = (fractionDone * 360.0) + START_DEGREE_OFFSET; + } + + // Stop precisely at the limit to avoid overshooting due to timer granularity + BOOL finished = (elapsedSinceStart >= timerLimit); + if (finished) { + [self stopTimer]; + return; + } + [self setNeedsDisplay]; } - (void)cancelTimer { - [timer invalidate]; + running = NO; + if (timer) { + [timer invalidate]; + timer = nil; + } } - (void)stopTimer { - [timer invalidate]; + [self cancelTimer]; if (completedBlock != nil) { - completedBlock(); + // Copy to local before clearing to avoid re-entrancy surprises in user code + SCLActionBlock block = completedBlock; + completedBlock = nil; + block(); } } -- (void)updateTimerButton:(NSTimer *)timer +- (void)pauseTimer { - if (_reverse) - { - currentTime -= TIMER_STEP; - currentAngle = (currentTime/timerLimit) * 360 + START_DEGREE_OFFSET; - - if(currentTime <= 0) { - [self stopTimer]; - } + if (!running) return; + running = NO; + CFTimeInterval now = CACurrentMediaTime(); + // Accumulate elapsed time so resume continues from the correct point + pausedElapsed += (now - startTime); + if (timer) { + [timer setFireDate:[NSDate distantFuture]]; } - else { - currentTime += TIMER_STEP; - currentAngle = (currentTime/timerLimit) * 360 + START_DEGREE_OFFSET; +} - if(currentAngle >= (360 + START_DEGREE_OFFSET)) { - [self stopTimer]; - } +- (void)resumeTimer +{ + if (running || timerLimit <= 0) return; + running = YES; + // Restart time base; pausedElapsed carries the previous progress + startTime = CACurrentMediaTime(); + if (timer) { + [timer setFireDate:[NSDate date]]; + } else { + __weak typeof(self) weakSelf = self; + timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_STEP repeats:YES block:^(NSTimer * _Nonnull t) { + [weakSelf updateTimerTick]; + }]; + [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; } - [self setNeedsDisplay]; } @end diff --git a/SCLAlertViewExample/Category/UIViewController+Alert.m b/SCLAlertViewExample/Category/UIViewController+Alert.m index ecb3b22..c56ddf9 100644 --- a/SCLAlertViewExample/Category/UIViewController+Alert.m +++ b/SCLAlertViewExample/Category/UIViewController+Alert.m @@ -3,13 +3,15 @@ // SCLAlertView // // Created by Diogo Autilio on 31/10/20. -// Copyright © 2020 AnyKey Entertainment. All rights reserved. +// Copyright © 2020-2025 AnyKey Entertainment. All rights reserved. // #import "UIViewController+Alert.h" @implementation UIViewController (Alert) +#pragma mark - Alerts + - (void)showAlertWithTitle:(NSString *)title message:(NSString *)message actionBlock:(nullable ActionBlock)actionBlock { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title diff --git a/SCLAlertViewExample/ViewController/ViewController.m b/SCLAlertViewExample/ViewController/ViewController.m index cdb1128..d5811e6 100644 --- a/SCLAlertViewExample/ViewController/ViewController.m +++ b/SCLAlertViewExample/ViewController/ViewController.m @@ -3,7 +3,7 @@ // SCLAlertView // // Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// Copyright (c) 2014-2025 AnyKey Entertainment. All rights reserved. // #import "ViewController.h" @@ -11,9 +11,9 @@ #import "UIViewController+Alert.h" @interface ViewController () - @end +// MARK: Constants NSString *kSuccessTitle = @"Congratulations"; NSString *kErrorTitle = @"Connection error"; NSString *kNoticeTitle = @"Notice"; @@ -25,6 +25,8 @@ @interface ViewController () @implementation ViewController +#pragma mark - Success + - (IBAction)showSuccess:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; @@ -34,12 +36,10 @@ - (IBAction)showSuccess:(id)sender button.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; - buttonConfig[@"backgroundColor"] = [UIColor whiteColor]; buttonConfig[@"textColor"] = [UIColor blackColor]; buttonConfig[@"borderWidth"] = @2.0f; buttonConfig[@"borderColor"] = [UIColor greenColor]; - return buttonConfig; }; @@ -52,7 +52,8 @@ - (IBAction)showSuccess:(id)sender [alert showSuccess:kSuccessTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; } -- (IBAction)showSuccessWithHorizontalButtons:(id)sender { +- (IBAction)showSuccessWithHorizontalButtons:(id)sender +{ SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; [alert setHorizontalButtons:YES]; @@ -61,12 +62,10 @@ - (IBAction)showSuccessWithHorizontalButtons:(id)sender { button.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; - buttonConfig[@"backgroundColor"] = [UIColor whiteColor]; buttonConfig[@"textColor"] = [UIColor blackColor]; buttonConfig[@"borderWidth"] = @2.0f; buttonConfig[@"borderColor"] = [UIColor greenColor]; - return buttonConfig; }; @@ -79,30 +78,42 @@ - (IBAction)showSuccessWithHorizontalButtons:(id)sender { [alert showSuccess:kSuccessTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; } +#pragma mark - Error + - (IBAction)showError:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - [alert showError:self title:@"An error with two title is presented ..." + [alert showError:self + title:@"An error with two title is presented ..." subTitle:@"You have not saved your Submission yet. Please save the Submission before accessing the Responses list. Blah de blah de blah, blah. Blah de blah de blah, blah.Blah de blah de blah, blah.Blah de blah de blah, blah.Blah de blah de blah, blah.Blah de blah de blah, End." - closeButtonTitle:@"OK" duration:0.0f]; + closeButtonTitle:@"OK" + duration:0.0f]; } +#pragma mark - Notice + - (IBAction)showNotice:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - alert.backgroundType = SCLAlertViewBackgroundBlur; - [alert showNotice:self title:kNoticeTitle subTitle:@"You've just displayed this awesome Pop Up View with blur effect" closeButtonTitle:kButtonTitle duration:0.0f]; + [alert showNotice:self + title:kNoticeTitle + subTitle:@"You've just displayed this awesome Pop Up View with blur effect" + closeButtonTitle:kButtonTitle + duration:0.0f]; } +#pragma mark - Warning + - (IBAction)showWarning:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - [alert showWarning:self title:kWarningTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; } +#pragma mark - Info + - (IBAction)showInfo:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -115,6 +126,8 @@ - (IBAction)showInfo:(id)sender [alert showInfo:self title:kInfoTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; } +#pragma mark - Edit + - (IBAction)showEdit:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -141,6 +154,8 @@ - (IBAction)showEditWithHorizontalButtons:(id)sender [alert showEdit:self title:kInfoTitle subTitle:kSubtitle closeButtonTitle:kButtonTitle duration:0.0f]; } +#pragma mark - Advanced + - (IBAction)showAdvanced:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -166,18 +181,16 @@ - (IBAction)showAdvanced:(id)sender alert.completeButtonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; - buttonConfig[@"backgroundColor"] = [UIColor greenColor]; buttonConfig[@"borderColor"] = [UIColor blackColor]; buttonConfig[@"borderWidth"] = @"1.0f"; buttonConfig[@"textColor"] = [UIColor blackColor]; - return buttonConfig; }; alert.attributedFormatBlock = ^NSAttributedString* (NSString *value) { - NSMutableAttributedString *subTitle = [[NSMutableAttributedString alloc]initWithString:value]; + NSMutableAttributedString *subTitle = [[NSMutableAttributedString alloc] initWithString:value]; NSRange redRange = [value rangeOfString:@"Attributed" options:NSCaseInsensitiveSearch]; [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:redRange]; @@ -220,18 +233,16 @@ - (IBAction)ShowAdvancedWithHorizontalButtons:(id)sender alert.completeButtonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; - buttonConfig[@"backgroundColor"] = [UIColor greenColor]; buttonConfig[@"borderColor"] = [UIColor blackColor]; buttonConfig[@"borderWidth"] = @"1.0f"; buttonConfig[@"textColor"] = [UIColor blackColor]; - return buttonConfig; }; alert.attributedFormatBlock = ^NSAttributedString* (NSString *value) { - NSMutableAttributedString *subTitle = [[NSMutableAttributedString alloc]initWithString:value]; + NSMutableAttributedString *subTitle = [[NSMutableAttributedString alloc] initWithString:value]; NSRange redRange = [value rangeOfString:@"Attributed" options:NSCaseInsensitiveSearch]; [subTitle addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:redRange]; @@ -248,13 +259,16 @@ - (IBAction)ShowAdvancedWithHorizontalButtons:(id)sender [alert showTitle:self title:@"Congratulations" subTitle:kAttributeTitle style:SCLAlertViewStyleSuccess closeButtonTitle:@"Done" duration:0.0f]; } +#pragma mark - Duration + - (IBAction)showWithDuration:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - [alert showNotice:self title:kNoticeTitle subTitle:@"You've just displayed this awesome Pop Up View with 5 seconds duration" closeButtonTitle:nil duration:5.0f]; } +#pragma mark - Custom + - (IBAction)showCustom:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -263,6 +277,8 @@ - (IBAction)showCustom:(id)sender [alert showCustom:self image:[UIImage imageNamed:@"git"] color:color title:@"Custom" subTitle:@"Add a custom icon and color for your own type of alert!" closeButtonTitle:@"OK" duration:0.0f]; } +#pragma mark - Validation + - (IBAction)showValidation:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; @@ -380,37 +396,48 @@ - (IBAction)showValidationWithHorizontalButtons:(id)sender [alert showEdit:self title:@"Validation" subTitle:@"Ensure the data is correct before dismissing!" closeButtonTitle:@"Cancel" duration:0]; } +#pragma mark - Waiting + - (IBAction)showWaiting:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; alert.showAnimationType = SCLAlertViewShowAnimationSlideInToCenter; alert.hideAnimationType = SCLAlertViewHideAnimationSlideOutFromCenter; - alert.backgroundType = SCLAlertViewBackgroundTransparent; - [alert showWaiting:self title:@"Waiting..." - subTitle:@"You've just displayed this awesome Pop Up View with transparent background" - closeButtonTitle:nil duration:5.0f]; + [alert showWaiting:self + title:@"Waiting..." + subTitle:@"You've just displayed this awesome Pop Up View with transparent background" + closeButtonTitle:nil + duration:5.0f]; } +#pragma mark - Timer + - (IBAction)showTimer:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; [alert addTimerToButtonIndex:0 reverse:YES]; - [alert showInfo:self title:@"Countdown Timer" - subTitle:@"This alert has a duration set, and a countdown timer on the Dismiss button to show how long is left." - closeButtonTitle:@"Dismiss" duration:10.0f]; + [alert showInfo:self + title:@"Countdown Timer" + subTitle:@"This alert has a duration set, and a countdown timer on the Dismiss button to show how long is left." + closeButtonTitle:@"Dismiss" + duration:10.0f]; } +#pragma mark - Question + - (IBAction)showQuestion:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] init]; - [alert showQuestion:self title:@"Question?" subTitle:kSubtitle closeButtonTitle:@"Dismiss" duration:0.0f]; } -- (IBAction)showSwitch:(id)sender { +#pragma mark - Switch + +- (IBAction)showSwitch:(id)sender +{ SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; alert.tintTopCircle = NO; alert.iconTintColor = [UIColor brownColor]; @@ -421,38 +448,37 @@ - (IBAction)showSwitch:(id)sender { [[SCLSwitchView appearance] setTintColor:[UIColor brownColor]]; SCLButton *button = [alert addButton:@"Done" target:self selector:@selector(firstButton)]; - button.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; buttonConfig[@"cornerRadius"] = @"17.5f"; - return buttonConfig; }; [alert showCustom:self image:[UIImage imageNamed:@"switch"] color:[UIColor brownColor] title:kInfoTitle subTitle:kSubtitle closeButtonTitle:nil duration:0.0f]; } +#pragma mark - Actions + - (void)firstButton { NSLog(@"First button tapped"); } +#pragma mark - Custom Button + - (IBAction)showWithButtonCustom:(id)sender { SCLAlertView *alert = [[SCLAlertView alloc] initWithNewWindow]; SCLButton *button = [alert addButton:@"First Button" target:self selector:@selector(firstButton)]; - button.buttonFormatBlock = ^NSDictionary* (void) { NSMutableDictionary *buttonConfig = [[NSMutableDictionary alloc] init]; - buttonConfig[@"backgroundColor"] = [UIColor whiteColor]; buttonConfig[@"textColor"] = [UIColor blackColor]; buttonConfig[@"borderWidth"] = @2.0f; buttonConfig[@"borderColor"] = [UIColor greenColor]; buttonConfig[@"font"] = [UIFont fontWithName:@"ComicSansMS" size:13]; - return buttonConfig; }; diff --git a/SCLAlertViewFramework/SCLAlertViewFramework.h b/SCLAlertViewFramework/SCLAlertViewFramework.h index 5981fc4..e4576ca 100644 --- a/SCLAlertViewFramework/SCLAlertViewFramework.h +++ b/SCLAlertViewFramework/SCLAlertViewFramework.h @@ -3,7 +3,7 @@ // SCLAlertView // // Created by Eugene Tulusha on 9/13/16. -// Copyright © 2016 AnyKey Entertainment. All rights reserved. +// Copyright © 2016-2025 AnyKey Entertainment. All rights reserved. // @import Foundation; From 140688346b6d320447f39bb59a903464a144fc20 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Fri, 10 Oct 2025 11:39:24 -0300 Subject: [PATCH 23/41] Replace old mise file with the new pattern --- .tool-versions | 1 - mise.toml | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 .tool-versions create mode 100644 mise.toml diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index 0b2d858..0000000 --- a/.tool-versions +++ /dev/null @@ -1 +0,0 @@ -ruby 3.1.2 diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..fc4993b --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +ruby = "3.1.2" From 366426d0461d781502e411d931513537083cbe7d Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Sat, 25 Oct 2025 07:54:34 -0300 Subject: [PATCH 24/41] fix: documentation language --- SCLAlertView/SCLAlertViewResponder.h | 8 ++++---- SCLAlertView/SCLTextView.m | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/SCLAlertView/SCLAlertViewResponder.h b/SCLAlertView/SCLAlertViewResponder.h index 31c438b..148a1fc 100644 --- a/SCLAlertView/SCLAlertViewResponder.h +++ b/SCLAlertView/SCLAlertViewResponder.h @@ -11,16 +11,16 @@ @interface SCLAlertViewResponder : NSObject -/// Inicializa o responder vinculado a uma instância de SCLAlertView. +/// Initializes the responder associated with an instance of SCLAlertView. - (instancetype)init:(SCLAlertView *)alertview; -/// Atualiza o título do alerta. +/// Updates the alert's title. - (void)setTitle:(NSString *)title; -/// Atualiza o subtítulo/texto do corpo do alerta. +/// Updates the alert's subtitle / body text. - (void)setSubTitle:(NSString *)subTitle; -/// Fecha o alerta. +/// Closes the alert. - (void)close; @end diff --git a/SCLAlertView/SCLTextView.m b/SCLAlertView/SCLTextView.m index 067e1b6..8fa0271 100644 --- a/SCLAlertView/SCLTextView.m +++ b/SCLAlertView/SCLTextView.m @@ -47,7 +47,7 @@ - (void)setup { self.autocapitalizationType = UITextAutocapitalizationTypeSentences; self.returnKeyType = UIReturnKeyDone; - // Padding interno via left/right views + // Internal padding via left/right views UIView *leftPad = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kSCLTextViewHorizontalPadding, 1)]; UIView *rightPad = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kSCLTextViewHorizontalPadding, 1)]; self.leftView = leftPad; @@ -55,7 +55,7 @@ - (void)setup { self.rightView = rightPad; self.rightViewMode = UITextFieldViewModeAlways; - // Altura mínima padrão + // Default minimum height CGRect f = self.frame; if (CGRectIsEmpty(f)) { f = CGRectMake(0, 0, 0, kSCLTextViewHeight); From 4f11ae68a5cef2065068ab3af84ed9af195c7742 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Sun, 26 Oct 2025 08:53:12 -0300 Subject: [PATCH 25/41] feat: add SPM support --- .gitignore | 9 +++------ Package.swift | 26 ++++++++++++++++++++++++++ SCLAlertView/SCLAlertView.h | 10 ++++++++++ SCLAlertView/SCLAlertView.m | 34 +++++++++++++++++++++++++++++----- 4 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 Package.swift diff --git a/.gitignore b/.gitignore index fd94552..eda364b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,10 +21,7 @@ DerivedData *.ipa *.xcuserstate -# CocoaPods +# SPM # -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control -# -# Pods/ +.build/ +Derived/ diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..5e1b66d --- /dev/null +++ b/Package.swift @@ -0,0 +1,26 @@ +// swift-tools-version:5.3 +import PackageDescription + +let package = Package( + name: "SCLAlertView-Objective-C", + platforms: [ + .iOS(.v12) + ], + products: [ + .library( + name: "SCLAlertView-Objective-C", + type: .dynamic, + targets: ["SCLAlertView-Objective-C"] + ) + ], + targets: [ + .target( + name: "SCLAlertView-Objective-C", + path: "SCLAlertView", + publicHeadersPath: ".", + cSettings: [ + .headerSearchPath("."), + ] + ) + ] +) diff --git a/SCLAlertView/SCLAlertView.h b/SCLAlertView/SCLAlertView.h index 084fd1f..2b88841 100755 --- a/SCLAlertView/SCLAlertView.h +++ b/SCLAlertView/SCLAlertView.h @@ -155,6 +155,16 @@ typedef NS_ENUM(NSInteger, SCLAlertViewBackground) */ - (instancetype)initWithNewWindow; +/** + Creates and returns a new alert configured to present in its own UIWindow. + + This convenience constructor is equivalent to [[SCLAlertView alloc] initWithNewWindow]. + + @return A newly created SCLAlertView instance ready to be shown in a dedicated window. + @note In Swift, use SCLAlertView.newWindow() due to NS_SWIFT_NAME(newWindow()). + */ ++ (instancetype)alertWithNewWindow NS_SWIFT_NAME(newWindow()); + /** Initializes an alert presented in a new UIWindow with custom width. diff --git a/SCLAlertView/SCLAlertView.m b/SCLAlertView/SCLAlertView.m index 409d956..59e4198 100755 --- a/SCLAlertView/SCLAlertView.m +++ b/SCLAlertView/SCLAlertView.m @@ -122,6 +122,11 @@ - (instancetype)initWithNewWindow return self; } ++ (instancetype)alertWithNewWindow +{ + return [[self alloc] initWithNewWindow]; +} + - (instancetype)initWithNewWindowWidth:(CGFloat)windowWidth { self = [self initWithWindowWidth:windowWidth]; @@ -261,15 +266,34 @@ - (void)setupViewWindowWidth:(CGFloat)windowWidth - (void)setupNewWindow { - // Save previous window + // Preserve the current key window to restore it after dismissing the alert self.previousWindow = [SCLAlertView scl_currentKeyWindow]; - - // Create a new one to show the alert + + // Create a dedicated window to host the alert UIWindow *alertWindow = [[UIWindow alloc] initWithFrame:[self mainScreenFrame]]; alertWindow.windowLevel = UIWindowLevelAlert; alertWindow.backgroundColor = [UIColor clearColor]; alertWindow.rootViewController = [UIViewController new]; alertWindow.accessibilityViewIsModal = YES; + + // On iOS 13+, explicitly attach the alert window to the active UIWindowScene + if (@available(iOS 13.0, *)) { + // Try to reuse the scene from the current key window, if available + UIWindow *key = [SCLAlertView scl_currentKeyWindow]; + if (key.windowScene != nil) { + alertWindow.windowScene = key.windowScene; + } else { + // Fallback: iterate through connected scenes and pick a foreground active UIWindowScene + for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) { + if (scene.activationState == UISceneActivationStateForegroundActive && + [scene isKindOfClass:[UIWindowScene class]]) { + alertWindow.windowScene = (UIWindowScene *)scene; + break; + } + } + } + } + self.SCLAlertWindow = alertWindow; self.usingNewWindow = YES; } @@ -1333,7 +1357,7 @@ - (void)hideView if (_usingNewWindow) { - // Restore previous window + // Restore the previous key window after hiding the alert [self.previousWindow makeKeyAndVisible]; self.previousWindow = nil; } @@ -1364,7 +1388,7 @@ - (void)fadeOutWithDuration:(NSTimeInterval)duration [self removeFromParentViewController]; if (self.usingNewWindow) { - // Remove current window + // Remove current alert window [self.SCLAlertWindow setHidden:YES]; self.SCLAlertWindow = nil; } From c18408f82f168d42cf72b2c0c95095f72f3ba730 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Sun, 26 Oct 2025 19:06:18 -0300 Subject: [PATCH 26/41] chore: use mise in the CI --- .github/workflows/Build.yml | 9 ++++++++- .ruby-version | 1 - 2 files changed, 8 insertions(+), 2 deletions(-) delete mode 100644 .ruby-version diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index d55e0a1..94a64be 100755 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -7,10 +7,17 @@ jobs: runs-on: macos-13 steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 + - name: Setup Xcode version uses: maxim-lobanov/setup-xcode@v1.6.0 with: xcode-version: 15.0.1 + + - name: Install Project Tools + uses: jdx/mise-action@v3 + with: + experimental: true + - name: Building iOS app run: exec ./.github/scripts/build_app.sh diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index ef538c2..0000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -3.1.2 From a175d5cb738c6190dc90f90f7748d279168b9d24 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Mon, 27 Oct 2025 10:27:07 -0300 Subject: [PATCH 27/41] Bump version to 1.4.0 --- SCLAlertView-Objective-C.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SCLAlertView-Objective-C.podspec b/SCLAlertView-Objective-C.podspec index deda426..55667ad 100644 --- a/SCLAlertView-Objective-C.podspec +++ b/SCLAlertView-Objective-C.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "SCLAlertView-Objective-C" - spec.version = "1.3.1" + spec.version = "1.4.0" spec.summary = "Beautiful animated Alert View. Written in Swift but ported to Objective-C" spec.homepage = "https://github.com/dogo/SCLAlertView" spec.screenshots = "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot.png", "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot2.png" From 3f29ee4bb0516fc5fc801b8484845fd632c6d2c3 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 28 Oct 2025 18:54:06 -0300 Subject: [PATCH 28/41] fix: remove hyphens from product name for better SPM/device compatibility --- Package.swift | 8 ++++---- SCLAlertView-Objective-C.podspec | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Package.swift b/Package.swift index 5e1b66d..d7583bf 100644 --- a/Package.swift +++ b/Package.swift @@ -2,20 +2,20 @@ import PackageDescription let package = Package( - name: "SCLAlertView-Objective-C", + name: "SCLAlertViewObjC", platforms: [ .iOS(.v12) ], products: [ .library( - name: "SCLAlertView-Objective-C", + name: "SCLAlertViewObjC", type: .dynamic, - targets: ["SCLAlertView-Objective-C"] + targets: ["SCLAlertViewObjC"] ) ], targets: [ .target( - name: "SCLAlertView-Objective-C", + name: "SCLAlertViewObjC", path: "SCLAlertView", publicHeadersPath: ".", cSettings: [ diff --git a/SCLAlertView-Objective-C.podspec b/SCLAlertView-Objective-C.podspec index 55667ad..b0a27bf 100644 --- a/SCLAlertView-Objective-C.podspec +++ b/SCLAlertView-Objective-C.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "SCLAlertView-Objective-C" - spec.version = "1.4.0" + spec.version = "1.4.1" spec.summary = "Beautiful animated Alert View. Written in Swift but ported to Objective-C" spec.homepage = "https://github.com/dogo/SCLAlertView" spec.screenshots = "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot.png", "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot2.png" From 21162426c3a46abba058fd1feea667414e0e1471 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Tue, 14 Sep 2021 01:01:38 -0300 Subject: [PATCH 29/41] Improve keyboard handling #300 --- SCLAlertView/SCLAlertView.m | 79 +++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 16 deletions(-) diff --git a/SCLAlertView/SCLAlertView.m b/SCLAlertView/SCLAlertView.m index 59e4198..d23146a 100755 --- a/SCLAlertView/SCLAlertView.m +++ b/SCLAlertView/SCLAlertView.m @@ -17,8 +17,6 @@ @import AVFoundation; @import AudioToolbox; -#define KEYBOARD_HEIGHT 80 -#define PREDICTION_BAR_HEIGHT 40 #define ADD_BUTTON_PADDING 10.0f #define DEFAULT_WINDOW_WIDTH 240 @@ -58,6 +56,9 @@ @interface SCLAlertView () @property (nonatomic) CGFloat subTitleHeight; @property (nonatomic) CGFloat subTitleY; +@property (nonatomic) CGPoint tmpContentViewFrameOrigin; +@property (nonatomic) CGPoint tmpCircleViewFrameOrigin; + @end @implementation SCLAlertView @@ -670,25 +671,71 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField - (void)keyboardWillShow:(NSNotification *)notification { if(_keyboardIsVisible) return; + + NSDictionary *userInfo = notification.userInfo; + NSTimeInterval animationDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; + UIViewAnimationOptions animationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16; + + // Get the keyboard frame in screen coordinates + CGRect keyboardFrameEnd = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; + + // Convert contentView frame to screen coordinates + UIWindow *window = self.view.window; + if (!window) { + window = _usingNewWindow ? _SCLAlertWindow : [SCLAlertView scl_currentKeyWindow]; + } - [UIView animateWithDuration:0.2f animations:^{ - CGRect f = self.view.frame; - f.origin.y -= KEYBOARD_HEIGHT + PREDICTION_BAR_HEIGHT; - self.view.frame = f; - }]; - _keyboardIsVisible = YES; + CGRect contentViewScreenFrame = [_contentView.superview convertRect:_contentView.frame toView:nil]; + CGFloat contentViewBottom = CGRectGetMaxY(contentViewScreenFrame); + CGFloat keyboardTop = CGRectGetMinY(keyboardFrameEnd); + + // Calculate how much the content view overlaps with the keyboard + CGFloat overlap = contentViewBottom - keyboardTop; + + // Add some padding so the content isn't flush against the keyboard + CGFloat padding = 10.0f; + + if (overlap > 0) { + _keyboardIsVisible = YES; + _tmpContentViewFrameOrigin = _contentView.frame.origin; + _tmpCircleViewFrameOrigin = _circleViewBackground.frame.origin; + + CGFloat offsetY = overlap + padding; + + [UIView animateWithDuration:animationDuration delay:0 options:animationCurve animations:^{ + CGRect contentFrame = self.contentView.frame; + contentFrame.origin.y -= offsetY; + self.contentView.frame = contentFrame; + + CGRect circleFrame = self.circleViewBackground.frame; + circleFrame.origin.y -= offsetY; + self.circleViewBackground.frame = circleFrame; + } completion:nil]; + } } - (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; + if(_keyboardIsVisible) { + NSDictionary *userInfo = notification.userInfo; + NSTimeInterval animationDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; + UIViewAnimationOptions animationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16; + + [UIView animateWithDuration:animationDuration delay:0 options:animationCurve animations:^{ + CGRect contentFrame = self.contentView.frame; + contentFrame.origin.y = self->_tmpContentViewFrameOrigin.y; + self.contentView.frame = contentFrame; + + CGRect circleFrame = self.circleViewBackground.frame; + circleFrame.origin.y = self->_tmpCircleViewFrameOrigin.y; + self.circleViewBackground.frame = circleFrame; + } completion:^(BOOL finished) { + self->_tmpContentViewFrameOrigin = CGPointZero; + self->_tmpCircleViewFrameOrigin = CGPointZero; + }]; + + _keyboardIsVisible = NO; + } } #pragma mark - Buttons From c1b53bdf676fce3f1db83e00cd3c2183be814d29 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Sun, 30 Nov 2025 08:16:23 -0300 Subject: [PATCH 30/41] chore(ci) : Update macOS to 15 and Xcode to 26.1 --- .github/scripts/build_app.sh | 2 +- .github/workflows/Build.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/scripts/build_app.sh b/.github/scripts/build_app.sh index 14ce85d..8268274 100755 --- a/.github/scripts/build_app.sh +++ b/.github/scripts/build_app.sh @@ -4,5 +4,5 @@ set -eo pipefail xcodebuild -project SCLAlertView.xcodeproj \ -scheme SCLAlertView \ - -destination platform=iOS\ Simulator,OS=17.2,name=iPhone\ 15 \ + -destination platform=iOS\ Simulator,OS=26.1,name=iPhone\ 16 \ clean build | xcpretty diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 94a64be..dc85dee 100755 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -4,7 +4,7 @@ on: [push, pull_request] jobs: build: name: Building SCLAlertView - runs-on: macos-13 + runs-on: macos-15 steps: - name: Checkout repository uses: actions/checkout@v4 @@ -12,7 +12,7 @@ jobs: - name: Setup Xcode version uses: maxim-lobanov/setup-xcode@v1.6.0 with: - xcode-version: 15.0.1 + xcode-version: 26.1 - name: Install Project Tools uses: jdx/mise-action@v3 From 5464e331ae26297c500cfe71cb0a31122ba5aac0 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Sun, 30 Nov 2025 08:22:07 -0300 Subject: [PATCH 31/41] Replace mise-action with ruby/setup-ruby, which uses precompiled binaries and is faster than building from source. --- .github/workflows/Build.yml | 7 ++++--- Gemfile.lock | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index dc85dee..274862a 100755 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -14,10 +14,11 @@ jobs: with: xcode-version: 26.1 - - name: Install Project Tools - uses: jdx/mise-action@v3 + - name: Setup Ruby + uses: ruby/setup-ruby@v1 with: - experimental: true + ruby-version: 3.1.2 + bundler-cache: true - name: Building iOS app run: exec ./.github/scripts/build_app.sh diff --git a/Gemfile.lock b/Gemfile.lock index fe58e35..dba6404 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -71,6 +71,7 @@ GEM escape (0.0.4) ethon (0.15.0) ffi (>= 1.15.0) + ffi (1.17.2-arm64-darwin) ffi (1.17.2-x86_64-darwin) fourflusher (2.3.1) fuzzy_match (2.0.4) @@ -105,6 +106,7 @@ GEM rexml (>= 3.3.6, < 4.0) PLATFORMS + arm64-darwin-22 x86_64-darwin-23 DEPENDENCIES From 0540be42283cf96f5af52ffc624ac1f09ce1cb26 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Sun, 30 Nov 2025 08:32:58 -0300 Subject: [PATCH 32/41] chore(ci): update building system --- .github/scripts/build_app.sh | 8 -------- .github/workflows/Build.yml | 16 ++++++++++++++-- 2 files changed, 14 insertions(+), 10 deletions(-) delete mode 100755 .github/scripts/build_app.sh diff --git a/.github/scripts/build_app.sh b/.github/scripts/build_app.sh deleted file mode 100755 index 8268274..0000000 --- a/.github/scripts/build_app.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -eo pipefail - -xcodebuild -project SCLAlertView.xcodeproj \ - -scheme SCLAlertView \ - -destination platform=iOS\ Simulator,OS=26.1,name=iPhone\ 16 \ - clean build | xcpretty diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 274862a..7d2e635 100755 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -5,6 +5,14 @@ jobs: build: name: Building SCLAlertView runs-on: macos-15 + strategy: + matrix: + scheme: [ + SCLAlertView + ] + destination: [ + 'platform=iOS Simulator,name=iPhone 16,OS=26.1' + ] steps: - name: Checkout repository uses: actions/checkout@v4 @@ -20,5 +28,9 @@ jobs: ruby-version: 3.1.2 bundler-cache: true - - name: Building iOS app - run: exec ./.github/scripts/build_app.sh + - name: Building ${{ matrix.scheme }} on ${{ matrix.destination }} + run: | + set -o pipefail && xcodebuild -project SCLAlertView.xcodeproj \ + -scheme ${{ matrix.scheme }} \ + -destination '${{ matrix.destination }}' \ + clean build | xcbeautify --renderer github-actions From 8a01c99db4ef476384eb9ba57b0423f18f7e3be9 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Sun, 30 Nov 2025 08:42:19 -0300 Subject: [PATCH 33/41] Fix race condition in keyboard hide animation Guard temp value reset in completion block to prevent corruption when keyboard is shown again during hide animation. --- SCLAlertView/SCLAlertView.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/SCLAlertView/SCLAlertView.m b/SCLAlertView/SCLAlertView.m index d23146a..5c7db95 100755 --- a/SCLAlertView/SCLAlertView.m +++ b/SCLAlertView/SCLAlertView.m @@ -721,6 +721,8 @@ - (void)keyboardWillHide:(NSNotification *)notification NSTimeInterval animationDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationOptions animationCurve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16; + _keyboardIsVisible = NO; + [UIView animateWithDuration:animationDuration delay:0 options:animationCurve animations:^{ CGRect contentFrame = self.contentView.frame; contentFrame.origin.y = self->_tmpContentViewFrameOrigin.y; @@ -730,11 +732,12 @@ - (void)keyboardWillHide:(NSNotification *)notification circleFrame.origin.y = self->_tmpCircleViewFrameOrigin.y; self.circleViewBackground.frame = circleFrame; } completion:^(BOOL finished) { - self->_tmpContentViewFrameOrigin = CGPointZero; - self->_tmpCircleViewFrameOrigin = CGPointZero; + // Only reset if keyboard hasn't been shown again during the animation + if (!self->_keyboardIsVisible) { + self->_tmpContentViewFrameOrigin = CGPointZero; + self->_tmpCircleViewFrameOrigin = CGPointZero; + } }]; - - _keyboardIsVisible = NO; } } From 09d5749dc3acfe0be3d6779845058252b83b9e59 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Sun, 30 Nov 2025 08:46:21 -0300 Subject: [PATCH 34/41] Bump version to 1.4.2 --- SCLAlertView-Objective-C.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SCLAlertView-Objective-C.podspec b/SCLAlertView-Objective-C.podspec index b0a27bf..db00796 100644 --- a/SCLAlertView-Objective-C.podspec +++ b/SCLAlertView-Objective-C.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "SCLAlertView-Objective-C" - spec.version = "1.4.1" + spec.version = "1.4.2" spec.summary = "Beautiful animated Alert View. Written in Swift but ported to Objective-C" spec.homepage = "https://github.com/dogo/SCLAlertView" spec.screenshots = "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot.png", "https://raw.githubusercontent.com/dogo/SCLAlertView/master/ScreenShots/ScreenShot2.png" From c6b9ee1f40328d0cb5dbe039857857aa3580eef2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:48:30 +0000 Subject: [PATCH 35/41] Bump json from 2.15.1 to 2.15.2.1 Bumps [json](https://github.com/ruby/json) from 2.15.1 to 2.15.2.1. - [Release notes](https://github.com/ruby/json/releases) - [Changelog](https://github.com/ruby/json/blob/master/CHANGES.md) - [Commits](https://github.com/ruby/json/compare/v2.15.1...v2.15.2.1) --- updated-dependencies: - dependency-name: json dependency-version: 2.15.2.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index dba6404..9578c69 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -73,6 +73,7 @@ GEM ffi (>= 1.15.0) ffi (1.17.2-arm64-darwin) ffi (1.17.2-x86_64-darwin) + ffi (1.17.2-x86_64-linux-gnu) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) @@ -80,7 +81,7 @@ GEM mutex_m i18n (1.14.7) concurrent-ruby (~> 1.0) - json (2.15.1) + json (2.15.2.1) logger (1.7.0) minitest (5.25.5) molinillo (0.8.0) @@ -108,6 +109,7 @@ GEM PLATFORMS arm64-darwin-22 x86_64-darwin-23 + x86_64-linux DEPENDENCIES cocoapods From bf5c37d08d50d729d967fa87ebff24e2e9f2bddd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2026 02:05:10 +0000 Subject: [PATCH 36/41] Bump activesupport from 7.2.2.2 to 7.2.3.1 Bumps [activesupport](https://github.com/rails/rails) from 7.2.2.2 to 7.2.3.1. - [Release notes](https://github.com/rails/rails/releases) - [Changelog](https://github.com/rails/rails/blob/v8.1.2.1/activesupport/CHANGELOG.md) - [Commits](https://github.com/rails/rails/compare/v7.2.2.2...v7.2.3.1) --- updated-dependencies: - dependency-name: activesupport dependency-version: 7.2.3.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9578c69..dc39f61 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,7 +5,7 @@ GEM base64 nkf rexml - activesupport (7.2.2.2) + activesupport (7.2.3.1) base64 benchmark (>= 0.3) bigdecimal @@ -14,7 +14,7 @@ GEM drb i18n (>= 1.6, < 2) logger (>= 1.4.2) - minitest (>= 5.1) + minitest (>= 5.1, < 6) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) addressable (2.8.7) @@ -24,8 +24,8 @@ GEM json (>= 1.5.1) atomos (0.1.3) base64 (0.3.0) - benchmark (0.4.1) - bigdecimal (3.3.0) + benchmark (0.5.0) + bigdecimal (4.0.1) claide (1.1.0) cocoapods (1.16.2) addressable (~> 2.8) @@ -65,8 +65,8 @@ GEM netrc (~> 0.11) cocoapods-try (1.2.0) colored2 (3.1.2) - concurrent-ruby (1.3.5) - connection_pool (2.5.4) + concurrent-ruby (1.3.6) + connection_pool (2.5.5) drb (2.2.3) escape (0.0.4) ethon (0.15.0) @@ -79,11 +79,11 @@ GEM gh_inspector (1.1.3) httpclient (2.9.0) mutex_m - i18n (1.14.7) + i18n (1.14.8) concurrent-ruby (~> 1.0) json (2.15.2.1) logger (1.7.0) - minitest (5.25.5) + minitest (5.27.0) molinillo (0.8.0) mutex_m (0.3.0) nanaimo (0.4.0) From 371f6b9af92cf8dbb77610d87930f6aadda6c7d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 08:57:49 +0000 Subject: [PATCH 37/41] Bump addressable from 2.8.7 to 2.9.0 Bumps [addressable](https://github.com/sporkmonger/addressable) from 2.8.7 to 2.9.0. - [Changelog](https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md) - [Commits](https://github.com/sporkmonger/addressable/compare/addressable-2.8.7...addressable-2.9.0) --- updated-dependencies: - dependency-name: addressable dependency-version: 2.9.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index dc39f61..b3bbdd9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -17,8 +17,8 @@ GEM minitest (>= 5.1, < 6) securerandom (>= 0.3) tzinfo (~> 2.0, >= 2.0.5) - addressable (2.8.7) - public_suffix (>= 2.0.2, < 7.0) + addressable (2.9.0) + public_suffix (>= 2.0.2, < 8.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) From ce031f2af49e14988eeb9a1deeeb260eb55559b2 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Mon, 25 May 2026 08:56:52 -0300 Subject: [PATCH 38/41] Bump Ruby version from 3.1.2 to 3.3.0 in Gemfile, Gemfile.lock, and mise.toml --- Gemfile | 2 +- Gemfile.lock | 51 ++++++++++++++++++++++++++++++++------------------- mise.toml | 2 +- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/Gemfile b/Gemfile index 5bc1f49..f464f57 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ # frozen_string_literal: true source "https://rubygems.org" -ruby "3.1.2" +ruby "3.3.0" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } diff --git a/Gemfile.lock b/Gemfile.lock index b3bbdd9..71db6a9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,10 +1,7 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.7) - base64 - nkf - rexml + CFPropertyList (3.0.8) activesupport (7.2.3.1) base64 benchmark (>= 0.3) @@ -25,7 +22,7 @@ GEM atomos (0.1.3) base64 (0.3.0) benchmark (0.5.0) - bigdecimal (4.0.1) + bigdecimal (4.1.2) claide (1.1.0) cocoapods (1.16.2) addressable (~> 2.8) @@ -66,14 +63,23 @@ GEM cocoapods-try (1.2.0) colored2 (3.1.2) concurrent-ruby (1.3.6) - connection_pool (2.5.5) + connection_pool (3.0.2) drb (2.2.3) escape (0.0.4) - ethon (0.15.0) + ethon (0.18.0) ffi (>= 1.15.0) - ffi (1.17.2-arm64-darwin) - ffi (1.17.2-x86_64-darwin) - ffi (1.17.2-x86_64-linux-gnu) + logger + ffi (1.17.4) + ffi (1.17.4-aarch64-linux-gnu) + ffi (1.17.4-aarch64-linux-musl) + ffi (1.17.4-arm-linux-gnu) + ffi (1.17.4-arm-linux-musl) + ffi (1.17.4-arm64-darwin) + ffi (1.17.4-x86-linux-gnu) + ffi (1.17.4-x86-linux-musl) + ffi (1.17.4-x86_64-darwin) + ffi (1.17.4-x86_64-linux-gnu) + ffi (1.17.4-x86_64-linux-musl) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) @@ -81,7 +87,7 @@ GEM mutex_m i18n (1.14.8) concurrent-ruby (~> 1.0) - json (2.15.2.1) + json (2.19.5) logger (1.7.0) minitest (5.27.0) molinillo (0.8.0) @@ -89,13 +95,12 @@ GEM nanaimo (0.4.0) nap (1.1.0) netrc (0.11.0) - nkf (0.2.0) public_suffix (4.0.7) rexml (3.4.4) ruby-macho (2.5.1) securerandom (0.4.1) - typhoeus (1.5.0) - ethon (>= 0.9.0, < 0.16.0) + typhoeus (1.6.0) + ethon (>= 0.18.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) xcodeproj (1.27.0) @@ -107,15 +112,23 @@ GEM rexml (>= 3.3.6, < 4.0) PLATFORMS - arm64-darwin-22 - x86_64-darwin-23 - x86_64-linux + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + ruby + x86-linux-gnu + x86-linux-musl + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl DEPENDENCIES cocoapods RUBY VERSION - ruby 3.1.2p20 + ruby 3.3.0p0 BUNDLED WITH - 2.3.7 + 2.5.3 diff --git a/mise.toml b/mise.toml index fc4993b..b0964ab 100644 --- a/mise.toml +++ b/mise.toml @@ -1,2 +1,2 @@ [tools] -ruby = "3.1.2" +ruby = "3.3.0" From 8bde2fec2afc1ef2f4cbf0668e902059fce9d20b Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Mon, 25 May 2026 08:56:52 -0300 Subject: [PATCH 39/41] Bump Ruby version from 3.1.2 to 3.3.0 in Gemfile, Gemfile.lock, and mise.toml --- .github/workflows/Build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 7d2e635..dcc21c6 100755 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -25,7 +25,7 @@ jobs: - name: Setup Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 3.1.2 + ruby-version: 3.3.0 bundler-cache: true - name: Building ${{ matrix.scheme }} on ${{ matrix.destination }} From b05dc0058cf11495f7bf54c75a88bd422bc3564b Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Mon, 25 May 2026 09:11:57 -0300 Subject: [PATCH 40/41] Fix button timer handling and adjust button width for zero buttons --- SCLAlertView/SCLAlertView.m | 11 ++++++++--- SCLAlertView/SCLButton.m | 5 +++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/SCLAlertView/SCLAlertView.m b/SCLAlertView/SCLAlertView.m index 5c7db95..3d69d55 100755 --- a/SCLAlertView/SCLAlertView.m +++ b/SCLAlertView/SCLAlertView.m @@ -856,8 +856,13 @@ - (void)buttonTapped:(SCLButton *)btn - (void)addTimerToButtonIndex:(NSInteger)buttonIndex reverse:(BOOL)reverse { + if (_buttons.count == 0) { + buttonTimer = nil; + return; + } + buttonIndex = MAX(buttonIndex, 0); - buttonIndex = MIN(buttonIndex, [_buttons count]); + buttonIndex = MIN(buttonIndex, (NSInteger)_buttons.count - 1); buttonTimer = [[SCLTimerDisplay alloc] initWithOrigin:CGPointMake(5, 5) radius:13 lineWidth:4]; buttonTimer.buttonIndex = buttonIndex; @@ -1062,7 +1067,8 @@ - (SCLAlertViewResponder *)showTitle:(UIViewController *)vc image:(UIImage *)ima if (buttonTimer && _buttons.count > 0) { - SCLButton *btn = _buttons[buttonTimer.buttonIndex]; + NSInteger buttonIndex = MIN(MAX(buttonTimer.buttonIndex, 0), (NSInteger)_buttons.count - 1); + SCLButton *btn = _buttons[buttonIndex]; btn.timer = buttonTimer; __weak __typeof(self) weakSelf = self; [buttonTimer startTimerWithTimeLimit:duration completed:^{ @@ -2106,4 +2112,3 @@ - (void)showAlertView:(SCLAlertView *)alertView onViewController:(UIViewControll } @end - diff --git a/SCLAlertView/SCLButton.m b/SCLAlertView/SCLButton.m index b4a966d..593b599 100755 --- a/SCLAlertView/SCLButton.m +++ b/SCLAlertView/SCLButton.m @@ -65,6 +65,11 @@ - (void)setupWithWindowWidth:(CGFloat)windowWidth - (void)adjustWidthWithWindowWidth:(CGFloat)windowWidth numberOfButtons:(NSUInteger)numberOfButtons { + if (numberOfButtons == 0) { + self.frame = CGRectMake(0.0f, 0.0f, MAX(windowWidth - (MARGIN_BUTTON * 2), 0.0f), MIN_HEIGHT); + return; + } + CGFloat allButtonsWidth = windowWidth - (MARGIN_BUTTON * 2); CGFloat buttonWidth = (allButtonsWidth - ((numberOfButtons - 1) * 10)) / numberOfButtons; From 555c48bcccda807c7b0fdbae05fffe85d920d1a4 Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Mon, 25 May 2026 09:27:12 -0300 Subject: [PATCH 41/41] Add unit tests for SCLAlertView components and helpers; enable code coverage --- SCLAlertView.xcodeproj/project.pbxproj | 26 ++- .../xcschemes/SCLAlertView.xcscheme | 3 +- SCLAlertViewTests/SCLAlertViewBuilderTests.m | 86 ++++++++ SCLAlertViewTests/SCLAlertViewButtonTests.m | 117 ++++++++++ .../SCLAlertViewComponentTests.m | 118 ++++++++++ .../SCLAlertViewPresentationTests.m | 208 ++++++++++++++++++ SCLAlertViewTests/SCLAlertViewTestHelpers.h | 30 +++ SCLAlertViewTests/SCLAlertViewTestHelpers.m | 73 ++++++ SCLAlertViewTests/SCLAlertViewTests.m | 40 ---- 9 files changed, 656 insertions(+), 45 deletions(-) create mode 100644 SCLAlertViewTests/SCLAlertViewBuilderTests.m create mode 100644 SCLAlertViewTests/SCLAlertViewButtonTests.m create mode 100644 SCLAlertViewTests/SCLAlertViewComponentTests.m create mode 100644 SCLAlertViewTests/SCLAlertViewPresentationTests.m create mode 100644 SCLAlertViewTests/SCLAlertViewTestHelpers.h create mode 100644 SCLAlertViewTests/SCLAlertViewTestHelpers.m delete mode 100644 SCLAlertViewTests/SCLAlertViewTests.m diff --git a/SCLAlertView.xcodeproj/project.pbxproj b/SCLAlertView.xcodeproj/project.pbxproj index fa74768..92bf763 100644 --- a/SCLAlertView.xcodeproj/project.pbxproj +++ b/SCLAlertView.xcodeproj/project.pbxproj @@ -28,7 +28,11 @@ DDAD0113254DEABA00270C67 /* UIViewController+Alert.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAD0111254DEABA00270C67 /* UIViewController+Alert.m */; }; DDAD011D254DEAEC00270C67 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAD0119254DEAEC00270C67 /* AppDelegate.m */; }; DDAD011E254DEAEC00270C67 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAD011B254DEAEC00270C67 /* ViewController.m */; }; - DDB15FBD19D5B7C600173158 /* SCLAlertViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FBC19D5B7C600173158 /* SCLAlertViewTests.m */; }; + DDAA00012F00000100A11E57 /* SCLAlertViewTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAA00072F00000100A11E57 /* SCLAlertViewTestHelpers.m */; }; + DDAA00022F00000100A11E57 /* SCLAlertViewButtonTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAA00082F00000100A11E57 /* SCLAlertViewButtonTests.m */; }; + DDAA00032F00000100A11E57 /* SCLAlertViewComponentTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAA00092F00000100A11E57 /* SCLAlertViewComponentTests.m */; }; + DDAA00042F00000100A11E57 /* SCLAlertViewPresentationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAA000A2F00000100A11E57 /* SCLAlertViewPresentationTests.m */; }; + DDAA00052F00000100A11E57 /* SCLAlertViewBuilderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDAA000B2F00000100A11E57 /* SCLAlertViewBuilderTests.m */; }; DDB15FD019D5B8BF00173158 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDB15FCF19D5B8BF00173158 /* Images.xcassets */; }; DDB15FD419D5B8DB00173158 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FD319D5B8DB00173158 /* main.m */; }; DDB15FD719D5B96500173158 /* SCLAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = DDB15FD619D5B96500173158 /* SCLAlertView.m */; }; @@ -88,7 +92,12 @@ DDB15F9D19D5B7C600173158 /* SCLAlertView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SCLAlertView.app; sourceTree = BUILT_PRODUCTS_DIR; }; DDB15FB619D5B7C600173158 /* SCLAlertViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SCLAlertViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DDB15FBB19D5B7C600173158 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - DDB15FBC19D5B7C600173158 /* SCLAlertViewTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewTests.m; sourceTree = ""; }; + DDAA00062F00000100A11E57 /* SCLAlertViewTestHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCLAlertViewTestHelpers.h; sourceTree = ""; }; + DDAA00072F00000100A11E57 /* SCLAlertViewTestHelpers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewTestHelpers.m; sourceTree = ""; }; + DDAA00082F00000100A11E57 /* SCLAlertViewButtonTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewButtonTests.m; sourceTree = ""; }; + DDAA00092F00000100A11E57 /* SCLAlertViewComponentTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewComponentTests.m; sourceTree = ""; }; + DDAA000A2F00000100A11E57 /* SCLAlertViewPresentationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewPresentationTests.m; sourceTree = ""; }; + DDAA000B2F00000100A11E57 /* SCLAlertViewBuilderTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SCLAlertViewBuilderTests.m; sourceTree = ""; }; DDB15FCF19D5B8BF00173158 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = SCLAlertViewExample/Images.xcassets; sourceTree = SOURCE_ROOT; }; DDB15FD319D5B8DB00173158 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = SCLAlertViewExample/main.m; sourceTree = SOURCE_ROOT; }; DDB15FD619D5B96500173158 /* SCLAlertView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCLAlertView.m; sourceTree = ""; }; @@ -236,7 +245,12 @@ DDB15FB919D5B7C600173158 /* SCLAlertViewTests */ = { isa = PBXGroup; children = ( - DDB15FBC19D5B7C600173158 /* SCLAlertViewTests.m */, + DDAA00062F00000100A11E57 /* SCLAlertViewTestHelpers.h */, + DDAA00072F00000100A11E57 /* SCLAlertViewTestHelpers.m */, + DDAA00082F00000100A11E57 /* SCLAlertViewButtonTests.m */, + DDAA00092F00000100A11E57 /* SCLAlertViewComponentTests.m */, + DDAA000A2F00000100A11E57 /* SCLAlertViewPresentationTests.m */, + DDAA000B2F00000100A11E57 /* SCLAlertViewBuilderTests.m */, DDB15FBA19D5B7C600173158 /* Supporting Files */, ); path = SCLAlertViewTests; @@ -461,7 +475,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DDB15FBD19D5B7C600173158 /* SCLAlertViewTests.m in Sources */, + DDAA00012F00000100A11E57 /* SCLAlertViewTestHelpers.m in Sources */, + DDAA00022F00000100A11E57 /* SCLAlertViewButtonTests.m in Sources */, + DDAA00032F00000100A11E57 /* SCLAlertViewComponentTests.m in Sources */, + DDAA00042F00000100A11E57 /* SCLAlertViewPresentationTests.m in Sources */, + DDAA00052F00000100A11E57 /* SCLAlertViewBuilderTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme b/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme index 5e094fc..a33ed47 100644 --- a/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme +++ b/SCLAlertView.xcodeproj/xcshareddata/xcschemes/SCLAlertView.xcscheme @@ -26,7 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> diff --git a/SCLAlertViewTests/SCLAlertViewBuilderTests.m b/SCLAlertViewTests/SCLAlertViewBuilderTests.m new file mode 100644 index 0000000..0516ac5 --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewBuilderTests.m @@ -0,0 +1,86 @@ +// +// SCLAlertViewBuilderTests.m +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewTestHelpers.h" + +@interface SCLAlertViewBuilderTests : SCLAlertViewTestCase +@end + +@implementation SCLAlertViewBuilderTests + +- (void)testBuilderAppliesPropertiesAndAddsContent +{ + SCLAlertViewBuilder *builder = [[SCLAlertViewBuilder alloc] init]; + builder.cornerRadius(9.0f) + .tintTopCircle(NO) + .statusBarHidden(YES) + .statusBarStyle(UIStatusBarStyleLightContent) + .addTextField(@"Name", @"Diogo") + .addSwitchViewWithLabelTitle(@"Enabled") + .addButtonWithActionBlock(@"OK", ^{ + }); + + XCTAssertEqualWithAccuracy(builder.alertView.cornerRadius, 9.0f, 0.001f); + XCTAssertFalse(builder.alertView.tintTopCircle); + XCTAssertTrue(builder.alertView.statusBarHidden); + XCTAssertEqual(builder.alertView.statusBarStyle, UIStatusBarStyleLightContent); + XCTAssertEqual([self buttonsInView:builder.alertView.view].count, 1U); +} + +- (void)testButtonBuilderCreatesButtonAndExposesIt +{ + SCLAlertViewBuilder *alertBuilder = [[SCLAlertViewBuilder alloc] init]; + SCLALertViewButtonBuilder *buttonBuilder = [[SCLALertViewButtonBuilder alloc] init]; + __block NSUInteger actionCount = 0; + + buttonBuilder.title(@"Save").actionBlock(^{ + actionCount += 1; + }); + alertBuilder.addButtonWithBuilder(buttonBuilder); + + XCTAssertNotNil(buttonBuilder.button); + [buttonBuilder.button sendActionsForControlEvents:UIControlEventTouchUpInside]; + XCTAssertEqual(actionCount, 1U); +} + +- (void)testTextFieldBuilderCreatesTextFieldAndExposesIt +{ + SCLAlertViewBuilder *alertBuilder = [[SCLAlertViewBuilder alloc] init]; + SCLALertViewTextFieldBuilder *textFieldBuilder = [[SCLALertViewTextFieldBuilder alloc] init]; + + textFieldBuilder.title(@"Email"); + alertBuilder.addTextFieldWithBuilder(textFieldBuilder); + + XCTAssertNotNil(textFieldBuilder.textField); + XCTAssertEqualObjects(textFieldBuilder.textField.placeholder, @"Email"); +} + +- (void)testShowBuilderStoresParametersAndCanShowAlert +{ + SCLAlertViewShowBuilder *showBuilder = [[SCLAlertViewShowBuilder alloc] init]; + UIViewController *viewController = [self presentingViewController]; + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + showBuilder.viewController(viewController) + .title(@"Hello") + .subTitle(@"World") + .style(SCLAlertViewStyleSuccess) + .closeButtonTitle(@"OK") + .duration(0.0); + [showBuilder showAlertView:alertView]; + + XCTAssertEqual(showBuilder.parameterViewController, viewController); + XCTAssertEqualObjects(showBuilder.parameterTitle, @"Hello"); + XCTAssertEqualObjects(alertView.labelTitle.text, @"Hello"); + XCTAssertEqualObjects(alertView.viewText.text, @"World"); + XCTAssertTrue([alertView isVisible]); + + [alertView hideView]; +} + +@end diff --git a/SCLAlertViewTests/SCLAlertViewButtonTests.m b/SCLAlertViewTests/SCLAlertViewButtonTests.m new file mode 100644 index 0000000..a5b5eb0 --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewButtonTests.m @@ -0,0 +1,117 @@ +// +// SCLAlertViewButtonTests.m +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewTestHelpers.h" + +@interface SCLAlertViewButtonTests : SCLAlertViewTestCase +@end + +@implementation SCLAlertViewButtonTests + +- (void)testButtonActionBlockRunsWhenTapped +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + __block NSUInteger actionCount = 0; + SCLButton *button = [alertView addButton:@"Run" actionBlock:^{ + actionCount += 1; + }]; + + [button sendActionsForControlEvents:UIControlEventTouchUpInside]; + + XCTAssertEqual(actionCount, 1U); +} + +- (void)testValidationBlockCanPreventAction +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + __block NSUInteger validationCount = 0; + __block NSUInteger actionCount = 0; + SCLButton *button = [alertView addButton:@"Save" validationBlock:^BOOL{ + validationCount += 1; + return NO; + } actionBlock:^{ + actionCount += 1; + }]; + + [button sendActionsForControlEvents:UIControlEventTouchUpInside]; + + XCTAssertEqual(validationCount, 1U); + XCTAssertEqual(actionCount, 0U); +} + +- (void)testValidationBlockAllowsAction +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + __block NSUInteger actionCount = 0; + SCLButton *button = [alertView addButton:@"Save" validationBlock:^BOOL{ + return YES; + } actionBlock:^{ + actionCount += 1; + }]; + + [button sendActionsForControlEvents:UIControlEventTouchUpInside]; + + XCTAssertEqual(actionCount, 1U); +} + +- (void)testSelectorButtonSendsActionToTarget +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + SCLAlertViewTestTarget *target = [[SCLAlertViewTestTarget alloc] init]; + SCLButton *button = [alertView addButton:@"Target" target:target selector:@selector(performAction)]; + + [button sendActionsForControlEvents:UIControlEventTouchUpInside]; + + XCTAssertEqual(target.actionCount, 1U); +} + +- (void)testButtonParseConfigAppliesSupportedKeys +{ + SCLButton *button = [[SCLButton alloc] initWithWindowWidth:240.0f]; + UIFont *font = [UIFont systemFontOfSize:19.0f weight:UIFontWeightBold]; + + [button parseConfig:@{ + @"backgroundColor": UIColor.blueColor, + @"textColor": UIColor.whiteColor, + @"cornerRadius": @7.0f, + @"borderWidth": @2.0f, + @"borderColor": UIColor.greenColor, + @"font": font + }]; + + XCTAssertEqualObjects(button.defaultBackgroundColor, UIColor.blueColor); + XCTAssertEqualObjects([button titleColorForState:UIControlStateNormal], UIColor.whiteColor); + XCTAssertEqualWithAccuracy(button.layer.cornerRadius, 7.0f, 0.001f); + XCTAssertEqualWithAccuracy(button.layer.borderWidth, 2.0f, 0.001f); + XCTAssertEqual(button.layer.borderColor, UIColor.greenColor.CGColor); + XCTAssertEqualObjects(button.titleLabel.font, font); +} + +- (void)testButtonHighlightUsesDarkerDefaultBackgroundColor +{ + SCLButton *button = [[SCLButton alloc] initWithWindowWidth:240.0f]; + button.defaultBackgroundColor = [UIColor colorWithRed:0.5f green:0.5f blue:0.5f alpha:1.0f]; + + button.highlighted = YES; + UIColor *highlightedColor = button.backgroundColor; + button.highlighted = NO; + + XCTAssertNotEqualObjects(highlightedColor, button.defaultBackgroundColor); + XCTAssertEqualObjects(button.backgroundColor, button.defaultBackgroundColor); +} + +- (void)testButtonWidthAdjustmentHandlesZeroButtons +{ + SCLButton *button = [[SCLButton alloc] initWithWindowWidth:240.0f]; + + XCTAssertNoThrow([button adjustWidthWithWindowWidth:240.0f numberOfButtons:0]); + XCTAssertEqualWithAccuracy(button.frame.size.width, 216.0f, 0.001f); + XCTAssertEqualWithAccuracy(button.frame.size.height, 35.0f, 0.001f); +} + +@end diff --git a/SCLAlertViewTests/SCLAlertViewComponentTests.m b/SCLAlertViewTests/SCLAlertViewComponentTests.m new file mode 100644 index 0000000..89cf16d --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewComponentTests.m @@ -0,0 +1,118 @@ +// +// SCLAlertViewComponentTests.m +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewTestHelpers.h" +#import "SCLTextView.h" +#import "SCLSwitchView.h" + +@interface SCLAlertViewComponentTests : SCLAlertViewTestCase +@end + +@implementation SCLAlertViewComponentTests + +- (void)testAddTextFieldConfiguresTextAndReturnKeys +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + SCLTextView *first = [alertView addTextField:@"Email" setDefaultText:@"a@example.com"]; + SCLTextView *second = [alertView addTextField:@"Password" setDefaultText:nil]; + + XCTAssertEqualObjects(first.placeholder, @"Email"); + XCTAssertEqualObjects(first.text, @"a@example.com"); + XCTAssertEqual((id)first.delegate, alertView); + XCTAssertEqual(first.returnKeyType, UIReturnKeyNext); + XCTAssertEqualObjects(second.placeholder, @"Password"); + XCTAssertEqual(second.returnKeyType, UIReturnKeyDone); +} + +- (void)testAddCustomTextFieldUpdatesPreviousReturnKey +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + UITextField *first = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 35.0f)]; + UITextField *second = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 35.0f)]; + + [alertView addCustomTextField:first]; + [alertView addCustomTextField:second]; + + XCTAssertEqual(first.returnKeyType, UIReturnKeyNext); + XCTAssertNotNil(first.superview); + XCTAssertNotNil(second.superview); +} + +- (void)testTextFieldReturnMovesFocusAndResignsLastField +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + SCLAlertViewTrackingTextField *first = [[SCLAlertViewTrackingTextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 35.0f)]; + SCLAlertViewTrackingTextField *second = [[SCLAlertViewTrackingTextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 35.0f)]; + [alertView addCustomTextField:first]; + [alertView addCustomTextField:second]; + + XCTAssertFalse([alertView textFieldShouldReturn:first]); + XCTAssertEqual(second.becomeFirstResponderCount, 1U); + + XCTAssertFalse([alertView textFieldShouldReturn:second]); + XCTAssertEqual(second.resignFirstResponderCount, 1U); +} + +- (void)testAddSwitchViewReturnsConfiguredSwitch +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + SCLSwitchView *switchView = [alertView addSwitchViewWithLabel:@"Remember me"]; + switchView.selected = YES; + switchView.tintColor = UIColor.redColor; + + XCTAssertEqualObjects(switchView.labelText, @"Remember me"); + XCTAssertTrue(switchView.isSelected); + XCTAssertEqualObjects(switchView.tintColor, UIColor.redColor); + XCTAssertNotNil(switchView.superview); +} + +- (void)testAddCustomViewReturnsSameAttachedView +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 80.0f, 25.0f)]; + + UIView *returnedView = [alertView addCustomView:customView]; + + XCTAssertEqual(returnedView, customView); + XCTAssertNotNil(customView.superview); +} + +- (void)testTextViewDefaultsAndSizing +{ + SCLTextView *textView = [[SCLTextView alloc] init]; + + XCTAssertEqual(textView.borderStyle, UITextBorderStyleRoundedRect); + XCTAssertEqual(textView.clearButtonMode, UITextFieldViewModeWhileEditing); + XCTAssertEqual(textView.returnKeyType, UIReturnKeyDone); + XCTAssertGreaterThanOrEqual(textView.frame.size.height, 35.0f); + XCTAssertGreaterThanOrEqual([textView intrinsicContentSize].height, 35.0f); + XCTAssertGreaterThanOrEqual([textView sizeThatFits:CGSizeMake(120.0f, 1.0f)].height, 35.0f); +} + +- (void)testSwitchViewPropertiesRoundTrip +{ + SCLSwitchView *switchView = [[SCLSwitchView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 40.0f)]; + UIFont *font = [UIFont systemFontOfSize:13.0f]; + + switchView.labelText = @"Enabled"; + switchView.labelColor = UIColor.purpleColor; + switchView.labelFont = font; + switchView.tintColor = UIColor.orangeColor; + switchView.selected = YES; + + XCTAssertEqualObjects(switchView.labelText, @"Enabled"); + XCTAssertEqualObjects(switchView.labelColor, UIColor.purpleColor); + XCTAssertEqualObjects(switchView.labelFont, font); + XCTAssertEqualObjects(switchView.tintColor, UIColor.orangeColor); + XCTAssertTrue(switchView.isSelected); + XCTAssertGreaterThan([switchView sizeThatFits:CGSizeMake(200.0f, 0.0f)].height, 0.0f); +} + +@end diff --git a/SCLAlertViewTests/SCLAlertViewPresentationTests.m b/SCLAlertViewTests/SCLAlertViewPresentationTests.m new file mode 100644 index 0000000..3b4f08b --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewPresentationTests.m @@ -0,0 +1,208 @@ +// +// SCLAlertViewPresentationTests.m +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewTestHelpers.h" +#import "SCLAlertViewResponder.h" + +@interface SCLAlertViewPresentationTests : SCLAlertViewTestCase +@end + +@implementation SCLAlertViewPresentationTests + +- (void)testDefaultInitializerConfiguresVisibleDefaults +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + XCTAssertNotNil(alertView.labelTitle); + XCTAssertNotNil(alertView.viewText); + XCTAssertEqual(alertView.showAnimationType, SCLAlertViewShowAnimationSlideInFromTop); + XCTAssertEqual(alertView.hideAnimationType, SCLAlertViewHideAnimationFadeOut); + XCTAssertEqual(alertView.backgroundType, SCLAlertViewBackgroundShadow); + XCTAssertTrue(alertView.tintTopCircle); + XCTAssertFalse(alertView.shouldDismissOnTapOutside); + XCTAssertNil(alertView.view.superview); +} + +- (void)testCustomWidthControlsInitialButtonWidth +{ + SCLAlertView *alertView = [[SCLAlertView alloc] initWithWidth:300.0f]; + + SCLButton *button = [alertView addButton:@"Continue" actionBlock:^{ + }]; + + XCTAssertEqualWithAccuracy(button.frame.size.width, 276.0f, 0.001f); +} + +- (void)testFontSettersApplyToExistingLabelsAndFutureButtons +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + [alertView setTitleFontFamily:@"HelveticaNeue-Bold" withSize:24.0f]; + [alertView setBodyTextFontFamily:@"HelveticaNeue-Italic" withSize:16.0f]; + [alertView setButtonsTextFontFamily:@"HelveticaNeue-Light" withSize:18.0f]; + SCLButton *button = [alertView addButton:@"OK" actionBlock:^{ + }]; + + XCTAssertEqualWithAccuracy(alertView.labelTitle.font.pointSize, 24.0f, 0.001f); + XCTAssertEqualObjects(alertView.labelTitle.font.fontName, @"HelveticaNeue-Bold"); + XCTAssertEqualWithAccuracy(alertView.viewText.font.pointSize, 16.0f, 0.001f); + XCTAssertEqualObjects(alertView.viewText.font.fontName, @"HelveticaNeue-Italic"); + XCTAssertEqualWithAccuracy(button.titleLabel.font.pointSize, 18.0f, 0.001f); +} + +- (void)testShowSuccessConfiguresTitleSubtitleVisibilityAndDismissCallback +{ + UIViewController *viewController = [self presentingViewController]; + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + __block NSUInteger dismissCount = 0; + [alertView alertIsDismissed:^{ + dismissCount += 1; + }]; + + [alertView showSuccess:viewController title:@"Saved" subTitle:@"Done" closeButtonTitle:@"OK" duration:0.0]; + + XCTAssertTrue([alertView isVisible]); + XCTAssertEqualObjects(alertView.labelTitle.text, @"Saved"); + XCTAssertEqualObjects(alertView.viewText.text, @"Done"); + XCTAssertEqual(alertView.parentViewController, viewController); + XCTAssertEqual([self buttonsInView:alertView.view].count, 1U); + + [alertView hideView]; + + XCTAssertEqual(dismissCount, 1U); +} + +- (void)testShowWithoutTitleRemovesTitleLabel +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + [alertView showInfo:[self presentingViewController] title:@" " subTitle:@"Body" closeButtonTitle:nil duration:0.0]; + + XCTAssertNil(alertView.labelTitle); + XCTAssertEqualObjects(alertView.viewText.text, @"Body"); + + [alertView hideView]; +} + +- (void)testShowWithoutSubtitleRemovesBodyText +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + [alertView showWarning:[self presentingViewController] title:@"Warning" subTitle:@"\n" closeButtonTitle:nil duration:0.0]; + + XCTAssertEqualObjects(alertView.labelTitle.text, @"Warning"); + XCTAssertNil(alertView.viewText); + + [alertView hideView]; +} + +- (void)testAttributedFormatBlockIsAppliedWhenShowingSubtitle +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + alertView.attributedFormatBlock = ^NSAttributedString *(NSString *value) { + return [[NSAttributedString alloc] initWithString:value attributes:@{ + NSForegroundColorAttributeName: UIColor.redColor + }]; + }; + + [alertView showNotice:[self presentingViewController] title:@"Notice" subTitle:@"Body" closeButtonTitle:nil duration:0.0]; + + UIColor *color = [alertView.viewText.attributedText attribute:NSForegroundColorAttributeName atIndex:0 effectiveRange:nil]; + XCTAssertEqualObjects(color, UIColor.redColor); + + [alertView hideView]; +} + +- (void)testButtonFormatBlockIsAppliedDuringShow +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + alertView.buttonFormatBlock = ^NSDictionary *{ + return @{ + @"backgroundColor": UIColor.blackColor, + @"textColor": UIColor.yellowColor, + @"borderWidth": @1.0f, + @"borderColor": UIColor.redColor + }; + }; + SCLButton *button = [alertView addButton:@"Custom" actionBlock:^{ + }]; + + [alertView showQuestion:[self presentingViewController] title:@"Question" subTitle:@"Body" closeButtonTitle:nil duration:0.0]; + + XCTAssertEqualObjects(button.defaultBackgroundColor, UIColor.blackColor); + XCTAssertEqualObjects([button titleColorForState:UIControlStateNormal], UIColor.yellowColor); + XCTAssertEqualWithAccuracy(button.layer.borderWidth, 1.0f, 0.001f); + XCTAssertEqual(button.layer.borderColor, UIColor.redColor.CGColor); + + [alertView hideView]; +} + +- (void)testCompleteButtonFormatBlockIsAppliedToCloseButton +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + alertView.completeButtonFormatBlock = ^NSDictionary *{ + return @{ + @"backgroundColor": UIColor.grayColor, + @"textColor": UIColor.whiteColor + }; + }; + + [alertView showError:[self presentingViewController] title:@"Error" subTitle:@"Body" closeButtonTitle:@"Close" duration:0.0]; + + SCLButton *button = [self buttonsInView:alertView.view].firstObject; + XCTAssertEqualObjects(button.defaultBackgroundColor, UIColor.grayColor); + XCTAssertEqualObjects([button titleColorForState:UIControlStateNormal], UIColor.whiteColor); + + [alertView hideView]; +} + +- (void)testButtonTimerClampsOutOfRangeIndex +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + [alertView addButton:@"OK" actionBlock:^{ + }]; + [alertView addTimerToButtonIndex:NSIntegerMax reverse:YES]; + + XCTAssertNoThrow([alertView showSuccess:[self presentingViewController] + title:@"Saved" + subTitle:@"Done" + closeButtonTitle:nil + duration:1.0]); + [alertView hideView]; +} + +- (void)testButtonTimerBeforeButtonsIsIgnored +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + + XCTAssertNoThrow([alertView addTimerToButtonIndex:0 reverse:NO]); + XCTAssertNoThrow([alertView showSuccess:[self presentingViewController] + title:@"Saved" + subTitle:@"Done" + closeButtonTitle:nil + duration:1.0]); + [alertView hideView]; +} + +- (void)testResponderUpdatesAlertAndClosesIt +{ + SCLAlertView *alertView = [[SCLAlertView alloc] init]; + [alertView showSuccess:[self presentingViewController] title:@"Old" subTitle:@"Old body" closeButtonTitle:nil duration:0.0]; + SCLAlertViewResponder *responder = [[SCLAlertViewResponder alloc] init:alertView]; + + [responder setTitle:@"New"]; + [responder setSubTitle:@"New body"]; + + XCTAssertEqualObjects(alertView.labelTitle.text, @"New"); + XCTAssertEqualObjects(alertView.viewText.text, @"New body"); + + [responder close]; + XCTAssertFalse([alertView isVisible]); +} + +@end diff --git a/SCLAlertViewTests/SCLAlertViewTestHelpers.h b/SCLAlertViewTests/SCLAlertViewTestHelpers.h new file mode 100644 index 0000000..1d20d0e --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewTestHelpers.h @@ -0,0 +1,30 @@ +// +// SCLAlertViewTestHelpers.h +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import +#import +#import "SCLAlertView.h" +#import "SCLButton.h" + +@interface SCLAlertView (Tests) +@end + +@interface SCLAlertViewTestCase : XCTestCase +- (UIViewController *)presentingViewController; +- (NSArray *)buttonsInView:(UIView *)view; +@end + +@interface SCLAlertViewTestTarget : NSObject +@property (nonatomic) NSUInteger actionCount; +- (void)performAction; +@end + +@interface SCLAlertViewTrackingTextField : UITextField +@property (nonatomic) NSUInteger becomeFirstResponderCount; +@property (nonatomic) NSUInteger resignFirstResponderCount; +@end diff --git a/SCLAlertViewTests/SCLAlertViewTestHelpers.m b/SCLAlertViewTests/SCLAlertViewTestHelpers.m new file mode 100644 index 0000000..32f1727 --- /dev/null +++ b/SCLAlertViewTests/SCLAlertViewTestHelpers.m @@ -0,0 +1,73 @@ +// +// SCLAlertViewTestHelpers.m +// SCLAlertViewTests +// +// Created by Diogo Autilio on 9/26/14. +// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. +// + +#import "SCLAlertViewTestHelpers.h" + +@implementation SCLAlertViewTestCase +{ + BOOL _animationsWereEnabled; +} + +- (void)setUp +{ + [super setUp]; + _animationsWereEnabled = UIView.areAnimationsEnabled; + [UIView setAnimationsEnabled:NO]; +} + +- (void)tearDown +{ + [UIView setAnimationsEnabled:_animationsWereEnabled]; + [super tearDown]; +} + +- (UIViewController *)presentingViewController +{ + UIViewController *viewController = [[UIViewController alloc] init]; + viewController.view.frame = CGRectMake(0.0f, 0.0f, 320.0f, 480.0f); + return viewController; +} + +- (NSArray *)buttonsInView:(UIView *)view +{ + NSMutableArray *buttons = [NSMutableArray array]; + if ([view isKindOfClass:SCLButton.class]) { + [buttons addObject:(SCLButton *)view]; + } + for (UIView *subview in view.subviews) { + [buttons addObjectsFromArray:[self buttonsInView:subview]]; + } + return buttons; +} + +@end + +@implementation SCLAlertViewTestTarget + +- (void)performAction +{ + self.actionCount += 1; +} + +@end + +@implementation SCLAlertViewTrackingTextField + +- (BOOL)becomeFirstResponder +{ + self.becomeFirstResponderCount += 1; + return YES; +} + +- (BOOL)resignFirstResponder +{ + self.resignFirstResponderCount += 1; + return YES; +} + +@end diff --git a/SCLAlertViewTests/SCLAlertViewTests.m b/SCLAlertViewTests/SCLAlertViewTests.m deleted file mode 100644 index 8b06453..0000000 --- a/SCLAlertViewTests/SCLAlertViewTests.m +++ /dev/null @@ -1,40 +0,0 @@ -// -// SCLAlertViewTests.m -// SCLAlertViewTests -// -// Created by Diogo Autilio on 9/26/14. -// Copyright (c) 2014-2016 AnyKey Entertainment. All rights reserved. -// - -#import -#import - -@interface SCLAlertViewTests : XCTestCase - -@end - -@implementation SCLAlertViewTests - -- (void)setUp { - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testExample { - // This is an example of a functional test case. - XCTAssert(YES, @"Pass"); -} - -- (void)testPerformanceExample { - // This is an example of a performance test case. - [self measureBlock:^{ - // Put the code you want to measure the time of here. - }]; -} - -@end