Compare commits
2 Commits
master
...
feature/ne
| Author | SHA1 | Date |
|---|---|---|
|
|
d24cecdec1 | |
|
|
d9518c8f51 |
|
|
@ -1,2 +0,0 @@
|
||||||
---
|
|
||||||
BUNDLE_PATH: ".gem"
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import sys, re, os
|
|
||||||
from subprocess import check_output
|
|
||||||
from sys import getdefaultencoding
|
|
||||||
|
|
||||||
getdefaultencoding() # utf-8
|
|
||||||
|
|
||||||
valid_commit_style = '^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style)(\(\S+\))?\!?: .+'
|
|
||||||
merge_commit_style = '^(m|M)erge .+'
|
|
||||||
|
|
||||||
success_title = 'SUCCESS'
|
|
||||||
success_color = '92m'
|
|
||||||
|
|
||||||
error_title = 'ERROR'
|
|
||||||
error_message = 'Incorrect commit message style!\nThe commit pattern:'
|
|
||||||
error_commit_pattern = ' type(scope): message | type: message \n'
|
|
||||||
error_color = '91m'
|
|
||||||
|
|
||||||
breaking_changes_message = 'If commit include Breaking changes use ! after type or scope:'
|
|
||||||
colored_breaking_changes_message = 'If commit include \033[91mBreaking changes\033[00m use \033[91m!\033[00m after type or scope:'
|
|
||||||
breaking_changes_commit_pattern = ' type(scope)!: message | type!: message \n'
|
|
||||||
|
|
||||||
available_types_message = 'Available commit types:'
|
|
||||||
available_commit_types = ['build: Changes that affect the build system or external dependencies',
|
|
||||||
'ci: Changes to our CI configuration files and scripts',
|
|
||||||
'docs: Documentation only changes',
|
|
||||||
'feat: A new feature. Correlates with MINOR in SemVer',
|
|
||||||
'fix: A bug fix. Correlates with PATCH in SemVer',
|
|
||||||
'perf: A code change that improves performance',
|
|
||||||
'refactor: A code change that neither fixes',
|
|
||||||
'revert: A revert to previous commit',
|
|
||||||
'style: Changes that do not affect the meaning of the code (white-space, formatting, etc)']
|
|
||||||
|
|
||||||
is_GUI_client = False
|
|
||||||
|
|
||||||
def print_result_header(result_title, color):
|
|
||||||
if not is_GUI_client:
|
|
||||||
print("[\033[96mcommit lint\033[00m] [\033[{}{}\033[00m]\n".format(color, result_title))
|
|
||||||
|
|
||||||
def print_pattern(pattern):
|
|
||||||
if is_GUI_client:
|
|
||||||
print(pattern)
|
|
||||||
else:
|
|
||||||
print("\033[96m{}\033[00m".format(pattern))
|
|
||||||
|
|
||||||
def print_error_message():
|
|
||||||
print_result_header(error_title, error_color)
|
|
||||||
|
|
||||||
print(error_message)
|
|
||||||
print_pattern(error_commit_pattern)
|
|
||||||
|
|
||||||
if is_GUI_client:
|
|
||||||
print(breaking_changes_message)
|
|
||||||
else:
|
|
||||||
print(colored_breaking_changes_message)
|
|
||||||
|
|
||||||
print_pattern(breaking_changes_commit_pattern)
|
|
||||||
print_available_commit_types()
|
|
||||||
|
|
||||||
def print_available_commit_types():
|
|
||||||
print(available_types_message)
|
|
||||||
|
|
||||||
for commit_type in available_commit_types:
|
|
||||||
print(" - %s" %commit_type)
|
|
||||||
|
|
||||||
def write_commit_message(fh, commit_msg):
|
|
||||||
fh.seek(0, 0)
|
|
||||||
fh.write(commit_msg)
|
|
||||||
|
|
||||||
def lint_commit_message(fh, commit_msg):
|
|
||||||
is_merge_commit = re.findall(merge_commit_style, commit_msg)
|
|
||||||
is_valid_commit = re.findall(valid_commit_style, commit_msg)
|
|
||||||
|
|
||||||
if is_valid_commit or is_merge_commit:
|
|
||||||
print_result_header(success_title, success_color)
|
|
||||||
write_commit_message(fh, commit_msg)
|
|
||||||
sys.exit(os.EX_OK)
|
|
||||||
else:
|
|
||||||
print_error_message()
|
|
||||||
sys.exit(os.EX_DATAERR)
|
|
||||||
|
|
||||||
def run_script():
|
|
||||||
commit_msg_filepath = sys.argv[1]
|
|
||||||
|
|
||||||
with open(commit_msg_filepath, 'r+') as fh:
|
|
||||||
commit_msg = fh.read()
|
|
||||||
lint_commit_message(fh, commit_msg)
|
|
||||||
|
|
||||||
try:
|
|
||||||
sys.stdin = open("/dev/tty", "r")
|
|
||||||
is_GUI_client = False
|
|
||||||
except:
|
|
||||||
is_GUI_client = True
|
|
||||||
|
|
||||||
run_script()
|
|
||||||
|
|
@ -1,18 +1,16 @@
|
||||||
|
# ================
|
||||||
|
# Swift.gitignore
|
||||||
|
# ================
|
||||||
|
|
||||||
# Xcode
|
# Xcode
|
||||||
#
|
#
|
||||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||||
|
|
||||||
## User settings
|
## Build generated
|
||||||
xcuserdata/
|
|
||||||
|
|
||||||
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
|
|
||||||
*.xcscmblueprint
|
|
||||||
*.xccheckout
|
|
||||||
|
|
||||||
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
|
|
||||||
build/
|
build/
|
||||||
DerivedData/
|
DerivedData
|
||||||
*.moved-aside
|
|
||||||
|
## Various settings
|
||||||
*.pbxuser
|
*.pbxuser
|
||||||
!default.pbxuser
|
!default.pbxuser
|
||||||
*.mode1v3
|
*.mode1v3
|
||||||
|
|
@ -21,14 +19,17 @@ DerivedData/
|
||||||
!default.mode2v3
|
!default.mode2v3
|
||||||
*.perspectivev3
|
*.perspectivev3
|
||||||
!default.perspectivev3
|
!default.perspectivev3
|
||||||
|
xcuserdata
|
||||||
|
|
||||||
|
## Other
|
||||||
|
*.xccheckout
|
||||||
|
*.moved-aside
|
||||||
|
*.xcuserstate
|
||||||
|
*.xcscmblueprint
|
||||||
|
|
||||||
## Obj-C/Swift specific
|
## Obj-C/Swift specific
|
||||||
*.hmap
|
*.hmap
|
||||||
|
|
||||||
## App packaging
|
|
||||||
*.ipa
|
*.ipa
|
||||||
*.dSYM.zip
|
|
||||||
*.dSYM
|
|
||||||
|
|
||||||
## Playgrounds
|
## Playgrounds
|
||||||
timeline.xctimeline
|
timeline.xctimeline
|
||||||
|
|
@ -38,14 +39,6 @@ playground.xcworkspace
|
||||||
#
|
#
|
||||||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
|
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
|
||||||
# Packages/
|
# Packages/
|
||||||
# Package.pins
|
|
||||||
# Package.resolved
|
|
||||||
# *.xcodeproj
|
|
||||||
#
|
|
||||||
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
|
|
||||||
# hence it is not needed unless you have added a package configuration file to your project
|
|
||||||
.swiftpm
|
|
||||||
|
|
||||||
.build/
|
.build/
|
||||||
|
|
||||||
# CocoaPods
|
# CocoaPods
|
||||||
|
|
@ -55,56 +48,30 @@ playground.xcworkspace
|
||||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||||
#
|
#
|
||||||
Pods/
|
Pods/
|
||||||
#
|
|
||||||
# Add this line if you want to avoid checking in source code from the Xcode workspace
|
|
||||||
# *.xcworkspace
|
|
||||||
|
|
||||||
# Carthage
|
# Carthage
|
||||||
#
|
#
|
||||||
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
||||||
Carthage/Checkouts
|
Carthage/Checkouts
|
||||||
|
|
||||||
Carthage/Build/
|
Carthage/Build
|
||||||
|
|
||||||
# Accio dependency management
|
|
||||||
Dependencies/
|
|
||||||
.accio/
|
|
||||||
|
|
||||||
# fastlane
|
# fastlane
|
||||||
#
|
#
|
||||||
# It is recommended to not store the screenshots in the git repo.
|
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||||
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
|
# screenshots whenever they are needed.
|
||||||
# For more information about the recommended setup visit:
|
# For more information about the recommended setup visit:
|
||||||
# https://docs.fastlane.tools/best-practices/source-control/#source-control
|
# https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md
|
||||||
|
|
||||||
fastlane/report.xml
|
fastlane/report.xml
|
||||||
fastlane/Preview.html
|
fastlane/screenshots
|
||||||
fastlane/screenshots/**/*.png
|
|
||||||
fastlane/test_output
|
|
||||||
|
|
||||||
# Code Injection
|
|
||||||
#
|
|
||||||
# After new code Injection tools there's a generated folder /iOSInjectionProject
|
|
||||||
# https://github.com/johnno1962/injectionforxcode
|
|
||||||
|
|
||||||
iOSInjectionProject/
|
# AppCode
|
||||||
|
# https://intellij-support.jetbrains.com/hc/en-us/articles/206544839-How-to-manage-projects-under-Version-Control-Systems
|
||||||
|
|
||||||
# homebrew-bundle
|
.idea/workspace.xml
|
||||||
Brewfile.lock.json
|
.idea/tasks.xml
|
||||||
|
|
||||||
# Node.js
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Touch Instinct custom
|
|
||||||
Downloads/
|
|
||||||
fastlane/README.md
|
|
||||||
Templates/
|
|
||||||
cpd-output.xml
|
cpd-output.xml
|
||||||
*.swp
|
|
||||||
*IDEWorkspaceChecks.plist
|
|
||||||
|
|
||||||
# Gem
|
|
||||||
.gem/
|
|
||||||
|
|
||||||
.DS_Store
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
[submodule "build-scripts"]
|
[submodule "build-scripts"]
|
||||||
path = build-scripts
|
path = build-scripts
|
||||||
url = https://git.svc.touchin.ru/TouchInstinct/BuildScripts.git
|
url = https://github.com/TouchInstinct/BuildScripts.git
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
5.0
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
|
||||||
|
language: swift
|
||||||
|
osx_image: xcode10
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- LC_CTYPE=en_US.UTF-8
|
||||||
|
- LANG=en_US.UTF-8
|
||||||
|
|
||||||
|
jdk:
|
||||||
|
- oraclejdk9
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- env
|
||||||
|
- locale
|
||||||
|
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
|
||||||
|
- xcpretty --version
|
||||||
|
- xcodebuild -version
|
||||||
|
- xcodebuild -showsdks
|
||||||
|
- pod install --repo-update
|
||||||
|
- brew install pmd
|
||||||
|
|
||||||
|
script:
|
||||||
|
- set -o pipefail
|
||||||
|
- xcodebuild -enableCodeCoverage YES CODE_SIGNING_ALLOWED=YES -workspace LeadKit.xcworkspace -scheme 'LeadKit iOS' -destination 'platform=iOS Simulator,OS=12.0,name=iPhone 7' build test | xcpretty -c
|
||||||
|
- xcodebuild -enableCodeCoverage YES CODE_SIGNING_ALLOWED=YES -workspace LeadKit.xcworkspace -scheme 'LeadKit iOS Extensions' -destination 'platform=iOS Simulator,OS=12.0,name=iPhone 7' build test | xcpretty -c
|
||||||
|
- xcodebuild -enableCodeCoverage YES CODE_SIGNING_ALLOWED=YES -workspace LeadKit.xcworkspace -scheme 'LeadKit tvOS' -destination 'platform=tvOS Simulator,name=Apple TV 4K' -sdk appletvsimulator build test | xcpretty -c
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- sleep 5
|
||||||
|
- bash < (curl -s https://codecov.io/bash)
|
||||||
565
CHANGELOG.md
565
CHANGELOG.md
|
|
@ -1,567 +1,10 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
### 1.56.0
|
|
||||||
- **Update**: `ViewSkeletonsConfiguration`. It's possible to enable or disable animation for specific skeletons now.
|
|
||||||
- **Added**: `HolderViewSkeletonsConfiguration` for skeleton root view configuration
|
|
||||||
- **Added**: `DashedBoundsLayer` can now be applied to `CALayer`
|
|
||||||
|
|
||||||
### 1.55.1
|
|
||||||
- **Update**: revert `TextSkeletonsConfiguration` line height calculation
|
|
||||||
|
|
||||||
### 1.55.0
|
|
||||||
|
|
||||||
- **Update**: use TouchInstinct `TableKit` fork instead of original one
|
|
||||||
- **Update**: remove default value from `BoolValueDefaultsStorage`
|
|
||||||
|
|
||||||
### 1.54.6
|
|
||||||
|
|
||||||
- **Added**: `xcprivacy` files
|
|
||||||
- **Update**: Correctly detect app reinstall in `AppInstallLifetimeSingleValueStorage`
|
|
||||||
- **Update**: use `xHeight` instead of `pointSize` for default skeleton line height calculation
|
|
||||||
- **Update**: update `linkTextAttributes` in `UITextView` when setting interactive url parts
|
|
||||||
|
|
||||||
|
|
||||||
### 1.54.5
|
|
||||||
|
|
||||||
- **Update**: Сhange `StatefulButton` event propogation avoidance method.
|
|
||||||
|
|
||||||
### 1.54.4
|
|
||||||
|
|
||||||
- **Update**: Fix `StatefulButton` state configuration for iOS 15+.
|
|
||||||
|
|
||||||
### 1.54.3
|
|
||||||
|
|
||||||
- **Update**: Set reasonable defaults for `SkeletonConfiguration`.
|
|
||||||
|
|
||||||
### 1.54.2
|
|
||||||
|
|
||||||
- **Update**: Changed access level from internal to public of title and subtitle view in `BaseTitleSubtitleView`.
|
|
||||||
|
|
||||||
### 1.54.1
|
|
||||||
|
|
||||||
- **Added**: `BaseTitleSubtitleView` which can be inherited for fine-tuning skeletons and other behavior.
|
|
||||||
- **Update**: Changed lines number calculation method in `TextSkeletonsConfiguration`.
|
|
||||||
|
|
||||||
|
|
||||||
### 1.54.0
|
|
||||||
|
|
||||||
- **Added**: `maxWidth` parameter to `BaseViewSkeletonsConfiguration`.
|
|
||||||
- **Added**: custom `SkeletonConfigurations` for nested `SkeletonPresenters`.
|
|
||||||
- **Update**: Many fixes and improvenments to `TextSkeletonsConfiguration`.
|
|
||||||
|
|
||||||
### 1.53.3
|
|
||||||
|
|
||||||
- **Update**: `Skeletonable` can now control custom geometry change notification.
|
|
||||||
- **Update**: Filter hidden views from skeletonable views by default.
|
|
||||||
|
|
||||||
### 1.53.2
|
|
||||||
|
|
||||||
- **Update**: `DefaultTitleSubtitleView` support for separated configuration of title and subtitle labels layout.
|
|
||||||
- **Update**: `BaseListItemView` fixed trailing insets when trailing view is hidden.
|
|
||||||
|
|
||||||
### 1.53.1
|
|
||||||
|
|
||||||
- **Update**: Insets layout heuristics for `WrappedViewHodler` implementations
|
|
||||||
|
|
||||||
### 1.53.0
|
|
||||||
|
|
||||||
- **Added**: Custom string attributes to `BaseTextAttributes`
|
|
||||||
- **Added**: Customizeable `UIViewBackground` and `UIViewBorder` for `UIView.Appearance`
|
|
||||||
- **Added**: Keychain single value storage for codable models -`CodableSingleValueKeychainStorage`
|
|
||||||
- **Update**: Renamed methods `startAnimation` and `stopAnimation` of `SkeletonPresenter`, so it won't conflict with `Animatable` protocol anymore
|
|
||||||
|
|
||||||
### 1.52.0
|
|
||||||
|
|
||||||
- **Added**: `TIApplication` module with core dependencies of main application and its extension targets
|
|
||||||
- **Added**: `DefaultHomogeneousItemsCollectionView` default collection view implementation with configurable identical-type cells
|
|
||||||
- **Update**: Changed implementation of `AppInstallLifetimeSingleValueStorage`. Now it uses `SingleValueStorage<Bool>` to be able to migrate stored UserDefaults values
|
|
||||||
- **Added**: `UserLocationFetcher.OnLocationFetchFailureCallback` and `ItemDistanceTo` in `TIMapUtils`
|
|
||||||
- **Added**: Tap handler closure to `DefaultConfigurableStatefulButton.ViewModel`
|
|
||||||
- **Added**: Universal DSL
|
|
||||||
|
|
||||||
|
|
||||||
### 1.51.0
|
|
||||||
|
|
||||||
- **Added**: `BaseModalViewController` implementing `PanModalPresentable` with additional functionality
|
|
||||||
- **Added**: `BaseModalWrapperViewController` for wrapping `UIViewController`s with `BaseModalViewController` functionality
|
|
||||||
|
|
||||||
### 1.50.0
|
|
||||||
|
|
||||||
- **Updated**: Fix activity indicator positioning for `StatefulButton` on iOS 15+ and disabled state touch handling
|
|
||||||
- **Added**: iOS 15+ activity indicator placement support in `StatefulButton`
|
|
||||||
- **Added**: `TICoreGraphicsUtils` module for drawing operations and other CoreGraphics related functionality
|
|
||||||
- **Update**: `MarkerIconFactory` can now return optional `UIImage`. In this case MapManagers will show the default marker icon.
|
|
||||||
|
|
||||||
### 1.49.0
|
|
||||||
|
|
||||||
- **Added**: `BaseMigratingSingleValueKeychainStorage` and `BaseMigratingSingleValueDefaultsStorage` implementations for migrating keys from one storage to another.
|
|
||||||
|
|
||||||
### 1.48.0
|
|
||||||
|
|
||||||
- **Added**: `BaseStackView` with configurable items appearance
|
|
||||||
- **Fixed**: `CollectionTableViewCell` self-sizing
|
|
||||||
- **Added**: `ViewAppearance.WrappedViewLayout` support for all `WrappedViewHolders`
|
|
||||||
- **Added**: `ViewCallbacks` support for all `BaseInitializeableViews`
|
|
||||||
|
|
||||||
### 1.47.0
|
|
||||||
|
|
||||||
- **Added**: `flatMap` operator for `AsyncOperation`
|
|
||||||
- **Update**: `CodableKeyValueStorage` now returns `Swift.Result` with typed errors.
|
|
||||||
- **Added**: `SingleValueExpirationStorage` for time aware entries (expirable api tokens, etc.)
|
|
||||||
- **Added**: `AsyncOperation` variants of process methods in NetworkServices.
|
|
||||||
|
|
||||||
### 1.46.0
|
|
||||||
|
|
||||||
- **Added**: `AsyncSingleValueStorage` and `SingleValueStorageAsyncWrapper<SingleValueStorage>` for async access to SingleValue storages wtih swift concurrency support
|
|
||||||
- **Added**: `BaseMapUISettings` used to configure map view of different providers + user location icon rendering for yandex maps
|
|
||||||
- **Added**: `UserLocationFetcher` helper that requests authorization and subscribes to user location updates
|
|
||||||
- **Update**: add `DEVELOPMENT_INSTALL` support for all podspecs and fix playground compilation issues
|
|
||||||
|
|
||||||
### 1.45.0
|
|
||||||
|
|
||||||
- **Added**: `SingleValueStorage` implementations + `AppInstallLifetimeSingleValueStorage` for automatically removing keychain items on app reinstall.
|
|
||||||
- **Added**: `TILogging` with error logging types
|
|
||||||
- **Update**: `DefaultRecoverableJsonNetworkService` supports iOS 12.
|
|
||||||
- **Update**: `DefaultFingerprintsProvider` now uses `SingleValueStorage`
|
|
||||||
|
|
||||||
### 1.44.0
|
|
||||||
|
|
||||||
- **Added**: HTTP status codes to `EndpointErrorResult.apiError` responses
|
|
||||||
- **Added**: SwiftLint pre-build SPM step to TINetworking module
|
|
||||||
|
|
||||||
### 1.43.1
|
|
||||||
|
|
||||||
- **Fixed**: build scripts submodule url
|
|
||||||
|
|
||||||
### 1.43.0
|
|
||||||
|
|
||||||
- **Added**: `TITextProcessing` for regex and text formatting added
|
|
||||||
|
|
||||||
### 1.42.1
|
|
||||||
|
|
||||||
- **Fixed**: Podspecs source and homepage urls
|
|
||||||
|
|
||||||
### 1.42.0
|
|
||||||
|
|
||||||
- **Added**: TIDeeplink to support deeplink API
|
|
||||||
|
|
||||||
### 1.41.0
|
|
||||||
|
|
||||||
- **Update**: added callbacks for views while skeletons change status to presented or hidden
|
|
||||||
|
|
||||||
### 1.40.0
|
|
||||||
|
|
||||||
- **Added**: `PlaceholderFactory` for creating `DefaultPlaceholderView` views
|
|
||||||
- **Added**: `DefaultPlaceholderImageView`
|
|
||||||
|
|
||||||
### 1.39.0
|
|
||||||
|
|
||||||
- **Added**: UIButton Appearance model
|
|
||||||
- **Added**: `SpacedWrappedViewLayout` for spacing configurations
|
|
||||||
- **Update**: UIView appearance model with border configurations
|
|
||||||
|
|
||||||
### 1.38.0
|
|
||||||
|
|
||||||
- **Added**: Placemarks states for icon updating
|
|
||||||
- **Added**: Selecting / deselecting markers through cluster manager
|
|
||||||
|
|
||||||
### 1.37.0
|
|
||||||
|
|
||||||
- **Added**: API for converting view hierarchy to skeletons
|
|
||||||
|
|
||||||
### 1.36.1
|
|
||||||
|
|
||||||
- **Update**: `YandexMapsMobile` version updated
|
|
||||||
- **Fix**: Map manager memory leak removed
|
|
||||||
|
|
||||||
### 1.36.0
|
|
||||||
|
|
||||||
- **Removed**: `TILogger`module
|
|
||||||
- **Updated**: moved `LoggingPresenter` to `TIDeveloperUtils` module.
|
|
||||||
|
|
||||||
### 1.35.1
|
|
||||||
|
|
||||||
- **Added**: Auto documentation generation for `TIFoundationUtils` playground and compile checks for playground before release
|
|
||||||
- **Updated**: `AsyncOperation` fixed ordering of chain operations execution
|
|
||||||
|
|
||||||
### 1.35.0
|
|
||||||
|
|
||||||
- **Added**: `TIDeveloperUtils` framework, that contains different utils for development
|
|
||||||
- **Added**: `UIView` and `UIViewController` extensions for showing SwiftUI previews
|
|
||||||
- **Added**: `DashedBoundsLayer` for debugging views' frames visually
|
|
||||||
|
|
||||||
### 1.34.0
|
|
||||||
|
|
||||||
- **Added**: `BaseListItemView` for displaying three views horizontally
|
|
||||||
- **Added**: `DefaultTitleSubtitleView` for displaying one or two labels vertically
|
|
||||||
- **Update**: `StatefulButton` now can be configured with `ViewAppearance` model for each state
|
|
||||||
|
|
||||||
### 1.33.0
|
|
||||||
|
|
||||||
- **Added**: `ViewAppearance` and `ViewLayout` models for setting up Views' appearance and layout
|
|
||||||
- **Added**: `TableKit.Row` extension for configuration inner View's appearance and layout
|
|
||||||
- **Added**: `WrappableView` with typealiases for creating wrapped in the container views
|
|
||||||
- **Added**: `CollectionTableViewCell` and `ContainerView`
|
|
||||||
- **Update**: Separator appearance configureation for table views
|
|
||||||
|
|
||||||
### 1.32.0
|
|
||||||
|
|
||||||
- **Added**: `BaseInitializableWebView` with navigation and error handling api.
|
|
||||||
|
|
||||||
### 1.31.0
|
|
||||||
|
|
||||||
- **Added**: `URLInteractiveTextView` for terms and conditions hints in login flow
|
|
||||||
|
|
||||||
### 1.30.0
|
|
||||||
|
|
||||||
- **Added**: Base classes for encryption and decryption user token with pin code or biometry
|
|
||||||
- **Added**: Pin code validators
|
|
||||||
|
|
||||||
### 1.29.1
|
|
||||||
|
|
||||||
- **Updated**: `BaseTextAttributes` correct detection of the necessity of using attributed string
|
|
||||||
|
|
||||||
### 1.29.0
|
|
||||||
|
|
||||||
- **Added**: `BaseTextAttributes`can now measure text size and provides paragraph style configuration API.
|
|
||||||
- **Removed**: `ViewText`. Was fully replaced with `BaseTextAttributes`
|
|
||||||
- **Fixed**: `Operation.flattenDependencies` used in `Operation.add(to:waitUntilFinished:)` now works correctly.
|
|
||||||
- **Added**: Now it's possible to add dependent operation to start of the queue.
|
|
||||||
|
|
||||||
### 1.28.0
|
|
||||||
|
|
||||||
- **Add**: `LoggingPresenter`to present list of logs with ability of sharing it
|
|
||||||
- **Add**: `TILogger` wrapper object to log events.
|
|
||||||
|
|
||||||
### 1.27.1
|
|
||||||
|
|
||||||
- **Fix**: Weak target reference in `RefreshControl`
|
|
||||||
|
|
||||||
### 1.27.0
|
|
||||||
|
|
||||||
- **Add**: Tag like filter collection view
|
|
||||||
- **Add**: List like filter table view
|
|
||||||
- **Add**: Range like filter view
|
|
||||||
|
|
||||||
### 1.26.3
|
|
||||||
- **Update**: Add @escaping in `RequestExecutor.ExecutionClosure`
|
|
||||||
|
|
||||||
### 1.26.2
|
|
||||||
- **Update**: Add failureCompletion in `RequestExecutor`
|
|
||||||
|
|
||||||
### 1.26.1
|
|
||||||
- **Fix**: Use OperationQueue instead of NSLock in `DefaultTokenInterceptor`
|
|
||||||
- **Update**: AsyncOperation refactoring
|
|
||||||
|
|
||||||
### 1.26.0
|
|
||||||
|
|
||||||
- **Add**: `TIEcommerce` module with Cart, products, promocodes, bonuses and other related actions.
|
|
||||||
|
|
||||||
### 1.25.0
|
|
||||||
|
|
||||||
- **Update**: `RequestError` cases now contain additional url assotiated value
|
|
||||||
- **Update**: Network requests error catching now throws `RequestError` with url
|
|
||||||
|
|
||||||
### 1.24.0
|
|
||||||
|
|
||||||
- **Add**: `AlertFactory` for presenting alerts in SwiftUI and UIKit.
|
|
||||||
|
|
||||||
### 1.23.0
|
|
||||||
|
|
||||||
- **Update**: `UITextView` now support configuration with `BaseTextAttributes`
|
|
||||||
- **Add**: `ReconfigurableView` & `ChangeableViewModel` for non-destructing state update
|
|
||||||
- **Add**: `WrappedViewHolder` protocol with table/collection view cell implementations
|
|
||||||
- **Add**: `UIViewPresenter` and `ReusableUIViewPresenter` protocols with default implementation for proper handling view/cells reuse
|
|
||||||
|
|
||||||
### 1.22.0
|
|
||||||
|
|
||||||
- **Update**: Asynchronous request preprocessing
|
|
||||||
|
|
||||||
### 1.21.0
|
|
||||||
|
|
||||||
- **Update**: `AsyncEventHandler` was replaced with `EndpointRequestRetrier`
|
|
||||||
- **Add**: `FingerprintsTrustEvaluator` and `FingerprintsProvider` for fingerprint-based host trust evaluation
|
|
||||||
- **Add**: `DefaultTokenInterceptor` for queue-based token refresh across all requests of single api interactor (network service).
|
|
||||||
- **Update**: `DefaultRecoverableJsonNetworkService` now returns collection of errors in result
|
|
||||||
- **Update**: `CancellableTask` was renamed to `Cancellable`. Cancellable implementations has been moved from `TIMoyaNetworking` to `TIFoundationUtils`.
|
|
||||||
- **Add**: `ApiInteractor` protocol with basic request/response methods
|
|
||||||
|
|
||||||
|
|
||||||
### 1.20.0
|
|
||||||
|
|
||||||
- **Add**: OpenAPI security schemes support for EndpointRequest's.
|
|
||||||
- **Update**: Replace `AdditionalHeadersPlugin` with `SecuritySchemePreprocessor` and `EndpointRequestPreprocessor` (with default implementations)
|
|
||||||
|
|
||||||
### 1.19.0
|
|
||||||
|
|
||||||
- **Add**: Add presenter protocols to `TISwiftUICore` and `TIUIKitCore` modules
|
|
||||||
- **Add**: `CodeConfirmPresenter` protocol and `DefaultCodeConfirmPresenter` implementation in `TIAuth` module
|
|
||||||
|
|
||||||
### 1.18.0
|
|
||||||
|
|
||||||
- **Add**: add MapManagers for routine maps configuration
|
|
||||||
|
|
||||||
### 1.17.0
|
|
||||||
|
|
||||||
- **Add**: add smooth CameraUpdate actions for supported maps
|
|
||||||
|
|
||||||
### 1.16.2
|
|
||||||
|
|
||||||
- **Update**: `DefaultRecoverableJsonNetworkService` now supports error forwarding from its error handlers to initial requests.
|
|
||||||
|
|
||||||
### 1.16.1
|
|
||||||
|
|
||||||
- **Update**: `DateFormattersReusePool` and `ISO8601DateFormattersReusePool` are now thread safe.
|
|
||||||
|
|
||||||
### 1.16.0
|
|
||||||
|
|
||||||
- **Add**: `TIMapUtils`, `TIAppleMapUtils`, `TIGoogleMapUtils` and `TIYandexMapUtils` modules for map items clustering and interacting with them.
|
|
||||||
|
|
||||||
### 1.15.0
|
|
||||||
|
|
||||||
- **Update**: Network services in TIMoyaNetworking now passes MoyaError in result of EnpointRequest execution.
|
|
||||||
- **Add**: `TINetworkingCache` module - caching results of EndpointRequests.
|
|
||||||
- **Important Note**: `TINetworkingCache` added via SPM may require you to add `DISABLE_DIAMOND_PROBLEM_DIAGNOSTIC=YES` flag to build settings of project target (see [probably related problem](https://forums.swift.org/t/adding-a-package-to-two-targets-in-one-projects-results-in-an-error/35007/18))
|
|
||||||
|
|
||||||
### 1.14.3
|
|
||||||
|
|
||||||
- **Fix**: Creating headerView and footerView when initializing a section with rows in `TITableKitUtils`.
|
|
||||||
- **Add**: Empty table section initialization method in `TITableKitUtils`.
|
|
||||||
|
|
||||||
### 1.14.2
|
|
||||||
|
|
||||||
- **Update**: DateFormatters properties preset in reuse pools
|
|
||||||
|
|
||||||
### 1.14.1
|
|
||||||
|
|
||||||
- **Fix**: Array encoding for `QueryStringParameterEncoding`
|
|
||||||
|
|
||||||
### 1.14.0
|
|
||||||
|
|
||||||
- **Add**: [Date] coding methods
|
|
||||||
|
|
||||||
### 1.13.0
|
|
||||||
|
|
||||||
- **Update**: Change access modifiers in `DefaultJsonNetworkService` from `public` to `open`, added additional Moya plugins processing
|
|
||||||
- **Add**: `DisplayDecodingErrorPlugin` for showing developer-frendly decoding error messages
|
|
||||||
- **Add**: Gemfile for cocoapods versioning
|
|
||||||
|
|
||||||
### 1.12.3
|
|
||||||
|
|
||||||
- **Fix**: Try parse date in ISO8601 format appending `.withFractionalSeconds` if `.withInternetDateTime` fails
|
|
||||||
|
|
||||||
### 1.12.2
|
|
||||||
|
|
||||||
- **Fix**: HeaderParameterEncoding encodes array correctly
|
|
||||||
|
|
||||||
### 1.12.1
|
|
||||||
|
|
||||||
- **Update**: DefaultRecoverableNetworkService `request` parameter was renamed to prevent ambgious reference
|
|
||||||
|
|
||||||
### 1.12.0
|
|
||||||
|
|
||||||
- **Update**: EndpointRequest Body can take a nil value
|
|
||||||
- **Update**: Parameter value can be nil as well
|
|
||||||
- **Update**: observe operator of AsyncOperation now accepts callback queue parameter
|
|
||||||
|
|
||||||
### 1.11.1
|
|
||||||
- **Fix**: `timeoutIntervalForRequest` parameter for `URLSessionConfiguration` in `NetworkServiceConfiguration` added.
|
|
||||||
|
|
||||||
### 1.11.0
|
|
||||||
- **Breaking changes**: many method signatures was changes in `TIMoyaNetworking`.
|
|
||||||
- **Add**: `ISO8601DateFormattersReusePool` and codable helpers for ISO8601 date (de)coding.
|
|
||||||
- **Add**: Moya plugin protocol for adding HTTP headers with default implementation.
|
|
||||||
|
|
||||||
### 1.10.0
|
|
||||||
- **Add**: `DefaultRecoverableJsonNetworkService` with error handling chain.
|
|
||||||
|
|
||||||
|
|
||||||
### 1.9.0
|
|
||||||
- **Add**: `TIMoyaNetworking` target - Moya + Swagger network service.
|
|
||||||
- **Update**: `TISwiftUtils` - added async closure typealiases.
|
|
||||||
- **Update**: `TIFoundationUtils` - added date formatting & decoding helpers.
|
|
||||||
|
|
||||||
### 1.8.0
|
|
||||||
- **Add**: `TIFoundationUtils.AsyncOperation` - generic subclass of Operation with chaining and result observation support
|
|
||||||
|
|
||||||
### 1.7.0
|
|
||||||
- **Add**: `TINetworking` - Swagger-frendly networking layer helpers
|
|
||||||
|
|
||||||
### 1.6.0
|
|
||||||
- **Add**: the pretty timer - TITimer.
|
|
||||||
|
|
||||||
### 1.5.0
|
|
||||||
- **Add**: `HeaderTransitionDelegate` - Helper for transition of TableView header and navigationBar title view
|
|
||||||
|
|
||||||
### 1.4.0
|
|
||||||
- **Update**: update minor dependencies.
|
|
||||||
- **Fix**: project's scripts.
|
|
||||||
|
|
||||||
### 1.3.0
|
|
||||||
- **Add**: `TIPaginator` - realisation of paginating items from a data source.
|
|
||||||
|
|
||||||
### 1.2.0
|
|
||||||
- **Add**: `TIKeychainUtils` - Set of helpers for Keychain classes.
|
|
||||||
|
|
||||||
### 1.1.1
|
|
||||||
- **Fix**: `StatefullButton` propagation
|
|
||||||
|
|
||||||
### 1.1.0
|
|
||||||
- **Add**: `BaseInitializeableViewController`, `BaseCustomViewController` and `BaseViewController` to TIUIKitCore.
|
|
||||||
- **Add**: `TableKitTableView` and `TableDirectorHolder` to TITableKitUtils.
|
|
||||||
|
|
||||||
### 1.0.0
|
|
||||||
- **API BreakingChanges**: up swift version to 5.1.
|
|
||||||
- **Update**: build scripts.
|
|
||||||
- **Update**: code with new swiftlint rules.
|
|
||||||
- **Update**: RxSwift to 6.0.0.
|
|
||||||
|
|
||||||
### 0.13.1
|
|
||||||
- **Fix**: LeadKit.podspec file.
|
|
||||||
|
|
||||||
### 0.13.0
|
|
||||||
- **Add**: Githook `prepare-commit-msg` to check commit's style.
|
|
||||||
- **Add**: Setup script.
|
|
||||||
|
|
||||||
### 0.12.0
|
|
||||||
- **Add**: StatefulButton & RoundedStatefulButton to TIUIElements.
|
|
||||||
- **Add**: added CACornerMask rounding extension to TIUIElements.
|
|
||||||
- **Add**: UIControl.State dictionary extensions to TIUIKitCore.
|
|
||||||
- **Add**: UIFont and CTFont extensions to TIUIKitCore.
|
|
||||||
- **Breaking change**: reworked BaseTextAttributes & ViewText. Removed ViewTextConfigurable protocol & conformances.
|
|
||||||
|
|
||||||
### 0.11.0
|
|
||||||
- **Add**: Cocoapods support for TI-family libraries.
|
|
||||||
- **Add**: `SeparatorConfigurable` and all helper types for separator configuration.
|
|
||||||
- **Add**: `BaseSeparatorCell` - `BaseInitializeableCell` subclass with separators support.
|
|
||||||
- **Add**: `TITableKitUtils` - set of helpers for TableKit classes.
|
|
||||||
- **Add**: `BaseTextAttributes` and `ViewText` implementation form LeadKit.
|
|
||||||
- **Update**: `BaseInitializableView` and `BaseInitializableControl` are moved to `TIUIElements` from `TIUIKitCore`.
|
|
||||||
|
|
||||||
### 0.10.9
|
|
||||||
- **Fix**: `change presentedOrTopViewController to open`.
|
|
||||||
|
|
||||||
### 0.10.8
|
|
||||||
- **Fix**: `Add presentedOrTopViewController`.
|
|
||||||
|
|
||||||
### 0.10.7
|
|
||||||
- **Fix**: `Add BaseOrientationController`.
|
|
||||||
- **Fix**: `Add videoOrientation extension`.
|
|
||||||
|
|
||||||
### 0.10.6
|
|
||||||
- **Fix**: `Add tvos exclude files`.
|
|
||||||
|
|
||||||
### 0.10.5
|
|
||||||
- **Add**: `OrientationNavigationController` .
|
|
||||||
- **Add**: `Forced Interface Orientation logic to BaseConfigurableController` .
|
|
||||||
- **Fix**: `Exclude files to watchos and tvos`.
|
|
||||||
|
|
||||||
### 0.10.4
|
|
||||||
- **Fix**: `noConnection` error.
|
|
||||||
|
|
||||||
### 0.10.3
|
|
||||||
- **Fix**: `mappingQueue` of `SessionManager`.
|
|
||||||
|
|
||||||
### 0.10.2
|
|
||||||
- **Add**: `RefreshControl` - a basic UIRefreshControl with fixed refresh action.
|
|
||||||
|
|
||||||
### 0.10.1
|
|
||||||
- **Update**: Third party dependencies: `Alamofire` 5.2.2, `RxAlamofire` 5.6.1
|
|
||||||
|
|
||||||
### 0.10.0
|
|
||||||
- **Update**: Third party dependencies: `RxSwift` (and all sub-dependencies) to 5.1.0, `Alamofire` 5.0, `SnapKit` 5.0
|
|
||||||
- **Refactored**: NetworkManager to use new Alamofire API
|
|
||||||
- **API BreakingChanges**: NetworkServiceConfiguration no longer accepts `ServerTrustPolicy`, it is now replaced by an instance of a `ServerTrustEvaluating` protocol. Full description and default implementations can be found at Alamofire [sources](https://github.com/Alamofire/Alamofire/blob/master/Source/ServerTrustEvaluation.swift). Since new evaluation is used, evaluation against self-signed certificates will now throw an AfError and abort any outcoming request. To support self-signed certificates use `DisabledTrustEvaluator` for specified host in configuration.
|
|
||||||
- **Removed**: UIImage+SupportExtensions, UIScrollView+Support
|
|
||||||
|
|
||||||
### 0.9.44
|
|
||||||
- **Add**: `TIFoundationUtils` - set of helpers for Foundation framework classes.
|
|
||||||
|
|
||||||
#### TISwiftUtils
|
|
||||||
- **Add**: `BackingStore` - a property wrapper that wraps storage and defines getter and setter for accessing value from it.
|
|
||||||
|
|
||||||
#### TIFoundationUtils
|
|
||||||
- **Add**: `CodableKeyValueStorage` - storage that can get and set codable objects by the key.
|
|
||||||
|
|
||||||
### 0.9.43
|
|
||||||
- **Fix**: `OTPSwiftView`'s dependencies.
|
|
||||||
|
|
||||||
### 0.9.42
|
|
||||||
- **Fix**: Logic bugs of `PaginationWrapper`.
|
|
||||||
|
|
||||||
### 0.9.41
|
|
||||||
- **Add**: `OTPSwiftView` - a fully customizable OTP view.
|
|
||||||
- **Add**: `BaseInitializableControl` UIControl conformance to InitializableView.
|
|
||||||
- **Add**: `TISwiftUtils` a bunch of useful helpers for development.
|
|
||||||
|
|
||||||
### 0.9.40
|
|
||||||
- **Fix**: Load more request repetion in `PaginationWrapper`.
|
|
||||||
|
|
||||||
### 0.9.39
|
|
||||||
- **Add**: `Animatable` protocol to TIUIKitCore.
|
|
||||||
- **Add**: `ActivityIndicator` protocol to TIUIKitCore.
|
|
||||||
- **Add**: `ActivityIndicatorHolder` protocol to TIUIKitCore.
|
|
||||||
- **Add**: `TIUIElements` for ui elements.
|
|
||||||
|
|
||||||
### 0.9.38
|
|
||||||
- **Add**: `BaseRxTableViewCell` is subclass of `UITableViewCell` class with support `InitializableView` and `DisposeBagHolder` protocols.
|
|
||||||
- **Add**: `ContainerTableCell` is container class that provides wrapping any `UIView` into `UITableViewCell`.
|
|
||||||
- **Add**: `BaseTappableViewModel` is simplifies interaction between view and viewModel for events of tapping.
|
|
||||||
- **Add**: `VoidTappableViewModel` is subclass of `BaseTappableViewModel` class with void payload type.
|
|
||||||
|
|
||||||
### 0.9.37
|
|
||||||
- **Fix**: ScrollView content offset of `PaginationWrapper` for iOS 13.
|
|
||||||
- **Fix**: Load more request crash of `PaginationWrapper`.
|
|
||||||
|
|
||||||
### 0.9.36
|
|
||||||
- **Add**: SPM Package.swift.
|
|
||||||
- **Add**: TITransitions via SPM.
|
|
||||||
- **Add**: TIUIKitCore via SPM.
|
|
||||||
- **Update**: Readme.
|
|
||||||
|
|
||||||
### 0.9.35
|
|
||||||
- **Add**: Selector `refreshAction()` for refresh control of `PaginationWrapper`.
|
|
||||||
|
|
||||||
### 0.9.34
|
|
||||||
- **Add**: `ButtonHolder` - protocol that contains button property.
|
|
||||||
- **Add**: `ButtonHolderView` - view which contains button.
|
|
||||||
- **Add**: Conformance `UIButton` to `ButtonHolder`.
|
|
||||||
- **Add**: Conformance `BasePlaceholderView` to `ButtonHolderView`.
|
|
||||||
- **[Breaking change]**: Replace functions `footerRetryButton() -> UIButton?` to `footerRetryView() -> ButtonHolderView?` and `footerRetryButtonHeight() -> CGFloat` to `footerRetryViewHeight() -> CGFloat` for `PaginationWrapperUIDelegate`.
|
|
||||||
- **[Breaking change]**: Replace functions `footerRetryButtonWillAppear()` to `footerRetryViewWillAppear()` and `footerRetryButtonWillDisappear()` to `footerRetryViewWillDisappear()` for `PaginationWrapperUIDelegate`.
|
|
||||||
|
|
||||||
### 0.9.33
|
|
||||||
- **Fix**: `CustomizableButtonView` container class that provides great customization.
|
|
||||||
- **Fix**: `CustomizableButtonViewModel` viewModel class for `CustomizableButtonView` configuration.
|
|
||||||
|
|
||||||
### 0.9.32
|
|
||||||
- **Fix**: `CustomizableButtonView` container class that provides great customization.
|
|
||||||
|
|
||||||
### 0.9.31
|
|
||||||
- **Add**: `@discardableResult` to function - `replace(with:at:with:manualBeginEndUpdates)` in `TableDirector`.
|
|
||||||
|
|
||||||
### 0.9.30
|
|
||||||
- **Add**: character `*` into a valid set of characters in the extension `telpromptURL` of String.
|
|
||||||
|
|
||||||
### 0.9.29
|
|
||||||
- **Update**: remove Carthage binary dependencies, update build scripts.
|
|
||||||
|
|
||||||
### 0.9.28
|
|
||||||
- **Add**: method `presentFullScreen(_ viewController:presentationStyle:animated:completion:)` for `UIViewController` that present any `viewController` modally in full screen mode by default (avoid problems with *iOS13* default presentation mode changed to `.automatic` stork)
|
|
||||||
|
|
||||||
### 0.9.27
|
|
||||||
- **Add**: method `date(from string:formats:parsedIn:)` method for `DateFormattingService` that parses date from string in one of the given formats with current region.
|
|
||||||
|
|
||||||
### 0.9.26
|
|
||||||
- **Add**: method `processResultFromConfigurationSingle` for `TotalCountCursor` that allows to get server response.
|
|
||||||
- **Add**: possibility to inherit from `TotalCountCursor`.
|
|
||||||
|
|
||||||
### 0.9.25
|
|
||||||
- **Add**: `queryItems` parameter for `ApiRequestParameters`.
|
|
||||||
- **Add**: `asQueryItems` method for `Encodable` that converts model to query items array.
|
|
||||||
|
|
||||||
### 0.9.24
|
### 0.9.24
|
||||||
- **Fix**: Make `ApiRequestParameters` properties public.
|
- **Add**: `NetworkErrorAlertBase` class that stores settings for network error alert.
|
||||||
|
- **Add**: `NetworkErrorHandler` protocol for classes that can handle network error.
|
||||||
|
- **Add**: `NetworkErrorHandlingType` enum with types of network error handling.
|
||||||
|
- **Add**: `handleNetworkError(type:handler:)` method for `Observable`, `Single` and `Completable` that handles network error.
|
||||||
|
|
||||||
### 0.9.23
|
### 0.9.23
|
||||||
- **Add**: Rounding for `Decimal`.
|
- **Add**: Rounding for `Decimal`.
|
||||||
|
|
|
||||||
14
Cartfile
14
Cartfile
|
|
@ -1,7 +1,7 @@
|
||||||
github "malcommac/SwiftDate"
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/SwiftDate/SwiftDate.json"
|
||||||
github "Alamofire/Alamofire"
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/Alamofire/Alamofire.json"
|
||||||
github "RxSwiftCommunity/RxAlamofire" ~> 6.1
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/RxAlamofire/RxAlamofire.json"
|
||||||
github "TouchInstinct/TableKit"
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/TableKit/TableKit.json"
|
||||||
github "ReactiveX/RxSwift" ~> 6.2
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/RxSwift/RxSwift.json"
|
||||||
github "pronebird/UIScrollView-InfiniteScroll" "1.1.0"
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/UIScrollView_InfiniteScroll/UIScrollView_InfiniteScroll.json"
|
||||||
github "SnapKit/SnapKit" ~> 5.0
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/SnapKit/SnapKit.json"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
github "Alamofire/Alamofire" "5.4.3"
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/Alamofire/Alamofire.json" "4.8.1"
|
||||||
github "ReactiveX/RxSwift" "6.2.0"
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/RxAlamofire/RxAlamofire.json" "4.3.0"
|
||||||
github "RxSwiftCommunity/RxAlamofire" "v6.1.2"
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/RxSwift/RxSwift.json" "4.4.2"
|
||||||
github "SnapKit/SnapKit" "5.0.1"
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/SnapKit/SnapKit.json" "4.2.0"
|
||||||
github "TouchInstinct/TableKit" "2.10008.1"
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/SwiftDate/SwiftDate.json" "5.1.0"
|
||||||
github "malcommac/SwiftDate" "6.3.1"
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/TableKit/TableKit.json" "2.10008.1"
|
||||||
github "pronebird/UIScrollView-InfiniteScroll" "1.1.0"
|
binary "https://raw.github.com/TouchInstinct/CarthageBinaries/master/UIScrollView_InfiniteScroll/UIScrollView_InfiniteScroll.json" "1.1.0"
|
||||||
|
|
|
||||||
5
Gemfile
5
Gemfile
|
|
@ -1,5 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
source "https://rubygems.org"
|
|
||||||
|
|
||||||
gem "cocoapods", "~> 1.11"
|
|
||||||
98
Gemfile.lock
98
Gemfile.lock
|
|
@ -1,98 +0,0 @@
|
||||||
GEM
|
|
||||||
remote: https://rubygems.org/
|
|
||||||
specs:
|
|
||||||
CFPropertyList (3.0.5)
|
|
||||||
rexml
|
|
||||||
activesupport (6.1.5)
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
addressable (~> 2.8)
|
|
||||||
claide (>= 1.0.2, < 2.0)
|
|
||||||
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)
|
|
||||||
cocoapods-search (>= 1.0.0, < 2.0)
|
|
||||||
cocoapods-trunk (>= 1.4.0, < 2.0)
|
|
||||||
cocoapods-try (>= 1.1.0, < 2.0)
|
|
||||||
colored2 (~> 3.1)
|
|
||||||
escape (~> 0.0.4)
|
|
||||||
fourflusher (>= 2.3.0, < 3.0)
|
|
||||||
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)
|
|
||||||
addressable (~> 2.8)
|
|
||||||
algoliasearch (~> 1.0)
|
|
||||||
concurrent-ruby (~> 1.1)
|
|
||||||
fuzzy_match (~> 2.0.4)
|
|
||||||
nap (~> 1.0)
|
|
||||||
netrc (~> 0.11)
|
|
||||||
public_suffix (~> 4.0)
|
|
||||||
typhoeus (~> 1.0)
|
|
||||||
cocoapods-deintegrate (1.0.5)
|
|
||||||
cocoapods-downloader (1.6.2)
|
|
||||||
cocoapods-plugins (1.0.0)
|
|
||||||
nap
|
|
||||||
cocoapods-search (1.0.1)
|
|
||||||
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.10)
|
|
||||||
escape (0.0.4)
|
|
||||||
ethon (0.15.0)
|
|
||||||
ffi (>= 1.15.0)
|
|
||||||
ffi (1.15.5)
|
|
||||||
fourflusher (2.3.1)
|
|
||||||
fuzzy_match (2.0.4)
|
|
||||||
gh_inspector (1.1.3)
|
|
||||||
httpclient (2.8.3)
|
|
||||||
i18n (1.10.0)
|
|
||||||
concurrent-ruby (~> 1.0)
|
|
||||||
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 (2.5.1)
|
|
||||||
typhoeus (1.4.0)
|
|
||||||
ethon (>= 0.9.0)
|
|
||||||
tzinfo (2.0.4)
|
|
||||||
concurrent-ruby (~> 1.0)
|
|
||||||
xcodeproj (1.21.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.5.4)
|
|
||||||
|
|
||||||
PLATFORMS
|
|
||||||
x86_64-darwin-20
|
|
||||||
x86_64-darwin-21
|
|
||||||
|
|
||||||
DEPENDENCIES
|
|
||||||
cocoapods (~> 1.11)
|
|
||||||
|
|
||||||
BUNDLED WITH
|
|
||||||
2.3.26
|
|
||||||
|
|
@ -1,33 +1,30 @@
|
||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = "LeadKit"
|
s.name = "LeadKit"
|
||||||
s.version = "1.35.0"
|
s.version = "0.9.24"
|
||||||
s.summary = "iOS framework with a bunch of tools for rapid development"
|
s.summary = "iOS framework with a bunch of tools for rapid development"
|
||||||
s.homepage = "https://git.svc.touchin.ru/TouchInstinct/LeadKit"
|
s.homepage = "https://github.com/TouchInstinct/LeadKit"
|
||||||
s.license = "Apache License, Version 2.0"
|
s.license = "Apache License, Version 2.0"
|
||||||
s.author = "Touch Instinct"
|
s.author = "Touch Instinct"
|
||||||
s.source = { :git => "https://git.svc.touchin.ru/TouchInstinct/LeadKit.git", :tag => s.version }
|
s.source = { :git => "https://github.com/TouchInstinct/LeadKit.git", :tag => s.version }
|
||||||
s.platform = :ios, '10.0'
|
s.platform = :ios, '9.0'
|
||||||
s.swift_versions = ['5.1']
|
|
||||||
|
|
||||||
s.subspec 'UIColorHex' do |ss|
|
s.subspec 'UIColorHex' do |ss|
|
||||||
ss.ios.deployment_target = '10.0'
|
ss.ios.deployment_target = '8.0'
|
||||||
ss.tvos.deployment_target = '10.0'
|
ss.tvos.deployment_target = '9.0'
|
||||||
ss.watchos.deployment_target = '3.0'
|
ss.watchos.deployment_target = '2.0'
|
||||||
|
|
||||||
ss.source_files = "Sources/Extensions/UIColor/UIColor+Hex.swift"
|
ss.source_files = "Sources/Extensions/UIColor/UIColor+Hex.swift"
|
||||||
end
|
end
|
||||||
|
|
||||||
s.subspec 'Core' do |ss|
|
s.subspec 'Core' do |ss|
|
||||||
ss.ios.deployment_target = '10.0'
|
ss.ios.deployment_target = '9.0'
|
||||||
ss.tvos.deployment_target = '10.0'
|
ss.tvos.deployment_target = '9.0'
|
||||||
ss.watchos.deployment_target = '3.0'
|
ss.watchos.deployment_target = '2.0'
|
||||||
|
|
||||||
ss.source_files = "Sources/**/*.swift"
|
ss.source_files = "Sources/**/*.swift"
|
||||||
ss.watchos.exclude_files = [
|
ss.watchos.exclude_files = [
|
||||||
"Sources/Classes/Controllers/**/*",
|
"Sources/Classes/Controllers/**/*",
|
||||||
"Sources/Classes/Views/SeparatorRowBox/*",
|
"Sources/Classes/Views/SeparatorRowBox/*",
|
||||||
"Sources/Classes/Views/BaseRxTableViewCell/*",
|
|
||||||
"Sources/Classes/Views/ContainerTableCell/*",
|
|
||||||
"Sources/Classes/Views/SeparatorCell/*",
|
"Sources/Classes/Views/SeparatorCell/*",
|
||||||
"Sources/Classes/Views/EmptyCell/*",
|
"Sources/Classes/Views/EmptyCell/*",
|
||||||
"Sources/Classes/Views/LabelTableViewCell/*",
|
"Sources/Classes/Views/LabelTableViewCell/*",
|
||||||
|
|
@ -46,6 +43,7 @@ Pod::Spec.new do |s|
|
||||||
"Sources/Extensions/NetworkService/NetworkService+RxLoadImage.swift",
|
"Sources/Extensions/NetworkService/NetworkService+RxLoadImage.swift",
|
||||||
"Sources/Extensions/DataLoading/GeneralDataLoading/GeneralDataLoadingController+DefaultImplementation.swift",
|
"Sources/Extensions/DataLoading/GeneralDataLoading/GeneralDataLoadingController+DefaultImplementation.swift",
|
||||||
"Sources/Extensions/DataLoading/PaginationDataLoading/*",
|
"Sources/Extensions/DataLoading/PaginationDataLoading/*",
|
||||||
|
"Sources/Extensions/Support/UIScrollView+Support.swift",
|
||||||
"Sources/Extensions/Support/UINavigationItem+Support.swift",
|
"Sources/Extensions/Support/UINavigationItem+Support.swift",
|
||||||
"Sources/Extensions/TableKit/**/*.swift",
|
"Sources/Extensions/TableKit/**/*.swift",
|
||||||
"Sources/Extensions/Array/Array+SeparatorRowBoxExtensions.swift",
|
"Sources/Extensions/Array/Array+SeparatorRowBoxExtensions.swift",
|
||||||
|
|
@ -68,21 +66,10 @@ Pod::Spec.new do |s|
|
||||||
"Sources/Structures/DrawingOperations/CALayerDrawingOperation.swift",
|
"Sources/Structures/DrawingOperations/CALayerDrawingOperation.swift",
|
||||||
"Sources/Structures/DrawingOperations/RoundDrawingOperation.swift",
|
"Sources/Structures/DrawingOperations/RoundDrawingOperation.swift",
|
||||||
"Sources/Structures/DrawingOperations/BorderDrawingOperation.swift",
|
"Sources/Structures/DrawingOperations/BorderDrawingOperation.swift",
|
||||||
"Sources/Structures/DataLoading/PaginationDataLoading/*",
|
"Sources/Structures/DataLoading/PaginationDataLoading/*"
|
||||||
"Sources/Extensions/UIInterfaceOrientation/*"
|
|
||||||
]
|
]
|
||||||
ss.tvos.exclude_files = [
|
ss.tvos.exclude_files = [
|
||||||
"Sources/Classes/Controllers/BaseConfigurableController.swift",
|
|
||||||
"Sources/Classes/Controllers/BaseCollectionContentController.swift",
|
|
||||||
"Sources/Classes/Views/TableViewWrapperView/TableViewWrapperView.swift",
|
|
||||||
"Sources/Classes/Views/CollectionViewWrapperView/CollectionViewWrapperView.swift",
|
|
||||||
"Sources/Classes/Controllers/BaseScrollContentController.swift",
|
|
||||||
"Sources/Classes/Controllers/BaseCustomViewController.swift",
|
|
||||||
"Sources/Classes/Controllers/BaseOrientationNavigationController.swift",
|
|
||||||
"Sources/Extensions/UIKit/UIDevice/UIDevice+ScreenOrientation.swift",
|
|
||||||
"Sources/Classes/Controllers/BaseTableContentController.swift",
|
"Sources/Classes/Controllers/BaseTableContentController.swift",
|
||||||
"Sources/Classes/Views/BaseRxTableViewCell/*",
|
|
||||||
"Sources/Classes/Views/ContainerTableCell/*",
|
|
||||||
"Sources/Classes/Views/SeparatorRowBox/*",
|
"Sources/Classes/Views/SeparatorRowBox/*",
|
||||||
"Sources/Classes/Views/SeparatorCell/*",
|
"Sources/Classes/Views/SeparatorCell/*",
|
||||||
"Sources/Classes/Views/EmptyCell/*",
|
"Sources/Classes/Views/EmptyCell/*",
|
||||||
|
|
@ -93,6 +80,7 @@ Pod::Spec.new do |s|
|
||||||
"Sources/Structures/Drawing/CALayerDrawingOperation.swift",
|
"Sources/Structures/Drawing/CALayerDrawingOperation.swift",
|
||||||
"Sources/Enums/Search/*",
|
"Sources/Enums/Search/*",
|
||||||
"Sources/Extensions/DataLoading/PaginationDataLoading/*",
|
"Sources/Extensions/DataLoading/PaginationDataLoading/*",
|
||||||
|
"Sources/Extensions/Support/UIScrollView+Support.swift",
|
||||||
"Sources/Extensions/Support/UINavigationItem+Support.swift",
|
"Sources/Extensions/Support/UINavigationItem+Support.swift",
|
||||||
"Sources/Extensions/TableKit/**/*.swift",
|
"Sources/Extensions/TableKit/**/*.swift",
|
||||||
"Sources/Extensions/Array/Array+SeparatorRowBoxExtensions.swift",
|
"Sources/Extensions/Array/Array+SeparatorRowBoxExtensions.swift",
|
||||||
|
|
@ -102,18 +90,16 @@ Pod::Spec.new do |s|
|
||||||
"Sources/Protocols/Views/SeparatorCell/*",
|
"Sources/Protocols/Views/SeparatorCell/*",
|
||||||
"Sources/Protocols/TableKit/**/*",
|
"Sources/Protocols/TableKit/**/*",
|
||||||
"Sources/Protocols/Controllers/SearchResultsViewController.swift",
|
"Sources/Protocols/Controllers/SearchResultsViewController.swift",
|
||||||
"Sources/Structures/DataLoading/PaginationDataLoading/*",
|
"Sources/Structures/DataLoading/PaginationDataLoading/*"
|
||||||
"Sources/Extensions/UIInterfaceOrientation/*",
|
|
||||||
"Sources/Classes/Controllers/BaseOrientationController.swift"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
ss.dependency "RxSwift", '~> 6.2'
|
ss.dependency "RxSwift", '~> 4'
|
||||||
ss.dependency "RxCocoa", '~> 6.2'
|
ss.dependency "RxCocoa", '~> 4'
|
||||||
ss.dependency "RxAlamofire", '~> 6.1'
|
ss.dependency "RxAlamofire", '~> 4'
|
||||||
ss.dependency "SwiftDate", '~> 6'
|
ss.dependency "SwiftDate", '~> 6'
|
||||||
|
|
||||||
ss.ios.dependency "TableKit", '~> 2.11'
|
ss.ios.dependency "TableKit", '~> 2.8'
|
||||||
ss.ios.dependency "SnapKit", '~> 5.0.1'
|
ss.ios.dependency "SnapKit", '~> 4.0.0'
|
||||||
ss.ios.dependency "UIScrollView-InfiniteScroll", '~> 1.1.0'
|
ss.ios.dependency "UIScrollView-InfiniteScroll", '~> 1.1.0'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 54;
|
objectVersion = 46;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
|
@ -15,51 +15,6 @@
|
||||||
36FE777320F669E300284C09 /* String+ConvertToHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FE776F20F669E300284C09 /* String+ConvertToHost.swift */; };
|
36FE777320F669E300284C09 /* String+ConvertToHost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FE776F20F669E300284C09 /* String+ConvertToHost.swift */; };
|
||||||
40F118471F8FEF97004AADAF /* AppearanceConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F118461F8FEF97004AADAF /* AppearanceConfigurable.swift */; };
|
40F118471F8FEF97004AADAF /* AppearanceConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F118461F8FEF97004AADAF /* AppearanceConfigurable.swift */; };
|
||||||
40F118491F8FF223004AADAF /* TableRow+AppearanceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F118481F8FF223004AADAF /* TableRow+AppearanceExtension.swift */; };
|
40F118491F8FF223004AADAF /* TableRow+AppearanceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F118481F8FF223004AADAF /* TableRow+AppearanceExtension.swift */; };
|
||||||
411073AF23466B41002DD9B9 /* UIViewController+PresentFullScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 411073AE23466B41002DD9B9 /* UIViewController+PresentFullScreen.swift */; };
|
|
||||||
4C4C7B52267FE27E006F3C70 /* RxAlamofire.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B47267FE27E006F3C70 /* RxAlamofire.xcframework */; };
|
|
||||||
4C4C7B56267FE27E006F3C70 /* RxSwift.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B49267FE27E006F3C70 /* RxSwift.xcframework */; };
|
|
||||||
4C4C7B5C267FE27E006F3C70 /* RxRelay.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4C267FE27E006F3C70 /* RxRelay.xcframework */; };
|
|
||||||
4C4C7B5E267FE27E006F3C70 /* Alamofire.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4D267FE27E006F3C70 /* Alamofire.xcframework */; };
|
|
||||||
4C4C7B60267FE27E006F3C70 /* SwiftDate.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4E267FE27E006F3C70 /* SwiftDate.xcframework */; };
|
|
||||||
4C4C7B62267FE27E006F3C70 /* RxBlocking.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4F267FE27E006F3C70 /* RxBlocking.xcframework */; };
|
|
||||||
4C4C7B66267FE27F006F3C70 /* RxCocoa.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B51267FE27E006F3C70 /* RxCocoa.xcframework */; };
|
|
||||||
4C4C7B7F267FE319006F3C70 /* Decimal+Rounding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A5D49422AA975000C7D254 /* Decimal+Rounding.swift */; };
|
|
||||||
4C4C7B83267FE32F006F3C70 /* Decimal+Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A5D49B22AAB6B700C7D254 /* Decimal+Values.swift */; };
|
|
||||||
4C4C7B8A267FE364006F3C70 /* Alamofire.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4D267FE27E006F3C70 /* Alamofire.xcframework */; };
|
|
||||||
4C4C7B8C267FE364006F3C70 /* RxAlamofire.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B47267FE27E006F3C70 /* RxAlamofire.xcframework */; };
|
|
||||||
4C4C7B8E267FE365006F3C70 /* RxBlocking.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4F267FE27E006F3C70 /* RxBlocking.xcframework */; };
|
|
||||||
4C4C7B90267FE365006F3C70 /* RxCocoa.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B51267FE27E006F3C70 /* RxCocoa.xcframework */; };
|
|
||||||
4C4C7B92267FE365006F3C70 /* RxRelay.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4C267FE27E006F3C70 /* RxRelay.xcframework */; };
|
|
||||||
4C4C7B94267FE365006F3C70 /* RxSwift.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B49267FE27E006F3C70 /* RxSwift.xcframework */; };
|
|
||||||
4C4C7B96267FE365006F3C70 /* RxTest.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B50267FE27E006F3C70 /* RxTest.xcframework */; };
|
|
||||||
4C4C7B98267FE365006F3C70 /* SnapKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4B267FE27E006F3C70 /* SnapKit.xcframework */; };
|
|
||||||
4C4C7B9A267FE365006F3C70 /* SwiftDate.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4E267FE27E006F3C70 /* SwiftDate.xcframework */; };
|
|
||||||
4C4C7BA7267FE3F6006F3C70 /* Decimal+Rounding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A5D49422AA975000C7D254 /* Decimal+Rounding.swift */; };
|
|
||||||
4C4C7BA8267FE3F6006F3C70 /* Decimal+Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A5D49B22AAB6B700C7D254 /* Decimal+Values.swift */; };
|
|
||||||
4C4C7BB7267FE4C9006F3C70 /* ButtonHolderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF65D1724DD6C080006B001 /* ButtonHolderView.swift */; };
|
|
||||||
4C4C7BBA267FE4DD006F3C70 /* ButtonHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF65D1324DD684A0006B001 /* ButtonHolder.swift */; };
|
|
||||||
4C4C7BBF267FE508006F3C70 /* Alamofire.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4D267FE27E006F3C70 /* Alamofire.xcframework */; };
|
|
||||||
4C4C7BC1267FE508006F3C70 /* RxAlamofire.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B47267FE27E006F3C70 /* RxAlamofire.xcframework */; };
|
|
||||||
4C4C7BC3267FE508006F3C70 /* RxBlocking.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4F267FE27E006F3C70 /* RxBlocking.xcframework */; };
|
|
||||||
4C4C7BC5267FE508006F3C70 /* RxCocoa.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B51267FE27E006F3C70 /* RxCocoa.xcframework */; };
|
|
||||||
4C4C7BC7267FE509006F3C70 /* RxRelay.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4C267FE27E006F3C70 /* RxRelay.xcframework */; };
|
|
||||||
4C4C7BC9267FE509006F3C70 /* RxSwift.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B49267FE27E006F3C70 /* RxSwift.xcframework */; };
|
|
||||||
4C4C7BCB267FE509006F3C70 /* RxTest.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B50267FE27E006F3C70 /* RxTest.xcframework */; };
|
|
||||||
4C4C7BCD267FE509006F3C70 /* SnapKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4B267FE27E006F3C70 /* SnapKit.xcframework */; };
|
|
||||||
4C4C7BCF267FE509006F3C70 /* SwiftDate.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4E267FE27E006F3C70 /* SwiftDate.xcframework */; };
|
|
||||||
4C4C7BD1267FE509006F3C70 /* TableKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B48267FE27E006F3C70 /* TableKit.xcframework */; };
|
|
||||||
4C4C7BD3267FE509006F3C70 /* UIScrollView_InfiniteScroll.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C4C7B4A267FE27E006F3C70 /* UIScrollView_InfiniteScroll.xcframework */; };
|
|
||||||
4CF65D1424DD684A0006B001 /* ButtonHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF65D1324DD684A0006B001 /* ButtonHolder.swift */; };
|
|
||||||
4CF65D1624DD69250006B001 /* UIButton+ButtonHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF65D1524DD69250006B001 /* UIButton+ButtonHolder.swift */; };
|
|
||||||
4CF65D1824DD6C080006B001 /* ButtonHolderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CF65D1724DD6C080006B001 /* ButtonHolderView.swift */; };
|
|
||||||
52421F8D24EAB52E00948DD1 /* ContainerTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52421F8C24EAB52E00948DD1 /* ContainerTableCell.swift */; };
|
|
||||||
52421F8F24EAB84900948DD1 /* BaseRxTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52421F8E24EAB84900948DD1 /* BaseRxTableViewCell.swift */; };
|
|
||||||
52421F9424EBCFAE00948DD1 /* VoidTappableViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52421F9324EBCFAE00948DD1 /* VoidTappableViewModel.swift */; };
|
|
||||||
52421F9624EBCFBB00948DD1 /* BaseTappableViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52421F9524EBCFBB00948DD1 /* BaseTappableViewModel.swift */; };
|
|
||||||
5E23631F25263EFA00E2F96B /* BaseOrientationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E23631E25263EFA00E2F96B /* BaseOrientationController.swift */; };
|
|
||||||
5E2364182526489A00E2F96B /* UIInterfaceOrientation+ VideoOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E2364172526489A00E2F96B /* UIInterfaceOrientation+ VideoOrientation.swift */; };
|
|
||||||
5ED2C0B2251A354E00D4E258 /* BaseOrientationNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ED2C0B1251A354E00D4E258 /* BaseOrientationNavigationController.swift */; };
|
|
||||||
5ED2C0B5251A366700D4E258 /* UIDevice+ScreenOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ED2C0B4251A366700D4E258 /* UIDevice+ScreenOrientation.swift */; };
|
|
||||||
67051ADB1EBC7C36008EADC0 /* SpinnerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67051ADA1EBC7C36008EADC0 /* SpinnerView.swift */; };
|
67051ADB1EBC7C36008EADC0 /* SpinnerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67051ADA1EBC7C36008EADC0 /* SpinnerView.swift */; };
|
||||||
67051ADD1EBC7C36008EADC0 /* SpinnerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67051ADA1EBC7C36008EADC0 /* SpinnerView.swift */; };
|
67051ADD1EBC7C36008EADC0 /* SpinnerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67051ADA1EBC7C36008EADC0 /* SpinnerView.swift */; };
|
||||||
6713C23720AF0C4D00875921 /* NetworkOperationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6713C23620AF0C4D00875921 /* NetworkOperationState.swift */; };
|
6713C23720AF0C4D00875921 /* NetworkOperationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6713C23620AF0C4D00875921 /* NetworkOperationState.swift */; };
|
||||||
|
|
@ -132,6 +87,7 @@
|
||||||
671462C81EB3396E00EAB194 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461FC1EB3396E00EAB194 /* String+Localization.swift */; };
|
671462C81EB3396E00EAB194 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461FC1EB3396E00EAB194 /* String+Localization.swift */; };
|
||||||
671462CA1EB3396E00EAB194 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461FC1EB3396E00EAB194 /* String+Localization.swift */; };
|
671462CA1EB3396E00EAB194 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461FC1EB3396E00EAB194 /* String+Localization.swift */; };
|
||||||
671462CB1EB3396E00EAB194 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461FC1EB3396E00EAB194 /* String+Localization.swift */; };
|
671462CB1EB3396E00EAB194 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461FC1EB3396E00EAB194 /* String+Localization.swift */; };
|
||||||
|
671462D01EB3396E00EAB194 /* UIScrollView+Support.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671461FF1EB3396E00EAB194 /* UIScrollView+Support.swift */; };
|
||||||
671462D41EB3396E00EAB194 /* TableDirector+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462011EB3396E00EAB194 /* TableDirector+Extensions.swift */; };
|
671462D41EB3396E00EAB194 /* TableDirector+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462011EB3396E00EAB194 /* TableDirector+Extensions.swift */; };
|
||||||
671462D81EB3396E00EAB194 /* TimeInterval+DateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462031EB3396E00EAB194 /* TimeInterval+DateComponents.swift */; };
|
671462D81EB3396E00EAB194 /* TimeInterval+DateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462031EB3396E00EAB194 /* TimeInterval+DateComponents.swift */; };
|
||||||
671462DA1EB3396E00EAB194 /* TimeInterval+DateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462031EB3396E00EAB194 /* TimeInterval+DateComponents.swift */; };
|
671462DA1EB3396E00EAB194 /* TimeInterval+DateComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462031EB3396E00EAB194 /* TimeInterval+DateComponents.swift */; };
|
||||||
|
|
@ -141,6 +97,8 @@
|
||||||
671462E71EB3396E00EAB194 /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462091EB3396E00EAB194 /* UIColor+Hex.swift */; };
|
671462E71EB3396E00EAB194 /* UIColor+Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462091EB3396E00EAB194 /* UIColor+Hex.swift */; };
|
||||||
671462EC1EB3396E00EAB194 /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */; };
|
671462EC1EB3396E00EAB194 /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */; };
|
||||||
671462EF1EB3396E00EAB194 /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */; };
|
671462EF1EB3396E00EAB194 /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */; };
|
||||||
|
671462F01EB3396E00EAB194 /* UIImage+SupportExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714620E1EB3396E00EAB194 /* UIImage+SupportExtensions.swift */; };
|
||||||
|
671462F31EB3396E00EAB194 /* UIImage+SupportExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6714620E1EB3396E00EAB194 /* UIImage+SupportExtensions.swift */; };
|
||||||
671462FC1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462131EB3396E00EAB194 /* UIView+XibNameProtocol.swift */; };
|
671462FC1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462131EB3396E00EAB194 /* UIView+XibNameProtocol.swift */; };
|
||||||
671462FF1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462131EB3396E00EAB194 /* UIView+XibNameProtocol.swift */; };
|
671462FF1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462131EB3396E00EAB194 /* UIView+XibNameProtocol.swift */; };
|
||||||
671463001EB3396E00EAB194 /* UIView+LoadFromNib.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462141EB3396E00EAB194 /* UIView+LoadFromNib.swift */; };
|
671463001EB3396E00EAB194 /* UIView+LoadFromNib.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462141EB3396E00EAB194 /* UIView+LoadFromNib.swift */; };
|
||||||
|
|
@ -306,7 +264,9 @@
|
||||||
6741CEC220E2430A00FEC4D9 /* UITableView+TableViewHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741CEC120E2430900FEC4D9 /* UITableView+TableViewHolder.swift */; };
|
6741CEC220E2430A00FEC4D9 /* UITableView+TableViewHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741CEC120E2430900FEC4D9 /* UITableView+TableViewHolder.swift */; };
|
||||||
6741CEC420E2430A00FEC4D9 /* UITableView+TableViewHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741CEC120E2430900FEC4D9 /* UITableView+TableViewHolder.swift */; };
|
6741CEC420E2430A00FEC4D9 /* UITableView+TableViewHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741CEC120E2430900FEC4D9 /* UITableView+TableViewHolder.swift */; };
|
||||||
6741CECE20E243F800FEC4D9 /* BaseCustomViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741CECC20E243F800FEC4D9 /* BaseCustomViewController.swift */; };
|
6741CECE20E243F800FEC4D9 /* BaseCustomViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741CECC20E243F800FEC4D9 /* BaseCustomViewController.swift */; };
|
||||||
|
6741CED020E243F800FEC4D9 /* BaseCustomViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741CECC20E243F800FEC4D9 /* BaseCustomViewController.swift */; };
|
||||||
6741CED120E243F800FEC4D9 /* BaseConfigurableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741CECD20E243F800FEC4D9 /* BaseConfigurableController.swift */; };
|
6741CED120E243F800FEC4D9 /* BaseConfigurableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741CECD20E243F800FEC4D9 /* BaseConfigurableController.swift */; };
|
||||||
|
6741CED320E243F800FEC4D9 /* BaseConfigurableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6741CECD20E243F800FEC4D9 /* BaseConfigurableController.swift */; };
|
||||||
674303CF214FB8F700EF4160 /* GeneralDataLoadingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674303CE214FB8F700EF4160 /* GeneralDataLoadingHandler.swift */; };
|
674303CF214FB8F700EF4160 /* GeneralDataLoadingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674303CE214FB8F700EF4160 /* GeneralDataLoadingHandler.swift */; };
|
||||||
674303D1214FB8F700EF4160 /* GeneralDataLoadingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674303CE214FB8F700EF4160 /* GeneralDataLoadingHandler.swift */; };
|
674303D1214FB8F700EF4160 /* GeneralDataLoadingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674303CE214FB8F700EF4160 /* GeneralDataLoadingHandler.swift */; };
|
||||||
674303D2214FB8F700EF4160 /* GeneralDataLoadingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674303CE214FB8F700EF4160 /* GeneralDataLoadingHandler.swift */; };
|
674303D2214FB8F700EF4160 /* GeneralDataLoadingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674303CE214FB8F700EF4160 /* GeneralDataLoadingHandler.swift */; };
|
||||||
|
|
@ -318,6 +278,7 @@
|
||||||
675C1FB41F97CA32007D5249 /* AppearanceConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F118461F8FEF97004AADAF /* AppearanceConfigurable.swift */; };
|
675C1FB41F97CA32007D5249 /* AppearanceConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F118461F8FEF97004AADAF /* AppearanceConfigurable.swift */; };
|
||||||
675C1FB51F97CA33007D5249 /* AppearanceConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F118461F8FEF97004AADAF /* AppearanceConfigurable.swift */; };
|
675C1FB51F97CA33007D5249 /* AppearanceConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F118461F8FEF97004AADAF /* AppearanceConfigurable.swift */; };
|
||||||
675E0AA921072FF400CDC143 /* BaseScrollContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */; };
|
675E0AA921072FF400CDC143 /* BaseScrollContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */; };
|
||||||
|
675E0AAB21072FF400CDC143 /* BaseScrollContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */; };
|
||||||
6760DC4D212F351700020BAE /* UIView+AddSubviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6760DC4C212F351700020BAE /* UIView+AddSubviews.swift */; };
|
6760DC4D212F351700020BAE /* UIView+AddSubviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6760DC4C212F351700020BAE /* UIView+AddSubviews.swift */; };
|
||||||
6760DC4F212F351700020BAE /* UIView+AddSubviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6760DC4C212F351700020BAE /* UIView+AddSubviews.swift */; };
|
6760DC4F212F351700020BAE /* UIView+AddSubviews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6760DC4C212F351700020BAE /* UIView+AddSubviews.swift */; };
|
||||||
6762131820A0BBA30034EEF1 /* TableSection+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6762131720A0BBA30034EEF1 /* TableSection+Extensions.swift */; };
|
6762131820A0BBA30034EEF1 /* TableSection+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6762131720A0BBA30034EEF1 /* TableSection+Extensions.swift */; };
|
||||||
|
|
@ -422,9 +383,12 @@
|
||||||
67CAF8C920652E2A00527085 /* TextFieldViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67CAF8C520652E2A00527085 /* TextFieldViewModel.swift */; };
|
67CAF8C920652E2A00527085 /* TextFieldViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67CAF8C520652E2A00527085 /* TextFieldViewModel.swift */; };
|
||||||
67CDEE401EB369BF00895905 /* ConfigurableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462241EB3396E00EAB194 /* ConfigurableController.swift */; };
|
67CDEE401EB369BF00895905 /* ConfigurableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 671462241EB3396E00EAB194 /* ConfigurableController.swift */; };
|
||||||
67DB7760210869D1001CB56B /* TableViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB775F210869D1001CB56B /* TableViewWrapperView.swift */; };
|
67DB7760210869D1001CB56B /* TableViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB775F210869D1001CB56B /* TableViewWrapperView.swift */; };
|
||||||
|
67DB7762210869D1001CB56B /* TableViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB775F210869D1001CB56B /* TableViewWrapperView.swift */; };
|
||||||
67DB776421086A12001CB56B /* BaseTableContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776321086A12001CB56B /* BaseTableContentController.swift */; };
|
67DB776421086A12001CB56B /* BaseTableContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776321086A12001CB56B /* BaseTableContentController.swift */; };
|
||||||
67DB776921087154001CB56B /* CollectionViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776821087154001CB56B /* CollectionViewWrapperView.swift */; };
|
67DB776921087154001CB56B /* CollectionViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776821087154001CB56B /* CollectionViewWrapperView.swift */; };
|
||||||
|
67DB776B21087154001CB56B /* CollectionViewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776821087154001CB56B /* CollectionViewWrapperView.swift */; };
|
||||||
67DB776D210871E8001CB56B /* BaseCollectionContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776C210871E8001CB56B /* BaseCollectionContentController.swift */; };
|
67DB776D210871E8001CB56B /* BaseCollectionContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776C210871E8001CB56B /* BaseCollectionContentController.swift */; };
|
||||||
|
67DB776F210871E8001CB56B /* BaseCollectionContentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67DB776C210871E8001CB56B /* BaseCollectionContentController.swift */; };
|
||||||
67E3524E2119ABE40035BDDB /* UITextField+ViewTextConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E3524D2119ABE40035BDDB /* UITextField+ViewTextConfigurable.swift */; };
|
67E3524E2119ABE40035BDDB /* UITextField+ViewTextConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E3524D2119ABE40035BDDB /* UITextField+ViewTextConfigurable.swift */; };
|
||||||
67E352502119ABE40035BDDB /* UITextField+ViewTextConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E3524D2119ABE40035BDDB /* UITextField+ViewTextConfigurable.swift */; };
|
67E352502119ABE40035BDDB /* UITextField+ViewTextConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E3524D2119ABE40035BDDB /* UITextField+ViewTextConfigurable.swift */; };
|
||||||
67E352522119AC060035BDDB /* UIButton+ViewTextConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E352512119AC060035BDDB /* UIButton+ViewTextConfigurable.swift */; };
|
67E352522119AC060035BDDB /* UIButton+ViewTextConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67E352512119AC060035BDDB /* UIButton+ViewTextConfigurable.swift */; };
|
||||||
|
|
@ -500,6 +464,25 @@
|
||||||
72AECC6C224A979D00D12E7C /* BaseSearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72AECC6A224A979D00D12E7C /* BaseSearchViewModel.swift */; };
|
72AECC6C224A979D00D12E7C /* BaseSearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72AECC6A224A979D00D12E7C /* BaseSearchViewModel.swift */; };
|
||||||
72AECC6F224A97B100D12E7C /* SearchResultsViewControllerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72AECC6E224A97B100D12E7C /* SearchResultsViewControllerState.swift */; };
|
72AECC6F224A97B100D12E7C /* SearchResultsViewControllerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72AECC6E224A97B100D12E7C /* SearchResultsViewControllerState.swift */; };
|
||||||
72AECC71224A97F100D12E7C /* SearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72AECC70224A97F000D12E7C /* SearchResultsViewController.swift */; };
|
72AECC71224A97F100D12E7C /* SearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72AECC70224A97F000D12E7C /* SearchResultsViewController.swift */; };
|
||||||
|
785EDF7C220072B500985ED4 /* SwiftDate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF76220072B400985ED4 /* SwiftDate.framework */; };
|
||||||
|
785EDF7D220072B500985ED4 /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF77220072B400985ED4 /* RxCocoa.framework */; };
|
||||||
|
785EDF7E220072B500985ED4 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF78220072B500985ED4 /* Alamofire.framework */; };
|
||||||
|
785EDF7F220072B500985ED4 /* RxAtomic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF79220072B500985ED4 /* RxAtomic.framework */; };
|
||||||
|
785EDF80220072B500985ED4 /* RxAlamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF7A220072B500985ED4 /* RxAlamofire.framework */; };
|
||||||
|
785EDF81220072B500985ED4 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF7B220072B500985ED4 /* RxSwift.framework */; };
|
||||||
|
785EDF8322007DF900985ED4 /* TableKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF8222007DF900985ED4 /* TableKit.framework */; };
|
||||||
|
785EDF8522007E5200985ED4 /* UIScrollView_InfiniteScroll.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF8422007E5200985ED4 /* UIScrollView_InfiniteScroll.framework */; };
|
||||||
|
785EDFA1220081F200985ED4 /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF9C220081F100985ED4 /* RxCocoa.framework */; };
|
||||||
|
785EDFA2220081F200985ED4 /* SwiftDate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF9D220081F100985ED4 /* SwiftDate.framework */; };
|
||||||
|
785EDFA3220081F200985ED4 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF9E220081F100985ED4 /* RxSwift.framework */; };
|
||||||
|
785EDFA4220081F200985ED4 /* RxAtomic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDF9F220081F100985ED4 /* RxAtomic.framework */; };
|
||||||
|
785EDFA5220081F200985ED4 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDFA0220081F100985ED4 /* Alamofire.framework */; };
|
||||||
|
785EDFB22200833100985ED4 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDFA8220082E600985ED4 /* Alamofire.framework */; };
|
||||||
|
785EDFB32200833100985ED4 /* RxAlamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDFA9220082E600985ED4 /* RxAlamofire.framework */; };
|
||||||
|
785EDFB42200833100985ED4 /* RxAtomic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDFAB220082E600985ED4 /* RxAtomic.framework */; };
|
||||||
|
785EDFB52200833100985ED4 /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDFA7220082E500985ED4 /* RxCocoa.framework */; };
|
||||||
|
785EDFB62200833100985ED4 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDFA6220082E500985ED4 /* RxSwift.framework */; };
|
||||||
|
785EDFB72200833100985ED4 /* SwiftDate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785EDFAA220082E600985ED4 /* SwiftDate.framework */; };
|
||||||
78EC7B1322019F5A0007DCFD /* String+TelpromptURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78EC7B1222019F5A0007DCFD /* String+TelpromptURL.swift */; };
|
78EC7B1322019F5A0007DCFD /* String+TelpromptURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78EC7B1222019F5A0007DCFD /* String+TelpromptURL.swift */; };
|
||||||
78EC7B1422019F5A0007DCFD /* String+TelpromptURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78EC7B1222019F5A0007DCFD /* String+TelpromptURL.swift */; };
|
78EC7B1422019F5A0007DCFD /* String+TelpromptURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78EC7B1222019F5A0007DCFD /* String+TelpromptURL.swift */; };
|
||||||
78EC7B1522019F5A0007DCFD /* String+TelpromptURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78EC7B1222019F5A0007DCFD /* String+TelpromptURL.swift */; };
|
78EC7B1522019F5A0007DCFD /* String+TelpromptURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78EC7B1222019F5A0007DCFD /* String+TelpromptURL.swift */; };
|
||||||
|
|
@ -510,6 +493,7 @@
|
||||||
82B4F8DD223903B800F6708C /* Block.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82B4F8DA223903B800F6708C /* Block.swift */; };
|
82B4F8DD223903B800F6708C /* Block.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82B4F8DA223903B800F6708C /* Block.swift */; };
|
||||||
82D2966D2264B1790067735C /* LabelTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82D2966A2264B1790067735C /* LabelTableViewCell.swift */; };
|
82D2966D2264B1790067735C /* LabelTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82D2966A2264B1790067735C /* LabelTableViewCell.swift */; };
|
||||||
82D2966F2264B1790067735C /* LabelCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82D2966C2264B1790067735C /* LabelCellViewModel.swift */; };
|
82D2966F2264B1790067735C /* LabelCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82D2966C2264B1790067735C /* LabelCellViewModel.swift */; };
|
||||||
|
82D296712264B4C10067735C /* SnapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82D296702264B4C10067735C /* SnapKit.framework */; };
|
||||||
82F8BB181F5DDED100C1061B /* Single+DeferredJust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F8BB171F5DDED100C1061B /* Single+DeferredJust.swift */; };
|
82F8BB181F5DDED100C1061B /* Single+DeferredJust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F8BB171F5DDED100C1061B /* Single+DeferredJust.swift */; };
|
||||||
8546C2E3224E86280059C255 /* ApiUploadRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8546C2E2224E86280059C255 /* ApiUploadRequestParameters.swift */; };
|
8546C2E3224E86280059C255 /* ApiUploadRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8546C2E2224E86280059C255 /* ApiUploadRequestParameters.swift */; };
|
||||||
8546C2E4224E86280059C255 /* ApiUploadRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8546C2E2224E86280059C255 /* ApiUploadRequestParameters.swift */; };
|
8546C2E4224E86280059C255 /* ApiUploadRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8546C2E2224E86280059C255 /* ApiUploadRequestParameters.swift */; };
|
||||||
|
|
@ -519,6 +503,14 @@
|
||||||
8546C2EA224E864F0059C255 /* Error+NetworkExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8546C2E7224E864F0059C255 /* Error+NetworkExtensions.swift */; };
|
8546C2EA224E864F0059C255 /* Error+NetworkExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8546C2E7224E864F0059C255 /* Error+NetworkExtensions.swift */; };
|
||||||
85A5D49522AA975000C7D254 /* Decimal+Rounding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A5D49422AA975000C7D254 /* Decimal+Rounding.swift */; };
|
85A5D49522AA975000C7D254 /* Decimal+Rounding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A5D49422AA975000C7D254 /* Decimal+Rounding.swift */; };
|
||||||
85A5D49C22AAB6B700C7D254 /* Decimal+Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A5D49B22AAB6B700C7D254 /* Decimal+Values.swift */; };
|
85A5D49C22AAB6B700C7D254 /* Decimal+Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85A5D49B22AAB6B700C7D254 /* Decimal+Values.swift */; };
|
||||||
|
85C343BC22B7B32400D9FAA5 /* NetworkErrorHandlingType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C343BB22B7B32400D9FAA5 /* NetworkErrorHandlingType.swift */; };
|
||||||
|
85C343BE22B7B34D00D9FAA5 /* NetworkErrorAlertBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C343BD22B7B34D00D9FAA5 /* NetworkErrorAlertBase.swift */; };
|
||||||
|
85C343C022B7B55800D9FAA5 /* NetworkErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C343BF22B7B55800D9FAA5 /* NetworkErrorHandler.swift */; };
|
||||||
|
85C343C122B7BD3200D9FAA5 /* NetworkErrorHandlingType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C343BB22B7B32400D9FAA5 /* NetworkErrorHandlingType.swift */; };
|
||||||
|
85C343C222B7BD3600D9FAA5 /* NetworkErrorHandlingType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C343BB22B7B32400D9FAA5 /* NetworkErrorHandlingType.swift */; };
|
||||||
|
85C343C422B7CC3600D9FAA5 /* Observable+NetworkErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C343C322B7CC3600D9FAA5 /* Observable+NetworkErrorHandling.swift */; };
|
||||||
|
85C343C622B7CE9C00D9FAA5 /* Completable+NetworkErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C343C522B7CE9C00D9FAA5 /* Completable+NetworkErrorHandling.swift */; };
|
||||||
|
85C343C822B7CEE200D9FAA5 /* Single+NetworkErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85C343C722B7CEE200D9FAA5 /* Single+NetworkErrorHandling.swift */; };
|
||||||
A658E54D1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54C1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift */; };
|
A658E54D1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54C1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift */; };
|
||||||
A658E5501F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54F1F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift */; };
|
A658E5501F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A658E54F1F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift */; };
|
||||||
A676AE481F97D28A001F9214 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A676AE471F97D28A001F9214 /* String+Extensions.swift */; };
|
A676AE481F97D28A001F9214 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A676AE471F97D28A001F9214 /* String+Extensions.swift */; };
|
||||||
|
|
@ -564,30 +556,6 @@
|
||||||
36FE776F20F669E300284C09 /* String+ConvertToHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+ConvertToHost.swift"; sourceTree = "<group>"; };
|
36FE776F20F669E300284C09 /* String+ConvertToHost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+ConvertToHost.swift"; sourceTree = "<group>"; };
|
||||||
40F118461F8FEF97004AADAF /* AppearanceConfigurable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceConfigurable.swift; sourceTree = "<group>"; };
|
40F118461F8FEF97004AADAF /* AppearanceConfigurable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceConfigurable.swift; sourceTree = "<group>"; };
|
||||||
40F118481F8FF223004AADAF /* TableRow+AppearanceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TableRow+AppearanceExtension.swift"; sourceTree = "<group>"; };
|
40F118481F8FF223004AADAF /* TableRow+AppearanceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TableRow+AppearanceExtension.swift"; sourceTree = "<group>"; };
|
||||||
411073AE23466B41002DD9B9 /* UIViewController+PresentFullScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+PresentFullScreen.swift"; sourceTree = "<group>"; };
|
|
||||||
4C4C7B46267FE275006F3C70 /* Build */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Build; path = Carthage/Build; sourceTree = "<group>"; };
|
|
||||||
4C4C7B47267FE27E006F3C70 /* RxAlamofire.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = RxAlamofire.xcframework; path = Carthage/Build/RxAlamofire.xcframework; sourceTree = "<group>"; };
|
|
||||||
4C4C7B48267FE27E006F3C70 /* TableKit.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = TableKit.xcframework; path = Carthage/Build/TableKit.xcframework; sourceTree = "<group>"; };
|
|
||||||
4C4C7B49267FE27E006F3C70 /* RxSwift.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = RxSwift.xcframework; path = Carthage/Build/RxSwift.xcframework; sourceTree = "<group>"; };
|
|
||||||
4C4C7B4A267FE27E006F3C70 /* UIScrollView_InfiniteScroll.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = UIScrollView_InfiniteScroll.xcframework; path = Carthage/Build/UIScrollView_InfiniteScroll.xcframework; sourceTree = "<group>"; };
|
|
||||||
4C4C7B4B267FE27E006F3C70 /* SnapKit.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = SnapKit.xcframework; path = Carthage/Build/SnapKit.xcframework; sourceTree = "<group>"; };
|
|
||||||
4C4C7B4C267FE27E006F3C70 /* RxRelay.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = RxRelay.xcframework; path = Carthage/Build/RxRelay.xcframework; sourceTree = "<group>"; };
|
|
||||||
4C4C7B4D267FE27E006F3C70 /* Alamofire.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Alamofire.xcframework; path = Carthage/Build/Alamofire.xcframework; sourceTree = "<group>"; };
|
|
||||||
4C4C7B4E267FE27E006F3C70 /* SwiftDate.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = SwiftDate.xcframework; path = Carthage/Build/SwiftDate.xcframework; sourceTree = "<group>"; };
|
|
||||||
4C4C7B4F267FE27E006F3C70 /* RxBlocking.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = RxBlocking.xcframework; path = Carthage/Build/RxBlocking.xcframework; sourceTree = "<group>"; };
|
|
||||||
4C4C7B50267FE27E006F3C70 /* RxTest.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = RxTest.xcframework; path = Carthage/Build/RxTest.xcframework; sourceTree = "<group>"; };
|
|
||||||
4C4C7B51267FE27E006F3C70 /* RxCocoa.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = RxCocoa.xcframework; path = Carthage/Build/RxCocoa.xcframework; sourceTree = "<group>"; };
|
|
||||||
4CF65D1324DD684A0006B001 /* ButtonHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonHolder.swift; sourceTree = "<group>"; };
|
|
||||||
4CF65D1524DD69250006B001 /* UIButton+ButtonHolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+ButtonHolder.swift"; sourceTree = "<group>"; };
|
|
||||||
4CF65D1724DD6C080006B001 /* ButtonHolderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonHolderView.swift; sourceTree = "<group>"; };
|
|
||||||
52421F8C24EAB52E00948DD1 /* ContainerTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContainerTableCell.swift; sourceTree = "<group>"; };
|
|
||||||
52421F8E24EAB84900948DD1 /* BaseRxTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseRxTableViewCell.swift; sourceTree = "<group>"; };
|
|
||||||
52421F9324EBCFAE00948DD1 /* VoidTappableViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoidTappableViewModel.swift; sourceTree = "<group>"; };
|
|
||||||
52421F9524EBCFBB00948DD1 /* BaseTappableViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTappableViewModel.swift; sourceTree = "<group>"; };
|
|
||||||
5E23631E25263EFA00E2F96B /* BaseOrientationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseOrientationController.swift; sourceTree = "<group>"; };
|
|
||||||
5E2364172526489A00E2F96B /* UIInterfaceOrientation+ VideoOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIInterfaceOrientation+ VideoOrientation.swift"; sourceTree = "<group>"; };
|
|
||||||
5ED2C0B1251A354E00D4E258 /* BaseOrientationNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseOrientationNavigationController.swift; sourceTree = "<group>"; };
|
|
||||||
5ED2C0B4251A366700D4E258 /* UIDevice+ScreenOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+ScreenOrientation.swift"; sourceTree = "<group>"; };
|
|
||||||
67051ADA1EBC7C36008EADC0 /* SpinnerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinnerView.swift; sourceTree = "<group>"; };
|
67051ADA1EBC7C36008EADC0 /* SpinnerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinnerView.swift; sourceTree = "<group>"; };
|
||||||
6713C23620AF0C4D00875921 /* NetworkOperationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkOperationState.swift; sourceTree = "<group>"; };
|
6713C23620AF0C4D00875921 /* NetworkOperationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkOperationState.swift; sourceTree = "<group>"; };
|
||||||
6713C23B20AF0D5900875921 /* NetworkOperationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkOperationModel.swift; sourceTree = "<group>"; };
|
6713C23B20AF0D5900875921 /* NetworkOperationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkOperationModel.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -613,10 +581,12 @@
|
||||||
671461F11EB3396E00EAB194 /* Observable+DeferredJust.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+DeferredJust.swift"; sourceTree = "<group>"; };
|
671461F11EB3396E00EAB194 /* Observable+DeferredJust.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Observable+DeferredJust.swift"; sourceTree = "<group>"; };
|
||||||
671461F61EB3396E00EAB194 /* Sequence+ConcurrentMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Sequence+ConcurrentMap.swift"; sourceTree = "<group>"; };
|
671461F61EB3396E00EAB194 /* Sequence+ConcurrentMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Sequence+ConcurrentMap.swift"; sourceTree = "<group>"; };
|
||||||
671461FC1EB3396E00EAB194 /* String+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Localization.swift"; sourceTree = "<group>"; };
|
671461FC1EB3396E00EAB194 /* String+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Localization.swift"; sourceTree = "<group>"; };
|
||||||
|
671461FF1EB3396E00EAB194 /* UIScrollView+Support.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Support.swift"; sourceTree = "<group>"; };
|
||||||
671462011EB3396E00EAB194 /* TableDirector+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TableDirector+Extensions.swift"; sourceTree = "<group>"; };
|
671462011EB3396E00EAB194 /* TableDirector+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TableDirector+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
671462031EB3396E00EAB194 /* TimeInterval+DateComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TimeInterval+DateComponents.swift"; sourceTree = "<group>"; };
|
671462031EB3396E00EAB194 /* TimeInterval+DateComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TimeInterval+DateComponents.swift"; sourceTree = "<group>"; };
|
||||||
671462091EB3396E00EAB194 /* UIColor+Hex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Hex.swift"; sourceTree = "<group>"; };
|
671462091EB3396E00EAB194 /* UIColor+Hex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Hex.swift"; sourceTree = "<group>"; };
|
||||||
6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extensions.swift"; sourceTree = "<group>"; };
|
6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
|
6714620E1EB3396E00EAB194 /* UIImage+SupportExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+SupportExtensions.swift"; sourceTree = "<group>"; };
|
||||||
671462131EB3396E00EAB194 /* UIView+XibNameProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+XibNameProtocol.swift"; sourceTree = "<group>"; };
|
671462131EB3396E00EAB194 /* UIView+XibNameProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+XibNameProtocol.swift"; sourceTree = "<group>"; };
|
||||||
671462141EB3396E00EAB194 /* UIView+LoadFromNib.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+LoadFromNib.swift"; sourceTree = "<group>"; };
|
671462141EB3396E00EAB194 /* UIView+LoadFromNib.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+LoadFromNib.swift"; sourceTree = "<group>"; };
|
||||||
671462151EB3396E00EAB194 /* UIView+LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+LoadingIndicator.swift"; sourceTree = "<group>"; };
|
671462151EB3396E00EAB194 /* UIView+LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+LoadingIndicator.swift"; sourceTree = "<group>"; };
|
||||||
|
|
@ -816,6 +786,12 @@
|
||||||
8546C2E7224E864F0059C255 /* Error+NetworkExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Error+NetworkExtensions.swift"; sourceTree = "<group>"; };
|
8546C2E7224E864F0059C255 /* Error+NetworkExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Error+NetworkExtensions.swift"; sourceTree = "<group>"; };
|
||||||
85A5D49422AA975000C7D254 /* Decimal+Rounding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Decimal+Rounding.swift"; sourceTree = "<group>"; };
|
85A5D49422AA975000C7D254 /* Decimal+Rounding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Decimal+Rounding.swift"; sourceTree = "<group>"; };
|
||||||
85A5D49B22AAB6B700C7D254 /* Decimal+Values.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Decimal+Values.swift"; sourceTree = "<group>"; };
|
85A5D49B22AAB6B700C7D254 /* Decimal+Values.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Decimal+Values.swift"; sourceTree = "<group>"; };
|
||||||
|
85C343BB22B7B32400D9FAA5 /* NetworkErrorHandlingType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkErrorHandlingType.swift; sourceTree = "<group>"; };
|
||||||
|
85C343BD22B7B34D00D9FAA5 /* NetworkErrorAlertBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkErrorAlertBase.swift; sourceTree = "<group>"; };
|
||||||
|
85C343BF22B7B55800D9FAA5 /* NetworkErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkErrorHandler.swift; sourceTree = "<group>"; };
|
||||||
|
85C343C322B7CC3600D9FAA5 /* Observable+NetworkErrorHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Observable+NetworkErrorHandling.swift"; sourceTree = "<group>"; };
|
||||||
|
85C343C522B7CE9C00D9FAA5 /* Completable+NetworkErrorHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Completable+NetworkErrorHandling.swift"; sourceTree = "<group>"; };
|
||||||
|
85C343C722B7CEE200D9FAA5 /* Single+NetworkErrorHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Single+NetworkErrorHandling.swift"; sourceTree = "<group>"; };
|
||||||
A658E54C1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TableRow+SeparatorsExtensions.swift"; sourceTree = "<group>"; };
|
A658E54C1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TableRow+SeparatorsExtensions.swift"; sourceTree = "<group>"; };
|
||||||
A658E54F1F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+SeparatorRowBoxExtensions.swift"; sourceTree = "<group>"; };
|
A658E54F1F8CD9350093527A /* Array+SeparatorRowBoxExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+SeparatorRowBoxExtensions.swift"; sourceTree = "<group>"; };
|
||||||
A66428A61F8A653600C6308D /* SeparatorCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorCell.swift; sourceTree = "<group>"; };
|
A66428A61F8A653600C6308D /* SeparatorCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorCell.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -846,17 +822,15 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
4C4C7BCB267FE509006F3C70 /* RxTest.xcframework in Frameworks */,
|
785EDF7E220072B500985ED4 /* Alamofire.framework in Frameworks */,
|
||||||
4C4C7BC1267FE508006F3C70 /* RxAlamofire.xcframework in Frameworks */,
|
785EDF81220072B500985ED4 /* RxSwift.framework in Frameworks */,
|
||||||
4C4C7BC5267FE508006F3C70 /* RxCocoa.xcframework in Frameworks */,
|
785EDF7F220072B500985ED4 /* RxAtomic.framework in Frameworks */,
|
||||||
4C4C7BCF267FE509006F3C70 /* SwiftDate.xcframework in Frameworks */,
|
785EDF7D220072B500985ED4 /* RxCocoa.framework in Frameworks */,
|
||||||
4C4C7BC3267FE508006F3C70 /* RxBlocking.xcframework in Frameworks */,
|
785EDF80220072B500985ED4 /* RxAlamofire.framework in Frameworks */,
|
||||||
4C4C7BCD267FE509006F3C70 /* SnapKit.xcframework in Frameworks */,
|
82D296712264B4C10067735C /* SnapKit.framework in Frameworks */,
|
||||||
4C4C7BC9267FE509006F3C70 /* RxSwift.xcframework in Frameworks */,
|
785EDF7C220072B500985ED4 /* SwiftDate.framework in Frameworks */,
|
||||||
4C4C7BD1267FE509006F3C70 /* TableKit.xcframework in Frameworks */,
|
785EDF8322007DF900985ED4 /* TableKit.framework in Frameworks */,
|
||||||
4C4C7BD3267FE509006F3C70 /* UIScrollView_InfiniteScroll.xcframework in Frameworks */,
|
785EDF8522007E5200985ED4 /* UIScrollView_InfiniteScroll.framework in Frameworks */,
|
||||||
4C4C7BC7267FE509006F3C70 /* RxRelay.xcframework in Frameworks */,
|
|
||||||
4C4C7BBF267FE508006F3C70 /* Alamofire.xcframework in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -864,13 +838,11 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
4C4C7B56267FE27E006F3C70 /* RxSwift.xcframework in Frameworks */,
|
785EDFA5220081F200985ED4 /* Alamofire.framework in Frameworks */,
|
||||||
4C4C7B62267FE27E006F3C70 /* RxBlocking.xcframework in Frameworks */,
|
785EDFA4220081F200985ED4 /* RxAtomic.framework in Frameworks */,
|
||||||
4C4C7B52267FE27E006F3C70 /* RxAlamofire.xcframework in Frameworks */,
|
785EDFA1220081F200985ED4 /* RxCocoa.framework in Frameworks */,
|
||||||
4C4C7B66267FE27F006F3C70 /* RxCocoa.xcframework in Frameworks */,
|
785EDFA2220081F200985ED4 /* SwiftDate.framework in Frameworks */,
|
||||||
4C4C7B5C267FE27E006F3C70 /* RxRelay.xcframework in Frameworks */,
|
785EDFA3220081F200985ED4 /* RxSwift.framework in Frameworks */,
|
||||||
4C4C7B5E267FE27E006F3C70 /* Alamofire.xcframework in Frameworks */,
|
|
||||||
4C4C7B60267FE27E006F3C70 /* SwiftDate.xcframework in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -878,15 +850,12 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
4C4C7B96267FE365006F3C70 /* RxTest.xcframework in Frameworks */,
|
785EDFB22200833100985ED4 /* Alamofire.framework in Frameworks */,
|
||||||
4C4C7B8C267FE364006F3C70 /* RxAlamofire.xcframework in Frameworks */,
|
785EDFB42200833100985ED4 /* RxAtomic.framework in Frameworks */,
|
||||||
4C4C7B90267FE365006F3C70 /* RxCocoa.xcframework in Frameworks */,
|
785EDFB62200833100985ED4 /* RxSwift.framework in Frameworks */,
|
||||||
4C4C7B9A267FE365006F3C70 /* SwiftDate.xcframework in Frameworks */,
|
785EDFB52200833100985ED4 /* RxCocoa.framework in Frameworks */,
|
||||||
4C4C7B8E267FE365006F3C70 /* RxBlocking.xcframework in Frameworks */,
|
785EDFB32200833100985ED4 /* RxAlamofire.framework in Frameworks */,
|
||||||
4C4C7B98267FE365006F3C70 /* SnapKit.xcframework in Frameworks */,
|
785EDFB72200833100985ED4 /* SwiftDate.framework in Frameworks */,
|
||||||
4C4C7B94267FE365006F3C70 /* RxSwift.xcframework in Frameworks */,
|
|
||||||
4C4C7B92267FE365006F3C70 /* RxRelay.xcframework in Frameworks */,
|
|
||||||
4C4C7B8A267FE364006F3C70 /* Alamofire.xcframework in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -902,64 +871,6 @@
|
||||||
path = UITableView;
|
path = UITableView;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
4CF65D1924DD6C3D0006B001 /* ButtonHolder */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
4CF65D1324DD684A0006B001 /* ButtonHolder.swift */,
|
|
||||||
4CF65D1724DD6C080006B001 /* ButtonHolderView.swift */,
|
|
||||||
);
|
|
||||||
path = ButtonHolder;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
52421F8B24EAB52E00948DD1 /* ContainerTableCell */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
52421F8C24EAB52E00948DD1 /* ContainerTableCell.swift */,
|
|
||||||
);
|
|
||||||
path = ContainerTableCell;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
52421F9024EAB84E00948DD1 /* BaseRxTableViewCell */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
52421F8E24EAB84900948DD1 /* BaseRxTableViewCell.swift */,
|
|
||||||
);
|
|
||||||
path = BaseRxTableViewCell;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
52421F9124EBCF6E00948DD1 /* ViewModels */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
52421F9224EBCF8600948DD1 /* TappableViewModel */,
|
|
||||||
);
|
|
||||||
path = ViewModels;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
52421F9224EBCF8600948DD1 /* TappableViewModel */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
52421F9524EBCFBB00948DD1 /* BaseTappableViewModel.swift */,
|
|
||||||
52421F9324EBCFAE00948DD1 /* VoidTappableViewModel.swift */,
|
|
||||||
);
|
|
||||||
path = TappableViewModel;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
5E2364162526488300E2F96B /* UIInterfaceOrientation */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
5E2364172526489A00E2F96B /* UIInterfaceOrientation+ VideoOrientation.swift */,
|
|
||||||
);
|
|
||||||
path = UIInterfaceOrientation;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
5ED2C0B3251A365800D4E258 /* UIDevice */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
5ED2C0B4251A366700D4E258 /* UIDevice+ScreenOrientation.swift */,
|
|
||||||
);
|
|
||||||
path = UIDevice;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
671461C41EB3396E00EAB194 /* Classes */ = {
|
671461C41EB3396E00EAB194 /* Classes */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
@ -968,7 +879,6 @@
|
||||||
6774527E2062566D0024EEEF /* DataLoading */,
|
6774527E2062566D0024EEEF /* DataLoading */,
|
||||||
671461D21EB3396E00EAB194 /* Services */,
|
671461D21EB3396E00EAB194 /* Services */,
|
||||||
671461D41EB3396E00EAB194 /* Views */,
|
671461D41EB3396E00EAB194 /* Views */,
|
||||||
52421F9124EBCF6E00948DD1 /* ViewModels */,
|
|
||||||
);
|
);
|
||||||
path = Classes;
|
path = Classes;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -1006,8 +916,6 @@
|
||||||
671461D41EB3396E00EAB194 /* Views */ = {
|
671461D41EB3396E00EAB194 /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
52421F9024EAB84E00948DD1 /* BaseRxTableViewCell */,
|
|
||||||
52421F8B24EAB52E00948DD1 /* ContainerTableCell */,
|
|
||||||
72005A1A2266226800ECE090 /* CustomizableButton */,
|
72005A1A2266226800ECE090 /* CustomizableButton */,
|
||||||
677B06B6211873E7006C947D /* BasePlaceholderView */,
|
677B06B6211873E7006C947D /* BasePlaceholderView */,
|
||||||
67DB77672108714A001CB56B /* CollectionViewWrapperView */,
|
67DB77672108714A001CB56B /* CollectionViewWrapperView */,
|
||||||
|
|
@ -1032,6 +940,7 @@
|
||||||
72AECC6D224A97B100D12E7C /* Search */,
|
72AECC6D224A97B100D12E7C /* Search */,
|
||||||
6774528A20625C860024EEEF /* DataLoading */,
|
6774528A20625C860024EEEF /* DataLoading */,
|
||||||
671461D81EB3396E00EAB194 /* LeadKitError.swift */,
|
671461D81EB3396E00EAB194 /* LeadKitError.swift */,
|
||||||
|
85C343BB22B7B32400D9FAA5 /* NetworkErrorHandlingType.swift */,
|
||||||
671461D91EB3396E00EAB194 /* ResizeMode.swift */,
|
671461D91EB3396E00EAB194 /* ResizeMode.swift */,
|
||||||
67FDC25E1FA310EA00C76A77 /* RequestError.swift */,
|
67FDC25E1FA310EA00C76A77 /* RequestError.swift */,
|
||||||
7295473E21E661E6009558E7 /* TitleType.swift */,
|
7295473E21E661E6009558E7 /* TitleType.swift */,
|
||||||
|
|
@ -1042,7 +951,6 @@
|
||||||
671461DA1EB3396E00EAB194 /* Extensions */ = {
|
671461DA1EB3396E00EAB194 /* Extensions */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
5E2364162526488300E2F96B /* UIInterfaceOrientation */,
|
|
||||||
6732F23C214C09DF00B446F2 /* Foundation */,
|
6732F23C214C09DF00B446F2 /* Foundation */,
|
||||||
671461DB1EB3396E00EAB194 /* Alamofire */,
|
671461DB1EB3396E00EAB194 /* Alamofire */,
|
||||||
EFBE57CE1EC35ED90040E00A /* Array */,
|
EFBE57CE1EC35ED90040E00A /* Array */,
|
||||||
|
|
@ -1156,6 +1064,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
7295474121E6628C009558E7 /* UINavigationItem+Support.swift */,
|
7295474121E6628C009558E7 /* UINavigationItem+Support.swift */,
|
||||||
|
671461FF1EB3396E00EAB194 /* UIScrollView+Support.swift */,
|
||||||
);
|
);
|
||||||
path = Support;
|
path = Support;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -1190,6 +1099,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */,
|
6714620D1EB3396E00EAB194 /* UIImage+Extensions.swift */,
|
||||||
|
6714620E1EB3396E00EAB194 /* UIImage+SupportExtensions.swift */,
|
||||||
);
|
);
|
||||||
path = UIImage;
|
path = UIImage;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -1214,7 +1124,6 @@
|
||||||
671462191EB3396E00EAB194 /* UIViewController+DefaultXibName.swift */,
|
671462191EB3396E00EAB194 /* UIViewController+DefaultXibName.swift */,
|
||||||
6714621A1EB3396E00EAB194 /* UIViewController+TopVisibleViewController.swift */,
|
6714621A1EB3396E00EAB194 /* UIViewController+TopVisibleViewController.swift */,
|
||||||
7295474321E66328009558E7 /* UIViewController+UpdateNavigationItemTitle.swift */,
|
7295474321E66328009558E7 /* UIViewController+UpdateNavigationItemTitle.swift */,
|
||||||
411073AE23466B41002DD9B9 /* UIViewController+PresentFullScreen.swift */,
|
|
||||||
);
|
);
|
||||||
path = UIViewController;
|
path = UIViewController;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -1248,6 +1157,7 @@
|
||||||
671462331EB3396E00EAB194 /* ConfigurableView.swift */,
|
671462331EB3396E00EAB194 /* ConfigurableView.swift */,
|
||||||
36BCEFAC229313FF00D5A37E /* Initializable.swift */,
|
36BCEFAC229313FF00D5A37E /* Initializable.swift */,
|
||||||
671462281EB3396E00EAB194 /* LoadingIndicator.swift */,
|
671462281EB3396E00EAB194 /* LoadingIndicator.swift */,
|
||||||
|
85C343BF22B7B55800D9FAA5 /* NetworkErrorHandler.swift */,
|
||||||
A676AE541F981121001F9214 /* ObservableMappable.swift */,
|
A676AE541F981121001F9214 /* ObservableMappable.swift */,
|
||||||
6714622B1EB3396E00EAB194 /* ResettableType.swift */,
|
6714622B1EB3396E00EAB194 /* ResettableType.swift */,
|
||||||
6714622C1EB3396E00EAB194 /* ReuseIdentifierProtocol.swift */,
|
6714622C1EB3396E00EAB194 /* ReuseIdentifierProtocol.swift */,
|
||||||
|
|
@ -1426,7 +1336,6 @@
|
||||||
672947E0206EA36B00AC6B6B /* UIKit */ = {
|
672947E0206EA36B00AC6B6B /* UIKit */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
5ED2C0B3251A365800D4E258 /* UIDevice */,
|
|
||||||
6741CEB220E242B600FEC4D9 /* CollectionViewHolder */,
|
6741CEB220E242B600FEC4D9 /* CollectionViewHolder */,
|
||||||
6741CEAD20E2428A00FEC4D9 /* TableViewHolder */,
|
6741CEAD20E2428A00FEC4D9 /* TableViewHolder */,
|
||||||
674AF55A1EC45B1600038A8F /* UIActivityIndicatorView */,
|
674AF55A1EC45B1600038A8F /* UIActivityIndicatorView */,
|
||||||
|
|
@ -1537,7 +1446,6 @@
|
||||||
6741CE9F20E2413300FEC4D9 /* UIKit */ = {
|
6741CE9F20E2413300FEC4D9 /* UIKit */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
4CF65D1924DD6C3D0006B001 /* ButtonHolder */,
|
|
||||||
6741CEA020E2416C00FEC4D9 /* ScrollViewHolder.swift */,
|
6741CEA020E2416C00FEC4D9 /* ScrollViewHolder.swift */,
|
||||||
6741CEA420E2418200FEC4D9 /* TableViewHolder.swift */,
|
6741CEA420E2418200FEC4D9 /* TableViewHolder.swift */,
|
||||||
6741CEA820E2418B00FEC4D9 /* CollectionViewHolder.swift */,
|
6741CEA820E2418B00FEC4D9 /* CollectionViewHolder.swift */,
|
||||||
|
|
@ -1587,8 +1495,6 @@
|
||||||
6741CECC20E243F800FEC4D9 /* BaseCustomViewController.swift */,
|
6741CECC20E243F800FEC4D9 /* BaseCustomViewController.swift */,
|
||||||
675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */,
|
675E0AA821072FF400CDC143 /* BaseScrollContentController.swift */,
|
||||||
67DB776321086A12001CB56B /* BaseTableContentController.swift */,
|
67DB776321086A12001CB56B /* BaseTableContentController.swift */,
|
||||||
5ED2C0B1251A354E00D4E258 /* BaseOrientationNavigationController.swift */,
|
|
||||||
5E23631E25263EFA00E2F96B /* BaseOrientationController.swift */,
|
|
||||||
);
|
);
|
||||||
path = Controllers;
|
path = Controllers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -1652,6 +1558,7 @@
|
||||||
671461C71EB3396E00EAB194 /* Cursors */,
|
671461C71EB3396E00EAB194 /* Cursors */,
|
||||||
6774529620625DA80024EEEF /* GeneralDataLoading */,
|
6774529620625DA80024EEEF /* GeneralDataLoading */,
|
||||||
671461CF1EB3396E00EAB194 /* PaginationDataLoading */,
|
671461CF1EB3396E00EAB194 /* PaginationDataLoading */,
|
||||||
|
85C343BD22B7B34D00D9FAA5 /* NetworkErrorAlertBase.swift */,
|
||||||
6774527F206256A20024EEEF /* RxDataLoadingModel.swift */,
|
6774527F206256A20024EEEF /* RxDataLoadingModel.swift */,
|
||||||
6713C24020AF189100875921 /* RxNetworkOperationModel.swift */,
|
6713C24020AF189100875921 /* RxNetworkOperationModel.swift */,
|
||||||
);
|
);
|
||||||
|
|
@ -1756,6 +1663,7 @@
|
||||||
children = (
|
children = (
|
||||||
671461F11EB3396E00EAB194 /* Observable+DeferredJust.swift */,
|
671461F11EB3396E00EAB194 /* Observable+DeferredJust.swift */,
|
||||||
677B06A521186AFE006C947D /* ObservableType+Extensions.swift */,
|
677B06A521186AFE006C947D /* ObservableType+Extensions.swift */,
|
||||||
|
85C343C322B7CC3600D9FAA5 /* Observable+NetworkErrorHandling.swift */,
|
||||||
);
|
);
|
||||||
path = ObservableType;
|
path = ObservableType;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -1773,6 +1681,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
677B06B121186C14006C947D /* Completable+DeferredJust.swift */,
|
677B06B121186C14006C947D /* Completable+DeferredJust.swift */,
|
||||||
|
85C343C522B7CE9C00D9FAA5 /* Completable+NetworkErrorHandling.swift */,
|
||||||
);
|
);
|
||||||
path = Completable;
|
path = Completable;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -1952,7 +1861,6 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
67E352512119AC060035BDDB /* UIButton+ViewTextConfigurable.swift */,
|
67E352512119AC060035BDDB /* UIButton+ViewTextConfigurable.swift */,
|
||||||
4CF65D1524DD69250006B001 /* UIButton+ButtonHolder.swift */,
|
|
||||||
);
|
);
|
||||||
path = UIButton;
|
path = UIButton;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -2063,18 +1971,6 @@
|
||||||
785EDF75220072B400985ED4 /* Frameworks */ = {
|
785EDF75220072B400985ED4 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
4C4C7B4D267FE27E006F3C70 /* Alamofire.xcframework */,
|
|
||||||
4C4C7B47267FE27E006F3C70 /* RxAlamofire.xcframework */,
|
|
||||||
4C4C7B4F267FE27E006F3C70 /* RxBlocking.xcframework */,
|
|
||||||
4C4C7B51267FE27E006F3C70 /* RxCocoa.xcframework */,
|
|
||||||
4C4C7B4C267FE27E006F3C70 /* RxRelay.xcframework */,
|
|
||||||
4C4C7B49267FE27E006F3C70 /* RxSwift.xcframework */,
|
|
||||||
4C4C7B50267FE27E006F3C70 /* RxTest.xcframework */,
|
|
||||||
4C4C7B4B267FE27E006F3C70 /* SnapKit.xcframework */,
|
|
||||||
4C4C7B4E267FE27E006F3C70 /* SwiftDate.xcframework */,
|
|
||||||
4C4C7B48267FE27E006F3C70 /* TableKit.xcframework */,
|
|
||||||
4C4C7B4A267FE27E006F3C70 /* UIScrollView_InfiniteScroll.xcframework */,
|
|
||||||
4C4C7B46267FE275006F3C70 /* Build */,
|
|
||||||
82D296702264B4C10067735C /* SnapKit.framework */,
|
82D296702264B4C10067735C /* SnapKit.framework */,
|
||||||
785EDFA0220081F100985ED4 /* Alamofire.framework */,
|
785EDFA0220081F100985ED4 /* Alamofire.framework */,
|
||||||
785EDF9F220081F100985ED4 /* RxAtomic.framework */,
|
785EDF9F220081F100985ED4 /* RxAtomic.framework */,
|
||||||
|
|
@ -2135,6 +2031,7 @@
|
||||||
children = (
|
children = (
|
||||||
82F8BB171F5DDED100C1061B /* Single+DeferredJust.swift */,
|
82F8BB171F5DDED100C1061B /* Single+DeferredJust.swift */,
|
||||||
677B06AA21186BB6006C947D /* Single+Extensions.swift */,
|
677B06AA21186BB6006C947D /* Single+Extensions.swift */,
|
||||||
|
85C343C722B7CEE200D9FAA5 /* Single+NetworkErrorHandling.swift */,
|
||||||
);
|
);
|
||||||
path = Single;
|
path = Single;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -2340,7 +2237,7 @@
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastSwiftUpdateCheck = 0830;
|
LastSwiftUpdateCheck = 0830;
|
||||||
LastUpgradeCheck = 1230;
|
LastUpgradeCheck = 1020;
|
||||||
ORGANIZATIONNAME = "Touch Instinct";
|
ORGANIZATIONNAME = "Touch Instinct";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
67186B271EB248F100CFAFFB = {
|
67186B271EB248F100CFAFFB = {
|
||||||
|
|
@ -2364,7 +2261,7 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = 78CFEE241C5C456B00F50370 /* Build configuration list for PBXProject "LeadKit" */;
|
buildConfigurationList = 78CFEE241C5C456B00F50370 /* Build configuration list for PBXProject "LeadKit" */;
|
||||||
compatibilityVersion = "Xcode 12.0";
|
compatibilityVersion = "Xcode 3.2";
|
||||||
developmentRegion = en;
|
developmentRegion = en;
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
|
|
@ -2420,7 +2317,7 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = ". run_swiftlint.sh\n";
|
shellScript = "CONFIG_PATH=${PROJECT_DIR}/build-scripts/xcode/.swiftlint.yml\n\nif which swiftlint >/dev/null; then\nswiftlint autocorrect --path Sources --config ${CONFIG_PATH} && swiftlint --path Sources --config ${CONFIG_PATH}\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||||
};
|
};
|
||||||
6782BBBC1EB31ED90086E0B8 /* SwiftLint */ = {
|
6782BBBC1EB31ED90086E0B8 /* SwiftLint */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
|
@ -2434,7 +2331,7 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = ". run_swiftlint.sh\n";
|
shellScript = "CONFIG_PATH=${PROJECT_DIR}/build-scripts/xcode/.swiftlint.yml\n\nif which swiftlint >/dev/null; then\nswiftlint autocorrect --path Sources --config ${CONFIG_PATH} && swiftlint --path Sources --config ${CONFIG_PATH}\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||||
};
|
};
|
||||||
6782BBBE1EB31F210086E0B8 /* SwiftLint */ = {
|
6782BBBE1EB31F210086E0B8 /* SwiftLint */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
|
@ -2448,7 +2345,7 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = ". run_swiftlint.sh\n";
|
shellScript = "CONFIG_PATH=${PROJECT_DIR}/build-scripts/xcode/.swiftlint.yml\n\nif which swiftlint >/dev/null; then\nswiftlint autocorrect --path Sources --config ${CONFIG_PATH} && swiftlint --path Sources --config ${CONFIG_PATH}\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||||
};
|
};
|
||||||
67887A0E1ECC856F008A9E1D /* CopyPaste Detection */ = {
|
67887A0E1ECC856F008A9E1D /* CopyPaste Detection */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
|
@ -2515,10 +2412,8 @@
|
||||||
678D26A420692BFF00B05B93 /* TextFieldViewModelEvents.swift in Sources */,
|
678D26A420692BFF00B05B93 /* TextFieldViewModelEvents.swift in Sources */,
|
||||||
671462801EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */,
|
671462801EB3396E00EAB194 /* DataRequest+Extensions.swift in Sources */,
|
||||||
67EB7FF8206175F700BDD9FB /* PaginationWrappable.swift in Sources */,
|
67EB7FF8206175F700BDD9FB /* PaginationWrappable.swift in Sources */,
|
||||||
52421F9624EBCFBB00948DD1 /* BaseTappableViewModel.swift in Sources */,
|
|
||||||
67990AD6213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift in Sources */,
|
67990AD6213EA6A50040D195 /* ContentLoadingViewModel+Extensions.swift in Sources */,
|
||||||
671463541EB3396E00EAB194 /* StaticViewHeightProtocol.swift in Sources */,
|
671463541EB3396E00EAB194 /* StaticViewHeightProtocol.swift in Sources */,
|
||||||
4CF65D1824DD6C080006B001 /* ButtonHolderView.swift in Sources */,
|
|
||||||
72AECC6B224A979D00D12E7C /* BaseSearchViewController.swift in Sources */,
|
72AECC6B224A979D00D12E7C /* BaseSearchViewController.swift in Sources */,
|
||||||
673CF4112063ABD100C329F6 /* GeneralDataLoadingState+Extensions.swift in Sources */,
|
673CF4112063ABD100C329F6 /* GeneralDataLoadingState+Extensions.swift in Sources */,
|
||||||
72005A1E2266226800ECE090 /* CustomizableButton.swift in Sources */,
|
72005A1E2266226800ECE090 /* CustomizableButton.swift in Sources */,
|
||||||
|
|
@ -2529,8 +2424,10 @@
|
||||||
671462841EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */,
|
671462841EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */,
|
||||||
EFBE57DB1EC361620040E00A /* UIView+Layout.swift in Sources */,
|
EFBE57DB1EC361620040E00A /* UIView+Layout.swift in Sources */,
|
||||||
6714634C1EB3396E00EAB194 /* ReuseIdentifierProtocol.swift in Sources */,
|
6714634C1EB3396E00EAB194 /* ReuseIdentifierProtocol.swift in Sources */,
|
||||||
|
671462F01EB3396E00EAB194 /* UIImage+SupportExtensions.swift in Sources */,
|
||||||
6741CEAF20E242A500FEC4D9 /* TableViewHolder+ScrollViewHolder.swift in Sources */,
|
6741CEAF20E242A500FEC4D9 /* TableViewHolder+ScrollViewHolder.swift in Sources */,
|
||||||
67CAF8C620652E2A00527085 /* TextFieldViewModel.swift in Sources */,
|
67CAF8C620652E2A00527085 /* TextFieldViewModel.swift in Sources */,
|
||||||
|
85C343C622B7CE9C00D9FAA5 /* Completable+NetworkErrorHandling.swift in Sources */,
|
||||||
671462681EB3396E00EAB194 /* NetworkService.swift in Sources */,
|
671462681EB3396E00EAB194 /* NetworkService.swift in Sources */,
|
||||||
67990ACA213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */,
|
67990ACA213EA5B70040D195 /* ContentLoadingViewModel.swift in Sources */,
|
||||||
671463101EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */,
|
671463101EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */,
|
||||||
|
|
@ -2545,13 +2442,12 @@
|
||||||
671462FC1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */,
|
671462FC1EB3396E00EAB194 /* UIView+XibNameProtocol.swift in Sources */,
|
||||||
67EB7FC0206140E600BDD9FB /* TotalCountCursor.swift in Sources */,
|
67EB7FC0206140E600BDD9FB /* TotalCountCursor.swift in Sources */,
|
||||||
36DAAF512007CC920090BE0D /* UITableView+Extensions.swift in Sources */,
|
36DAAF512007CC920090BE0D /* UITableView+Extensions.swift in Sources */,
|
||||||
4CF65D1624DD69250006B001 /* UIButton+ButtonHolder.swift in Sources */,
|
|
||||||
671463841EB3396E00EAB194 /* ResizeDrawingOperation.swift in Sources */,
|
671463841EB3396E00EAB194 /* ResizeDrawingOperation.swift in Sources */,
|
||||||
6774528D20625C9E0024EEEF /* GeneralDataLoadingState.swift in Sources */,
|
6774528D20625C9E0024EEEF /* GeneralDataLoadingState.swift in Sources */,
|
||||||
72005A1F2266226800ECE090 /* CustomizableButtonViewModel.swift in Sources */,
|
72005A1F2266226800ECE090 /* CustomizableButtonViewModel.swift in Sources */,
|
||||||
677B06C4211884F3006C947D /* BaseTextAttributes.swift in Sources */,
|
677B06C4211884F3006C947D /* BaseTextAttributes.swift in Sources */,
|
||||||
5ED2C0B2251A354E00D4E258 /* BaseOrientationNavigationController.swift in Sources */,
|
|
||||||
675E0AA921072FF400CDC143 /* BaseScrollContentController.swift in Sources */,
|
675E0AA921072FF400CDC143 /* BaseScrollContentController.swift in Sources */,
|
||||||
|
671462D01EB3396E00EAB194 /* UIScrollView+Support.swift in Sources */,
|
||||||
671463901EB3396E00EAB194 /* TemplateDrawingOperation.swift in Sources */,
|
671463901EB3396E00EAB194 /* TemplateDrawingOperation.swift in Sources */,
|
||||||
A658E54D1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */,
|
A658E54D1F8CD7790093527A /* TableRow+SeparatorsExtensions.swift in Sources */,
|
||||||
85A5D49522AA975000C7D254 /* Decimal+Rounding.swift in Sources */,
|
85A5D49522AA975000C7D254 /* Decimal+Rounding.swift in Sources */,
|
||||||
|
|
@ -2564,7 +2460,6 @@
|
||||||
82D2966D2264B1790067735C /* LabelTableViewCell.swift in Sources */,
|
82D2966D2264B1790067735C /* LabelTableViewCell.swift in Sources */,
|
||||||
671463301EB3396E00EAB194 /* CursorType.swift in Sources */,
|
671463301EB3396E00EAB194 /* CursorType.swift in Sources */,
|
||||||
67FDC25F1FA310EA00C76A77 /* RequestError.swift in Sources */,
|
67FDC25F1FA310EA00C76A77 /* RequestError.swift in Sources */,
|
||||||
5E2364182526489A00E2F96B /* UIInterfaceOrientation+ VideoOrientation.swift in Sources */,
|
|
||||||
677B06A021186A69006C947D /* SharedSequence+Extensions.swift in Sources */,
|
677B06A021186A69006C947D /* SharedSequence+Extensions.swift in Sources */,
|
||||||
6760DC4D212F351700020BAE /* UIView+AddSubviews.swift in Sources */,
|
6760DC4D212F351700020BAE /* UIView+AddSubviews.swift in Sources */,
|
||||||
67745268206249360024EEEF /* UITableView+PaginationWrappable.swift in Sources */,
|
67745268206249360024EEEF /* UITableView+PaginationWrappable.swift in Sources */,
|
||||||
|
|
@ -2579,11 +2474,13 @@
|
||||||
671463281EB3396E00EAB194 /* BaseViewModel.swift in Sources */,
|
671463281EB3396E00EAB194 /* BaseViewModel.swift in Sources */,
|
||||||
A6E0DDDF1F8A696F002CA74E /* SeparatorCell.swift in Sources */,
|
A6E0DDDF1F8A696F002CA74E /* SeparatorCell.swift in Sources */,
|
||||||
67153E40207DFBA80049D8C0 /* FloatingPoint+DegreesRadiansConvertion.swift in Sources */,
|
67153E40207DFBA80049D8C0 /* FloatingPoint+DegreesRadiansConvertion.swift in Sources */,
|
||||||
|
85C343C822B7CEE200D9FAA5 /* Single+NetworkErrorHandling.swift in Sources */,
|
||||||
671462AC1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */,
|
671462AC1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */,
|
||||||
671463001EB3396E00EAB194 /* UIView+LoadFromNib.swift in Sources */,
|
671463001EB3396E00EAB194 /* UIView+LoadFromNib.swift in Sources */,
|
||||||
6741CEB420E242C100FEC4D9 /* CollectionViewHolder+ScrollViewHolder.swift in Sources */,
|
6741CEB420E242C100FEC4D9 /* CollectionViewHolder+ScrollViewHolder.swift in Sources */,
|
||||||
A676AE501F9810C1001F9214 /* Any+Cast.swift in Sources */,
|
A676AE501F9810C1001F9214 /* Any+Cast.swift in Sources */,
|
||||||
78EC7B1322019F5A0007DCFD /* String+TelpromptURL.swift in Sources */,
|
78EC7B1322019F5A0007DCFD /* String+TelpromptURL.swift in Sources */,
|
||||||
|
85C343C422B7CC3600D9FAA5 /* Observable+NetworkErrorHandling.swift in Sources */,
|
||||||
72AECC6F224A97B100D12E7C /* SearchResultsViewControllerState.swift in Sources */,
|
72AECC6F224A97B100D12E7C /* SearchResultsViewControllerState.swift in Sources */,
|
||||||
6714627C1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */,
|
6714627C1EB3396E00EAB194 /* SessionManager+Extensions.swift in Sources */,
|
||||||
671462D41EB3396E00EAB194 /* TableDirector+Extensions.swift in Sources */,
|
671462D41EB3396E00EAB194 /* TableDirector+Extensions.swift in Sources */,
|
||||||
|
|
@ -2593,7 +2490,6 @@
|
||||||
67E902572125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift in Sources */,
|
67E902572125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift in Sources */,
|
||||||
671462781EB3396E00EAB194 /* ResizeMode.swift in Sources */,
|
671462781EB3396E00EAB194 /* ResizeMode.swift in Sources */,
|
||||||
67E902512125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift in Sources */,
|
67E902512125B064008EDF45 /* BuildInNumberTypes+NSNumberConvertible.swift in Sources */,
|
||||||
5ED2C0B5251A366700D4E258 /* UIDevice+ScreenOrientation.swift in Sources */,
|
|
||||||
A676AE551F98112E001F9214 /* ObservableMappable.swift in Sources */,
|
A676AE551F98112E001F9214 /* ObservableMappable.swift in Sources */,
|
||||||
6741CEA520E2418200FEC4D9 /* TableViewHolder.swift in Sources */,
|
6741CEA520E2418200FEC4D9 /* TableViewHolder.swift in Sources */,
|
||||||
8546C2E3224E86280059C255 /* ApiUploadRequestParameters.swift in Sources */,
|
8546C2E3224E86280059C255 /* ApiUploadRequestParameters.swift in Sources */,
|
||||||
|
|
@ -2624,7 +2520,6 @@
|
||||||
A6E0DDF11F8A6C80002CA74E /* SeparatorConfiguration.swift in Sources */,
|
A6E0DDF11F8A6C80002CA74E /* SeparatorConfiguration.swift in Sources */,
|
||||||
6727477F206CD3BD00725163 /* ViewText+Extensions.swift in Sources */,
|
6727477F206CD3BD00725163 /* ViewText+Extensions.swift in Sources */,
|
||||||
67EB7FEB2061667900BDD9FB /* DefaultTotalCountCursorListingResult.swift in Sources */,
|
67EB7FEB2061667900BDD9FB /* DefaultTotalCountCursorListingResult.swift in Sources */,
|
||||||
4CF65D1424DD684A0006B001 /* ButtonHolder.swift in Sources */,
|
|
||||||
671AD26C206A3E8500EAF887 /* Array+TotalCountCursorListingResult.swift in Sources */,
|
671AD26C206A3E8500EAF887 /* Array+TotalCountCursorListingResult.swift in Sources */,
|
||||||
673CF4382063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */,
|
673CF4382063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */,
|
||||||
B85B768720B1CF6700F837C4 /* Encodable+Extensions.swift in Sources */,
|
B85B768720B1CF6700F837C4 /* Encodable+Extensions.swift in Sources */,
|
||||||
|
|
@ -2639,7 +2534,6 @@
|
||||||
671463081EB3396E00EAB194 /* UIView+Rotation.swift in Sources */,
|
671463081EB3396E00EAB194 /* UIView+Rotation.swift in Sources */,
|
||||||
6714626C1EB3396E00EAB194 /* XibView.swift in Sources */,
|
6714626C1EB3396E00EAB194 /* XibView.swift in Sources */,
|
||||||
67274778206CD0B500725163 /* UILabel+ViewTextConfigurable.swift in Sources */,
|
67274778206CD0B500725163 /* UILabel+ViewTextConfigurable.swift in Sources */,
|
||||||
5E23631F25263EFA00E2F96B /* BaseOrientationController.swift in Sources */,
|
|
||||||
67ED2BE520B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */,
|
67ED2BE520B44F4300508B3E /* InitializableView+DefaultImplementation.swift in Sources */,
|
||||||
36FE777020F669E300284C09 /* String+ConvertToHost.swift in Sources */,
|
36FE777020F669E300284C09 /* String+ConvertToHost.swift in Sources */,
|
||||||
6774529220625D170024EEEF /* GeneralDataLoadingModel.swift in Sources */,
|
6774529220625D170024EEEF /* GeneralDataLoadingModel.swift in Sources */,
|
||||||
|
|
@ -2659,14 +2553,12 @@
|
||||||
6727478A206CD83600725163 /* DateFormat.swift in Sources */,
|
6727478A206CD83600725163 /* DateFormat.swift in Sources */,
|
||||||
67745280206256A20024EEEF /* RxDataLoadingModel.swift in Sources */,
|
67745280206256A20024EEEF /* RxDataLoadingModel.swift in Sources */,
|
||||||
A6F32C081F6EBDAA00AC08EE /* String+LocalizedComponent.swift in Sources */,
|
A6F32C081F6EBDAA00AC08EE /* String+LocalizedComponent.swift in Sources */,
|
||||||
|
85C343BC22B7B32400D9FAA5 /* NetworkErrorHandlingType.swift in Sources */,
|
||||||
671462881EB3396E00EAB194 /* CGFloat+Pixels.swift in Sources */,
|
671462881EB3396E00EAB194 /* CGFloat+Pixels.swift in Sources */,
|
||||||
411073AF23466B41002DD9B9 /* UIViewController+PresentFullScreen.swift in Sources */,
|
|
||||||
671462941EB3396E00EAB194 /* CGSize+CGContextSize.swift in Sources */,
|
671462941EB3396E00EAB194 /* CGSize+CGContextSize.swift in Sources */,
|
||||||
6741CEA920E2418B00FEC4D9 /* CollectionViewHolder.swift in Sources */,
|
6741CEA920E2418B00FEC4D9 /* CollectionViewHolder.swift in Sources */,
|
||||||
52421F9424EBCFAE00948DD1 /* VoidTappableViewModel.swift in Sources */,
|
|
||||||
67745279206252020024EEEF /* DataLoadingState.swift in Sources */,
|
67745279206252020024EEEF /* DataLoadingState.swift in Sources */,
|
||||||
671463641EB3396E00EAB194 /* ViewHeightProtocol.swift in Sources */,
|
671463641EB3396E00EAB194 /* ViewHeightProtocol.swift in Sources */,
|
||||||
52421F8F24EAB84900948DD1 /* BaseRxTableViewCell.swift in Sources */,
|
|
||||||
67EB7FDA20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */,
|
67EB7FDA20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */,
|
||||||
671462481EB3396E00EAB194 /* FixedPageCursor.swift in Sources */,
|
671462481EB3396E00EAB194 /* FixedPageCursor.swift in Sources */,
|
||||||
671462C81EB3396E00EAB194 /* String+Localization.swift in Sources */,
|
671462C81EB3396E00EAB194 /* String+Localization.swift in Sources */,
|
||||||
|
|
@ -2683,6 +2575,7 @@
|
||||||
40F118471F8FEF97004AADAF /* AppearanceConfigurable.swift in Sources */,
|
40F118471F8FEF97004AADAF /* AppearanceConfigurable.swift in Sources */,
|
||||||
671463181EB3396E00EAB194 /* UIWindow+Extensions.swift in Sources */,
|
671463181EB3396E00EAB194 /* UIWindow+Extensions.swift in Sources */,
|
||||||
67274769206CCC9D00725163 /* ViewBackground.swift in Sources */,
|
67274769206CCC9D00725163 /* ViewBackground.swift in Sources */,
|
||||||
|
85C343BE22B7B34D00D9FAA5 /* NetworkErrorAlertBase.swift in Sources */,
|
||||||
671463781EB3396E00EAB194 /* CALayerDrawingOperation.swift in Sources */,
|
671463781EB3396E00EAB194 /* CALayerDrawingOperation.swift in Sources */,
|
||||||
6714632C1EB3396E00EAB194 /* ConfigurableController.swift in Sources */,
|
6714632C1EB3396E00EAB194 /* ConfigurableController.swift in Sources */,
|
||||||
6714628C1EB3396E00EAB194 /* CGImage+Alpha.swift in Sources */,
|
6714628C1EB3396E00EAB194 /* CGImage+Alpha.swift in Sources */,
|
||||||
|
|
@ -2704,6 +2597,7 @@
|
||||||
67EB7FC7206148D000BDD9FB /* TotalCountCursorListingResult.swift in Sources */,
|
67EB7FC7206148D000BDD9FB /* TotalCountCursorListingResult.swift in Sources */,
|
||||||
36BCEFAD229313FF00D5A37E /* Initializable.swift in Sources */,
|
36BCEFAD229313FF00D5A37E /* Initializable.swift in Sources */,
|
||||||
67745286206259CF0024EEEF /* Rx+RxDataSourceProtocol.swift in Sources */,
|
67745286206259CF0024EEEF /* Rx+RxDataSourceProtocol.swift in Sources */,
|
||||||
|
85C343C022B7B55800D9FAA5 /* NetworkErrorHandler.swift in Sources */,
|
||||||
67955D52206D216B0021ECD2 /* Singleton.swift in Sources */,
|
67955D52206D216B0021ECD2 /* Singleton.swift in Sources */,
|
||||||
67EB7FE420615DE000BDD9FB /* DataSource.swift in Sources */,
|
67EB7FE420615DE000BDD9FB /* DataSource.swift in Sources */,
|
||||||
67EB7FD420615D1700BDD9FB /* ResettableCursorType.swift in Sources */,
|
67EB7FD420615D1700BDD9FB /* ResettableCursorType.swift in Sources */,
|
||||||
|
|
@ -2714,7 +2608,6 @@
|
||||||
678D267920691D8200B05B93 /* DataModelFieldBinding.swift in Sources */,
|
678D267920691D8200B05B93 /* DataModelFieldBinding.swift in Sources */,
|
||||||
72AECC71224A97F100D12E7C /* SearchResultsViewController.swift in Sources */,
|
72AECC71224A97F100D12E7C /* SearchResultsViewController.swift in Sources */,
|
||||||
673CF4342063E29B00C329F6 /* TextWithButtonPlaceholder.swift in Sources */,
|
673CF4342063E29B00C329F6 /* TextWithButtonPlaceholder.swift in Sources */,
|
||||||
52421F8D24EAB52E00948DD1 /* ContainerTableCell.swift in Sources */,
|
|
||||||
673CF4222063D90600C329F6 /* DisposeBagHolder.swift in Sources */,
|
673CF4222063D90600C329F6 /* DisposeBagHolder.swift in Sources */,
|
||||||
67DB776D210871E8001CB56B /* BaseCollectionContentController.swift in Sources */,
|
67DB776D210871E8001CB56B /* BaseCollectionContentController.swift in Sources */,
|
||||||
82B4F8DB223903B800F6708C /* Block.swift in Sources */,
|
82B4F8DB223903B800F6708C /* Block.swift in Sources */,
|
||||||
|
|
@ -2729,8 +2622,6 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
4C4C7B83267FE32F006F3C70 /* Decimal+Values.swift in Sources */,
|
|
||||||
4C4C7B7F267FE319006F3C70 /* Decimal+Rounding.swift in Sources */,
|
|
||||||
67EB7FE620615DE000BDD9FB /* DataSource.swift in Sources */,
|
67EB7FE620615DE000BDD9FB /* DataSource.swift in Sources */,
|
||||||
6714634A1EB3396E00EAB194 /* ResettableType.swift in Sources */,
|
6714634A1EB3396E00EAB194 /* ResettableType.swift in Sources */,
|
||||||
6713C23E20AF0D5900875921 /* NetworkOperationModel.swift in Sources */,
|
6713C23E20AF0D5900875921 /* NetworkOperationModel.swift in Sources */,
|
||||||
|
|
@ -2783,6 +2674,7 @@
|
||||||
671463821EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */,
|
671463821EB3396E00EAB194 /* PaddingDrawingOperation.swift in Sources */,
|
||||||
6714632A1EB3396E00EAB194 /* BaseViewModel.swift in Sources */,
|
6714632A1EB3396E00EAB194 /* BaseViewModel.swift in Sources */,
|
||||||
671462AE1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */,
|
671462AE1EB3396E00EAB194 /* Observable+DeferredJust.swift in Sources */,
|
||||||
|
85C343C122B7BD3200D9FAA5 /* NetworkErrorHandlingType.swift in Sources */,
|
||||||
677B06B421186C14006C947D /* Completable+DeferredJust.swift in Sources */,
|
677B06B421186C14006C947D /* Completable+DeferredJust.swift in Sources */,
|
||||||
67EB7FDC20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */,
|
67EB7FDC20615D5B00BDD9FB /* ResettableRxCursorDataSource.swift in Sources */,
|
||||||
A6F32C0B1F6EBE5C00AC08EE /* String+LocalizedComponent.swift in Sources */,
|
A6F32C0B1F6EBE5C00AC08EE /* String+LocalizedComponent.swift in Sources */,
|
||||||
|
|
@ -2857,10 +2749,6 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
4C4C7BBA267FE4DD006F3C70 /* ButtonHolder.swift in Sources */,
|
|
||||||
4C4C7BB7267FE4C9006F3C70 /* ButtonHolderView.swift in Sources */,
|
|
||||||
4C4C7BA7267FE3F6006F3C70 /* Decimal+Rounding.swift in Sources */,
|
|
||||||
4C4C7BA8267FE3F6006F3C70 /* Decimal+Values.swift in Sources */,
|
|
||||||
6714634B1EB3396E00EAB194 /* ResettableType.swift in Sources */,
|
6714634B1EB3396E00EAB194 /* ResettableType.swift in Sources */,
|
||||||
82B4F8DD223903B800F6708C /* Block.swift in Sources */,
|
82B4F8DD223903B800F6708C /* Block.swift in Sources */,
|
||||||
671462E71EB3396E00EAB194 /* UIColor+Hex.swift in Sources */,
|
671462E71EB3396E00EAB194 /* UIColor+Hex.swift in Sources */,
|
||||||
|
|
@ -2881,10 +2769,12 @@
|
||||||
671463631EB3396E00EAB194 /* SupportProtocol.swift in Sources */,
|
671463631EB3396E00EAB194 /* SupportProtocol.swift in Sources */,
|
||||||
671462871EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */,
|
671462871EB3396E00EAB194 /* CGContext+Initializers.swift in Sources */,
|
||||||
6714634F1EB3396E00EAB194 /* ReuseIdentifierProtocol.swift in Sources */,
|
6714634F1EB3396E00EAB194 /* ReuseIdentifierProtocol.swift in Sources */,
|
||||||
|
671462F31EB3396E00EAB194 /* UIImage+SupportExtensions.swift in Sources */,
|
||||||
6714626B1EB3396E00EAB194 /* NetworkService.swift in Sources */,
|
6714626B1EB3396E00EAB194 /* NetworkService.swift in Sources */,
|
||||||
67E352612119B7570035BDDB /* BasePlaceholerView.swift in Sources */,
|
67E352612119B7570035BDDB /* BasePlaceholerView.swift in Sources */,
|
||||||
673CF43A2063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */,
|
673CF43A2063E7CE00C329F6 /* GeneralDataLoadingController+DefaultImplementation.swift in Sources */,
|
||||||
671463131EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */,
|
671463131EB3396E00EAB194 /* UIViewController+DefaultXibName.swift in Sources */,
|
||||||
|
85C343C222B7BD3600D9FAA5 /* NetworkErrorHandlingType.swift in Sources */,
|
||||||
78EC7B1522019F5A0007DCFD /* String+TelpromptURL.swift in Sources */,
|
78EC7B1522019F5A0007DCFD /* String+TelpromptURL.swift in Sources */,
|
||||||
671462931EB3396E00EAB194 /* CGImage+Crop.swift in Sources */,
|
671462931EB3396E00EAB194 /* CGImage+Crop.swift in Sources */,
|
||||||
6727477A206CD0B500725163 /* UILabel+ViewTextConfigurable.swift in Sources */,
|
6727477A206CD0B500725163 /* UILabel+ViewTextConfigurable.swift in Sources */,
|
||||||
|
|
@ -2902,6 +2792,7 @@
|
||||||
671463A51EB33FF600EAB194 /* Animatable.swift in Sources */,
|
671463A51EB33FF600EAB194 /* Animatable.swift in Sources */,
|
||||||
67CAF8C920652E2A00527085 /* TextFieldViewModel.swift in Sources */,
|
67CAF8C920652E2A00527085 /* TextFieldViewModel.swift in Sources */,
|
||||||
67E352592119ACF30035BDDB /* ViewTextConfigurable+Extensions.swift in Sources */,
|
67E352592119ACF30035BDDB /* ViewTextConfigurable+Extensions.swift in Sources */,
|
||||||
|
675E0AAB21072FF400CDC143 /* BaseScrollContentController.swift in Sources */,
|
||||||
6714629B1EB3396E00EAB194 /* CGSize+Resize.swift in Sources */,
|
6714629B1EB3396E00EAB194 /* CGSize+Resize.swift in Sources */,
|
||||||
677B06C221187559006C947D /* ViewTextConfigurable.swift in Sources */,
|
677B06C221187559006C947D /* ViewTextConfigurable.swift in Sources */,
|
||||||
671463331EB3396E00EAB194 /* CursorType.swift in Sources */,
|
671463331EB3396E00EAB194 /* CursorType.swift in Sources */,
|
||||||
|
|
@ -2924,6 +2815,7 @@
|
||||||
6714632B1EB3396E00EAB194 /* BaseViewModel.swift in Sources */,
|
6714632B1EB3396E00EAB194 /* BaseViewModel.swift in Sources */,
|
||||||
673564F42068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift in Sources */,
|
673564F42068C2AD00F0CBED /* NumberFormattingService+DefaultImplementation.swift in Sources */,
|
||||||
677452A220625EEE0024EEEF /* PaginationDataLoadingModel.swift in Sources */,
|
677452A220625EEE0024EEEF /* PaginationDataLoadingModel.swift in Sources */,
|
||||||
|
67DB776F210871E8001CB56B /* BaseCollectionContentController.swift in Sources */,
|
||||||
673CF4362063E29B00C329F6 /* TextWithButtonPlaceholder.swift in Sources */,
|
673CF4362063E29B00C329F6 /* TextWithButtonPlaceholder.swift in Sources */,
|
||||||
A6F32C0C1F6EBE5C00AC08EE /* String+LocalizedComponent.swift in Sources */,
|
A6F32C0C1F6EBE5C00AC08EE /* String+LocalizedComponent.swift in Sources */,
|
||||||
6741CEB620E242C100FEC4D9 /* CollectionViewHolder+ScrollViewHolder.swift in Sources */,
|
6741CEB620E242C100FEC4D9 /* CollectionViewHolder+ScrollViewHolder.swift in Sources */,
|
||||||
|
|
@ -2940,6 +2832,7 @@
|
||||||
67745289206259CF0024EEEF /* Rx+RxDataSourceProtocol.swift in Sources */,
|
67745289206259CF0024EEEF /* Rx+RxDataSourceProtocol.swift in Sources */,
|
||||||
67386A8F206CF3F6004EDA6C /* DateFormattingService+DefaultImplementation.swift in Sources */,
|
67386A8F206CF3F6004EDA6C /* DateFormattingService+DefaultImplementation.swift in Sources */,
|
||||||
671463071EB3396E00EAB194 /* UIView+LoadingIndicator.swift in Sources */,
|
671463071EB3396E00EAB194 /* UIView+LoadingIndicator.swift in Sources */,
|
||||||
|
67DB7762210869D1001CB56B /* TableViewWrapperView.swift in Sources */,
|
||||||
6774526E206249E30024EEEF /* UICollectionView+BackgroundViewHolder.swift in Sources */,
|
6774526E206249E30024EEEF /* UICollectionView+BackgroundViewHolder.swift in Sources */,
|
||||||
671463A91EB340C000EAB194 /* UIViewController+ConfigurableController.swift in Sources */,
|
671463A91EB340C000EAB194 /* UIViewController+ConfigurableController.swift in Sources */,
|
||||||
673564F92068C68D00F0CBED /* NumberFormat.swift in Sources */,
|
673564F92068C68D00F0CBED /* NumberFormat.swift in Sources */,
|
||||||
|
|
@ -2962,12 +2855,14 @@
|
||||||
67EB7FD720615D1700BDD9FB /* ResettableCursorType.swift in Sources */,
|
67EB7FD720615D1700BDD9FB /* ResettableCursorType.swift in Sources */,
|
||||||
671463371EB3396E00EAB194 /* DrawingOperation.swift in Sources */,
|
671463371EB3396E00EAB194 /* DrawingOperation.swift in Sources */,
|
||||||
67153E3D207DFADA0049D8C0 /* RotateDrawingOperation.swift in Sources */,
|
67153E3D207DFADA0049D8C0 /* RotateDrawingOperation.swift in Sources */,
|
||||||
|
6741CED320E243F800FEC4D9 /* BaseConfigurableController.swift in Sources */,
|
||||||
67274782206CD3BD00725163 /* ViewText+Extensions.swift in Sources */,
|
67274782206CD3BD00725163 /* ViewText+Extensions.swift in Sources */,
|
||||||
673CF42E2063DE5900C329F6 /* TextPlaceholderView.swift in Sources */,
|
673CF42E2063DE5900C329F6 /* TextPlaceholderView.swift in Sources */,
|
||||||
6741CEB120E242A500FEC4D9 /* TableViewHolder+ScrollViewHolder.swift in Sources */,
|
6741CEB120E242A500FEC4D9 /* TableViewHolder+ScrollViewHolder.swift in Sources */,
|
||||||
6741CEA320E2416C00FEC4D9 /* ScrollViewHolder.swift in Sources */,
|
6741CEA320E2416C00FEC4D9 /* ScrollViewHolder.swift in Sources */,
|
||||||
B84CB06B20B702260090DB91 /* Encodable+Extensions.swift in Sources */,
|
B84CB06B20B702260090DB91 /* Encodable+Extensions.swift in Sources */,
|
||||||
671462731EB3396E00EAB194 /* CursorError.swift in Sources */,
|
671462731EB3396E00EAB194 /* CursorError.swift in Sources */,
|
||||||
|
6741CED020E243F800FEC4D9 /* BaseCustomViewController.swift in Sources */,
|
||||||
6732F242214C09F900B446F2 /* UserDefaults+Codable.swift in Sources */,
|
6732F242214C09F900B446F2 /* UserDefaults+Codable.swift in Sources */,
|
||||||
677B06B521186C14006C947D /* Completable+DeferredJust.swift in Sources */,
|
677B06B521186C14006C947D /* Completable+DeferredJust.swift in Sources */,
|
||||||
6727478D206CD83600725163 /* DateFormat.swift in Sources */,
|
6727478D206CD83600725163 /* DateFormat.swift in Sources */,
|
||||||
|
|
@ -3003,6 +2898,7 @@
|
||||||
6714637B1EB3396E00EAB194 /* CALayerDrawingOperation.swift in Sources */,
|
6714637B1EB3396E00EAB194 /* CALayerDrawingOperation.swift in Sources */,
|
||||||
67E902592125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift in Sources */,
|
67E902592125B66E008EDF45 /* UIImageView+ExpandCollapseDisclosure.swift in Sources */,
|
||||||
6741CEA720E2418200FEC4D9 /* TableViewHolder.swift in Sources */,
|
6741CEA720E2418200FEC4D9 /* TableViewHolder.swift in Sources */,
|
||||||
|
67DB776B21087154001CB56B /* CollectionViewWrapperView.swift in Sources */,
|
||||||
6774529520625D170024EEEF /* GeneralDataLoadingModel.swift in Sources */,
|
6774529520625D170024EEEF /* GeneralDataLoadingModel.swift in Sources */,
|
||||||
6713C23A20AF0C4D00875921 /* NetworkOperationState.swift in Sources */,
|
6713C23A20AF0C4D00875921 /* NetworkOperationState.swift in Sources */,
|
||||||
6774529D20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */,
|
6774529D20625E5B0024EEEF /* PaginationDataLoadingState.swift in Sources */,
|
||||||
|
|
@ -3057,12 +2953,8 @@
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-iOS.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-iOS.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
"@loader_path/Frameworks",
|
|
||||||
);
|
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-iOS";
|
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-iOS";
|
||||||
PRODUCT_NAME = LeadKit;
|
PRODUCT_NAME = LeadKit;
|
||||||
|
|
@ -3091,12 +2983,8 @@
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-iOS.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-iOS.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
"@loader_path/Frameworks",
|
|
||||||
);
|
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-iOS";
|
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-iOS";
|
||||||
PRODUCT_NAME = LeadKit;
|
PRODUCT_NAME = LeadKit;
|
||||||
|
|
@ -3124,11 +3012,7 @@
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-watchOS.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-watchOS.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
"@loader_path/Frameworks",
|
|
||||||
);
|
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-watchOS";
|
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-watchOS";
|
||||||
PRODUCT_NAME = LeadKit;
|
PRODUCT_NAME = LeadKit;
|
||||||
|
|
@ -3160,11 +3044,7 @@
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-watchOS.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-watchOS.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
"@loader_path/Frameworks",
|
|
||||||
);
|
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-watchOS";
|
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-watchOS";
|
||||||
PRODUCT_NAME = LeadKit;
|
PRODUCT_NAME = LeadKit;
|
||||||
|
|
@ -3194,11 +3074,7 @@
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-tvOS.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-tvOS.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
"@loader_path/Frameworks",
|
|
||||||
);
|
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-tvOS";
|
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-tvOS";
|
||||||
PRODUCT_NAME = LeadKit;
|
PRODUCT_NAME = LeadKit;
|
||||||
|
|
@ -3207,7 +3083,7 @@
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
SWIFT_VERSION = 4.2;
|
SWIFT_VERSION = 4.2;
|
||||||
TARGETED_DEVICE_FAMILY = 3;
|
TARGETED_DEVICE_FAMILY = 3;
|
||||||
TVOS_DEPLOYMENT_TARGET = 10.0;
|
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
|
|
@ -3229,11 +3105,7 @@
|
||||||
);
|
);
|
||||||
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-tvOS.plist";
|
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info-tvOS.plist";
|
||||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
"$(inherited)",
|
|
||||||
"@executable_path/Frameworks",
|
|
||||||
"@loader_path/Frameworks",
|
|
||||||
);
|
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=200 -Xfrontend -warn-long-function-bodies=200 -Xfrontend -debug-time-function-bodies";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-tvOS";
|
PRODUCT_BUNDLE_IDENTIFIER = "ru.touchin.LeadKit-tvOS";
|
||||||
PRODUCT_NAME = LeadKit;
|
PRODUCT_NAME = LeadKit;
|
||||||
|
|
@ -3241,7 +3113,7 @@
|
||||||
SKIP_INSTALL = YES;
|
SKIP_INSTALL = YES;
|
||||||
SWIFT_VERSION = 4.2;
|
SWIFT_VERSION = 4.2;
|
||||||
TARGETED_DEVICE_FAMILY = 3;
|
TARGETED_DEVICE_FAMILY = 3;
|
||||||
TVOS_DEPLOYMENT_TARGET = 10.0;
|
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
|
@ -3268,7 +3140,6 @@
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
|
@ -3294,7 +3165,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
|
@ -3328,7 +3199,6 @@
|
||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
|
||||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
|
@ -3348,11 +3218,10 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1230"
|
LastUpgradeVersion = "1020"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|
@ -27,15 +27,6 @@
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "67186B271EB248F100CFAFFB"
|
|
||||||
BuildableName = "LeadKit.framework"
|
|
||||||
BlueprintName = "LeadKit iOS"
|
|
||||||
ReferencedContainer = "container:LeadKit.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
skipped = "NO">
|
skipped = "NO">
|
||||||
|
|
@ -48,6 +39,17 @@
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</TestableReference>
|
</TestableReference>
|
||||||
</Testables>
|
</Testables>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "67186B271EB248F100CFAFFB"
|
||||||
|
BuildableName = "LeadKit.framework"
|
||||||
|
BlueprintName = "LeadKit iOS"
|
||||||
|
ReferencedContainer = "container:LeadKit.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
|
@ -68,6 +70,8 @@
|
||||||
ReferencedContainer = "container:LeadKit.xcodeproj">
|
ReferencedContainer = "container:LeadKit.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</MacroExpansion>
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1230"
|
LastUpgradeVersion = "1020"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|
@ -27,15 +27,6 @@
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<MacroExpansion>
|
|
||||||
<BuildableReference
|
|
||||||
BuildableIdentifier = "primary"
|
|
||||||
BlueprintIdentifier = "6782BB9F1EB31D590086E0B8"
|
|
||||||
BuildableName = "LeadKit.framework"
|
|
||||||
BlueprintName = "LeadKit tvOS"
|
|
||||||
ReferencedContainer = "container:LeadKit.xcodeproj">
|
|
||||||
</BuildableReference>
|
|
||||||
</MacroExpansion>
|
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
skipped = "NO">
|
skipped = "NO">
|
||||||
|
|
@ -48,6 +39,17 @@
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</TestableReference>
|
</TestableReference>
|
||||||
</Testables>
|
</Testables>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "6782BB9F1EB31D590086E0B8"
|
||||||
|
BuildableName = "LeadKit.framework"
|
||||||
|
BlueprintName = "LeadKit tvOS"
|
||||||
|
ReferencedContainer = "container:LeadKit.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
|
|
@ -68,6 +70,8 @@
|
||||||
ReferencedContainer = "container:LeadKit.xcodeproj">
|
ReferencedContainer = "container:LeadKit.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</MacroExpansion>
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Workspace
|
<Workspace
|
||||||
version = "1.0">
|
version = "1.0">
|
||||||
<FileRef location = "group:TIUIElements.playground"></FileRef>
|
<FileRef
|
||||||
<FileRef
|
location = "group:LeadKit.xcodeproj">
|
||||||
location = "group:TIUIElements.xcodeproj">
|
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Pods/Pods.xcodeproj">
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
107
Makefile
107
Makefile
|
|
@ -1,107 +0,0 @@
|
||||||
export SRCROOT := $(shell pwd)
|
|
||||||
|
|
||||||
push_to_podspecs: TISwiftUtils.target TIFoundationUtils.target TICoreGraphicsUtils.target TIKeychainUtils.target TIUIKitCore.target TIUIElements.target TIWebView.target TIBottomSheet.target TISwiftUICore.target TITableKitUtils.target TIDeeplink.target TIDeveloperUtils.target TILogging.target TINetworking.target TIMoyaNetworking.target TINetworkingCache.target TIMapUtils.target TIAppleMapUtils.target TIGoogleMapUtils.target TIPagination.target TIAuth.target TIEcommerce.target TITextProcessing.target TIApplication.target
|
|
||||||
$(call clean)
|
|
||||||
|
|
||||||
TISwiftUtils.target:
|
|
||||||
MODULE_NAME="TISwiftUtils" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TISwiftUtils.target
|
|
||||||
|
|
||||||
TIFoundationUtils.target: TISwiftUtils.target TILogging.target
|
|
||||||
MODULE_NAME="TIFoundationUtils" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIFoundationUtils.target
|
|
||||||
|
|
||||||
TICoreGraphicsUtils.target:
|
|
||||||
MODULE_NAME="TICoreGraphicsUtils" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TICoreGraphicsUtils.target
|
|
||||||
|
|
||||||
TIKeychainUtils.target: TIFoundationUtils.target
|
|
||||||
MODULE_NAME="TIKeychainUtils" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIKeychainUtils.target
|
|
||||||
|
|
||||||
TIUIKitCore.target: TISwiftUtils.target
|
|
||||||
MODULE_NAME="TIUIKitCore" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIUIKitCore.target
|
|
||||||
|
|
||||||
TIUIElements.target: TIUIKitCore.target TILogging.target
|
|
||||||
MODULE_NAME="TIUIElements" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIUIElements.target
|
|
||||||
|
|
||||||
TIWebView.target: TIUIKitCore.target
|
|
||||||
MODULE_NAME="TIWebView" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIWebView.target
|
|
||||||
|
|
||||||
TIBottomSheet.target: TIUIElements.target
|
|
||||||
MODULE_NAME="TIBottomSheet" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIBottomSheet.target
|
|
||||||
|
|
||||||
TISwiftUICore.target: TIUIKitCore.target
|
|
||||||
MODULE_NAME="TISwiftUICore" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TISwiftUICore.target
|
|
||||||
|
|
||||||
TITableKitUtils.target: TIUIElements.target
|
|
||||||
MODULE_NAME="TITableKitUtils" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TITableKitUtils.target
|
|
||||||
|
|
||||||
TIDeeplink.target: TIFoundationUtils.target
|
|
||||||
MODULE_NAME="TIDeeplink" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIDeeplink.target
|
|
||||||
|
|
||||||
TIDeveloperUtils.target: TIUIElements.target
|
|
||||||
MODULE_NAME="TIDeveloperUtils" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIDeveloperUtils.target
|
|
||||||
|
|
||||||
TINetworking.target: TIFoundationUtils.target
|
|
||||||
MODULE_NAME="TINetworking" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TINetworking.target
|
|
||||||
|
|
||||||
TILogging.target:
|
|
||||||
MODULE_NAME="TILogging" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TILogging.target
|
|
||||||
|
|
||||||
TIMoyaNetworking.target: TINetworking.target
|
|
||||||
MODULE_NAME="TIMoyaNetworking" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIMoyaNetworking.target
|
|
||||||
|
|
||||||
TINetworkingCache.target: TINetworking.target
|
|
||||||
MODULE_NAME="TINetworkingCache" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TINetworkingCache.target
|
|
||||||
|
|
||||||
TIMapUtils.target: TILogging TICoreGraphicsUtils.target
|
|
||||||
MODULE_NAME="TIMapUtils" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIMapUtils.target
|
|
||||||
|
|
||||||
TIAppleMapUtils.target: TIMapUtils.target
|
|
||||||
MODULE_NAME="TIAppleMapUtils" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIAppleMapUtils.target
|
|
||||||
|
|
||||||
TIGoogleMapUtils.target: TIMapUtils.target
|
|
||||||
MODULE_NAME="TIGoogleMapUtils" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIGoogleMapUtils.target
|
|
||||||
|
|
||||||
TIYandexMapUtils.target: TIMapUtils.target
|
|
||||||
MODULE_NAME="TIYandexMapUtils" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIYandexMapUtils.target
|
|
||||||
|
|
||||||
TIPagination.target: TISwiftUtils.target
|
|
||||||
MODULE_NAME="TIPagination" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIPagination.target
|
|
||||||
|
|
||||||
TIAuth.target: TIUIKitCore.target TIKeychainUtils.target
|
|
||||||
MODULE_NAME="TIAuth" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIAuth.target
|
|
||||||
|
|
||||||
TIEcommerce.target: TINetworking.target TIUIElements.target
|
|
||||||
MODULE_NAME="TIEcommerce" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIEcommerce.target
|
|
||||||
|
|
||||||
TITextProcessing.target:
|
|
||||||
MODULE_NAME="TITextProcessing" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TITextProcessing.target
|
|
||||||
|
|
||||||
TIApplication.target: TIFoundationUtils.target TILogging.target
|
|
||||||
MODULE_NAME="TIApplication" ./project-scripts/push_to_podspecs.sh
|
|
||||||
touch TIApplication.target
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm *.target
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 MiB |
|
|
@ -1,151 +0,0 @@
|
||||||
# OTPSwiftView
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
A fully customizable OTP view.
|
|
||||||
|
|
||||||
<p align="left">
|
|
||||||
<img src="Assets/preview.gif" width=300 height=533>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
# Usage
|
|
||||||
```swift
|
|
||||||
class ViewController: UIViewController {
|
|
||||||
let otpView = CustomOTPSwiftView() // Custom OTP view
|
|
||||||
|
|
||||||
let config = OTPCodeConfig(codeSymbolsCount: 6, // Base configuration of OTP view
|
|
||||||
spacing: 6,
|
|
||||||
customSpacing: [2: 20])
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
|
|
||||||
/*
|
|
||||||
Add your codeView and set layout
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Configure OTP view */
|
|
||||||
|
|
||||||
otpView.configure(with: config)
|
|
||||||
|
|
||||||
/* Bind events */
|
|
||||||
|
|
||||||
otpView.onTextEnter = { code in
|
|
||||||
// Get code from codeView
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update text */
|
|
||||||
|
|
||||||
otpView.code = "234435"
|
|
||||||
|
|
||||||
/* Update focus */
|
|
||||||
|
|
||||||
otpView.beginFirstResponder() // show keyboard
|
|
||||||
otpView.resignFirstResponder() // hide keyboard
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# Customization
|
|
||||||
## Single OTP View
|
|
||||||
*OTPView* is a base class that describes a single OTP textfield.
|
|
||||||
To customize the appearance and layout, you must inherit from the OTPView.
|
|
||||||
*Don't forget to add UIGestureRecognizer to call closure `onTap?()`. Use UITapGestureRecognizer to avoid bugs.*
|
|
||||||
|
|
||||||
```swift
|
|
||||||
import OTPSwiftView
|
|
||||||
|
|
||||||
class CustomOTPView: OTPView {
|
|
||||||
override func addViews() {
|
|
||||||
super.addViews()
|
|
||||||
|
|
||||||
// Adding additional views to current view. The OTP textfield has already been added.
|
|
||||||
}
|
|
||||||
|
|
||||||
override func configureLayout() {
|
|
||||||
super.configureLayout()
|
|
||||||
|
|
||||||
// Confgiure layout of subviews
|
|
||||||
}
|
|
||||||
|
|
||||||
override func bindViews() {
|
|
||||||
super.bindViews()
|
|
||||||
|
|
||||||
// Binding to data or user actions
|
|
||||||
|
|
||||||
let gesture = UITapGestureRecognizer(target: self, action: #selector(onTapAction))
|
|
||||||
addGestureRecognizer(gesture)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func onTapAction() {
|
|
||||||
onTap?()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func configureAppearance() {
|
|
||||||
super.configureAppearance()
|
|
||||||
|
|
||||||
// Appearance configuration method
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
*If needed to set validation for input use `validationClosure: ValidationClosure<String>?`*. For example, only numbers validation:
|
|
||||||
|
|
||||||
```swift
|
|
||||||
import OTPSwiftView
|
|
||||||
|
|
||||||
class CustomOTPView: OTPView {
|
|
||||||
|
|
||||||
override func bindViews() {
|
|
||||||
super.bindViews()
|
|
||||||
|
|
||||||
codeTextField.validationClosure = { input in
|
|
||||||
input.allSatisfy { $0.isNumber }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## OTPSwiftView
|
|
||||||
*OTPSwiftView* is a base class that is responsible for the layout of single OTP views.
|
|
||||||
As with OTPView, you should create an heir class to configure your full OTP view.
|
|
||||||
|
|
||||||
```swift
|
|
||||||
import OTPSwiftView
|
|
||||||
|
|
||||||
final class CustomOTPSwiftView: OTPSwiftView<CustomOTPView> {
|
|
||||||
override func addViews() {
|
|
||||||
super.addViews()
|
|
||||||
|
|
||||||
// Adding additional views to current code view. The single OTP views has already been added.
|
|
||||||
}
|
|
||||||
|
|
||||||
override func configureLayout() {
|
|
||||||
super.configureLayout()
|
|
||||||
|
|
||||||
// Confgiure layout of subviews
|
|
||||||
}
|
|
||||||
|
|
||||||
override func bindViews() {
|
|
||||||
super.bindViews()
|
|
||||||
|
|
||||||
// Binding to data or user actions
|
|
||||||
}
|
|
||||||
|
|
||||||
override func configureAppearance() {
|
|
||||||
super.configureAppearance()
|
|
||||||
|
|
||||||
// Appearance configuration method
|
|
||||||
}
|
|
||||||
|
|
||||||
override func configure(with config: OTPCodeConfig) {
|
|
||||||
super.configure(with: config)
|
|
||||||
|
|
||||||
// Configure you code view with configuration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# Installation via SPM
|
|
||||||
|
|
||||||
You can install this framework as a target of LeadKit.
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2020 Touch Instinct
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the Software), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
/// Base configuration for OTPSwiftView
|
|
||||||
open class OTPCodeConfig {
|
|
||||||
public typealias Spacing = [Int: CGFloat]
|
|
||||||
|
|
||||||
public let codeSymbolsCount: Int
|
|
||||||
public let spacing: CGFloat
|
|
||||||
public let customSpacing: Spacing?
|
|
||||||
|
|
||||||
public init(codeSymbolsCount: Int, spacing: CGFloat, customSpacing: Spacing?) {
|
|
||||||
self.codeSymbolsCount = codeSymbolsCount
|
|
||||||
self.spacing = spacing
|
|
||||||
self.customSpacing = customSpacing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,149 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2020 Touch Instinct
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the Software), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import TIUIElements
|
|
||||||
import TISwiftUtils
|
|
||||||
|
|
||||||
/// Base full OTP View for entering the verification code
|
|
||||||
open class OTPSwiftView<View: OTPView>: BaseInitializableControl {
|
|
||||||
private var emptyOTPView: View? {
|
|
||||||
textFieldsCollection.first { $0.codeTextField.text.orEmpty.isEmpty } ?? textFieldsCollection.last
|
|
||||||
}
|
|
||||||
|
|
||||||
public private(set) var codeStackView = UIStackView()
|
|
||||||
public private(set) var textFieldsCollection: [View] = []
|
|
||||||
|
|
||||||
public var onTextEnter: ParameterClosure<String>?
|
|
||||||
|
|
||||||
public var code: String {
|
|
||||||
get {
|
|
||||||
textFieldsCollection.compactMap { $0.codeTextField.text }.joined()
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
textFieldsCollection.first?.codeTextField.set(inputText: newValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override var isFirstResponder: Bool {
|
|
||||||
!textFieldsCollection.allSatisfy { !$0.codeTextField.isFirstResponder }
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func addViews() {
|
|
||||||
super.addViews()
|
|
||||||
|
|
||||||
addSubview(codeStackView)
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func configureAppearance() {
|
|
||||||
super.configureAppearance()
|
|
||||||
|
|
||||||
codeStackView.contentMode = .center
|
|
||||||
codeStackView.distribution = .fillEqually
|
|
||||||
}
|
|
||||||
|
|
||||||
open func configure(with config: OTPCodeConfig) {
|
|
||||||
textFieldsCollection = createTextFields(numberOfFields: config.codeSymbolsCount)
|
|
||||||
|
|
||||||
codeStackView.addArrangedSubviews(textFieldsCollection)
|
|
||||||
codeStackView.spacing = config.spacing
|
|
||||||
|
|
||||||
configure(customSpacing: config.customSpacing, for: codeStackView)
|
|
||||||
|
|
||||||
bindTextFields(with: config)
|
|
||||||
}
|
|
||||||
|
|
||||||
@discardableResult
|
|
||||||
open override func becomeFirstResponder() -> Bool {
|
|
||||||
guard let emptyOTPView = emptyOTPView, !emptyOTPView.isFirstResponder else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return emptyOTPView.codeTextField.becomeFirstResponder()
|
|
||||||
}
|
|
||||||
|
|
||||||
@discardableResult
|
|
||||||
open override func resignFirstResponder() -> Bool {
|
|
||||||
guard let emptyOTPView = emptyOTPView, emptyOTPView.isFirstResponder else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return emptyOTPView.codeTextField.resignFirstResponder()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Configure textfields
|
|
||||||
|
|
||||||
private extension OTPSwiftView {
|
|
||||||
func configure(customSpacing: OTPCodeConfig.Spacing?, for stackView: UIStackView) {
|
|
||||||
guard let customSpacing = customSpacing else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
customSpacing.forEach { viewIndex, spacing in
|
|
||||||
guard viewIndex < stackView.arrangedSubviews.count, viewIndex >= .zero else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.set(spacing: spacing,
|
|
||||||
after: stackView.arrangedSubviews[viewIndex],
|
|
||||||
for: stackView)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func set(spacing: CGFloat, after view: UIView, for stackView: UIStackView) {
|
|
||||||
stackView.setCustomSpacing(spacing, after: view)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createTextFields(numberOfFields: Int) -> [View] {
|
|
||||||
var textFieldsCollection: [View] = []
|
|
||||||
|
|
||||||
(.zero..<numberOfFields).forEach { _ in
|
|
||||||
let textField = View()
|
|
||||||
textField.codeTextField.previousTextField = textFieldsCollection.last?.codeTextField
|
|
||||||
textFieldsCollection.last?.codeTextField.nextTextField = textField.codeTextField
|
|
||||||
textFieldsCollection.append(textField)
|
|
||||||
}
|
|
||||||
|
|
||||||
return textFieldsCollection
|
|
||||||
}
|
|
||||||
|
|
||||||
func bindTextFields(with config: OTPCodeConfig) {
|
|
||||||
let onTextChangedSignal: VoidClosure = { [weak self] in
|
|
||||||
guard let code = self?.code else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let correctedCode = code.prefix(config.codeSymbolsCount).string
|
|
||||||
self?.onTextEnter?(correctedCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
let onTap: VoidClosure = { [weak self] in
|
|
||||||
self?.becomeFirstResponder()
|
|
||||||
}
|
|
||||||
|
|
||||||
textFieldsCollection.forEach {
|
|
||||||
$0.codeTextField.onTextChangedSignal = onTextChangedSignal
|
|
||||||
$0.onTap = onTap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2020 Touch Instinct
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the Software), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import TISwiftUtils
|
|
||||||
|
|
||||||
/// Base one symbol textfield
|
|
||||||
open class OTPTextField: UITextField {
|
|
||||||
private let maxSymbolsCount = 1
|
|
||||||
|
|
||||||
public weak var previousTextField: OTPTextField?
|
|
||||||
public weak var nextTextField: OTPTextField?
|
|
||||||
|
|
||||||
public var onTextChangedSignal: VoidClosure?
|
|
||||||
public var validationClosure: Closure<String, Bool>?
|
|
||||||
public var caretHeight: CGFloat?
|
|
||||||
|
|
||||||
public var lastNotEmpty: OTPTextField {
|
|
||||||
let isLastNotEmpty = !text.orEmpty.isEmpty && nextTextField?.text.orEmpty.isEmpty ?? true
|
|
||||||
return isLastNotEmpty ? self : nextTextField?.lastNotEmpty ?? self
|
|
||||||
}
|
|
||||||
|
|
||||||
open override var font: UIFont? {
|
|
||||||
didSet {
|
|
||||||
if caretHeight == nil, let font = font {
|
|
||||||
caretHeight = font.pointSize - font.descender
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
|
|
||||||
delegate = self
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(*, unavailable)
|
|
||||||
required public init?(coder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func deleteBackward() {
|
|
||||||
guard text.orEmpty.isEmpty else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
onTextChangedSignal?()
|
|
||||||
previousTextField?.text = ""
|
|
||||||
previousTextField?.becomeFirstResponder()
|
|
||||||
}
|
|
||||||
|
|
||||||
public func set(inputText: String) {
|
|
||||||
text = inputText.prefix(maxSymbolsCount).string
|
|
||||||
|
|
||||||
let nextInputText = inputText.count >= maxSymbolsCount
|
|
||||||
? inputText.suffix(inputText.count - maxSymbolsCount).string
|
|
||||||
: ""
|
|
||||||
|
|
||||||
nextTextField?.set(inputText: nextInputText)
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func caretRect(for position: UITextPosition) -> CGRect {
|
|
||||||
guard let caretHeight = caretHeight else {
|
|
||||||
return super.caretRect(for: position)
|
|
||||||
}
|
|
||||||
|
|
||||||
var superRect = super.caretRect(for: position)
|
|
||||||
superRect.size.height = caretHeight
|
|
||||||
|
|
||||||
return superRect
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
||||||
let view = super.hitTest(point, with: event)
|
|
||||||
return view == self && isFirstResponder ? view : nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension OTPTextField: UITextFieldDelegate {
|
|
||||||
public func textField(_ textField: UITextField,
|
|
||||||
shouldChangeCharactersIn range: NSRange,
|
|
||||||
replacementString string: String) -> Bool {
|
|
||||||
guard let textField = textField as? OTPTextField else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
let isInputEmpty = textField.text.orEmpty.isEmpty && string.isEmpty
|
|
||||||
|
|
||||||
guard isInputEmpty || validationClosure?(string) ?? true else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch range.length {
|
|
||||||
case 0: // set text to textfield
|
|
||||||
textField.set(inputText: string)
|
|
||||||
|
|
||||||
let currentTextField = textField.lastNotEmpty.nextTextField ?? textField.lastNotEmpty
|
|
||||||
currentTextField.becomeFirstResponder()
|
|
||||||
textField.onTextChangedSignal?()
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
case 1: // remove character from textfield
|
|
||||||
textField.text = ""
|
|
||||||
textField.onTextChangedSignal?()
|
|
||||||
return false
|
|
||||||
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2020 Touch Instinct
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the Software), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import TIUIElements
|
|
||||||
import TISwiftUtils
|
|
||||||
|
|
||||||
/// Base OTP view with textfield for entering a one symbol
|
|
||||||
open class OTPView: BaseInitializableView {
|
|
||||||
public let codeTextField = OTPTextField()
|
|
||||||
|
|
||||||
public var onTap: VoidClosure?
|
|
||||||
|
|
||||||
open override func addViews() {
|
|
||||||
super.addViews()
|
|
||||||
|
|
||||||
addSubview(codeTextField)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
{
|
|
||||||
"pins" : [
|
|
||||||
{
|
|
||||||
"identity" : "alamofire",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/Alamofire/Alamofire.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "bc268c28fb170f494de9e9927c371b8342979ece",
|
|
||||||
"version" : "5.7.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "antlr4",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/antlr/antlr4",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "44d87bc1d130c88aa452894aa5f7e2f710f68253",
|
|
||||||
"version" : "4.10.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "cache",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/hyperoslo/Cache.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "c7f4d633049c3bd649a353bad36f6c17e9df085f",
|
|
||||||
"version" : "6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "cursors",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/petropavel13/Cursors",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "52f27b82cb1cbbc2b5fd09514c48b9c75e3b0300",
|
|
||||||
"version" : "0.6.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "keychainaccess",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/kishikawakatsumi/KeychainAccess.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "84e546727d66f1adc5439debad16270d0fdd04e7",
|
|
||||||
"version" : "4.2.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "moya",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/Moya/Moya.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "c263811c1f3dbf002be9bd83107f7cdc38992b26",
|
|
||||||
"version" : "15.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "panmodal",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://git.svc.touchin.ru/TouchInstinct/PanModal",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "ced7c1703f90746df0224b6e0d33c146d9ae4284",
|
|
||||||
"version" : "1.3.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "reactiveswift",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/ReactiveCocoa/ReactiveSwift.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "c43bae3dac73fdd3cb906bd5a1914686ca71ed3c",
|
|
||||||
"version" : "6.7.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "rxswift",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/ReactiveX/RxSwift.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "9dcaa4b333db437b0fbfaf453fad29069044a8b4",
|
|
||||||
"version" : "6.6.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "tablekit",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://git.svc.touchin.ru/TouchInstinct/TableKit.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "fec9537745799fab55df7477cb3ec2b4ea5c254d",
|
|
||||||
"version" : "2.12.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"version" : 2
|
|
||||||
}
|
|
||||||
198
Package.swift
198
Package.swift
|
|
@ -1,198 +0,0 @@
|
||||||
// swift-tools-version:5.7
|
|
||||||
|
|
||||||
#if canImport(PackageDescription)
|
|
||||||
|
|
||||||
import PackageDescription
|
|
||||||
|
|
||||||
let package = Package(
|
|
||||||
name: "LeadKit",
|
|
||||||
platforms: [
|
|
||||||
.iOS(.v12)
|
|
||||||
],
|
|
||||||
products: [
|
|
||||||
|
|
||||||
// MARK: - Application
|
|
||||||
|
|
||||||
.library(name: "TIApplication", targets: ["TIApplication"]),
|
|
||||||
|
|
||||||
// MARK: - UIKit
|
|
||||||
|
|
||||||
.library(name: "TIUIKitCore", targets: ["TIUIKitCore"]),
|
|
||||||
.library(name: "TIUIElements", targets: ["TIUIElements"]),
|
|
||||||
.library(name: "TIWebView", targets: ["TIWebView"]),
|
|
||||||
.library(name: "TIBottomSheet", targets: ["TIBottomSheet"]),
|
|
||||||
|
|
||||||
// MARK: - SwiftUI
|
|
||||||
|
|
||||||
.library(name: "TISwiftUICore", targets: ["TISwiftUICore"]),
|
|
||||||
|
|
||||||
// MARK: - Utils
|
|
||||||
.library(name: "TISwiftUtils", targets: ["TISwiftUtils"]),
|
|
||||||
.library(name: "TIFoundationUtils", targets: ["TIFoundationUtils"]),
|
|
||||||
.library(name: "TICoreGraphicsUtils", targets: ["TICoreGraphicsUtils"]),
|
|
||||||
.library(name: "TIKeychainUtils", targets: ["TIKeychainUtils"]),
|
|
||||||
.library(name: "TITableKitUtils", targets: ["TITableKitUtils"]),
|
|
||||||
.library(name: "TIDeeplink", targets: ["TIDeeplink"]),
|
|
||||||
.library(name: "TIDeveloperUtils", targets: ["TIDeveloperUtils"]),
|
|
||||||
|
|
||||||
// MARK: - Networking
|
|
||||||
|
|
||||||
.library(name: "TINetworking", targets: ["TINetworking"]),
|
|
||||||
.library(name: "TIMoyaNetworking", targets: ["TIMoyaNetworking"]),
|
|
||||||
.library(name: "TINetworkingCache", targets: ["TINetworkingCache"]),
|
|
||||||
|
|
||||||
// MARK: - Maps
|
|
||||||
|
|
||||||
.library(name: "TIMapUtils", targets: ["TIMapUtils"]),
|
|
||||||
.library(name: "TIAppleMapUtils", targets: ["TIAppleMapUtils"]),
|
|
||||||
|
|
||||||
// MARK: - Elements
|
|
||||||
|
|
||||||
.library(name: "OTPSwiftView", targets: ["OTPSwiftView"]),
|
|
||||||
.library(name: "TITransitions", targets: ["TITransitions"]),
|
|
||||||
.library(name: "TIPagination", targets: ["TIPagination"]),
|
|
||||||
.library(name: "TIAuth", targets: ["TIAuth"]),
|
|
||||||
.library(name: "TIEcommerce", targets: ["TIEcommerce"]),
|
|
||||||
.library(name: "TITextProcessing", targets: ["TITextProcessing"])
|
|
||||||
],
|
|
||||||
dependencies: [
|
|
||||||
.package(url: "https://git.svc.touchin.ru/TouchInstinct/TableKit.git", .upToNextMinor(from: "2.12.0")),
|
|
||||||
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", .upToNextMajor(from: "4.2.2")),
|
|
||||||
.package(url: "https://github.com/petropavel13/Cursors", .upToNextMajor(from: "0.5.1")),
|
|
||||||
.package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.4.0")),
|
|
||||||
.package(url: "https://github.com/Moya/Moya.git", .upToNextMajor(from: "15.0.0")),
|
|
||||||
.package(url: "https://github.com/hyperoslo/Cache.git", .upToNextMajor(from: "6.0.0")),
|
|
||||||
.package(url: "https://github.com/antlr/antlr4", .upToNextMinor(from: "4.10.1")),
|
|
||||||
.package(url: "https://git.svc.touchin.ru/TouchInstinct/PanModal", .upToNextMinor(from: "1.3.0"))
|
|
||||||
],
|
|
||||||
targets: [
|
|
||||||
|
|
||||||
// MARK: - Application architecture
|
|
||||||
|
|
||||||
.target(name: "TIApplication",
|
|
||||||
dependencies: ["TILogging", "TIFoundationUtils", "KeychainAccess"],
|
|
||||||
path: "TIApplication/Sources",
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
// MARK: - UIKit
|
|
||||||
|
|
||||||
.target(name: "TIUIKitCore", dependencies: ["TISwiftUtils"], path: "TIUIKitCore/Sources"),
|
|
||||||
|
|
||||||
.target(name: "TIUIElements",
|
|
||||||
dependencies: ["TIUIKitCore", "TILogging"],
|
|
||||||
path: "TIUIElements/Sources",
|
|
||||||
exclude: ["../TIUIElements.app"],
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
.target(name: "TIWebView", dependencies: ["TIUIKitCore", "TISwiftUtils"], path: "TIWebView/Sources"),
|
|
||||||
.target(name: "TIBottomSheet",
|
|
||||||
dependencies: ["PanModal", "TIUIElements", "TIUIKitCore", "TISwiftUtils"],
|
|
||||||
path: "TIBottomSheet/Sources",
|
|
||||||
exclude: ["../TIBottomSheet.app"],
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
// MARK: - SwiftUI
|
|
||||||
|
|
||||||
.target(name: "TISwiftUICore",
|
|
||||||
dependencies: ["TIUIKitCore", "TISwiftUtils"],
|
|
||||||
path: "TISwiftUICore/Sources"),
|
|
||||||
|
|
||||||
// MARK: - Utils
|
|
||||||
|
|
||||||
.target(name: "TISwiftUtils",
|
|
||||||
path: "TISwiftUtils/Sources",
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
.target(name: "TIFoundationUtils",
|
|
||||||
dependencies: ["TISwiftUtils", "TILogging"],
|
|
||||||
path: "TIFoundationUtils",
|
|
||||||
exclude: ["TIFoundationUtils.app"],
|
|
||||||
resources: [
|
|
||||||
.copy("PrivacyInfo.xcprivacy"),
|
|
||||||
],
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
.target(name: "TICoreGraphicsUtils",
|
|
||||||
dependencies: [],
|
|
||||||
path: "TICoreGraphicsUtils/Sources",
|
|
||||||
exclude: ["../TICoreGraphicsUtils.app"],
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
.target(name: "TIKeychainUtils",
|
|
||||||
dependencies: ["TIFoundationUtils", "KeychainAccess"],
|
|
||||||
path: "TIKeychainUtils/Sources",
|
|
||||||
exclude: ["../TIKeychainUtils.app"],
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
.target(name: "TITableKitUtils", dependencies: ["TIUIElements", "TableKit"], path: "TITableKitUtils/Sources"),
|
|
||||||
.target(name: "TIDeeplink", dependencies: ["TIFoundationUtils"], path: "TIDeeplink", exclude: ["TIDeeplink.app"]),
|
|
||||||
.target(name: "TIDeveloperUtils", dependencies: ["TISwiftUtils", "TIUIKitCore", "TIUIElements"], path: "TIDeveloperUtils/Sources"),
|
|
||||||
.target(name: "TILogging", path: "TILogging/Sources", plugins: ["TISwiftLintPlugin"]),
|
|
||||||
|
|
||||||
// MARK: - Networking
|
|
||||||
|
|
||||||
.target(name: "TINetworking",
|
|
||||||
dependencies: ["TIFoundationUtils", "Alamofire", "TILogging"],
|
|
||||||
path: "TINetworking/Sources",
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
.target(name: "TIMoyaNetworking",
|
|
||||||
dependencies: ["TINetworking", "Moya"],
|
|
||||||
path: "TIMoyaNetworking/Sources",
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
.target(name: "TINetworkingCache",
|
|
||||||
dependencies: ["TINetworking", "Cache"],
|
|
||||||
path: "TINetworkingCache/Sources",
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
// MARK: - Maps
|
|
||||||
|
|
||||||
.target(name: "TIMapUtils",
|
|
||||||
dependencies: ["TILogging", "TICoreGraphicsUtils"],
|
|
||||||
path: "TIMapUtils/Sources",
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
.target(name: "TIAppleMapUtils",
|
|
||||||
dependencies: ["TIMapUtils"],
|
|
||||||
path: "TIAppleMapUtils/Sources",
|
|
||||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
|
||||||
|
|
||||||
// MARK: - Elements
|
|
||||||
|
|
||||||
.target(name: "OTPSwiftView", dependencies: ["TIUIElements"], path: "OTPSwiftView/Sources"),
|
|
||||||
.target(name: "TITransitions", path: "TITransitions/Sources"),
|
|
||||||
.target(name: "TIPagination", dependencies: ["Cursors", "TISwiftUtils"], path: "TIPagination/Sources"),
|
|
||||||
.target(name: "TIAuth", dependencies: ["TIUIKitCore", "TIKeychainUtils"], path: "TIAuth/Sources"),
|
|
||||||
.target(name: "TIEcommerce", dependencies: ["TIFoundationUtils", "TISwiftUtils", "TINetworking", "TIUIKitCore", "TIUIElements"], path: "TIEcommerce/Sources"),
|
|
||||||
.target(name: "TITextProcessing",
|
|
||||||
dependencies: [.product(name: "Antlr4", package: "antlr4")],
|
|
||||||
path: "TITextProcessing/Sources",
|
|
||||||
exclude: ["../TITextProcessing.app"]),
|
|
||||||
|
|
||||||
.binaryTarget(name: "SwiftLintBinary",
|
|
||||||
url: "https://github.com/realm/SwiftLint/releases/download/0.52.2/SwiftLintBinary-macos.artifactbundle.zip",
|
|
||||||
checksum: "89651e1c87fb62faf076ef785a5b1af7f43570b2b74c6773526e0d5114e0578e"),
|
|
||||||
|
|
||||||
.plugin(name: "TISwiftLintPlugin",
|
|
||||||
capability: .buildTool(),
|
|
||||||
dependencies: ["SwiftLintBinary"]),
|
|
||||||
|
|
||||||
// MARK: - Tests
|
|
||||||
|
|
||||||
.testTarget(
|
|
||||||
name: "TITimerTests",
|
|
||||||
dependencies: ["TIFoundationUtils"],
|
|
||||||
path: "Tests/TITimerTests"),
|
|
||||||
.testTarget(
|
|
||||||
name: "TITextProcessingTests",
|
|
||||||
dependencies: ["TITextProcessing"],
|
|
||||||
path: "Tests/TITextProcessingTests"),
|
|
||||||
.testTarget(
|
|
||||||
name: "TIFoundationUtilsTests",
|
|
||||||
dependencies: ["TIFoundationUtils", "TISwiftUtils", "TILogging"],
|
|
||||||
path: "Tests/TIFoundationUtilsTests")
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2023 Touch Instinct
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the Software), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import PackagePlugin
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
@main
|
|
||||||
struct SwiftLintPlugin: BuildToolPlugin {
|
|
||||||
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
|
|
||||||
let swiftlintScriptPath = context.package.directory.appending(["build-scripts", "xcode", "build_phases", "swiftlint.sh"])
|
|
||||||
|
|
||||||
let swiftlintExecutablePath = try context.tool(named: "swiftlint").path
|
|
||||||
|
|
||||||
let srcRoot = context.package.directory.string
|
|
||||||
let targetDir = target.directory.string
|
|
||||||
|
|
||||||
let relativeTargetDir = targetDir.replacingOccurrences(of: srcRoot, with: "")
|
|
||||||
let clearRelativeTargetDir = relativeTargetDir[relativeTargetDir.index(after: relativeTargetDir.startIndex)...] // trim leading /
|
|
||||||
|
|
||||||
return [
|
|
||||||
.prebuildCommand(displayName: "SwiftLint linting \(target.name)...",
|
|
||||||
executable: swiftlintScriptPath,
|
|
||||||
arguments: [
|
|
||||||
swiftlintExecutablePath,
|
|
||||||
context.package.directory.appending(subpath: "swiftlint_base.yml")
|
|
||||||
],
|
|
||||||
environment: [
|
|
||||||
"SCRIPT_DIR": swiftlintScriptPath.removingLastComponent().string,
|
|
||||||
"SRCROOT": srcRoot,
|
|
||||||
"SCRIPT_INPUT_FILE_COUNT": "1",
|
|
||||||
"SCRIPT_INPUT_FILE_0": clearRelativeTargetDir,
|
|
||||||
// "FORCE_LINT": "1", // Lint all files in target (not only modified)
|
|
||||||
// "AUTOCORRECT": "1"
|
|
||||||
],
|
|
||||||
outputFilesDirectory: context.package.directory)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
139
README.md
139
README.md
|
|
@ -1,139 +1,2 @@
|
||||||
# LeadKit
|
# LeadKit
|
||||||
|
LeadKit it's a iOS framework with a bunch of tools for rapid app development
|
||||||
LeadKit is the iOS framework with a bunch of tools for rapid app development.
|
|
||||||
|
|
||||||
This repository contains the following frameworks:
|
|
||||||
|
|
||||||
- [TISwiftUtils](TISwiftUtils) - a bunch of useful helpers for Swift development.
|
|
||||||
- [TIFoundationUtils](TIFoundationUtils) - set of helpers for Foundation framework classes.
|
|
||||||
- [TIUIKitCore](TIUIKitCore) - core ui elements and protocols from LeadKit.
|
|
||||||
- [TISwiftUICore](TISwiftUICore) Core UI elements: protocols, views and helpers.
|
|
||||||
- [TIUIElements](TIUIElements) - bunch of of useful protocols and views.
|
|
||||||
- [OTPSwiftView](OTPSwiftView) - a fully customizable OTP view.
|
|
||||||
- [TITableKitUtils](TITableKitUtils) - set of helpers for TableKit classes.
|
|
||||||
- [TIKeychainUtils](TIKeychainUtils) - set of helpers for Keychain classes.
|
|
||||||
- [TIPagination](TIPagination) - realisation of paginating items from a data source.
|
|
||||||
- [TINetworking](TINetworking) - Swagger-frendly networking layer helpers.
|
|
||||||
- [TIMoyaNetworking](TIMoyaNetworking) - Moya + Swagger network service.
|
|
||||||
- [TIAppleMapUtils](TIAppleMapUtils) - set of helpers for map objects clustering and interacting using Apple MapKit.
|
|
||||||
- [TIGoogleMapUtils](TIGoogleMapUtils) - set of helpers for map objects clustering and interacting using Google Maps SDK.
|
|
||||||
- [TIYandexMapUtils](TIYandexMapUtils) - set of helpers for map objects clustering and interacting using Yandex Maps SDK.
|
|
||||||
- [TIAuth](TIAuth) - login, registration, confirmation and other related actions
|
|
||||||
|
|
||||||
## Playgrounds
|
|
||||||
|
|
||||||
### Create new Playground
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ cd TIModuleName
|
|
||||||
|
|
||||||
$ touch PlaygroundPodfile
|
|
||||||
|
|
||||||
$ echo "ENV[\"DEVELOPMENT_INSTALL\"] = \"true\"
|
|
||||||
|
|
||||||
target 'TIModuleName' do
|
|
||||||
platform :ios, IOS_VERSION_NUMBER
|
|
||||||
use_frameworks!
|
|
||||||
|
|
||||||
pod 'TIDependencyModuleName', :path => '../../../../TIDependencyModuleName/TIDependencyModuleName.podspec'
|
|
||||||
pod 'TIModuleName', :path => '../../../../TIModuleName/TIModuleName.podspec'
|
|
||||||
end" > PlaygroundPodfile
|
|
||||||
|
|
||||||
$ nef playground --name TIModuleName --cocoapods --custom-podfile PlaygroundPodfile
|
|
||||||
```
|
|
||||||
See example of `PlaygroundPodfile` in `TIFoundationUtils`
|
|
||||||
|
|
||||||
|
|
||||||
### Rename/add pages to Playground
|
|
||||||
|
|
||||||
For every new feature in module create new Playground page with documentation in comments. See [nef markdown documentation](https://github.com/bow-swift/nef#-generating-a-markdown-project).
|
|
||||||
|
|
||||||
### Create symlink to nef playground
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ cd TIModuleName
|
|
||||||
$ ln -s TIModuleName.app/Contents/MacOS/TIModuleName.playground TIModuleName.playground
|
|
||||||
```
|
|
||||||
|
|
||||||
### Add nef files to TIModuleName.app/.gitignore
|
|
||||||
|
|
||||||
```
|
|
||||||
# gitignore nef files
|
|
||||||
**/build/
|
|
||||||
**/nef/
|
|
||||||
LICENSE
|
|
||||||
```
|
|
||||||
|
|
||||||
### Exclude .app bundles from package sources
|
|
||||||
|
|
||||||
#### SPM
|
|
||||||
|
|
||||||
```swift
|
|
||||||
.target(name: "TIModuleName", dependencies: ..., path: ..., exclude: ["TIModuleName.app"]),
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Podspec
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
sources = 'your_sources_expression'
|
|
||||||
if ENV["DEVELOPMENT_INSTALL"] # installing using :path =>
|
|
||||||
s.source_files = sources
|
|
||||||
s.exclude_files = s.name + '.app'
|
|
||||||
else
|
|
||||||
s.source_files = s.name + '/' + sources
|
|
||||||
s.exclude_files = s.name + '/*.app'
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
## Docs:
|
|
||||||
|
|
||||||
- [TIFoundationUtils](docs/tifoundationutils)
|
|
||||||
* [AsyncOperation](docs/tifoundationutils/asyncoperation.md)
|
|
||||||
- [TICoreGraphicsUtils](docs/ticoregraphicsutils)
|
|
||||||
* [DrawingOperations](docs/ticoregraphicsutils/drawingoperations.md)
|
|
||||||
- [TIKeychainUtils](docs/tikeychainutils)
|
|
||||||
* [SingleValueStorage](docs/tikeychainutils/singlevaluestorage.md)
|
|
||||||
- [TIUIElements](docs/tiuielements)
|
|
||||||
* [Skeletons](docs/tiuielements/skeletons.md)
|
|
||||||
* [Placeholders](docs/tiuielements/placeholder.md)
|
|
||||||
- [TITextProcessing](docs/titextprocessing)
|
|
||||||
* [TITextProcessing](docs/titextprocessing/titextprocessing.md)
|
|
||||||
- [TIDeeplink](docs/tideeplink/deeplinks.md)
|
|
||||||
- [TIBottomSheet](docs/tibottomsheet/tibottomsheet.md)
|
|
||||||
- [Semantic Commit Messages](docs/semantic-commit-messages.md) - commit message codestyle.
|
|
||||||
- [Snippets](docs/snippets.md) - useful commands and scripts for development.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
- Run following script in framework's folder:
|
|
||||||
```
|
|
||||||
./setup
|
|
||||||
```
|
|
||||||
|
|
||||||
- If legacy [Source](https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/master/Sources) folder needed, [build dependencies for LeadKit.xcodeproj](https://git.svc.touchin.ru/TouchInstinct/LeadKit/blob/master/docs/snippets.md#build-dependencies-for-LeadKit.xcodeproj).
|
|
||||||
|
|
||||||
- Make sure the commit message codestyle is followed. More about [Semantic Commit Messages](docs/semantic-commit-messages.md).
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### SPM
|
|
||||||
|
|
||||||
```swift
|
|
||||||
dependencies: [
|
|
||||||
.package(url: "https://git.svc.touchin.ru/TouchInstinct/LeadKit.git", from: "x.y.z"),
|
|
||||||
],
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cocoapods
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
source 'https://git.svc.touchin.ru/TouchInstinct/Podspecs.git'
|
|
||||||
|
|
||||||
pod 'TISwiftUtils', 'x.y.z'
|
|
||||||
pod 'TIFoundationUtils', 'x.y.z'
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Legacy
|
|
||||||
|
|
||||||
Code located in root `Sources` folder and `LeadKit.podspec` should be treated as legacy and shouldn't be used in newly created projects. Please use TI* modules via SPM or CocoaPods.
|
|
||||||
|
|
@ -26,11 +26,11 @@ import UIKit
|
||||||
open class BaseCollectionContentController<ViewModel>: BaseScrollContentController<ViewModel, CollectionViewWrapperView> {
|
open class BaseCollectionContentController<ViewModel>: BaseScrollContentController<ViewModel, CollectionViewWrapperView> {
|
||||||
|
|
||||||
override open func createView() -> CollectionViewWrapperView {
|
override open func createView() -> CollectionViewWrapperView {
|
||||||
CollectionViewWrapperView(layout: UICollectionViewFlowLayout())
|
return CollectionViewWrapperView(layout: UICollectionViewFlowLayout())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contained UICollectionView instance.
|
/// Contained UICollectionView instance.
|
||||||
public var collectionView: UICollectionView {
|
public var collectionView: UICollectionView {
|
||||||
customView.collectionView
|
return customView.collectionView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
import UIKit.UIViewController
|
import UIKit.UIViewController
|
||||||
|
|
||||||
/// Base controller that should be configured with view model.
|
/// Base controller that should be configured with view model.
|
||||||
open class BaseConfigurableController<ViewModel>: BaseOrientationController, ConfigurableController {
|
open class BaseConfigurableController<ViewModel>: UIViewController, ConfigurableController {
|
||||||
|
|
||||||
/// A view model instance used by this controller.
|
/// A view model instance used by this controller.
|
||||||
public let viewModel: ViewModel
|
public let viewModel: ViewModel
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,6 @@ open class BaseCustomViewController<ViewModel, View: UIView>: BaseConfigurableCo
|
||||||
///
|
///
|
||||||
/// - Returns: Initialized custom view.
|
/// - Returns: Initialized custom view.
|
||||||
open func createView() -> View {
|
open func createView() -> View {
|
||||||
View()
|
return View()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
import Foundation
|
|
||||||
|
|
||||||
open class BaseOrientationController: UIViewController {
|
|
||||||
|
|
||||||
/// Ability to set forced screen orientation
|
|
||||||
open var forcedInterfaceOrientation: UIInterfaceOrientation?
|
|
||||||
|
|
||||||
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
|
||||||
switch forcedInterfaceOrientation {
|
|
||||||
case .landscapeLeft:
|
|
||||||
return .landscapeLeft
|
|
||||||
|
|
||||||
case .landscapeRight:
|
|
||||||
return .landscapeRight
|
|
||||||
|
|
||||||
case .portrait:
|
|
||||||
return .portrait
|
|
||||||
|
|
||||||
case .portraitUpsideDown:
|
|
||||||
return .portraitUpsideDown
|
|
||||||
|
|
||||||
default:
|
|
||||||
return super.supportedInterfaceOrientations
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
|
|
||||||
forcedInterfaceOrientation ?? super.preferredInterfaceOrientationForPresentation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
import UIKit
|
|
||||||
|
|
||||||
open class OrientationNavigationController: UINavigationController {
|
|
||||||
|
|
||||||
// MARK: - Public properties
|
|
||||||
|
|
||||||
open var presentedOrTopViewController: UIViewController? {
|
|
||||||
presentedViewController ?? topViewController
|
|
||||||
}
|
|
||||||
|
|
||||||
open override var shouldAutorotate: Bool {
|
|
||||||
presentedOrTopViewController?.shouldAutorotate
|
|
||||||
?? super.shouldAutorotate
|
|
||||||
}
|
|
||||||
|
|
||||||
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
|
||||||
presentedOrTopViewController?.supportedInterfaceOrientations
|
|
||||||
?? super.supportedInterfaceOrientations
|
|
||||||
}
|
|
||||||
|
|
||||||
open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
|
|
||||||
presentedOrTopViewController?.preferredInterfaceOrientationForPresentation
|
|
||||||
?? super.preferredInterfaceOrientationForPresentation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -49,13 +49,13 @@ open class BaseScrollContentController<ViewModel, View: ScrollViewHolderView>: B
|
||||||
|
|
||||||
/// Contained UIScrollView instance.
|
/// Contained UIScrollView instance.
|
||||||
public var scrollView: UIScrollView {
|
public var scrollView: UIScrollView {
|
||||||
customView.scrollView
|
return customView.scrollView
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default insets used for contained scroll view.
|
/// Default insets used for contained scroll view.
|
||||||
public var defaultInsets: UIEdgeInsets {
|
public var defaultInsets: UIEdgeInsets {
|
||||||
get {
|
get {
|
||||||
defaultInsetsRelay.value
|
return defaultInsetsRelay.value
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
defaultInsetsRelay.accept(newValue)
|
defaultInsetsRelay.accept(newValue)
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,11 @@ open class BaseTableContentController<ViewModel>: BaseScrollContentController<Vi
|
||||||
///
|
///
|
||||||
/// - Returns: Initialized TableDirector.
|
/// - Returns: Initialized TableDirector.
|
||||||
open func createTableDirector() -> TableDirector {
|
open func createTableDirector() -> TableDirector {
|
||||||
TableDirector(tableView: tableView)
|
return TableDirector(tableView: tableView)
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func createView() -> TableViewWrapperView {
|
override open func createView() -> TableViewWrapperView {
|
||||||
TableViewWrapperView(tableViewStyle: .plain)
|
return TableViewWrapperView(tableViewStyle: .plain)
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func configureAppearance() {
|
override open func configureAppearance() {
|
||||||
|
|
@ -47,6 +47,6 @@ open class BaseTableContentController<ViewModel>: BaseScrollContentController<Vi
|
||||||
|
|
||||||
/// Contained UITableView instance.
|
/// Contained UITableView instance.
|
||||||
public var tableView: UITableView {
|
public var tableView: UITableView {
|
||||||
customView.tableView
|
return customView.tableView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,17 +42,17 @@ public class FixedPageCursor<Cursor: CursorType>: CursorType, RxDataSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
public var exhausted: Bool {
|
public var exhausted: Bool {
|
||||||
cursor.exhausted && cursor.count == count
|
return cursor.exhausted && cursor.count == count
|
||||||
}
|
}
|
||||||
|
|
||||||
public private(set) var count: Int = 0
|
public private(set) var count: Int = 0
|
||||||
|
|
||||||
public subscript(index: Int) -> Cursor.Element {
|
public subscript(index: Int) -> Cursor.Element {
|
||||||
cursor[index]
|
return cursor[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
public func loadNextBatch() -> Single<[Cursor.Element]> {
|
public func loadNextBatch() -> Single<[Cursor.Element]> {
|
||||||
Single.deferred {
|
return Single.deferred {
|
||||||
if self.exhausted {
|
if self.exhausted {
|
||||||
return .error(CursorError.exhausted)
|
return .error(CursorError.exhausted)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ public extension CursorType {
|
||||||
/// - Parameter transform: closure to transform elements
|
/// - Parameter transform: closure to transform elements
|
||||||
/// - Returns: new MapCursor instance
|
/// - Returns: new MapCursor instance
|
||||||
func flatMap<T>(transform: @escaping MapCursor<Self, T>.Transform) -> MapCursor<Self, T> {
|
func flatMap<T>(transform: @escaping MapCursor<Self, T>.Transform) -> MapCursor<Self, T> {
|
||||||
MapCursor(cursor: self, transform: transform)
|
return MapCursor(cursor: self, transform: transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates ResettableMapCursor with current cursor
|
/// Creates ResettableMapCursor with current cursor
|
||||||
|
|
@ -39,7 +39,7 @@ public extension CursorType {
|
||||||
func flatMap<T>(transform: @escaping ResettableMapCursor<Self, T>.Transform)
|
func flatMap<T>(transform: @escaping ResettableMapCursor<Self, T>.Transform)
|
||||||
-> ResettableMapCursor<Self, T> where Self: ResettableCursorType {
|
-> ResettableMapCursor<Self, T> where Self: ResettableCursorType {
|
||||||
|
|
||||||
ResettableMapCursor(cursor: self, transform: transform)
|
return ResettableMapCursor(cursor: self, transform: transform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,19 +67,19 @@ public class MapCursor<Cursor: CursorType, T>: CursorType, RxDataSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
public var exhausted: Bool {
|
public var exhausted: Bool {
|
||||||
cursor.exhausted
|
return cursor.exhausted
|
||||||
}
|
}
|
||||||
|
|
||||||
public var count: Int {
|
public var count: Int {
|
||||||
elements.count
|
return elements.count
|
||||||
}
|
}
|
||||||
|
|
||||||
public subscript(index: Int) -> T {
|
public subscript(index: Int) -> T {
|
||||||
elements[index]
|
return elements[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
public func loadNextBatch() -> Single<[T]> {
|
public func loadNextBatch() -> Single<[T]> {
|
||||||
cursor.loadNextBatch().map { newItems in
|
return cursor.loadNextBatch().map { newItems in
|
||||||
let transformedNewItems = newItems.compactMap(self.transform)
|
let transformedNewItems = newItems.compactMap(self.transform)
|
||||||
self.elements += transformedNewItems
|
self.elements += transformedNewItems
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ public final class SingleLoadCursorConfiguration<Element>: TotalCountCursorConfi
|
||||||
}
|
}
|
||||||
|
|
||||||
public func resultSingle() -> Single<ResultType> {
|
public func resultSingle() -> Single<ResultType> {
|
||||||
loadingSingle
|
return loadingSingle
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(resetFrom other: SingleLoadCursorConfiguration) {
|
public init(resetFrom other: SingleLoadCursorConfiguration) {
|
||||||
|
|
@ -67,15 +67,15 @@ public class SingleLoadCursor<Element>: ResettableCursorType {
|
||||||
public private(set) var exhausted = false
|
public private(set) var exhausted = false
|
||||||
|
|
||||||
public var count: Int {
|
public var count: Int {
|
||||||
content.count
|
return content.count
|
||||||
}
|
}
|
||||||
|
|
||||||
public subscript(index: Int) -> Element {
|
public subscript(index: Int) -> Element {
|
||||||
content[index]
|
return content[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
public func loadNextBatch() -> Single<[Element]> {
|
public func loadNextBatch() -> Single<[Element]> {
|
||||||
Single.deferred {
|
return Single.deferred {
|
||||||
if self.exhausted {
|
if self.exhausted {
|
||||||
return .error(CursorError.exhausted)
|
return .error(CursorError.exhausted)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,11 @@ public class StaticCursor<Element>: ResettableRxDataSourceCursor {
|
||||||
public private(set) var count = 0
|
public private(set) var count = 0
|
||||||
|
|
||||||
public subscript(index: Int) -> Element {
|
public subscript(index: Int) -> Element {
|
||||||
content[index]
|
return content[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
public func loadNextBatch() -> Single<[Element]> {
|
public func loadNextBatch() -> Single<[Element]> {
|
||||||
Single.deferred {
|
return Single.deferred {
|
||||||
if self.exhausted {
|
if self.exhausted {
|
||||||
return .error(CursorError.exhausted)
|
return .error(CursorError.exhausted)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
import RxSwift
|
import RxSwift
|
||||||
import RxCocoa
|
import RxCocoa
|
||||||
|
|
||||||
open class TotalCountCursor<CursorConfiguration: TotalCountCursorConfiguration>: ResettableRxDataSourceCursor {
|
public final class TotalCountCursor<CursorConfiguration: TotalCountCursorConfiguration>: ResettableRxDataSourceCursor {
|
||||||
|
|
||||||
public typealias Element = CursorConfiguration.ResultType.ElementType
|
public typealias Element = CursorConfiguration.ResultType.ElementType
|
||||||
public typealias ResultType = [Element]
|
public typealias ResultType = [Element]
|
||||||
|
|
@ -35,15 +35,15 @@ open class TotalCountCursor<CursorConfiguration: TotalCountCursorConfiguration>:
|
||||||
public private(set) var totalCount: Int = .max
|
public private(set) var totalCount: Int = .max
|
||||||
|
|
||||||
public var exhausted: Bool {
|
public var exhausted: Bool {
|
||||||
count >= totalCount
|
return count >= totalCount
|
||||||
}
|
}
|
||||||
|
|
||||||
public var count: Int {
|
public var count: Int {
|
||||||
elements.count
|
return elements.count
|
||||||
}
|
}
|
||||||
|
|
||||||
public subscript(index: Int) -> Element {
|
public subscript(index: Int) -> Element {
|
||||||
elements[index]
|
return elements[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(configuration: CursorConfiguration) {
|
public init(configuration: CursorConfiguration) {
|
||||||
|
|
@ -54,12 +54,8 @@ open class TotalCountCursor<CursorConfiguration: TotalCountCursorConfiguration>:
|
||||||
configuration = other.configuration.reset()
|
configuration = other.configuration.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
open func processResultFromConfigurationSingle() -> Single<CursorConfiguration.ResultType> {
|
|
||||||
configuration.resultSingle()
|
|
||||||
}
|
|
||||||
|
|
||||||
public func loadNextBatch() -> Single<[Element]> {
|
public func loadNextBatch() -> Single<[Element]> {
|
||||||
processResultFromConfigurationSingle()
|
return configuration.resultSingle()
|
||||||
.do(onSuccess: { [weak self] listingResult in
|
.do(onSuccess: { [weak self] listingResult in
|
||||||
self?.totalCount = listingResult.totalCount
|
self?.totalCount = listingResult.totalCount
|
||||||
self?.elements = (self?.elements ?? []) + listingResult.results
|
self?.elements = (self?.elements ?? []) + listingResult.results
|
||||||
|
|
|
||||||
|
|
@ -63,28 +63,28 @@ open class GeneralDataLoadingViewModel<ResultType>: BaseViewModel, GeneralDataLo
|
||||||
|
|
||||||
/// Returns observable that emits current loading state.
|
/// Returns observable that emits current loading state.
|
||||||
open var loadingStateObservable: Observable<LoadingState> {
|
open var loadingStateObservable: Observable<LoadingState> {
|
||||||
loadingStateRelay.asObservable()
|
return loadingStateRelay.asObservable()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns driver that emits current loading state.
|
/// Returns driver that emits current loading state.
|
||||||
open var loadingStateDriver: Driver<LoadingState> {
|
open var loadingStateDriver: Driver<LoadingState> {
|
||||||
loadingStateRelay.asDriver()
|
return loadingStateRelay.asDriver()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// By default returns true if loading state == .result.
|
/// By default returns true if loading state == .result.
|
||||||
open var hasContent: Bool {
|
open var hasContent: Bool {
|
||||||
currentLoadingState.hasResult
|
return currentLoadingState.hasResult
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns current result if it exists.
|
/// Returns current result if it exists.
|
||||||
public var currentResult: ResultType? {
|
public var currentResult: ResultType? {
|
||||||
currentLoadingState.result
|
return currentLoadingState.result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Current state of loading process.
|
/// Current state of loading process.
|
||||||
private(set) public var currentLoadingState: LoadingState {
|
private(set) public var currentLoadingState: LoadingState {
|
||||||
get {
|
get {
|
||||||
loadingStateRelay.value
|
return loadingStateRelay.value
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
loadingStateRelay.accept(newValue)
|
loadingStateRelay.accept(newValue)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2023 Touch Instinct
|
// Copyright (c) 2019 Touch Instinct
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the Software), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
// in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
// The above copyright notice and this permission notice shall be included in
|
// The above copyright notice and this permission notice shall be included in
|
||||||
// all copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
|
@ -22,29 +22,25 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
public extension UIViewController {
|
/// Base for network error alert setup
|
||||||
|
public final class NetworkErrorAlertBase<ErrorType: Error & Hashable> {
|
||||||
|
|
||||||
/// Shows skeletons
|
let customErrorModels: [ErrorType: Any]
|
||||||
|
let alertActions: [UIAlertAction]
|
||||||
|
let globalErrorAction: VoidBlock?
|
||||||
|
|
||||||
|
/// Initializer for network error alert base
|
||||||
///
|
///
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - viewsToSkeletons: views that will be converted to skeletons.
|
/// - customErrorModels: additional information for specific errors
|
||||||
/// If nil was passed subviews of the view will be converted to skeletons
|
/// - alertActions: alert actions
|
||||||
/// - config: configuration of the skeletons' layers
|
/// - globalErrorAction: optional action for global error
|
||||||
func showSkeletons(viewsToSkeletons: [UIView]?,
|
init(customErrorModels: [ErrorType: Any],
|
||||||
_ config: SkeletonsConfiguration) {
|
alertActions: [UIAlertAction],
|
||||||
|
globalErrorAction: VoidBlock?) {
|
||||||
|
|
||||||
view.showSkeletons(viewsToSkeletons: viewsToSkeletons, config)
|
self.customErrorModels = customErrorModels
|
||||||
}
|
self.alertActions = alertActions
|
||||||
|
self.globalErrorAction = globalErrorAction
|
||||||
func hideSkeletons() {
|
|
||||||
view.hideSkeletons()
|
|
||||||
}
|
|
||||||
|
|
||||||
func startSkeletonAnimation() {
|
|
||||||
view.startSkeletonAnimation()
|
|
||||||
}
|
|
||||||
|
|
||||||
func stopSkeletonAnimation() {
|
|
||||||
view.stopSkeletonAnimation()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -22,11 +22,9 @@
|
||||||
|
|
||||||
import RxSwift
|
import RxSwift
|
||||||
|
|
||||||
public typealias RxPaginationDataLoadingModel<Cursor: ResettableRxDataSourceCursor> =
|
|
||||||
RxDataLoadingModel<PaginationDataLoadingState<Cursor>>
|
|
||||||
|
|
||||||
/// Data loading model for PaginationDataLoadingState with ResettableRxDataSourceCursor as data source.
|
/// Data loading model for PaginationDataLoadingState with ResettableRxDataSourceCursor as data source.
|
||||||
public final class PaginationDataLoadingModel<Cursor: ResettableRxDataSourceCursor>: RxPaginationDataLoadingModel<Cursor> {
|
public final class PaginationDataLoadingModel<Cursor: ResettableRxDataSourceCursor>:
|
||||||
|
RxDataLoadingModel<PaginationDataLoadingState<Cursor>> {
|
||||||
|
|
||||||
private enum LoadType {
|
private enum LoadType {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
||||||
/// so the handler can be triggered before reaching end. Defaults to 0.0;
|
/// so the handler can be triggered before reaching end. Defaults to 0.0;
|
||||||
public var infiniteScrollTriggerOffset: CGFloat {
|
public var infiniteScrollTriggerOffset: CGFloat {
|
||||||
get {
|
get {
|
||||||
wrappedView.scrollView.infiniteScrollTriggerOffset
|
return wrappedView.scrollView.infiniteScrollTriggerOffset
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
wrappedView.scrollView.infiniteScrollTriggerOffset = newValue
|
wrappedView.scrollView.infiniteScrollTriggerOffset = newValue
|
||||||
|
|
@ -60,15 +60,13 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var bottom: CGFloat {
|
|
||||||
wrappedView.scrollView.contentSize.height - wrappedView.scrollView.frame.size.height
|
|
||||||
}
|
|
||||||
|
|
||||||
private let disposeBag = DisposeBag()
|
private let disposeBag = DisposeBag()
|
||||||
|
|
||||||
private var currentPlaceholderView: UIView?
|
private var currentPlaceholderView: UIView?
|
||||||
private var currentPlaceholderViewTopConstraint: NSLayoutConstraint?
|
private var currentPlaceholderViewTopConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
|
private let applicationCurrentyActive = BehaviorRelay(value: true)
|
||||||
|
|
||||||
/// Initializer with table view, placeholders container view, cusor and delegate parameters.
|
/// Initializer with table view, placeholders container view, cusor and delegate parameters.
|
||||||
///
|
///
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
|
|
@ -89,6 +87,8 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
||||||
bindViewModelStates()
|
bindViewModelStates()
|
||||||
|
|
||||||
createRefreshControl()
|
createRefreshControl()
|
||||||
|
|
||||||
|
bindAppStateNotifications()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method that reload all data in internal view model.
|
/// Method that reload all data in internal view model.
|
||||||
|
|
@ -121,7 +121,7 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
||||||
if case .initial = afterState {
|
if case .initial = afterState {
|
||||||
wrappedView.scrollView.isUserInteractionEnabled = false
|
wrappedView.scrollView.isUserInteractionEnabled = false
|
||||||
|
|
||||||
removeAllPlaceholderView()
|
removeCurrentPlaceholderView()
|
||||||
|
|
||||||
guard let loadingIndicator = uiDelegate?.initialLoadingIndicator() else {
|
guard let loadingIndicator = uiDelegate?.initialLoadingIndicator() else {
|
||||||
return
|
return
|
||||||
|
|
@ -144,7 +144,7 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
||||||
|
|
||||||
private func onLoadingMoreState(afterState: LoadingState) {
|
private func onLoadingMoreState(afterState: LoadingState) {
|
||||||
if case .error = afterState { // user tap retry button in table footer
|
if case .error = afterState { // user tap retry button in table footer
|
||||||
uiDelegate?.footerRetryViewWillDisappear()
|
uiDelegate?.footerRetryButtonWillDisappear()
|
||||||
wrappedView.footerView = nil
|
wrappedView.footerView = nil
|
||||||
addInfiniteScroll(withHandler: false)
|
addInfiniteScroll(withHandler: false)
|
||||||
wrappedView.scrollView.beginInfiniteScroll(true)
|
wrappedView.scrollView.beginInfiniteScroll(true)
|
||||||
|
|
@ -160,23 +160,22 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
||||||
if case .initialLoading = afterState {
|
if case .initialLoading = afterState {
|
||||||
delegate?.paginationWrapper(didReload: newItems, using: cursor)
|
delegate?.paginationWrapper(didReload: newItems, using: cursor)
|
||||||
|
|
||||||
removeAllPlaceholderView()
|
removeCurrentPlaceholderView()
|
||||||
|
|
||||||
wrappedView.scrollView.refreshControl?.endRefreshing()
|
wrappedView.scrollView.support.refreshControl?.endRefreshing()
|
||||||
|
|
||||||
addInfiniteScroll(withHandler: true)
|
addInfiniteScroll(withHandler: true)
|
||||||
} else if case .loadingMore = afterState {
|
} else if case .loadingMore = afterState {
|
||||||
delegate?.paginationWrapper(didLoad: newItems, using: cursor)
|
delegate?.paginationWrapper(didLoad: newItems, using: cursor)
|
||||||
|
|
||||||
removeAllPlaceholderView()
|
readdInfiniteScrollWithHandler()
|
||||||
addInfiniteScrollWithHandler()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func onErrorState(error: Error, afterState: LoadingState) {
|
private func onErrorState(error: Error, afterState: LoadingState) {
|
||||||
if case .initialLoading = afterState {
|
if case .initialLoading = afterState {
|
||||||
defer {
|
defer {
|
||||||
wrappedView.scrollView.refreshControl?.endRefreshing()
|
wrappedView.scrollView.support.refreshControl?.endRefreshing()
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate?.clearData()
|
delegate?.clearData()
|
||||||
|
|
@ -187,42 +186,38 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
||||||
}
|
}
|
||||||
|
|
||||||
replacePlaceholderViewIfNeeded(with: errorView)
|
replacePlaceholderViewIfNeeded(with: errorView)
|
||||||
} else {
|
} else if case .loadingMore = afterState {
|
||||||
guard let retryView = uiDelegate?.footerRetryView(),
|
guard let retryButton = uiDelegate?.footerRetryButton(),
|
||||||
let retryViewHeight = uiDelegate?.footerRetryViewHeight() else {
|
let retryButtonHeight = uiDelegate?.footerRetryButtonHeight() else {
|
||||||
|
|
||||||
removeInfiniteScroll()
|
removeInfiniteScroll()
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
retryView.frame = CGRect(x: 0, y: 0, width: wrappedView.scrollView.bounds.width, height: retryViewHeight)
|
retryButton.frame = CGRect(x: 0, y: 0, width: wrappedView.scrollView.bounds.width, height: retryButtonHeight)
|
||||||
retryView.button.addTarget(self, action: #selector(retryEvent), for: .touchUpInside)
|
|
||||||
|
|
||||||
uiDelegate?.footerRetryViewWillAppear()
|
retryButton.rx
|
||||||
|
.controlEvent(.touchUpInside)
|
||||||
|
.asDriver()
|
||||||
|
.drive(retryEvent)
|
||||||
|
.disposed(by: disposeBag)
|
||||||
|
|
||||||
|
uiDelegate?.footerRetryButtonWillAppear()
|
||||||
|
|
||||||
removeInfiniteScroll { scrollView in
|
removeInfiniteScroll { scrollView in
|
||||||
self.wrappedView.footerView = retryView
|
self.wrappedView.footerView = retryButton
|
||||||
|
|
||||||
let shouldUpdateContentOffset = Int(scrollView.contentOffset.y + retryViewHeight) >= Int(self.bottom)
|
let newContentOffset = CGPoint(x: 0, y: scrollView.contentOffset.y + retryButtonHeight)
|
||||||
|
|
||||||
if shouldUpdateContentOffset {
|
scrollView.setContentOffset(newContentOffset, animated: true)
|
||||||
let newContentOffset = CGPoint(x: 0, y: scrollView.contentOffset.y + retryViewHeight)
|
|
||||||
scrollView.setContentOffset(newContentOffset, animated: true)
|
|
||||||
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
scrollView.setContentOffset(newContentOffset, animated: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func retryEvent() {
|
|
||||||
paginationViewModel.loadMore()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func onEmptyState() {
|
private func onEmptyState() {
|
||||||
defer {
|
defer {
|
||||||
wrappedView.scrollView.refreshControl?.endRefreshing()
|
wrappedView.scrollView.support.refreshControl?.endRefreshing()
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate?.clearData()
|
delegate?.clearData()
|
||||||
|
|
@ -236,7 +231,7 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
||||||
|
|
||||||
private func replacePlaceholderViewIfNeeded(with placeholderView: UIView) {
|
private func replacePlaceholderViewIfNeeded(with placeholderView: UIView) {
|
||||||
wrappedView.scrollView.isUserInteractionEnabled = true
|
wrappedView.scrollView.isUserInteractionEnabled = true
|
||||||
removeAllPlaceholderView()
|
removeCurrentPlaceholderView()
|
||||||
|
|
||||||
placeholderView.translatesAutoresizingMaskIntoConstraints = false
|
placeholderView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
placeholderView.isHidden = false
|
placeholderView.isHidden = false
|
||||||
|
|
@ -268,10 +263,9 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
||||||
|
|
||||||
private func onExhaustedState() {
|
private func onExhaustedState() {
|
||||||
removeInfiniteScroll()
|
removeInfiniteScroll()
|
||||||
removeAllPlaceholderView()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addInfiniteScrollWithHandler() {
|
private func readdInfiniteScrollWithHandler() {
|
||||||
removeInfiniteScroll()
|
removeInfiniteScroll()
|
||||||
addInfiniteScroll(withHandler: true)
|
addInfiniteScroll(withHandler: true)
|
||||||
}
|
}
|
||||||
|
|
@ -295,47 +289,70 @@ final public class PaginationWrapper<Cursor: ResettableRxDataSourceCursor, Deleg
|
||||||
|
|
||||||
private func createRefreshControl() {
|
private func createRefreshControl() {
|
||||||
let refreshControl = UIRefreshControl()
|
let refreshControl = UIRefreshControl()
|
||||||
refreshControl.addTarget(self, action: #selector(refreshAction), for: .valueChanged)
|
refreshControl.rx
|
||||||
|
.controlEvent(.valueChanged)
|
||||||
|
.asDriver()
|
||||||
|
.drive(reloadEvent)
|
||||||
|
.disposed(by: disposeBag)
|
||||||
|
|
||||||
wrappedView.scrollView.refreshControl = refreshControl
|
wrappedView.scrollView.support.setRefreshControl(refreshControl)
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func refreshAction() {
|
|
||||||
// it is implemented the combined behavior of `touchUpInside` and `touchUpOutside` using `CFRunLoopPerformBlock`,
|
|
||||||
// which `UIRefreshControl` does not support
|
|
||||||
CFRunLoopPerformBlock(CFRunLoopGetMain(), CFRunLoopMode.defaultMode.rawValue) { [weak self] in
|
|
||||||
self?.reload()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func removeRefreshControl() {
|
private func removeRefreshControl() {
|
||||||
wrappedView.scrollView.refreshControl = nil
|
wrappedView.scrollView.support.setRefreshControl(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func bindViewModelStates() {
|
private func bindViewModelStates() {
|
||||||
paginationViewModel.stateDriver
|
paginationViewModel.stateDriver
|
||||||
|
.flatMap { [applicationCurrentyActive] state -> Driver<LoadingState> in
|
||||||
|
if applicationCurrentyActive.value {
|
||||||
|
return .just(state)
|
||||||
|
} else {
|
||||||
|
return applicationCurrentyActive
|
||||||
|
.asObservable()
|
||||||
|
.filter { $0 }
|
||||||
|
.delay(0.5, scheduler: MainScheduler.instance)
|
||||||
|
.asDriver(onErrorJustReturn: true)
|
||||||
|
.replace(with: state)
|
||||||
|
}
|
||||||
|
}
|
||||||
.drive(stateChanged)
|
.drive(stateChanged)
|
||||||
.disposed(by: disposeBag)
|
.disposed(by: disposeBag)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func removeAllPlaceholderView() {
|
private func removeCurrentPlaceholderView() {
|
||||||
wrappedView.backgroundView = nil
|
wrappedView.backgroundView = nil
|
||||||
wrappedView.footerView = nil
|
}
|
||||||
|
|
||||||
|
private func bindAppStateNotifications() {
|
||||||
|
let notificationCenter = NotificationCenter.default.rx
|
||||||
|
|
||||||
|
notificationCenter.notification(UIApplication.willResignActiveNotification)
|
||||||
|
.replace(with: false)
|
||||||
|
.asDriver(onErrorJustReturn: false)
|
||||||
|
.drive(applicationCurrentyActive)
|
||||||
|
.disposed(by: disposeBag)
|
||||||
|
|
||||||
|
notificationCenter.notification(UIApplication.didBecomeActiveNotification)
|
||||||
|
.replace(with: true)
|
||||||
|
.asDriver(onErrorJustReturn: true)
|
||||||
|
.drive(applicationCurrentyActive)
|
||||||
|
.disposed(by: disposeBag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension PaginationWrapper {
|
private extension PaginationWrapper {
|
||||||
|
|
||||||
private var stateChanged: Binder<LoadingState> {
|
private var stateChanged: Binder<LoadingState> {
|
||||||
Binder(self) { base, value in
|
return Binder(self) { base, value in
|
||||||
switch value {
|
switch value {
|
||||||
case .initial:
|
case .initial:
|
||||||
base.onInitialState()
|
base.onInitialState()
|
||||||
|
|
||||||
case let .initialLoading(after):
|
case .initialLoading(let after):
|
||||||
base.onLoadingState(afterState: after)
|
base.onLoadingState(afterState: after)
|
||||||
|
|
||||||
case let .loadingMore(after):
|
case .loadingMore(let after):
|
||||||
base.onLoadingMoreState(afterState: after)
|
base.onLoadingMoreState(afterState: after)
|
||||||
|
|
||||||
case let .results(newItems, from, after):
|
case let .results(newItems, from, after):
|
||||||
|
|
@ -353,8 +370,20 @@ private extension PaginationWrapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var retryEvent: Binder<Void> {
|
||||||
|
return Binder(self) { base, _ in
|
||||||
|
base.paginationViewModel.loadMore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var reloadEvent: Binder<Void> {
|
||||||
|
return Binder(self) { base, _ in
|
||||||
|
base.reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var scrollOffsetChanged: Binder<CGPoint> {
|
var scrollOffsetChanged: Binder<CGPoint> {
|
||||||
Binder(self) { base, value in
|
return Binder(self) { base, value in
|
||||||
base.currentPlaceholderViewTopConstraint?.constant = -value.y
|
base.currentPlaceholderViewTopConstraint?.constant = -value.y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ open class RxNetworkOperationModel<LoadingStateType: NetworkOperationState>: Net
|
||||||
private let errorHandler: ErrorHandler
|
private let errorHandler: ErrorHandler
|
||||||
|
|
||||||
open var stateDriver: Driver<LoadingStateType> {
|
open var stateDriver: Driver<LoadingStateType> {
|
||||||
stateRelay.asDriver()
|
return stateRelay.asDriver()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Model initializer with data source and custom error handler.
|
/// Model initializer with data source and custom error handler.
|
||||||
|
|
@ -81,17 +81,16 @@ open class RxNetworkOperationModel<LoadingStateType: NetworkOperationState>: Net
|
||||||
func requestResult(from dataSource: DataSourceType) {
|
func requestResult(from dataSource: DataSourceType) {
|
||||||
currentRequestDisposable = dataSource
|
currentRequestDisposable = dataSource
|
||||||
.resultSingle()
|
.resultSingle()
|
||||||
.observe(on: MainScheduler.instance)
|
|
||||||
.subscribe(onSuccess: { [weak self] result in
|
.subscribe(onSuccess: { [weak self] result in
|
||||||
self?.onGot(result: result, from: dataSource)
|
self?.onGot(result: result, from: dataSource)
|
||||||
}, onFailure: { [weak self] error in
|
}, onError: { [weak self] error in
|
||||||
self?.onGot(error: error)
|
self?.onGot(error: error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var state: LoadingStateType {
|
var state: LoadingStateType {
|
||||||
get {
|
get {
|
||||||
stateRelay.value
|
return stateRelay.value
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
stateRelay.accept(newValue)
|
stateRelay.accept(newValue)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import UIKit
|
||||||
public typealias SearchResultsController = UIViewController & SearchResultsViewController
|
public typealias SearchResultsController = UIViewController & SearchResultsViewController
|
||||||
|
|
||||||
/// Class that allows to enter text for search and then displays search results in table view
|
/// Class that allows to enter text for search and then displays search results in table view
|
||||||
open class BaseSearchViewController < Item,
|
open class BaseSearchViewController<Item,
|
||||||
ItemViewModel,
|
ItemViewModel,
|
||||||
ViewModel,
|
ViewModel,
|
||||||
CustomView: UIView & TableViewHolder>: BaseCustomViewController<ViewModel, CustomView>
|
CustomView: UIView & TableViewHolder>: BaseCustomViewController<ViewModel, CustomView>
|
||||||
|
|
@ -58,15 +58,15 @@ where ViewModel: BaseSearchViewModel<Item, ItemViewModel> {
|
||||||
open override func bindViews() {
|
open override func bindViews() {
|
||||||
super.bindViews()
|
super.bindViews()
|
||||||
viewModel.itemsViewModelsDriver
|
viewModel.itemsViewModelsDriver
|
||||||
.drive(with: self) { owner, viewModels in
|
.drive(onNext: { [weak self] viewModels in
|
||||||
owner.handle(itemViewModels: viewModels)
|
self?.handle(itemViewModels: viewModels)
|
||||||
}
|
})
|
||||||
.disposed(by: disposeBag)
|
.disposed(by: disposeBag)
|
||||||
|
|
||||||
Observable.merge(searchResults, resetResults)
|
Observable.merge(searchResults, resetResults)
|
||||||
.subscribe(with: self) { owner, state in
|
.subscribe(onNext: { [weak self] state in
|
||||||
owner.handle(searchResultsState: state)
|
self?.handle(searchResultsState: state)
|
||||||
}
|
})
|
||||||
.disposed(by: disposeBag)
|
.disposed(by: disposeBag)
|
||||||
|
|
||||||
let searchText = searchController.searchBar.rx.text
|
let searchText = searchController.searchBar.rx.text
|
||||||
|
|
@ -112,11 +112,11 @@ where ViewModel: BaseSearchViewModel<Item, ItemViewModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
open var searchBarPlaceholder: String {
|
open var searchBarPlaceholder: String {
|
||||||
""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
open var searchBarColor: UIColor {
|
open var searchBarColor: UIColor {
|
||||||
.gray
|
return .gray
|
||||||
}
|
}
|
||||||
|
|
||||||
open var statusBarView: UIView {
|
open var statusBarView: UIView {
|
||||||
|
|
@ -131,7 +131,7 @@ where ViewModel: BaseSearchViewModel<Item, ItemViewModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
open var statusBarColor: UIColor {
|
open var statusBarColor: UIColor {
|
||||||
.black
|
return .black
|
||||||
}
|
}
|
||||||
|
|
||||||
open func updateContent(with viewModels: [ItemViewModel]) {
|
open func updateContent(with viewModels: [ItemViewModel]) {
|
||||||
|
|
@ -144,15 +144,15 @@ where ViewModel: BaseSearchViewModel<Item, ItemViewModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
open var resetResults: Observable<SearchResultsViewControllerState> {
|
open var resetResults: Observable<SearchResultsViewControllerState> {
|
||||||
searchController.rx.willPresent
|
return searchController.rx.willPresent
|
||||||
.map { SearchResultsViewControllerState.initial }
|
.map { SearchResultsViewControllerState.initial }
|
||||||
}
|
}
|
||||||
|
|
||||||
open var searchResults: Observable<SearchResultsViewControllerState> {
|
open var searchResults: Observable<SearchResultsViewControllerState> {
|
||||||
viewModel.searchResultsDriver
|
return viewModel.searchResultsDriver
|
||||||
.asObservable()
|
.asObservable()
|
||||||
.compactMap { [weak self] viewModels -> SearchResultsViewControllerState? in
|
.map { [weak self] viewModels -> SearchResultsViewControllerState in
|
||||||
self?.stateForUpdate(with: viewModels)
|
self?.stateForUpdate(with: viewModels) ?? .rowsContent(rows: [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ open class BaseSearchViewModel<Item, ItemViewModel>: GeneralDataLoadingViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
open var itemsViewModelsDriver: Driver<[ItemViewModel]> {
|
open var itemsViewModelsDriver: Driver<[ItemViewModel]> {
|
||||||
loadingResultObservable
|
return loadingResultObservable
|
||||||
.compactMap { [weak self] items in
|
.map { [weak self] items in
|
||||||
self?.viewModels(from: items)
|
self?.viewModels(from: items)
|
||||||
}
|
}
|
||||||
.flatMap { Observable.from(optional: $0) }
|
.flatMap { Observable.from(optional: $0) }
|
||||||
|
|
@ -45,16 +45,16 @@ open class BaseSearchViewModel<Item, ItemViewModel>: GeneralDataLoadingViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
open var searchDebounceInterval: RxTimeInterval {
|
open var searchDebounceInterval: RxTimeInterval {
|
||||||
.seconds(1)
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
open var searchResultsDriver: Driver<[ItemViewModel]> {
|
open var searchResultsDriver: Driver<[ItemViewModel]> {
|
||||||
searchTextRelay.debounce(searchDebounceInterval, scheduler: MainScheduler.instance)
|
return searchTextRelay.debounce(searchDebounceInterval, scheduler: MainScheduler.instance)
|
||||||
.withLatestFrom(loadingResultObservable) { ($0, $1) }
|
.withLatestFrom(loadingResultObservable) { ($0, $1) }
|
||||||
.flatMapLatest { [weak self] searchText, items -> Observable<ItemsList> in
|
.flatMapLatest { [weak self] searchText, items -> Observable<ItemsList> in
|
||||||
self?.search(by: searchText, from: items).asObservable() ?? .empty()
|
self?.search(by: searchText, from: items).asObservable() ?? .empty()
|
||||||
}
|
}
|
||||||
.compactMap { [weak self] items in
|
.map { [weak self] items in
|
||||||
self?.viewModels(from: items)
|
self?.viewModels(from: items)
|
||||||
}
|
}
|
||||||
.flatMap { Observable.from(optional: $0) }
|
.flatMap { Observable.from(optional: $0) }
|
||||||
|
|
@ -71,29 +71,29 @@ open class BaseSearchViewModel<Item, ItemViewModel>: GeneralDataLoadingViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
open func bind(searchText: Observable<String>) -> Disposable {
|
open func bind(searchText: Observable<String>) -> Disposable {
|
||||||
searchText.bind(to: searchTextRelay)
|
return searchText.bind(to: searchTextRelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func viewModels(from items: ItemsList) -> [ItemViewModel] {
|
private func viewModels(from items: ItemsList) -> [ItemViewModel] {
|
||||||
items.map { self.viewModel(from: $0) }
|
return items.map { self.viewModel(from: $0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
open var loadingResultObservable: Observable<ResultType> {
|
open var loadingResultObservable: Observable<ResultType> {
|
||||||
loadingStateDriver
|
return loadingStateDriver
|
||||||
.asObservable()
|
.asObservable()
|
||||||
.map { $0.result }
|
.map { $0.result }
|
||||||
.flatMap { Observable.from(optional: $0) }
|
.flatMap { Observable.from(optional: $0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
open var loadingErrorObservable: Observable<Error> {
|
open var loadingErrorObservable: Observable<Error> {
|
||||||
loadingStateDriver
|
return loadingStateDriver
|
||||||
.asObservable()
|
.asObservable()
|
||||||
.map { $0.error }
|
.map { $0.error }
|
||||||
.flatMap { Observable.from(optional: $0) }
|
.flatMap { Observable.from(optional: $0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
open var firstLoadingResultObservable: Single<ResultType> {
|
open var firstLoadingResultObservable: Single<ResultType> {
|
||||||
loadingResultObservable
|
return loadingResultObservable
|
||||||
.take(1)
|
.take(1)
|
||||||
.asSingle()
|
.asSingle()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ open class NetworkService {
|
||||||
|
|
||||||
/// Driver that emits true when active requests count != 0 and false otherwise.
|
/// Driver that emits true when active requests count != 0 and false otherwise.
|
||||||
public var isActivityIndicatorVisibleDriver: Driver<Bool> {
|
public var isActivityIndicatorVisibleDriver: Driver<Bool> {
|
||||||
requestCountRelay.asDriver().map { $0 != 0 }.distinctUntilChanged()
|
return requestCountRelay.asDriver().map { $0 != 0 }.distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// - Parameter sessionManager: Alamofire.SessionManager to use for requests
|
/// - Parameter sessionManager: Alamofire.SessionManager to use for requests
|
||||||
|
|
@ -63,12 +63,12 @@ open class NetworkService {
|
||||||
public func rxObservableRequest<T: ObservableMappable>(with parameters: ApiRequestParameters,
|
public func rxObservableRequest<T: ObservableMappable>(with parameters: ApiRequestParameters,
|
||||||
additionalValidStatusCodes: Set<Int> = [],
|
additionalValidStatusCodes: Set<Int> = [],
|
||||||
decoder: JSONDecoder = JSONDecoder())
|
decoder: JSONDecoder = JSONDecoder())
|
||||||
-> Observable<SessionManager.ModelResponse<T>> {
|
-> Observable<SessionManager.ModelResponse<T>> {
|
||||||
|
|
||||||
sessionManager.rx.responseObservableModel(requestParameters: parameters,
|
return sessionManager.rx.responseObservableModel(requestParameters: parameters,
|
||||||
additionalValidStatusCodes: additionalValidStatusCodes,
|
additionalValidStatusCodes: additionalValidStatusCodes,
|
||||||
decoder: decoder)
|
decoder: decoder)
|
||||||
.counterTracking(for: self)
|
.counterTracking(for: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform reactive request to get mapped ImmutableMappable model and http response
|
/// Perform reactive request to get mapped ImmutableMappable model and http response
|
||||||
|
|
@ -81,12 +81,12 @@ open class NetworkService {
|
||||||
public func rxRequest<T: Decodable>(with parameters: ApiRequestParameters,
|
public func rxRequest<T: Decodable>(with parameters: ApiRequestParameters,
|
||||||
additionalValidStatusCodes: Set<Int> = [],
|
additionalValidStatusCodes: Set<Int> = [],
|
||||||
decoder: JSONDecoder = JSONDecoder())
|
decoder: JSONDecoder = JSONDecoder())
|
||||||
-> Observable<SessionManager.ModelResponse<T>> {
|
-> Observable<SessionManager.ModelResponse<T>> {
|
||||||
|
|
||||||
sessionManager.rx.responseModel(requestParameters: parameters,
|
return sessionManager.rx.responseModel(requestParameters: parameters,
|
||||||
additionalValidStatusCodes: additionalValidStatusCodes,
|
additionalValidStatusCodes: additionalValidStatusCodes,
|
||||||
decoder: decoder)
|
decoder: decoder)
|
||||||
.counterTracking(for: self)
|
.counterTracking(for: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform reactive request to get data and http response
|
/// Perform reactive request to get data and http response
|
||||||
|
|
@ -96,11 +96,11 @@ open class NetworkService {
|
||||||
/// - additionalValidStatusCodes: set of additional valid status codes
|
/// - additionalValidStatusCodes: set of additional valid status codes
|
||||||
/// - Returns: Observable of tuple containing (HTTPURLResponse, Data)
|
/// - Returns: Observable of tuple containing (HTTPURLResponse, Data)
|
||||||
public func rxDataRequest(with parameters: ApiRequestParameters, additionalValidStatusCodes: Set<Int> = [])
|
public func rxDataRequest(with parameters: ApiRequestParameters, additionalValidStatusCodes: Set<Int> = [])
|
||||||
-> Observable<SessionManager.DataResponse> {
|
-> Observable<SessionManager.DataResponse> {
|
||||||
|
|
||||||
sessionManager.rx.responseData(requestParameters: parameters,
|
return sessionManager.rx.responseData(requestParameters: parameters,
|
||||||
additionalValidStatusCodes: additionalValidStatusCodes)
|
additionalValidStatusCodes: additionalValidStatusCodes)
|
||||||
.counterTracking(for: self)
|
.counterTracking(for: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform reactive request to upload data and get Observable model and http response
|
/// Perform reactive request to upload data and get Observable model and http response
|
||||||
|
|
@ -113,12 +113,12 @@ open class NetworkService {
|
||||||
public func rxUploadRequest<T: Decodable>(with parameters: ApiUploadRequestParameters,
|
public func rxUploadRequest<T: Decodable>(with parameters: ApiUploadRequestParameters,
|
||||||
additionalValidStatusCodes: Set<Int> = [],
|
additionalValidStatusCodes: Set<Int> = [],
|
||||||
decoder: JSONDecoder = JSONDecoder())
|
decoder: JSONDecoder = JSONDecoder())
|
||||||
-> Observable<SessionManager.ModelResponse<T>> {
|
-> Observable<SessionManager.ModelResponse<T>> {
|
||||||
|
|
||||||
sessionManager.rx.uploadResponseModel(requestParameters: parameters,
|
return sessionManager.rx.uploadResponseModel(requestParameters: parameters,
|
||||||
additionalValidStatusCodes: additionalValidStatusCodes,
|
additionalValidStatusCodes: additionalValidStatusCodes,
|
||||||
decoder: decoder)
|
decoder: decoder)
|
||||||
.counterTracking(for: self)
|
.counterTracking(for: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,8 +144,8 @@ public extension Observable {
|
||||||
///
|
///
|
||||||
/// - Parameter networkService: NetworkService to operate on it
|
/// - Parameter networkService: NetworkService to operate on it
|
||||||
/// - Returns: The source sequence with the side-effecting behavior applied.
|
/// - Returns: The source sequence with the side-effecting behavior applied.
|
||||||
func counterTracking(for networkService: NetworkService) -> Observable<Observable.Element> {
|
func counterTracking(for networkService: NetworkService) -> Observable<Observable.E> {
|
||||||
`do`(onSubscribe: {
|
return `do`(onSubscribe: {
|
||||||
networkService.increaseRequestCounter()
|
networkService.increaseRequestCounter()
|
||||||
}, onDispose: {
|
}, onDispose: {
|
||||||
networkService.decreaseRequestCounter()
|
networkService.decreaseRequestCounter()
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
import Alamofire
|
import Alamofire
|
||||||
|
|
||||||
/// Session Manager stored in NetworkService
|
/// Session Manager stored in NetworkService
|
||||||
open class SessionManager: Alamofire.Session {
|
open class SessionManager: Alamofire.SessionManager {
|
||||||
|
|
||||||
/// Response with HTTP URL Response and target object
|
/// Response with HTTP URL Response and target object
|
||||||
public typealias ModelResponse<T> = (response: HTTPURLResponse, model: T)
|
public typealias ModelResponse<T> = (response: HTTPURLResponse, model: T)
|
||||||
|
|
@ -38,40 +38,25 @@ open class SessionManager: Alamofire.Session {
|
||||||
public let mappingQueue: DispatchQueue
|
public let mappingQueue: DispatchQueue
|
||||||
|
|
||||||
public init(configuration: URLSessionConfiguration,
|
public init(configuration: URLSessionConfiguration,
|
||||||
serverTrustManager: ServerTrustManager,
|
serverTrustPolicyManager: ServerTrustPolicyManager,
|
||||||
acceptableStatusCodes: Set<Int>,
|
acceptableStatusCodes: Set<Int>,
|
||||||
mappingQueue: DispatchQueue) {
|
mappingQueue: DispatchQueue) {
|
||||||
|
|
||||||
self.acceptableStatusCodes = acceptableStatusCodes
|
self.acceptableStatusCodes = acceptableStatusCodes
|
||||||
self.mappingQueue = mappingQueue
|
self.mappingQueue = mappingQueue
|
||||||
|
|
||||||
let delegate = SessionDelegate()
|
super.init(configuration: configuration, serverTrustPolicyManager: serverTrustPolicyManager)
|
||||||
|
|
||||||
let delegateQueue = OperationQueue()
|
|
||||||
delegateQueue.underlyingQueue = mappingQueue
|
|
||||||
|
|
||||||
let session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: delegateQueue)
|
|
||||||
|
|
||||||
super.init(session: session,
|
|
||||||
delegate: delegate,
|
|
||||||
rootQueue: mappingQueue,
|
|
||||||
serverTrustManager: serverTrustManager)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(session: URLSession,
|
public init?(session: URLSession,
|
||||||
delegate: SessionDelegate,
|
delegate: SessionDelegate,
|
||||||
serverTrustManager: ServerTrustManager,
|
serverTrustPolicyManager: ServerTrustPolicyManager,
|
||||||
acceptableStatusCodes: Set<Int>,
|
acceptableStatusCodes: Set<Int>,
|
||||||
mappingQueue: DispatchQueue) {
|
mappingQueue: DispatchQueue) {
|
||||||
|
|
||||||
self.acceptableStatusCodes = acceptableStatusCodes
|
self.acceptableStatusCodes = acceptableStatusCodes
|
||||||
self.mappingQueue = mappingQueue
|
self.mappingQueue = mappingQueue
|
||||||
|
|
||||||
session.delegateQueue.underlyingQueue = mappingQueue
|
super.init(session: session, delegate: delegate, serverTrustPolicyManager: serverTrustPolicyManager)
|
||||||
|
|
||||||
super.init(session: session,
|
|
||||||
delegate: delegate,
|
|
||||||
rootQueue: mappingQueue,
|
|
||||||
serverTrustManager: serverTrustManager)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2020 Touch Instinct
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the Software), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import RxCocoa
|
|
||||||
import RxSwift
|
|
||||||
|
|
||||||
open class BaseTappableViewModel<PayloadType> {
|
|
||||||
private let tapRelay = PublishRelay<PayloadType>()
|
|
||||||
|
|
||||||
public var tapDriver: Driver<PayloadType> {
|
|
||||||
tapRelay.asDriver(onErrorDriveWith: .empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
public var tapObservable: Observable<PayloadType> {
|
|
||||||
tapRelay.asObservable()
|
|
||||||
}
|
|
||||||
|
|
||||||
public func bind(tapObservable: Observable<PayloadType>) -> Disposable {
|
|
||||||
tapObservable.bind(to: tapRelay)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func tap(payload: PayloadType) {
|
|
||||||
tapRelay.accept(payload)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2020 Touch Instinct
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the Software), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
open class VoidTappableViewModel: BaseTappableViewModel<Void> {
|
|
||||||
public func tap() {
|
|
||||||
tap(payload: ())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -62,16 +62,16 @@ public extension BasePlaceholderViewModel {
|
||||||
|
|
||||||
/// Returns true if description is not nil.
|
/// Returns true if description is not nil.
|
||||||
var hasDescription: Bool {
|
var hasDescription: Bool {
|
||||||
description != nil
|
return description != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true buttonTitle is not nil.
|
/// Returns true buttonTitle is not nil.
|
||||||
var hasButton: Bool {
|
var hasButton: Bool {
|
||||||
buttonTitle != nil
|
return buttonTitle != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if centerImage is not nil.
|
/// Returns true if centerImage is not nil.
|
||||||
var hasCenterImage: Bool {
|
var hasCenterImage: Bool {
|
||||||
centerImage != nil
|
return centerImage != nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import UIKit
|
||||||
|
|
||||||
/// Layoutless placeholder view. This class is used as views holder & configurator.
|
/// Layoutless placeholder view. This class is used as views holder & configurator.
|
||||||
/// You should inherit it and implement layout.
|
/// You should inherit it and implement layout.
|
||||||
open class BasePlaceholderView: ButtonHolderView, InitializableView {
|
open class BasePlaceholderView: UIView, InitializableView {
|
||||||
|
|
||||||
/// Title label of placeholder view.
|
/// Title label of placeholder view.
|
||||||
public let titleLabel = UILabel()
|
public let titleLabel = UILabel()
|
||||||
|
|
@ -55,7 +55,7 @@ open class BasePlaceholderView: ButtonHolderView, InitializableView {
|
||||||
///
|
///
|
||||||
/// - Returns: UIButton (sub)class.
|
/// - Returns: UIButton (sub)class.
|
||||||
open func createButton() -> UIButton {
|
open func createButton() -> UIButton {
|
||||||
UIButton()
|
return UIButton()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - InitializableView
|
// MARK: - InitializableView
|
||||||
|
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2020 Touch Instinct
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the Software), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import RxSwift
|
|
||||||
|
|
||||||
open class BaseRxTableViewCell: UITableViewCell, InitializableView, DisposeBagHolder {
|
|
||||||
|
|
||||||
// MARK: - Properties
|
|
||||||
|
|
||||||
public var disposeBag = DisposeBag()
|
|
||||||
|
|
||||||
// MARK: - Initialization
|
|
||||||
|
|
||||||
override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
|
||||||
super.init(style: .default, reuseIdentifier: reuseIdentifier)
|
|
||||||
|
|
||||||
initializeView()
|
|
||||||
}
|
|
||||||
|
|
||||||
@available(*, unavailable)
|
|
||||||
required public init?(coder aDecoder: NSCoder) {
|
|
||||||
super.init(coder: aDecoder)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Override
|
|
||||||
|
|
||||||
override open func prepareForReuse() {
|
|
||||||
super.prepareForReuse()
|
|
||||||
|
|
||||||
disposeBag = DisposeBag()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - InitializableView
|
|
||||||
|
|
||||||
open func addViews() {
|
|
||||||
// overriding
|
|
||||||
}
|
|
||||||
|
|
||||||
open func bindViews() {
|
|
||||||
// overriding
|
|
||||||
}
|
|
||||||
|
|
||||||
open func configureLayout() {
|
|
||||||
// overriding
|
|
||||||
}
|
|
||||||
|
|
||||||
open func configureAppearance() {
|
|
||||||
selectionStyle = .none
|
|
||||||
}
|
|
||||||
|
|
||||||
open func localize() {
|
|
||||||
// overriding
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) 2020 Touch Instinct
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the Software), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import RxSwift
|
|
||||||
import TableKit
|
|
||||||
|
|
||||||
open class ContainerTableCell<TView: UIView>: BaseRxTableViewCell, ConfigurableCell where TView: ConfigurableView {
|
|
||||||
|
|
||||||
// MARK: - Properties
|
|
||||||
|
|
||||||
private let wrappedView = TView()
|
|
||||||
|
|
||||||
open var shouldConfigureDefaultConstraints: Bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
open var contentInsets: UIEdgeInsets {
|
|
||||||
.zero
|
|
||||||
}
|
|
||||||
|
|
||||||
open var contentViewBackgroundColor: UIColor {
|
|
||||||
.clear
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - ConfigurableCell
|
|
||||||
|
|
||||||
open func configure(with viewModel: TView.ViewModelType) {
|
|
||||||
disposeBag = DisposeBag()
|
|
||||||
wrappedView.configure(with: viewModel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - InitializableView
|
|
||||||
|
|
||||||
override open func addViews() {
|
|
||||||
super.addViews()
|
|
||||||
|
|
||||||
contentView.addSubview(wrappedView)
|
|
||||||
}
|
|
||||||
|
|
||||||
override open func configureLayout() {
|
|
||||||
super.configureLayout()
|
|
||||||
|
|
||||||
if shouldConfigureDefaultConstraints {
|
|
||||||
wrappedView.snp.makeConstraints {
|
|
||||||
$0.edges.equalToSuperview().inset(contentInsets)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
configureCustomConstraints(forWrappedView: wrappedView)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override open func configureAppearance() {
|
|
||||||
super.configureAppearance()
|
|
||||||
|
|
||||||
contentView.backgroundColor = contentViewBackgroundColor
|
|
||||||
backgroundColor = contentViewBackgroundColor
|
|
||||||
}
|
|
||||||
|
|
||||||
open func configureCustomConstraints(forWrappedView view: TView) { }
|
|
||||||
}
|
|
||||||
|
|
@ -48,7 +48,7 @@ open class CustomizableButton: UIButton {
|
||||||
}
|
}
|
||||||
|
|
||||||
func backgroundColor(for state: UIControl.State) -> UIColor? {
|
func backgroundColor(for state: UIControl.State) -> UIColor? {
|
||||||
backgroundColors[state]
|
return backgroundColors[state]
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateBackgroundColor() {
|
private func updateBackgroundColor() {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import RxSwift
|
import RxSwift
|
||||||
|
import RxCocoa
|
||||||
|
|
||||||
public typealias Spinner = UIView & Animatable
|
public typealias Spinner = UIView & Animatable
|
||||||
|
|
||||||
|
|
@ -45,20 +46,18 @@ public struct CustomizableButtonState: OptionSet {
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
|
|
||||||
public var isLoading: Bool {
|
public var isLoading: Bool {
|
||||||
contains(.loading)
|
return contains(.loading)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// container class that acts like a button and provides great customization
|
/// container class that acts like a button and provides great customization
|
||||||
open class CustomizableButtonView: UIView, InitializableView, ConfigurableView {
|
open class CustomizableButtonView: UIView, InitializableView {
|
||||||
|
|
||||||
// MARK: - Stored Properties
|
// MARK: - Stored Properties
|
||||||
|
|
||||||
public private(set) var disposeBag = DisposeBag()
|
private let disposeBag = DisposeBag()
|
||||||
|
|
||||||
private let button = CustomizableButton()
|
private let button = CustomizableButton()
|
||||||
|
public var tapOnDisabledButton: VoidBlock?
|
||||||
open var tapOnDisabledButton: VoidBlock?
|
|
||||||
|
|
||||||
public var shadowView = UIView() {
|
public var shadowView = UIView() {
|
||||||
willSet {
|
willSet {
|
||||||
|
|
@ -72,7 +71,9 @@ open class CustomizableButtonView: UIView, InitializableView, ConfigurableView {
|
||||||
|
|
||||||
public var spinnerView: Spinner? {
|
public var spinnerView: Spinner? {
|
||||||
willSet {
|
willSet {
|
||||||
removeSpinner()
|
if newValue == nil {
|
||||||
|
removeSpinner()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
didSet {
|
didSet {
|
||||||
if spinnerView != nil {
|
if spinnerView != nil {
|
||||||
|
|
@ -88,26 +89,21 @@ open class CustomizableButtonView: UIView, InitializableView, ConfigurableView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var buttonTitle: String = "" {
|
public var buttonIsDisabledWhileLoading = false
|
||||||
willSet {
|
|
||||||
button.text = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var hidesLabelWhenLoading = false
|
public var hidesLabelWhenLoading = false
|
||||||
|
|
||||||
// MARK: - Computed Properties
|
// MARK: - Computed Properties
|
||||||
|
|
||||||
public var tapObservable: Observable<Void> {
|
public var tapObservable: Observable<Void> {
|
||||||
button.rx.tap.asObservable()
|
return button.rx.tap.asObservable()
|
||||||
}
|
}
|
||||||
|
|
||||||
override open var forFirstBaselineLayout: UIView {
|
override open var forFirstBaselineLayout: UIView {
|
||||||
button.forFirstBaselineLayout
|
return button.forFirstBaselineLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
override open var forLastBaselineLayout: UIView {
|
override open var forLastBaselineLayout: UIView {
|
||||||
button.forLastBaselineLayout
|
return button.forLastBaselineLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||||
|
|
@ -142,6 +138,8 @@ open class CustomizableButtonView: UIView, InitializableView, ConfigurableView {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func set(active: Bool) {
|
private func set(active: Bool) {
|
||||||
|
button.isEnabled = buttonIsDisabledWhileLoading || !active
|
||||||
|
|
||||||
if hidesLabelWhenLoading {
|
if hidesLabelWhenLoading {
|
||||||
button.titleLabel?.layer.opacity = active ? 0 : 1
|
button.titleLabel?.layer.opacity = active ? 0 : 1
|
||||||
}
|
}
|
||||||
|
|
@ -174,7 +172,6 @@ open class CustomizableButtonView: UIView, InitializableView, ConfigurableView {
|
||||||
private func configureConstraints() {
|
private func configureConstraints() {
|
||||||
button.pinToSuperview(with: appearance.buttonInsets)
|
button.pinToSuperview(with: appearance.buttonInsets)
|
||||||
configureShadowViewConstraints()
|
configureShadowViewConstraints()
|
||||||
layoutIfNeeded()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func configureSpinnerConstraints() {
|
private func configureSpinnerConstraints() {
|
||||||
|
|
@ -189,7 +186,6 @@ open class CustomizableButtonView: UIView, InitializableView, ConfigurableView {
|
||||||
spinnerView.centerXAnchor.constraint(equalTo: button.centerXAnchor),
|
spinnerView.centerXAnchor.constraint(equalTo: button.centerXAnchor),
|
||||||
spinnerView.centerYAnchor.constraint(equalTo: button.centerYAnchor)
|
spinnerView.centerYAnchor.constraint(equalTo: button.centerYAnchor)
|
||||||
]
|
]
|
||||||
|
|
||||||
case .leftToText(let offset):
|
case .leftToText(let offset):
|
||||||
if let buttonLabel = button.titleLabel {
|
if let buttonLabel = button.titleLabel {
|
||||||
constraints = [
|
constraints = [
|
||||||
|
|
@ -197,7 +193,6 @@ open class CustomizableButtonView: UIView, InitializableView, ConfigurableView {
|
||||||
spinnerView.trailingAnchor.constraint(equalTo: buttonLabel.leadingAnchor, constant: -offset)
|
spinnerView.trailingAnchor.constraint(equalTo: buttonLabel.leadingAnchor, constant: -offset)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
case .rightToText(let offset):
|
case .rightToText(let offset):
|
||||||
if let buttonLabel = button.titleLabel {
|
if let buttonLabel = button.titleLabel {
|
||||||
constraints = [
|
constraints = [
|
||||||
|
|
@ -211,20 +206,20 @@ open class CustomizableButtonView: UIView, InitializableView, ConfigurableView {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func configureShadowViewConstraints() {
|
private func configureShadowViewConstraints() {
|
||||||
shadowView.constraintToEdges(of: button, with: .zero)
|
shadowView.constaintToEdges(of: button, with: .zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Initializable View
|
// MARK: - Initializable View
|
||||||
|
|
||||||
open func addViews() {
|
public func addViews() {
|
||||||
addSubviews(shadowView, button)
|
addSubviews(shadowView, button)
|
||||||
}
|
}
|
||||||
|
|
||||||
open func configureAppearance() {
|
public func configureAppearance() {
|
||||||
button.titleLabel?.numberOfLines = appearance.numberOfLines
|
button.titleLabel?.numberOfLines = appearance.numberOfLines
|
||||||
button.titleLabel?.font = appearance.buttonFont
|
button.titleLabel?.font = appearance.buttonFont
|
||||||
button.alpha = appearance.alpha
|
|
||||||
|
|
||||||
|
button.set(titles: appearance.buttonStateTitles)
|
||||||
button.set(attributtedTitles: appearance.buttonStateAttributtedTitles)
|
button.set(attributtedTitles: appearance.buttonStateAttributtedTitles)
|
||||||
button.set(titleColors: appearance.buttonTitleStateColors)
|
button.set(titleColors: appearance.buttonTitleStateColors)
|
||||||
button.set(images: appearance.buttonStateIcons)
|
button.set(images: appearance.buttonStateIcons)
|
||||||
|
|
@ -242,20 +237,33 @@ open class CustomizableButtonView: UIView, InitializableView, ConfigurableView {
|
||||||
button.layer.cornerRadius = 0
|
button.layer.cornerRadius = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
setNeedsDisplay()
|
button.titleLabel?.isHidden = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open func configure(with viewModel: CustomizableButtonViewModel) {
|
private extension UIView {
|
||||||
disposeBag = DisposeBag()
|
func constaintToEdges(of view: UIView, with offset: UIEdgeInsets) {
|
||||||
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
let constraints = [
|
||||||
|
leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: offset.left),
|
||||||
|
trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: offset.right),
|
||||||
|
topAnchor.constraint(equalTo: view.topAnchor, constant: offset.top),
|
||||||
|
bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: offset.bottom),
|
||||||
|
]
|
||||||
|
NSLayoutConstraint.activate(constraints)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension CustomizableButtonView: ConfigurableView {
|
||||||
|
public func configure(with viewModel: CustomizableButtonViewModel) {
|
||||||
viewModel.stateDriver.drive(stateBinder).disposed(by: disposeBag)
|
viewModel.stateDriver.drive(stateBinder).disposed(by: disposeBag)
|
||||||
viewModel.bind(tapObservable: tapObservable).disposed(by: disposeBag)
|
viewModel.bind(tapObservable: tapObservable).disposed(by: disposeBag)
|
||||||
|
|
||||||
button.text = viewModel.buttonTitle
|
|
||||||
appearance = viewModel.appearance
|
appearance = viewModel.appearance
|
||||||
}
|
}
|
||||||
|
|
||||||
private var stateBinder: Binder<CustomizableButtonState> {
|
private var stateBinder: Binder<CustomizableButtonState> {
|
||||||
Binder(self) { base, value in
|
return Binder(self) { base, value in
|
||||||
base.configureButton(withState: value)
|
base.configureButton(withState: value)
|
||||||
base.onStateChange(value)
|
base.onStateChange(value)
|
||||||
}
|
}
|
||||||
|
|
@ -266,43 +274,34 @@ open class CustomizableButtonView: UIView, InitializableView, ConfigurableView {
|
||||||
}
|
}
|
||||||
|
|
||||||
open func configureButton(withState state: CustomizableButtonState) {
|
open func configureButton(withState state: CustomizableButtonState) {
|
||||||
button.isEnabled = ![.disabled, .loading].contains(state)
|
button.isEnabled = state.contains(.enabled) && !state.contains(.disabled)
|
||||||
isUserInteractionEnabled = button.isEnabled
|
|
||||||
button.isHighlighted = state.contains(.highlighted) && !state.contains(.normal)
|
button.isHighlighted = state.contains(.highlighted) && !state.contains(.normal)
|
||||||
set(active: state.contains(.loading))
|
set(active: state.contains(.loading))
|
||||||
setNeedsDisplay()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension UIView {
|
|
||||||
func constraintToEdges(of view: UIView, with offset: UIEdgeInsets) {
|
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
let constraints = [
|
|
||||||
leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: offset.left),
|
|
||||||
trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: offset.right),
|
|
||||||
topAnchor.constraint(equalTo: view.topAnchor, constant: offset.top),
|
|
||||||
bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: offset.bottom)
|
|
||||||
]
|
|
||||||
NSLayoutConstraint.activate(constraints)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension CustomizableButtonView {
|
public extension CustomizableButtonView {
|
||||||
struct Appearance {
|
struct Appearance {
|
||||||
|
|
||||||
public var buttonFont: UIFont
|
var buttonFont: UIFont
|
||||||
public var buttonStateAttributtedTitles: [UIControl.State: NSAttributedString]
|
|
||||||
public var buttonTitleStateColors: [UIControl.State: UIColor]
|
var buttonStateTitles: [UIControl.State: String]
|
||||||
public var buttonBackgroundStateColors: [UIControl.State: UIColor]
|
var buttonStateAttributtedTitles: [UIControl.State: NSAttributedString]
|
||||||
public var buttonStateIcons: [UIControl.State: UIImage]
|
var buttonTitleStateColors: [UIControl.State: UIColor]
|
||||||
public var buttonIconOffset: UIOffset
|
var buttonBackgroundStateColors: [UIControl.State: UIColor]
|
||||||
public var buttonInsets: UIEdgeInsets
|
var buttonStateIcons: [UIControl.State: UIImage]
|
||||||
public var buttonCornerRadius: CGFloat?
|
|
||||||
public var spinnerPosition: SpinnerPosition
|
var buttonIconOffset: UIOffset
|
||||||
public var numberOfLines: Int
|
var buttonInsets: UIEdgeInsets
|
||||||
public var alpha: CGFloat
|
|
||||||
|
var buttonCornerRadius: CGFloat?
|
||||||
|
|
||||||
|
var spinnerPosition: SpinnerPosition
|
||||||
|
|
||||||
|
var numberOfLines: Int
|
||||||
|
|
||||||
public init(buttonFont: UIFont = .systemFont(ofSize: 15),
|
public init(buttonFont: UIFont = .systemFont(ofSize: 15),
|
||||||
|
buttonStateTitles: [UIControl.State: String] = [:],
|
||||||
buttonStateAttributtedTitles: [UIControl.State: NSAttributedString] = [:],
|
buttonStateAttributtedTitles: [UIControl.State: NSAttributedString] = [:],
|
||||||
buttonTitleStateColors: [UIControl.State: UIColor] = [:],
|
buttonTitleStateColors: [UIControl.State: UIColor] = [:],
|
||||||
buttonBackgroundStateColors: [UIControl.State: UIColor] = [:],
|
buttonBackgroundStateColors: [UIControl.State: UIColor] = [:],
|
||||||
|
|
@ -311,21 +310,26 @@ public extension CustomizableButtonView {
|
||||||
buttonInsets: UIEdgeInsets = .zero,
|
buttonInsets: UIEdgeInsets = .zero,
|
||||||
buttonCornerRadius: CGFloat? = nil,
|
buttonCornerRadius: CGFloat? = nil,
|
||||||
spinnerPosition: SpinnerPosition = .center,
|
spinnerPosition: SpinnerPosition = .center,
|
||||||
numberOfLines: Int = 0,
|
numberOfLines: Int = 0) {
|
||||||
alpha: CGFloat = 1) {
|
|
||||||
|
|
||||||
self.buttonFont = buttonFont
|
self.buttonFont = buttonFont
|
||||||
|
|
||||||
|
self.buttonStateTitles = buttonStateTitles
|
||||||
self.buttonStateAttributtedTitles = buttonStateAttributtedTitles
|
self.buttonStateAttributtedTitles = buttonStateAttributtedTitles
|
||||||
self.buttonTitleStateColors = buttonTitleStateColors
|
self.buttonTitleStateColors = buttonTitleStateColors
|
||||||
self.buttonBackgroundStateColors = buttonBackgroundStateColors
|
self.buttonBackgroundStateColors = buttonBackgroundStateColors
|
||||||
self.buttonStateIcons = buttonStateIcons
|
self.buttonStateIcons = buttonStateIcons
|
||||||
|
|
||||||
self.buttonIconOffset = buttonIconOffset
|
self.buttonIconOffset = buttonIconOffset
|
||||||
self.buttonInsets = buttonInsets
|
self.buttonInsets = buttonInsets
|
||||||
|
|
||||||
self.buttonCornerRadius = buttonCornerRadius
|
self.buttonCornerRadius = buttonCornerRadius
|
||||||
|
|
||||||
self.spinnerPosition = spinnerPosition
|
self.spinnerPosition = spinnerPosition
|
||||||
|
|
||||||
self.numberOfLines = numberOfLines
|
self.numberOfLines = numberOfLines
|
||||||
self.alpha = alpha
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SpinnerPosition {
|
enum SpinnerPosition {
|
||||||
|
|
|
||||||
|
|
@ -31,23 +31,21 @@ open class CustomizableButtonViewModel {
|
||||||
private let stateRelay = BehaviorRelay(value: CustomizableButtonState.enabled)
|
private let stateRelay = BehaviorRelay(value: CustomizableButtonState.enabled)
|
||||||
private let tapRelay = BehaviorRelay(value: ())
|
private let tapRelay = BehaviorRelay(value: ())
|
||||||
public let appearance: Appearance
|
public let appearance: Appearance
|
||||||
public let buttonTitle: String
|
|
||||||
|
|
||||||
public init(buttonTitle: String, appearance: Appearance) {
|
public init(appearance: Appearance) {
|
||||||
self.buttonTitle = buttonTitle
|
|
||||||
self.appearance = appearance
|
self.appearance = appearance
|
||||||
}
|
}
|
||||||
|
|
||||||
open var stateDriver: Driver<CustomizableButtonState> {
|
open var stateDriver: Driver<CustomizableButtonState> {
|
||||||
stateRelay.asDriver()
|
return stateRelay.asDriver()
|
||||||
}
|
}
|
||||||
|
|
||||||
func bind(tapObservable: Observable<Void>) -> Disposable {
|
func bind(tapObservable: Observable<Void>) -> Disposable {
|
||||||
tapObservable.bind(to: tapRelay)
|
return tapObservable.bind(to: tapRelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var tapDriver: Driver<Void> {
|
public var tapDriver: Driver<Void> {
|
||||||
tapRelay.asDriver()
|
return tapRelay.asDriver()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateState(with newState: CustomizableButtonState) {
|
public func updateState(with newState: CustomizableButtonState) {
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,6 @@ public final class EmptyCellRow: TableRow<EmptyCell> {
|
||||||
|
|
||||||
/// Used for set custom height to each cell, not for each cell type
|
/// Used for set custom height to each cell, not for each cell type
|
||||||
override public var defaultHeight: CGFloat? {
|
override public var defaultHeight: CGFloat? {
|
||||||
rowHeight
|
return rowHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,11 +93,11 @@ open class LabelTableViewCell: SeparatorCell, InitializableView, ConfigurableCel
|
||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private var labelInsets: UIEdgeInsets {
|
private var labelInsets: UIEdgeInsets {
|
||||||
viewModel?.labelInsets ?? .zero
|
return viewModel?.labelInsets ?? .zero
|
||||||
}
|
}
|
||||||
|
|
||||||
private var contentInsets: UIEdgeInsets {
|
private var contentInsets: UIEdgeInsets {
|
||||||
viewModel?.contentInsets ?? .zero
|
return viewModel?.contentInsets ?? .zero
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Subclass methods to override
|
// MARK: - Subclass methods to override
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import UIKit
|
||||||
public final class SpinnerView: UIView, Animatable, LoadingIndicator {
|
public final class SpinnerView: UIView, Animatable, LoadingIndicator {
|
||||||
|
|
||||||
private var animating: Bool {
|
private var animating: Bool {
|
||||||
imageView?.layer.animation(forKey: CABasicAnimation.rotationKeyPath) != nil
|
return imageView?.layer.animation(forKey: CABasicAnimation.rotationKeyPath) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
private var startTime = CFTimeInterval(0)
|
private var startTime = CFTimeInterval(0)
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ public final class DataModelFieldBinding<T> {
|
||||||
/// - Parameter textDriver: Driver that emits new text values.
|
/// - Parameter textDriver: Driver that emits new text values.
|
||||||
/// - Returns: Disposable object that can be used to unsubscribe the observer from the behaviour relay.
|
/// - Returns: Disposable object that can be used to unsubscribe the observer from the behaviour relay.
|
||||||
public func mergeStringToModel(from textDriver: Driver<String?>) -> Disposable {
|
public func mergeStringToModel(from textDriver: Driver<String?>) -> Disposable {
|
||||||
textDriver.map { [modelRelay, mergeFieldClosure] in
|
return textDriver.map { [modelRelay, mergeFieldClosure] in
|
||||||
mergeFieldClosure(modelRelay.value, $0)
|
mergeFieldClosure(modelRelay.value, $0)
|
||||||
}
|
}
|
||||||
.drive(modelRelay)
|
.drive(modelRelay)
|
||||||
|
|
@ -65,7 +65,7 @@ public final class DataModelFieldBinding<T> {
|
||||||
|
|
||||||
/// A Driver that will emit current field value.
|
/// A Driver that will emit current field value.
|
||||||
public var fieldDriver: Driver<String?> {
|
public var fieldDriver: Driver<String?> {
|
||||||
modelDriver.map(getFieldClosure)
|
return modelDriver.map(getFieldClosure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,13 +109,12 @@ public extension BehaviorRelay {
|
||||||
/// - getFieldClosure: Closure for getting field string reprerentation from data model.
|
/// - getFieldClosure: Closure for getting field string reprerentation from data model.
|
||||||
/// - mergeFieldClosure: Closure for merging new field value into data model.
|
/// - mergeFieldClosure: Closure for merging new field value into data model.
|
||||||
/// - Returns: DataModelFieldBinding instance.
|
/// - Returns: DataModelFieldBinding instance.
|
||||||
func fieldBinding(getFieldClosure: @escaping DataModelFieldBinding<Element>.GetFieldClosure,
|
func fieldBinding(getFieldClosure: @escaping DataModelFieldBinding<E>.GetFieldClosure,
|
||||||
mergeFieldClosure: @escaping DataModelFieldBinding<Element>.MergeFieldClosure)
|
mergeFieldClosure: @escaping DataModelFieldBinding<E>.MergeFieldClosure) -> DataModelFieldBinding<E> {
|
||||||
-> DataModelFieldBinding<Element> {
|
|
||||||
|
|
||||||
DataModelFieldBinding(modelRelay: self,
|
return DataModelFieldBinding(modelRelay: self,
|
||||||
getFieldClosure: getFieldClosure,
|
getFieldClosure: getFieldClosure,
|
||||||
mergeFieldClosure: mergeFieldClosure)
|
mergeFieldClosure: mergeFieldClosure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,7 +123,7 @@ public extension BehaviorRelay where Element == String? {
|
||||||
/// Creates DataModelFieldBinding configured with behaviour relay itself.
|
/// Creates DataModelFieldBinding configured with behaviour relay itself.
|
||||||
///
|
///
|
||||||
/// - Returns: DataModelFieldBinding instance.
|
/// - Returns: DataModelFieldBinding instance.
|
||||||
func fieldBinding() -> DataModelFieldBinding<Element> {
|
func fieldBinding() -> DataModelFieldBinding<E> {
|
||||||
DataModelFieldBinding(modelRelay: self)
|
return DataModelFieldBinding(modelRelay: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ open class TextFieldViewModel < ViewEvents: TextFieldViewEvents,
|
||||||
/// View events driver that will emit view events structure
|
/// View events driver that will emit view events structure
|
||||||
/// when view will bind itself to the view model.
|
/// when view will bind itself to the view model.
|
||||||
public var viewEventsDriver: Driver<ViewEvents> {
|
public var viewEventsDriver: Driver<ViewEvents> {
|
||||||
viewEventsRelay
|
return viewEventsRelay
|
||||||
.asDriver()
|
.asDriver()
|
||||||
.flatMap { viewEvents -> Driver<ViewEvents> in
|
.flatMap { viewEvents -> Driver<ViewEvents> in
|
||||||
guard let viewEvents = viewEvents else {
|
guard let viewEvents = viewEvents else {
|
||||||
|
|
@ -77,7 +77,7 @@ public extension TextFieldViewModel {
|
||||||
/// - Parameter closure: Closure that takes a view events parameter and returns Disposable.
|
/// - Parameter closure: Closure that takes a view events parameter and returns Disposable.
|
||||||
/// - Returns: Disposable object that can be used to unsubscribe the observer from the binding.
|
/// - Returns: Disposable object that can be used to unsubscribe the observer from the binding.
|
||||||
func mapViewEvents(_ closure: @escaping MapViewEventClosure) -> Disposable {
|
func mapViewEvents(_ closure: @escaping MapViewEventClosure) -> Disposable {
|
||||||
mapViewEvents { [closure($0)] }
|
return mapViewEvents { [closure($0)] }
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias MapViewEventsClosure = (ViewEvents) -> [Disposable]
|
typealias MapViewEventsClosure = (ViewEvents) -> [Disposable]
|
||||||
|
|
@ -87,7 +87,7 @@ public extension TextFieldViewModel {
|
||||||
/// - Parameter closure: Closure that takes a view events parameter and returns [Disposable].
|
/// - Parameter closure: Closure that takes a view events parameter and returns [Disposable].
|
||||||
/// - Returns: Disposable object that can be used to unsubscribe the observer from the binding.
|
/// - Returns: Disposable object that can be used to unsubscribe the observer from the binding.
|
||||||
func mapViewEvents(_ closure: @escaping MapViewEventsClosure) -> Disposable {
|
func mapViewEvents(_ closure: @escaping MapViewEventsClosure) -> Disposable {
|
||||||
viewEventsDriver
|
return viewEventsDriver
|
||||||
.map { [weak self] in
|
.map { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ open class XibView: UIView {
|
||||||
/// Nib name used to instantiate inner view
|
/// Nib name used to instantiate inner view
|
||||||
/// - NOTE: Be very carefully when you're intending to change this line
|
/// - NOTE: Be very carefully when you're intending to change this line
|
||||||
open var innerViewNibName: String {
|
open var innerViewNibName: String {
|
||||||
typeName(of: type(of: self))
|
return typeName(of: type(of: self))
|
||||||
}
|
}
|
||||||
|
|
||||||
public convenience init() {
|
public convenience init() {
|
||||||
|
|
|
||||||
|
|
@ -41,28 +41,28 @@ extension GeneralDataLoadingState: DataLoadingState {
|
||||||
public typealias DataSourceType = DS
|
public typealias DataSourceType = DS
|
||||||
|
|
||||||
public static var initialState: GeneralDataLoadingState<DS> {
|
public static var initialState: GeneralDataLoadingState<DS> {
|
||||||
.initial
|
return .initial
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var emptyState: GeneralDataLoadingState<DS> {
|
public static var emptyState: GeneralDataLoadingState<DS> {
|
||||||
.empty
|
return .empty
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func initialLoadingState(after: GeneralDataLoadingState<DS>) -> GeneralDataLoadingState<DS> {
|
public static func initialLoadingState(after: GeneralDataLoadingState<DS>) -> GeneralDataLoadingState<DS> {
|
||||||
.loading
|
return .loading
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func resultState(result: DS.ResultType,
|
public static func resultState(result: DS.ResultType,
|
||||||
from: DS,
|
from: DS,
|
||||||
after: GeneralDataLoadingState<DS>) -> GeneralDataLoadingState<DS> {
|
after: GeneralDataLoadingState<DS>) -> GeneralDataLoadingState<DS> {
|
||||||
|
|
||||||
.result(newResult: result, from: from)
|
return .result(newResult: result, from: from)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func errorState(error: Error,
|
public static func errorState(error: Error,
|
||||||
after: GeneralDataLoadingState<DS>) -> GeneralDataLoadingState<DS> {
|
after: GeneralDataLoadingState<DS>) -> GeneralDataLoadingState<DS> {
|
||||||
|
|
||||||
.error(error: error)
|
return .error(error: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var isInitialState: Bool {
|
public var isInitialState: Bool {
|
||||||
|
|
|
||||||
|
|
@ -45,28 +45,28 @@ extension PaginationDataLoadingState: DataLoadingState {
|
||||||
public typealias DataSourceType = DS
|
public typealias DataSourceType = DS
|
||||||
|
|
||||||
public static var initialState: PaginationDataLoadingState<DS> {
|
public static var initialState: PaginationDataLoadingState<DS> {
|
||||||
.initial
|
return .initial
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var emptyState: PaginationDataLoadingState<DS> {
|
public static var emptyState: PaginationDataLoadingState<DS> {
|
||||||
.empty
|
return .empty
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func initialLoadingState(after: PaginationDataLoadingState<DS>) -> PaginationDataLoadingState<DS> {
|
public static func initialLoadingState(after: PaginationDataLoadingState<DS>) -> PaginationDataLoadingState<DS> {
|
||||||
.initialLoading(after: after)
|
return .initialLoading(after: after)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func resultState(result: DS.ResultType,
|
public static func resultState(result: DS.ResultType,
|
||||||
from: DataSourceType,
|
from: DataSourceType,
|
||||||
after: PaginationDataLoadingState<DS>) -> PaginationDataLoadingState<DS> {
|
after: PaginationDataLoadingState<DS>) -> PaginationDataLoadingState<DS> {
|
||||||
|
|
||||||
.results(newItems: result, from: from, after: after)
|
return .results(newItems: result, from: from, after: after)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func errorState(error: Error,
|
public static func errorState(error: Error,
|
||||||
after: PaginationDataLoadingState<DS>) -> PaginationDataLoadingState<DS> {
|
after: PaginationDataLoadingState<DS>) -> PaginationDataLoadingState<DS> {
|
||||||
|
|
||||||
.error(error: error, after: after)
|
return .error(error: error, after: after)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var isInitialState: Bool {
|
public var isInitialState: Bool {
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,8 @@ import Foundation
|
||||||
/// Enum that represents common errors in LeadKit framework
|
/// Enum that represents common errors in LeadKit framework
|
||||||
///
|
///
|
||||||
/// - failedToCastValue: attempt to cast was failed
|
/// - failedToCastValue: attempt to cast was failed
|
||||||
/// - failedToDecode: attempt to decoding was failed
|
|
||||||
/// - failedToEncodeQueryItems: attempt to encoding to query items was failed
|
|
||||||
public enum LeadKitError: Error {
|
public enum LeadKitError: Error {
|
||||||
|
|
||||||
case failedToCastValue(expectedType: Any.Type, givenType: Any.Type)
|
case failedToCastValue(expectedType: Any.Type, givenType: Any.Type)
|
||||||
case failedToDecode(reason: String)
|
case failedToDecode(reason: String)
|
||||||
case failedToEncodeQueryItems
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019 Touch Instinct
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Enum with types of possible error handlings
|
||||||
|
///
|
||||||
|
/// - ignore: do nothing
|
||||||
|
/// - action: do action passed in block
|
||||||
|
/// - alert: show alert with NetworkErrorAlertBase
|
||||||
|
public enum NetworkErrorHandlingType<Handler: NetworkErrorHandler> {
|
||||||
|
case ignore
|
||||||
|
case action(ParameterClosure<Error>)
|
||||||
|
case alert(base: NetworkErrorAlertBase<Handler.ErrorType>)
|
||||||
|
|
||||||
|
/// Handles error for selected type
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - error: occured error
|
||||||
|
/// - handler: handler for alert type
|
||||||
|
func handle(error: Error, with handler: Handler?) {
|
||||||
|
switch self {
|
||||||
|
case .ignore:
|
||||||
|
break
|
||||||
|
|
||||||
|
case .action(let action):
|
||||||
|
action(error)
|
||||||
|
|
||||||
|
case .alert(let base):
|
||||||
|
handler?.showNetworkErrorAlert(error: error,
|
||||||
|
customErrorModels: base.customErrorModels,
|
||||||
|
alertActions: base.alertActions,
|
||||||
|
globalErrorAction: base.globalErrorAction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -31,8 +31,8 @@ import Alamofire
|
||||||
/// - mapping: Errors that occurs during mapping json into model.
|
/// - mapping: Errors that occurs during mapping json into model.
|
||||||
public enum RequestError: Error {
|
public enum RequestError: Error {
|
||||||
|
|
||||||
case noConnection(url: String?)
|
case noConnection
|
||||||
case network(error: Error, response: Data?, url: String?)
|
case network(error: Error, response: Data?)
|
||||||
case invalidResponse(error: AFError, response: Data?, url: String?)
|
case invalidResponse(error: AFError, response: Data?)
|
||||||
case mapping(error: Error, response: Data, url: String?)
|
case mapping(error: Error, response: Data)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ public extension Reactive where Base: DataRequest {
|
||||||
func apiResponse<T: Decodable>(mappingQueue: DispatchQueue = .global(), decoder: JSONDecoder)
|
func apiResponse<T: Decodable>(mappingQueue: DispatchQueue = .global(), decoder: JSONDecoder)
|
||||||
-> Observable<SessionManager.ModelResponse<T>> {
|
-> Observable<SessionManager.ModelResponse<T>> {
|
||||||
|
|
||||||
response(onQueue: mappingQueue)
|
return response(onQueue: mappingQueue)
|
||||||
.tryMapResult { response, data in
|
.tryMapResult { response, data in
|
||||||
(response, try decoder.decode(T.self, from: data))
|
(response, try decoder.decode(T.self, from: data))
|
||||||
}
|
}
|
||||||
|
|
@ -50,7 +50,7 @@ public extension Reactive where Base: DataRequest {
|
||||||
func observableApiResponse<T: ObservableMappable>(mappingQueue: DispatchQueue = .global(), decoder: JSONDecoder)
|
func observableApiResponse<T: ObservableMappable>(mappingQueue: DispatchQueue = .global(), decoder: JSONDecoder)
|
||||||
-> Observable<SessionManager.ModelResponse<T>> {
|
-> Observable<SessionManager.ModelResponse<T>> {
|
||||||
|
|
||||||
response(onQueue: mappingQueue)
|
return response(onQueue: mappingQueue)
|
||||||
.tryMapObservableResult { response, value in
|
.tryMapObservableResult { response, value in
|
||||||
let json = try JSONSerialization.jsonObject(with: value, options: [])
|
let json = try JSONSerialization.jsonObject(with: value, options: [])
|
||||||
return T.create(from: json, with: decoder)
|
return T.create(from: json, with: decoder)
|
||||||
|
|
@ -64,55 +64,49 @@ public extension Reactive where Base: DataRequest {
|
||||||
/// - Parameter mappingQueue: The dispatch queue to use for mapping
|
/// - Parameter mappingQueue: The dispatch queue to use for mapping
|
||||||
/// - Returns: Observable with HTTP URL Response and data
|
/// - Returns: Observable with HTTP URL Response and data
|
||||||
func dataApiResponse(mappingQueue: DispatchQueue) -> Observable<SessionManager.DataResponse> {
|
func dataApiResponse(mappingQueue: DispatchQueue) -> Observable<SessionManager.DataResponse> {
|
||||||
response(onQueue: mappingQueue)
|
return response(onQueue: mappingQueue)
|
||||||
.map { $0 as SessionManager.DataResponse }
|
.map { $0 as SessionManager.DataResponse }
|
||||||
.catchAsRequestError(with: self.base)
|
.catchAsRequestError(with: self.base)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func response(onQueue queue: DispatchQueue) -> Observable<(HTTPURLResponse, Data)> {
|
private func response(onQueue queue: DispatchQueue) -> Observable<(HTTPURLResponse, Data)> {
|
||||||
responseResult(queue: queue, responseSerializer: DataResponseSerializer())
|
return responseResult(queue: queue, responseSerializer: DataRequest.dataResponseSerializer())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension ObservableType where Element == DataRequest {
|
public extension ObservableType where E == DataRequest {
|
||||||
|
|
||||||
/// Method that validates status codes and catch network errors
|
/// Method that validates status codes and catch network errors
|
||||||
///
|
///
|
||||||
/// - Parameter statusCodes: set of status codes to validate
|
/// - Parameter statusCodes: set of status codes to validate
|
||||||
/// - Returns: Observable on self
|
/// - Returns: Observable on self
|
||||||
func validate(statusCodes: Set<Int>, url: String? = nil) -> Observable<Element> {
|
func validate(statusCodes: Set<Int>) -> Observable<E> {
|
||||||
map { $0.validate(statusCode: statusCodes) }
|
return map { $0.validate(statusCode: statusCodes) }
|
||||||
.catchAsRequestError(url: url)
|
.catchAsRequestError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension ObservableType where Element == ServerResponse {
|
private extension ObservableType where E == ServerResponse {
|
||||||
|
|
||||||
func tryMapResult<R>(_ transform: @escaping (Element) throws -> R) -> Observable<R> {
|
func tryMapResult<R>(_ transform: @escaping (E) throws -> R) -> Observable<R> {
|
||||||
map {
|
return map {
|
||||||
do {
|
do {
|
||||||
return try transform($0)
|
return try transform($0)
|
||||||
} catch {
|
} catch {
|
||||||
throw RequestError.mapping(error: error,
|
throw RequestError.mapping(error: error, response: $0.1)
|
||||||
response: $0.1,
|
|
||||||
url: $0.0.url?.absoluteString)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryMapObservableResult<R>(_ transform: @escaping (Element) throws -> Observable<R>) -> Observable<R> {
|
func tryMapObservableResult<R>(_ transform: @escaping (E) throws -> Observable<R>) -> Observable<R> {
|
||||||
flatMap { response, result -> Observable<R> in
|
return flatMap { response, result -> Observable<R> in
|
||||||
do {
|
do {
|
||||||
return try transform((response, result))
|
return try transform((response, result))
|
||||||
.catch {
|
.catchError {
|
||||||
throw RequestError.mapping(error: $0,
|
throw RequestError.mapping(error: $0, response: result)
|
||||||
response: result,
|
|
||||||
url: response.url?.absoluteString)
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
throw RequestError.mapping(error: error,
|
throw RequestError.mapping(error: error, response: result)
|
||||||
response: result,
|
|
||||||
url: response.url?.absoluteString)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -120,11 +114,10 @@ private extension ObservableType where Element == ServerResponse {
|
||||||
|
|
||||||
private extension ObservableType {
|
private extension ObservableType {
|
||||||
|
|
||||||
func catchAsRequestError(with request: DataRequest? = nil,
|
func catchAsRequestError(with request: DataRequest? = nil) -> Observable<E> {
|
||||||
url: String? = nil) -> Observable<Element> {
|
return catchError { error in
|
||||||
self.catch { error in
|
|
||||||
let resultError: RequestError
|
let resultError: RequestError
|
||||||
let response = request?.data
|
let response = request?.delegate.data
|
||||||
|
|
||||||
switch error {
|
switch error {
|
||||||
case let requestError as RequestError:
|
case let requestError as RequestError:
|
||||||
|
|
@ -133,32 +126,23 @@ private extension ObservableType {
|
||||||
case let urlError as URLError:
|
case let urlError as URLError:
|
||||||
switch urlError.code {
|
switch urlError.code {
|
||||||
case .notConnectedToInternet:
|
case .notConnectedToInternet:
|
||||||
resultError = .noConnection(url: url)
|
resultError = .noConnection
|
||||||
|
|
||||||
default:
|
default:
|
||||||
resultError = .network(error: urlError, response: response, url: url)
|
resultError = .network(error: urlError, response: response)
|
||||||
}
|
}
|
||||||
|
|
||||||
case let afError as AFError:
|
case let afError as AFError:
|
||||||
switch afError {
|
switch afError {
|
||||||
case let .sessionTaskFailed(error):
|
|
||||||
switch error {
|
|
||||||
case let urlError as URLError where urlError.code == .notConnectedToInternet:
|
|
||||||
resultError = .noConnection(url: url)
|
|
||||||
|
|
||||||
default:
|
|
||||||
resultError = .network(error: error, response: response, url: url)
|
|
||||||
}
|
|
||||||
|
|
||||||
case .responseSerializationFailed, .responseValidationFailed:
|
case .responseSerializationFailed, .responseValidationFailed:
|
||||||
resultError = .invalidResponse(error: afError, response: response, url: url)
|
resultError = .invalidResponse(error: afError, response: response)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
resultError = .network(error: afError, response: response, url: url)
|
resultError = .network(error: afError, response: response)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
resultError = .network(error: error, response: response, url: url)
|
resultError = .network(error: error, response: response)
|
||||||
}
|
}
|
||||||
|
|
||||||
throw resultError
|
throw resultError
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ enum RequestUsageError: Error {
|
||||||
|
|
||||||
case getMethodForbidden
|
case getMethodForbidden
|
||||||
case urlEncodingForbidden
|
case urlEncodingForbidden
|
||||||
case unableToHandleQueryParams
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension Reactive where Base: SessionManager {
|
public extension Reactive where Base: SessionManager {
|
||||||
|
|
@ -50,10 +49,10 @@ public extension Reactive where Base: SessionManager {
|
||||||
_ url: URLConvertible,
|
_ url: URLConvertible,
|
||||||
parameters: [Any]? = nil,
|
parameters: [Any]? = nil,
|
||||||
encoding: JSONEncoding = .default,
|
encoding: JSONEncoding = .default,
|
||||||
headers: HTTPHeaders? = nil)
|
headers: [String: String]? = nil)
|
||||||
-> Observable<DataRequest> {
|
-> Observable<DataRequest> {
|
||||||
|
|
||||||
Observable.deferred {
|
return Observable.deferred {
|
||||||
|
|
||||||
guard method != .get else {
|
guard method != .get else {
|
||||||
assertionFailure("Unable to pass array in get request")
|
assertionFailure("Unable to pass array in get request")
|
||||||
|
|
@ -73,53 +72,41 @@ public extension Reactive where Base: SessionManager {
|
||||||
/// - requestParameters: api parameters to pass Alamofire
|
/// - requestParameters: api parameters to pass Alamofire
|
||||||
/// - additionalValidStatusCodes: set of additional valid status codes
|
/// - additionalValidStatusCodes: set of additional valid status codes
|
||||||
/// - Returns: Observable with request
|
/// - Returns: Observable with request
|
||||||
func apiRequest(requestParameters: ApiRequestParameters, additionalValidStatusCodes: Set<Int>) -> Observable<DataRequest> {
|
func apiRequest(requestParameters: ApiRequestParameters, additionalValidStatusCodes: Set<Int>)
|
||||||
.deferred {
|
-> Observable<DataRequest> {
|
||||||
var url = try requestParameters.url.asURL()
|
|
||||||
|
|
||||||
if let queryItems = requestParameters.queryItems {
|
let requestObservable: Observable<DataRequest>
|
||||||
guard var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
|
|
||||||
return .error(RequestUsageError.unableToHandleQueryParams)
|
|
||||||
}
|
|
||||||
|
|
||||||
urlComponents.queryItems = queryItems
|
switch requestParameters.parameters {
|
||||||
url = try urlComponents.asURL()
|
case .dictionary(let parameters)?:
|
||||||
|
requestObservable = request(requestParameters.method,
|
||||||
|
requestParameters.url,
|
||||||
|
parameters: parameters,
|
||||||
|
encoding: requestParameters.encoding,
|
||||||
|
headers: requestParameters.headers)
|
||||||
|
|
||||||
|
case .array(let parameters)?:
|
||||||
|
guard let encoding = requestParameters.encoding as? JSONEncoding else {
|
||||||
|
assertionFailure("Invalid encoding type with array parameter")
|
||||||
|
return .error(RequestUsageError.urlEncodingForbidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
let requestObservable: Observable<DataRequest>
|
requestObservable = request(requestParameters.method,
|
||||||
|
requestParameters.url,
|
||||||
|
parameters: parameters,
|
||||||
|
encoding: encoding,
|
||||||
|
headers: requestParameters.headers)
|
||||||
|
|
||||||
switch requestParameters.parameters {
|
case .none:
|
||||||
case .dictionary(let parameters)?:
|
requestObservable = request(requestParameters.method,
|
||||||
requestObservable = self.request(requestParameters.method,
|
requestParameters.url,
|
||||||
url,
|
parameters: nil as Parameters?,
|
||||||
parameters: parameters,
|
encoding: requestParameters.encoding,
|
||||||
encoding: requestParameters.encoding,
|
headers: requestParameters.headers)
|
||||||
headers: requestParameters.headers)
|
|
||||||
|
|
||||||
case .array(let parameters)?:
|
|
||||||
guard let encoding = requestParameters.encoding as? JSONEncoding else {
|
|
||||||
assertionFailure("Invalid encoding type with array parameter")
|
|
||||||
return .error(RequestUsageError.urlEncodingForbidden)
|
|
||||||
}
|
|
||||||
|
|
||||||
requestObservable = self.request(requestParameters.method,
|
|
||||||
url,
|
|
||||||
parameters: parameters,
|
|
||||||
encoding: encoding,
|
|
||||||
headers: requestParameters.headers)
|
|
||||||
|
|
||||||
case .none:
|
|
||||||
requestObservable = self.request(requestParameters.method,
|
|
||||||
url,
|
|
||||||
parameters: nil as Parameters?,
|
|
||||||
encoding: requestParameters.encoding,
|
|
||||||
headers: requestParameters.headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestObservable
|
|
||||||
.validate(statusCodes: self.base.acceptableStatusCodes.union(additionalValidStatusCodes),
|
|
||||||
url: url.absoluteString)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return requestObservable
|
||||||
|
.validate(statusCodes: self.base.acceptableStatusCodes.union(additionalValidStatusCodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method that executes request and serializes response into target object
|
/// Method that executes request and serializes response into target object
|
||||||
|
|
@ -134,7 +121,7 @@ public extension Reactive where Base: SessionManager {
|
||||||
decoder: JSONDecoder)
|
decoder: JSONDecoder)
|
||||||
-> Observable<SessionManager.ModelResponse<T>> {
|
-> Observable<SessionManager.ModelResponse<T>> {
|
||||||
|
|
||||||
apiRequest(requestParameters: requestParameters, additionalValidStatusCodes: additionalValidStatusCodes)
|
return apiRequest(requestParameters: requestParameters, additionalValidStatusCodes: additionalValidStatusCodes)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
$0.rx.apiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder)
|
$0.rx.apiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder)
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +139,7 @@ public extension Reactive where Base: SessionManager {
|
||||||
decoder: JSONDecoder)
|
decoder: JSONDecoder)
|
||||||
-> Observable<SessionManager.ModelResponse<T>> {
|
-> Observable<SessionManager.ModelResponse<T>> {
|
||||||
|
|
||||||
apiRequest(requestParameters: requestParameters, additionalValidStatusCodes: additionalValidStatusCodes)
|
return apiRequest(requestParameters: requestParameters, additionalValidStatusCodes: additionalValidStatusCodes)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
$0.rx.observableApiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder)
|
$0.rx.observableApiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder)
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +154,7 @@ public extension Reactive where Base: SessionManager {
|
||||||
func responseData(requestParameters: ApiRequestParameters, additionalValidStatusCodes: Set<Int>)
|
func responseData(requestParameters: ApiRequestParameters, additionalValidStatusCodes: Set<Int>)
|
||||||
-> Observable<SessionManager.DataResponse> {
|
-> Observable<SessionManager.DataResponse> {
|
||||||
|
|
||||||
apiRequest(requestParameters: requestParameters, additionalValidStatusCodes: additionalValidStatusCodes)
|
return apiRequest(requestParameters: requestParameters, additionalValidStatusCodes: additionalValidStatusCodes)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
$0.rx.dataApiResponse(mappingQueue: self.base.mappingQueue)
|
$0.rx.dataApiResponse(mappingQueue: self.base.mappingQueue)
|
||||||
}
|
}
|
||||||
|
|
@ -185,15 +172,14 @@ public extension Reactive where Base: SessionManager {
|
||||||
decoder: JSONDecoder)
|
decoder: JSONDecoder)
|
||||||
-> Observable<SessionManager.ModelResponse<T>> {
|
-> Observable<SessionManager.ModelResponse<T>> {
|
||||||
|
|
||||||
Observable.deferred {
|
return Observable.deferred {
|
||||||
|
|
||||||
let urlRequest = try URLRequest(url: requestParameters.url, method: .post, headers: requestParameters.headers)
|
let urlRequest = try URLRequest(url: requestParameters.url, method: .post, headers: requestParameters.headers)
|
||||||
let data = try requestParameters.formData.encode()
|
let data = try requestParameters.formData.encode()
|
||||||
|
|
||||||
return self.upload(data, urlRequest: urlRequest)
|
return self.upload(data, urlRequest: urlRequest)
|
||||||
.map { $0 as DataRequest }
|
.map { $0 as DataRequest }
|
||||||
.validate(statusCodes: self.base.acceptableStatusCodes.union(additionalValidStatusCodes),
|
.validate(statusCodes: self.base.acceptableStatusCodes.union(additionalValidStatusCodes))
|
||||||
url: try? requestParameters.url.asURL().absoluteString)
|
|
||||||
.flatMap {
|
.flatMap {
|
||||||
$0.rx.apiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder)
|
$0.rx.apiResponse(mappingQueue: self.base.mappingQueue, decoder: decoder)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,6 @@ public extension Array {
|
||||||
|
|
||||||
// Subscript for safe access to element by index
|
// Subscript for safe access to element by index
|
||||||
subscript(safe index: Index) -> Element? {
|
subscript(safe index: Index) -> Element? {
|
||||||
(index < count && index >= 0) ? self[index] : nil
|
return (index < count && index >= 0) ? self[index] : nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,11 @@ public extension Array where Element: TableKitViewModel {
|
||||||
|
|
||||||
/// Creates [Row] array from TableKitViewModels.
|
/// Creates [Row] array from TableKitViewModels.
|
||||||
var tableRows: [Row] {
|
var tableRows: [Row] {
|
||||||
map { $0.tableRow }
|
return map { $0.tableRow }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates TableSection with empty, zero height header and footer.
|
/// Creates TableSection with empty, zero height header and footer.
|
||||||
var onlyRowsSection: TableSection {
|
var onlyRowsSection: TableSection {
|
||||||
TableSection(onlyRows: tableRows)
|
return TableSection(onlyRows: tableRows)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ public extension Array where Element == SeparatorRowBox {
|
||||||
|
|
||||||
/// Create rows from SeparatorRowBox array
|
/// Create rows from SeparatorRowBox array
|
||||||
var rows: [Row] {
|
var rows: [Row] {
|
||||||
map { $0.row }
|
return map { $0.row }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configure separators from SeparatorRowBox array
|
/// Configure separators from SeparatorRowBox array
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,10 @@ extension Array: TotalCountCursorListingResult {
|
||||||
public typealias ElementType = Element
|
public typealias ElementType = Element
|
||||||
|
|
||||||
public var results: [Element] {
|
public var results: [Element] {
|
||||||
self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
public var totalCount: Int {
|
public var totalCount: Int {
|
||||||
count
|
return count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,20 +35,4 @@ public extension Encodable {
|
||||||
|
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method that converts encodable model to URLQueryItems array
|
|
||||||
/// - Returns: URLQueryItems array
|
|
||||||
func asUrlQueryItems() throws -> [URLQueryItem] {
|
|
||||||
try toJSON().map {
|
|
||||||
if ($1 is [String: Any] || $1 is [Any]),
|
|
||||||
let jsonData = try? JSONSerialization.data(withJSONObject: $1, options: []),
|
|
||||||
let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
||||||
return URLQueryItem(name: $0, value: jsonString)
|
|
||||||
} else if let value = $1 as? CustomStringConvertible {
|
|
||||||
return URLQueryItem(name: $0, value: value.description)
|
|
||||||
} else {
|
|
||||||
throw LeadKitError.failedToEncodeQueryItems
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,6 @@ public extension Comparable {
|
||||||
/// - parameter bounds: Lower and uppper bounds tuple
|
/// - parameter bounds: Lower and uppper bounds tuple
|
||||||
/// - returns: Current value if it fits range, otherwise lower if value is too small or upper if value is too big
|
/// - returns: Current value if it fits range, otherwise lower if value is too small or upper if value is too big
|
||||||
func `in`(bounds: (lower: Self, upper: Self)) -> Self {
|
func `in`(bounds: (lower: Self, upper: Self)) -> Self {
|
||||||
min(max(bounds.lower, self), bounds.upper)
|
return min(max(bounds.lower, self), bounds.upper)
|
||||||
}
|
|
||||||
|
|
||||||
/// Use this function to restrict comparable with lower and upper values
|
|
||||||
/// - parameter range: ClosedRange representing bounds
|
|
||||||
/// - returns: Current value if it fits range, otherwise lower if value is too small or upper if value is too big
|
|
||||||
func `in`(range: ClosedRange<Self>) -> Self {
|
|
||||||
`in`(bounds: (lower: range.lowerBound, upper: range.upperBound))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,6 @@ import RxSwift
|
||||||
public extension RxDataSource where Self: CursorType {
|
public extension RxDataSource where Self: CursorType {
|
||||||
|
|
||||||
func resultSingle() -> Single<[Element]> {
|
func resultSingle() -> Single<[Element]> {
|
||||||
loadNextBatch()
|
return loadNextBatch()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,14 @@ import Foundation
|
||||||
public extension CursorType {
|
public extension CursorType {
|
||||||
|
|
||||||
subscript(range: CountableRange<Int>) -> [Self.Element] {
|
subscript(range: CountableRange<Int>) -> [Self.Element] {
|
||||||
range.map { self[$0] }
|
return range.map { self[$0] }
|
||||||
}
|
}
|
||||||
|
|
||||||
subscript(range: CountableClosedRange<Int>) -> [Self.Element] {
|
subscript(range: CountableClosedRange<Int>) -> [Self.Element] {
|
||||||
range.map { self[$0] }
|
return range.map { self[$0] }
|
||||||
}
|
}
|
||||||
|
|
||||||
var loadedElements: [Self.Element] {
|
var loadedElements: [Self.Element] {
|
||||||
self[0..<count]
|
return self[0..<count]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ public extension TotalCountCursorListingResult {
|
||||||
/// - Parameter transform: closure to transform results
|
/// - Parameter transform: closure to transform results
|
||||||
/// - Returns: new DefaultTotalCountCursorListingResult instance
|
/// - Returns: new DefaultTotalCountCursorListingResult instance
|
||||||
func asDefaultListingResult<E>(transform: ((ElementType) -> E)) -> DefaultTotalCountCursorListingResult<E> {
|
func asDefaultListingResult<E>(transform: ((ElementType) -> E)) -> DefaultTotalCountCursorListingResult<E> {
|
||||||
DefaultTotalCountCursorListingResult(results: results.map(transform),
|
return DefaultTotalCountCursorListingResult(results: results.map(transform),
|
||||||
totalCount: totalCount)
|
totalCount: totalCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method that creates DefaultTotalCountCursorListingResult
|
/// Method that creates DefaultTotalCountCursorListingResult
|
||||||
|
|
@ -37,7 +37,7 @@ public extension TotalCountCursorListingResult {
|
||||||
///
|
///
|
||||||
/// - Returns: new DefaultTotalCountCursorListingResult instance
|
/// - Returns: new DefaultTotalCountCursorListingResult instance
|
||||||
func asDefaultListingResult() -> DefaultTotalCountCursorListingResult<ElementType> {
|
func asDefaultListingResult() -> DefaultTotalCountCursorListingResult<ElementType> {
|
||||||
DefaultTotalCountCursorListingResult(results: results,
|
return DefaultTotalCountCursorListingResult(results: results,
|
||||||
totalCount: totalCount)
|
totalCount: totalCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,13 @@ public extension GeneralDataLoadingController {
|
||||||
// MARK: - DisposeBagHolder default implementation
|
// MARK: - DisposeBagHolder default implementation
|
||||||
|
|
||||||
var disposeBag: DisposeBag {
|
var disposeBag: DisposeBag {
|
||||||
viewModel.disposeBag
|
return viewModel.disposeBag
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - StatefulViewController default implementation
|
// MARK: - StatefulViewController default implementation
|
||||||
|
|
||||||
func hasContent() -> Bool {
|
func hasContent() -> Bool {
|
||||||
viewModel.hasContent
|
return viewModel.hasContent
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - GeneralDataLoadingController default implementation
|
// MARK: - GeneralDataLoadingController default implementation
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import RxCocoa
|
||||||
internal extension GeneralDataLoadingHandler where Self: AnyObject {
|
internal extension GeneralDataLoadingHandler where Self: AnyObject {
|
||||||
|
|
||||||
var stateChangeBinder: Binder<GeneralDataLoadingState<Single<ResultType>>> {
|
var stateChangeBinder: Binder<GeneralDataLoadingState<Single<ResultType>>> {
|
||||||
Binder(self) { base, value in
|
return Binder(self) { base, value in
|
||||||
switch value {
|
switch value {
|
||||||
case .loading:
|
case .loading:
|
||||||
base.onLoadingState()
|
base.onLoadingState()
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ public extension GeneralDataLoadingViewModel {
|
||||||
|
|
||||||
/// Emit elements of ResultType from state observable.
|
/// Emit elements of ResultType from state observable.
|
||||||
var resultObservable: Observable<ResultType> {
|
var resultObservable: Observable<ResultType> {
|
||||||
loadingStateObservable.flatMap { state -> Observable<ResultType> in
|
return loadingStateObservable.flatMap { state -> Observable<ResultType> in
|
||||||
switch state {
|
switch state {
|
||||||
case .result(let newResult, _):
|
case .result(let newResult, _):
|
||||||
return .just(newResult)
|
return .just(newResult)
|
||||||
|
|
@ -47,7 +47,7 @@ public extension GeneralDataLoadingViewModel {
|
||||||
|
|
||||||
/// Emit elements of ResultType from state driver.
|
/// Emit elements of ResultType from state driver.
|
||||||
var resultDriver: Driver<ResultType> {
|
var resultDriver: Driver<ResultType> {
|
||||||
loadingStateDriver.flatMap { state -> Driver<ResultType> in
|
return loadingStateDriver.flatMap { state -> Driver<ResultType> in
|
||||||
switch state {
|
switch state {
|
||||||
case .result(let newResult, _):
|
case .result(let newResult, _):
|
||||||
return .just(newResult)
|
return .just(newResult)
|
||||||
|
|
|
||||||
|
|
@ -25,15 +25,15 @@ import UIKit
|
||||||
public extension PaginationWrapperUIDelegate {
|
public extension PaginationWrapperUIDelegate {
|
||||||
|
|
||||||
func emptyPlaceholder() -> UIView? {
|
func emptyPlaceholder() -> UIView? {
|
||||||
TextPlaceholderView(title: .empty)
|
return TextPlaceholderView(title: .empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
func customInitialLoadingErrorHandling(for error: Error) -> Bool {
|
func customInitialLoadingErrorHandling(for error: Error) -> Bool {
|
||||||
false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func errorPlaceholder(for error: Error) -> UIView? {
|
func errorPlaceholder(for error: Error) -> UIView? {
|
||||||
TextPlaceholderView(title: .error)
|
return TextPlaceholderView(title: .error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initialLoadingIndicator() -> AnyLoadingIndicator? {
|
func initialLoadingIndicator() -> AnyLoadingIndicator? {
|
||||||
|
|
@ -49,7 +49,7 @@ public extension PaginationWrapperUIDelegate {
|
||||||
return AnyLoadingIndicator(indicator)
|
return AnyLoadingIndicator(indicator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func footerRetryView() -> ButtonHolderView? {
|
func footerRetryButton() -> UIButton? {
|
||||||
let retryButton = UIButton(type: .custom)
|
let retryButton = UIButton(type: .custom)
|
||||||
retryButton.backgroundColor = .lightGray
|
retryButton.backgroundColor = .lightGray
|
||||||
retryButton.setTitle("Retry load more", for: .normal)
|
retryButton.setTitle("Retry load more", for: .normal)
|
||||||
|
|
@ -57,15 +57,15 @@ public extension PaginationWrapperUIDelegate {
|
||||||
return retryButton
|
return retryButton
|
||||||
}
|
}
|
||||||
|
|
||||||
func footerRetryViewHeight() -> CGFloat {
|
func footerRetryButtonHeight() -> CGFloat {
|
||||||
44
|
return 44
|
||||||
}
|
}
|
||||||
|
|
||||||
func footerRetryViewWillAppear() {
|
func footerRetryButtonWillAppear() {
|
||||||
// by default - nothing will happen
|
// by default - nothing will happen
|
||||||
}
|
}
|
||||||
|
|
||||||
func footerRetryViewWillDisappear() {
|
func footerRetryButtonWillDisappear() {
|
||||||
// by default - nothing will happen
|
// by default - nothing will happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ extension UITableView: PaginationWrappable {
|
||||||
|
|
||||||
public var footerView: UIView? {
|
public var footerView: UIView? {
|
||||||
get {
|
get {
|
||||||
tableFooterView
|
return tableFooterView
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
tableFooterView = newValue
|
tableFooterView = newValue
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ extension Observable: RxDataSource {
|
||||||
public typealias ResultType = Element
|
public typealias ResultType = Element
|
||||||
|
|
||||||
public func resultSingle() -> Single<ResultType> {
|
public func resultSingle() -> Single<ResultType> {
|
||||||
asSingle()
|
return asSingle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,6 +41,6 @@ extension Single: RxDataSource {
|
||||||
public typealias ResultType = Element
|
public typealias ResultType = Element
|
||||||
|
|
||||||
public func resultSingle() -> Single<ResultType> {
|
public func resultSingle() -> Single<ResultType> {
|
||||||
asObservable().asSingle()
|
return asObservable().asSingle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ public extension DateFormattingService {
|
||||||
format: DateFormatType,
|
format: DateFormatType,
|
||||||
defaultDate: DateInRegion = Date().inDefaultRegion()) -> DateInRegion {
|
defaultDate: DateInRegion = Date().inDefaultRegion()) -> DateInRegion {
|
||||||
|
|
||||||
date(from: string, format: format, parsedIn: nil) ?? defaultDate
|
return date(from: string, format: format, parsedIn: nil) ?? defaultDate
|
||||||
}
|
}
|
||||||
|
|
||||||
func date(from string: String,
|
func date(from string: String,
|
||||||
|
|
@ -40,20 +40,8 @@ public extension DateFormattingService {
|
||||||
return format.stringToDateFormat.toDate(string, region: region)
|
return format.stringToDateFormat.toDate(string, region: region)
|
||||||
}
|
}
|
||||||
|
|
||||||
func date(from string: String, formats: [DateFormatType], parsedIn: Region?) -> DateInRegion? {
|
|
||||||
let region = parsedIn ?? currentRegion
|
|
||||||
|
|
||||||
for format in formats {
|
|
||||||
if let parsedDate = format.stringToDateFormat.toDate(string, region: region) {
|
|
||||||
return parsedDate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func string(from date: DateRepresentable, format: DateFormatType) -> String {
|
func string(from date: DateRepresentable, format: DateFormatType) -> String {
|
||||||
format.dateToStringFormat.toString(date)
|
return format.dateToStringFormat.toString(date)
|
||||||
}
|
}
|
||||||
|
|
||||||
func string(from date: DateRepresentable, format: DateFormatType, formattedIn: Region?) -> String {
|
func string(from date: DateRepresentable, format: DateFormatType, formattedIn: Region?) -> String {
|
||||||
|
|
@ -79,7 +67,7 @@ public extension DateFormattingService where Self: Singleton {
|
||||||
format: DateFormatType,
|
format: DateFormatType,
|
||||||
defaultDate: DateInRegion = Date().inDefaultRegion()) -> DateInRegion {
|
defaultDate: DateInRegion = Date().inDefaultRegion()) -> DateInRegion {
|
||||||
|
|
||||||
shared.date(from: string, format: format, defaultDate: defaultDate)
|
return shared.date(from: string, format: format, defaultDate: defaultDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method parses date from string in given format with current region.
|
/// Method parses date from string in given format with current region.
|
||||||
|
|
@ -90,18 +78,7 @@ public extension DateFormattingService where Self: Singleton {
|
||||||
/// - parsedIn: A region that should be used for date parsing. In case of nil defaultRegion will be used.
|
/// - parsedIn: A region that should be used for date parsing. In case of nil defaultRegion will be used.
|
||||||
/// - Returns: Date parsed from given string or default date if parsing did fail.
|
/// - Returns: Date parsed from given string or default date if parsing did fail.
|
||||||
static func date(from string: String, format: DateFormatType, parsedIn: Region?) -> DateInRegion? {
|
static func date(from string: String, format: DateFormatType, parsedIn: Region?) -> DateInRegion? {
|
||||||
shared.date(from: string, format: format, parsedIn: parsedIn)
|
return shared.date(from: string, format: format, parsedIn: parsedIn)
|
||||||
}
|
|
||||||
|
|
||||||
/// Method parses date from string in one of the given formats with current region.
|
|
||||||
///
|
|
||||||
/// - Parameters:
|
|
||||||
/// - string: String to use for date parsing.
|
|
||||||
/// - formats: Formats that should be used for date parsing.
|
|
||||||
/// - parsedIn: A region that should be used for date parsing. In case of nil defaultRegion will be used.
|
|
||||||
/// - Returns: Date parsed from given string or default date if parsing did fail.
|
|
||||||
static func date(from string: String, formats: [DateFormatType], parsedIn: Region?) -> DateInRegion? {
|
|
||||||
shared.date(from: string, formats: formats, parsedIn: parsedIn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method format date in given format.
|
/// Method format date in given format.
|
||||||
|
|
@ -111,7 +88,7 @@ public extension DateFormattingService where Self: Singleton {
|
||||||
/// - format: Format that should be used for date formatting.
|
/// - format: Format that should be used for date formatting.
|
||||||
/// - Returns: String that contains formatted date or nil if formatting did fail.
|
/// - Returns: String that contains formatted date or nil if formatting did fail.
|
||||||
static func string(from date: DateRepresentable, format: DateFormatType) -> String {
|
static func string(from date: DateRepresentable, format: DateFormatType) -> String {
|
||||||
shared.string(from: date, format: format)
|
return shared.string(from: date, format: format)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method format date in given format for specific region.
|
/// Method format date in given format for specific region.
|
||||||
|
|
@ -122,6 +99,6 @@ public extension DateFormattingService where Self: Singleton {
|
||||||
/// - formattedIn: A region that should be used for date formatting. In case of nil defaultRegion will be used.
|
/// - formattedIn: A region that should be used for date formatting. In case of nil defaultRegion will be used.
|
||||||
/// - Returns: String that contains formatted date or nil if formatting did fail.
|
/// - Returns: String that contains formatted date or nil if formatting did fail.
|
||||||
static func string(from date: DateRepresentable, format: DateFormatType, formattedIn: Region?) -> String {
|
static func string(from date: DateRepresentable, format: DateFormatType, formattedIn: Region?) -> String {
|
||||||
shared.string(from: date, format: format, formattedIn: formattedIn)
|
return shared.string(from: date, format: format, formattedIn: formattedIn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,11 @@ public extension Decimal {
|
||||||
|
|
||||||
/// Conver Decimal to Double value
|
/// Conver Decimal to Double value
|
||||||
var doubleValue: Double {
|
var doubleValue: Double {
|
||||||
NSDecimalNumber(decimal: self).doubleValue
|
return NSDecimalNumber(decimal: self).doubleValue
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Conver Decimal to Int value
|
/// Conver Decimal to Int value
|
||||||
var intValue: Int {
|
var intValue: Int {
|
||||||
NSDecimalNumber(decimal: self).intValue
|
return NSDecimalNumber(decimal: self).intValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,11 @@ public extension CGContext {
|
||||||
static func create(forCGImage cgImage: CGImage,
|
static func create(forCGImage cgImage: CGImage,
|
||||||
fallbackColorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()) -> CGContext? {
|
fallbackColorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()) -> CGContext? {
|
||||||
|
|
||||||
create(width: cgImage.width,
|
return create(width: cgImage.width,
|
||||||
height: cgImage.height,
|
height: cgImage.height,
|
||||||
bitmapInfo: cgImage.bitmapInfo,
|
bitmapInfo: cgImage.bitmapInfo,
|
||||||
colorSpace: cgImage.colorSpace ?? fallbackColorSpace,
|
colorSpace: cgImage.colorSpace ?? fallbackColorSpace,
|
||||||
bitsPerComponent: cgImage.bitsPerComponent)
|
bitsPerComponent: cgImage.bitsPerComponent)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a bitmap graphics context.
|
/// Creates a bitmap graphics context.
|
||||||
|
|
@ -65,12 +65,12 @@ public extension CGContext {
|
||||||
colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB(),
|
colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB(),
|
||||||
bitsPerComponent: Int = 8) -> CGContext? {
|
bitsPerComponent: Int = 8) -> CGContext? {
|
||||||
|
|
||||||
CGContext(data: nil,
|
return CGContext(data: nil,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
bitsPerComponent: bitsPerComponent,
|
bitsPerComponent: bitsPerComponent,
|
||||||
bytesPerRow: 0,
|
bytesPerRow: 0,
|
||||||
space: colorSpace,
|
space: colorSpace,
|
||||||
bitmapInfo: bitmapInfo.rawValue)
|
bitmapInfo: bitmapInfo.rawValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,6 @@ import CoreGraphics.CGGeometry
|
||||||
public extension CGSize {
|
public extension CGSize {
|
||||||
|
|
||||||
var ceiledContextSize: CGContextSize {
|
var ceiledContextSize: CGContextSize {
|
||||||
(width: Int(ceil(width)), height: Int(ceil(height)))
|
return (width: Int(ceil(width)), height: Int(ceil(height)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
@available(iOS 10.0, tvOS 10.0, *)
|
||||||
public extension UIImage {
|
public extension UIImage {
|
||||||
|
|
||||||
/// Creates an image filled by given color.
|
/// Creates an image filled by given color.
|
||||||
|
|
@ -55,7 +56,7 @@ public extension UIImage {
|
||||||
/// - Parameter color: Color to fill template image.
|
/// - Parameter color: Color to fill template image.
|
||||||
/// - Returns: A new UIImage rendered with given color or original image if something goes wrong.
|
/// - Returns: A new UIImage rendered with given color or original image if something goes wrong.
|
||||||
func renderTemplate(withColor color: UIColor) -> UIImage {
|
func renderTemplate(withColor color: UIColor) -> UIImage {
|
||||||
withCGImage { image in
|
return withCGImage { image in
|
||||||
let operation = TemplateDrawingOperation(image: image,
|
let operation = TemplateDrawingOperation(image: image,
|
||||||
imageSize: size,
|
imageSize: size,
|
||||||
color: color.cgColor)
|
color: color.cgColor)
|
||||||
|
|
@ -77,7 +78,7 @@ public extension UIImage {
|
||||||
color: UIColor,
|
color: UIColor,
|
||||||
extendSize: Bool = false) -> UIImage {
|
extendSize: Bool = false) -> UIImage {
|
||||||
|
|
||||||
withCGImage { image in
|
return withCGImage { image in
|
||||||
let roundOperation = RoundDrawingOperation(image: image,
|
let roundOperation = RoundDrawingOperation(image: image,
|
||||||
imageSize: size,
|
imageSize: size,
|
||||||
radius: cornerRadius)
|
radius: cornerRadius)
|
||||||
|
|
@ -101,7 +102,7 @@ public extension UIImage {
|
||||||
///
|
///
|
||||||
/// - Returns: A new circled image or original image if something goes wrong.
|
/// - Returns: A new circled image or original image if something goes wrong.
|
||||||
func roundCornersToCircle() -> UIImage {
|
func roundCornersToCircle() -> UIImage {
|
||||||
withCGImage { image in
|
return withCGImage { image in
|
||||||
let radius = CGFloat(min(size.width, size.height) / 2)
|
let radius = CGFloat(min(size.width, size.height) / 2)
|
||||||
|
|
||||||
let operation = RoundDrawingOperation(image: image,
|
let operation = RoundDrawingOperation(image: image,
|
||||||
|
|
@ -123,7 +124,7 @@ public extension UIImage {
|
||||||
borderColor: UIColor,
|
borderColor: UIColor,
|
||||||
extendSize: Bool = false) -> UIImage {
|
extendSize: Bool = false) -> UIImage {
|
||||||
|
|
||||||
withCGImage { image in
|
return withCGImage { image in
|
||||||
let radius = CGFloat(min(size.width, size.height) / 2)
|
let radius = CGFloat(min(size.width, size.height) / 2)
|
||||||
|
|
||||||
let roundOperation = RoundDrawingOperation(image: image,
|
let roundOperation = RoundDrawingOperation(image: image,
|
||||||
|
|
@ -157,7 +158,7 @@ public extension UIImage {
|
||||||
contentMode: ResizeMode = .scaleToFill,
|
contentMode: ResizeMode = .scaleToFill,
|
||||||
cropToImageBounds: Bool = false) -> UIImage {
|
cropToImageBounds: Bool = false) -> UIImage {
|
||||||
|
|
||||||
withCGImage { image in
|
return withCGImage { image in
|
||||||
let operation = ResizeDrawingOperation(image: image,
|
let operation = ResizeDrawingOperation(image: image,
|
||||||
imageSize: size,
|
imageSize: size,
|
||||||
preferredNewSize: newSize,
|
preferredNewSize: newSize,
|
||||||
|
|
@ -172,7 +173,7 @@ public extension UIImage {
|
||||||
///
|
///
|
||||||
/// - Returns: A copy of the given image, adding an alpha channel if it doesn't already have one.
|
/// - Returns: A copy of the given image, adding an alpha channel if it doesn't already have one.
|
||||||
func applyAlpha() -> UIImage {
|
func applyAlpha() -> UIImage {
|
||||||
withCGImage { image in
|
return withCGImage { image in
|
||||||
guard !image.hasAlpha else {
|
guard !image.hasAlpha else {
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
@ -190,7 +191,7 @@ public extension UIImage {
|
||||||
/// - Parameter padding: The padding amount.
|
/// - Parameter padding: The padding amount.
|
||||||
/// - Returns: A new padded image or original image if something goes wrong.
|
/// - Returns: A new padded image or original image if something goes wrong.
|
||||||
func applyPadding(_ padding: CGFloat) -> UIImage {
|
func applyPadding(_ padding: CGFloat) -> UIImage {
|
||||||
withCGImage { image in
|
return withCGImage { image in
|
||||||
let operation = PaddingDrawingOperation(image: image, imageSize: size, padding: padding)
|
let operation = PaddingDrawingOperation(image: image, imageSize: size, padding: padding)
|
||||||
|
|
||||||
return operation.imageFromNewRenderer(scale: scale).redraw()
|
return operation.imageFromNewRenderer(scale: scale).redraw()
|
||||||
|
|
@ -204,7 +205,7 @@ public extension UIImage {
|
||||||
/// - clockwise: Should rotate image clockwise.
|
/// - clockwise: Should rotate image clockwise.
|
||||||
/// - Returns: A new rotated image or original image if something goes wrong.
|
/// - Returns: A new rotated image or original image if something goes wrong.
|
||||||
func rotate(degrees: CGFloat, clockwise: Bool = true) -> UIImage {
|
func rotate(degrees: CGFloat, clockwise: Bool = true) -> UIImage {
|
||||||
withCGImage { image in
|
return withCGImage { image in
|
||||||
let radians = degrees.degreesToRadians()
|
let radians = degrees.degreesToRadians()
|
||||||
|
|
||||||
let operation = RotateDrawingOperation(image: image,
|
let operation = RotateDrawingOperation(image: image,
|
||||||
|
|
@ -218,7 +219,7 @@ public extension UIImage {
|
||||||
|
|
||||||
/// Workaround to fix flipped image rendering (by Y)
|
/// Workaround to fix flipped image rendering (by Y)
|
||||||
private func redraw() -> UIImage {
|
private func redraw() -> UIImage {
|
||||||
withCGImage { image in
|
return withCGImage { image in
|
||||||
let operation = ImageDrawingOperation(image: image, newSize: size)
|
let operation = ImageDrawingOperation(image: image, newSize: size)
|
||||||
|
|
||||||
return operation.imageFromNewRenderer(scale: scale)
|
return operation.imageFromNewRenderer(scale: scale)
|
||||||
|
|
@ -234,6 +235,7 @@ public extension UIImage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(iOS 10.0, tvOS 10.0, *)
|
||||||
internal extension DrawingOperation {
|
internal extension DrawingOperation {
|
||||||
|
|
||||||
func imageFromNewRenderer(scale: CGFloat) -> UIImage {
|
func imageFromNewRenderer(scale: CGFloat) -> UIImage {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,283 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2017 Touch Instinct
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the Software), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
public extension Support where Base: UIImage {
|
||||||
|
|
||||||
|
/// Creates an image filled by given color.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - color: The color to fill
|
||||||
|
/// - size: The size of an new image.
|
||||||
|
/// - Returns: A new instanse of UIImage with given size and color or nil if something goes wrong.
|
||||||
|
static func imageWith(color: UIColor, size: CGSize) -> Support<UIImage>? {
|
||||||
|
let width = Int(ceil(size.width))
|
||||||
|
let height = Int(ceil(size.height))
|
||||||
|
|
||||||
|
let operation = SolidFillDrawingOperation(color: color.cgColor, width: width, height: height)
|
||||||
|
|
||||||
|
return operation.imageFromNewContext(scale: UIScreen.main.scale)?.support
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an image from a UIView.
|
||||||
|
///
|
||||||
|
/// - Parameter fromView: The source view.
|
||||||
|
/// - Returns: A new instance of UIImage or nil if something goes wrong.
|
||||||
|
static func imageFrom(view: UIView) -> Support<UIImage>? {
|
||||||
|
let operation = CALayerDrawingOperation(layer: view.layer, size: view.bounds.size)
|
||||||
|
|
||||||
|
guard let rotatedImage = operation.imageFromNewContext(scale: UIScreen.main.scale) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let flipOperation = rotatedImage.cgImage?.flipYOperation(size: rotatedImage.size)
|
||||||
|
|
||||||
|
return flipOperation?.imageFromNewContext(scale: rotatedImage.scale)?.support
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render current template UIImage into new image using given color.
|
||||||
|
///
|
||||||
|
/// - Parameter color: Color to fill template image.
|
||||||
|
/// - Returns: A new UIImage rendered with given color or nil if something goes wrong.
|
||||||
|
func renderTemplate(withColor color: UIColor) -> Support<UIImage>? {
|
||||||
|
return withCGImage { image in
|
||||||
|
let operation = TemplateDrawingOperation(image: image,
|
||||||
|
imageSize: base.size,
|
||||||
|
color: color.cgColor)
|
||||||
|
|
||||||
|
guard let templateImage = operation.imageFromNewContext(scale: base.scale) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let flipOperation = templateImage.cgImage?.flipYOperation(size: templateImage.size)
|
||||||
|
|
||||||
|
return flipOperation?.imageFromNewContext(scale: templateImage.scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new image with rounded corners and border.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - cornerRadius: The corner radius.
|
||||||
|
/// - borderWidth: The size of the border.
|
||||||
|
/// - color: The color of the border.
|
||||||
|
/// - extendSize: Extend result image size and don't overlap source image by border.
|
||||||
|
/// - Returns: A new image with rounded corners or nil if something goes wrong.
|
||||||
|
func roundCorners(cornerRadius: CGFloat,
|
||||||
|
borderWidth: CGFloat,
|
||||||
|
color: UIColor,
|
||||||
|
extendSize: Bool = false) -> Support<UIImage>? {
|
||||||
|
|
||||||
|
return withCGImage { image in
|
||||||
|
let roundOperation = RoundDrawingOperation(image: image,
|
||||||
|
imageSize: base.size,
|
||||||
|
radius: cornerRadius)
|
||||||
|
|
||||||
|
guard let roundImage = roundOperation.cgImageFromNewContext(scale: base.scale) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let borderOperation = BorderDrawingOperation(image: roundImage,
|
||||||
|
imageSize: base.size,
|
||||||
|
border: borderWidth,
|
||||||
|
color: color.cgColor,
|
||||||
|
radius: cornerRadius,
|
||||||
|
extendSize: extendSize)
|
||||||
|
|
||||||
|
return borderOperation.imageFromNewContext(scale: base.scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new circle image.
|
||||||
|
///
|
||||||
|
/// - Returns: A new circled image or nil if something goes wrong.
|
||||||
|
func roundCornersToCircle() -> Support<UIImage>? {
|
||||||
|
return withCGImage { image in
|
||||||
|
let radius = CGFloat(min(base.size.width, base.size.height) / 2)
|
||||||
|
|
||||||
|
let operation = RoundDrawingOperation(image: image,
|
||||||
|
imageSize: base.size,
|
||||||
|
radius: radius)
|
||||||
|
|
||||||
|
return operation.imageFromNewContext(scale: base.scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new circle image with a border.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - borderWidth: The size of the border.
|
||||||
|
/// - borderColor: The color of the border.
|
||||||
|
/// - extendSize: Extend result image size and don't overlap source image by border (default = false).
|
||||||
|
/// - Returns: A new image with rounded corners or nil if something goes wrong.
|
||||||
|
func roundCornersToCircle(borderWidth: CGFloat,
|
||||||
|
borderColor: UIColor,
|
||||||
|
extendSize: Bool = false) -> Support<UIImage>? {
|
||||||
|
|
||||||
|
return withCGImage { image in
|
||||||
|
let radius = CGFloat(min(base.size.width, base.size.height) / 2)
|
||||||
|
|
||||||
|
let roundOperation = RoundDrawingOperation(image: image,
|
||||||
|
imageSize: base.size,
|
||||||
|
radius: radius)
|
||||||
|
|
||||||
|
guard let roundImage = roundOperation.cgImageFromNewContext(scale: base.scale) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let borderOperation = BorderDrawingOperation(image: roundImage,
|
||||||
|
imageSize: base.size,
|
||||||
|
border: borderWidth,
|
||||||
|
color: borderColor.cgColor,
|
||||||
|
radius: radius,
|
||||||
|
extendSize: extendSize)
|
||||||
|
|
||||||
|
return borderOperation.imageFromNewContext(scale: base.scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a resized copy of an image.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - newSize: The new size of the image.
|
||||||
|
/// - contentMode: The way to handle the content in the new size.
|
||||||
|
/// - cropToImageBounds: Should output image size match resized image size.
|
||||||
|
/// Note: If passed true with ResizeMode.scaleAspectFit content mode it will give the original image.
|
||||||
|
/// - Returns: A new image scaled to new size.
|
||||||
|
func resize(newSize: CGSize,
|
||||||
|
contentMode: ResizeMode = .scaleToFill,
|
||||||
|
cropToImageBounds: Bool = false) -> Support<UIImage>? {
|
||||||
|
|
||||||
|
return withCGImage { image in
|
||||||
|
let operation = ResizeDrawingOperation(image: image,
|
||||||
|
imageSize: base.size,
|
||||||
|
preferredNewSize: newSize,
|
||||||
|
resizeMode: contentMode,
|
||||||
|
cropToImageBounds: cropToImageBounds)
|
||||||
|
|
||||||
|
return operation.imageFromNewContext(scale: base.scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds an alpha channel if UIImage doesn't already have one.
|
||||||
|
///
|
||||||
|
/// - Returns: A copy of the given image, adding an alpha channel if it doesn't already have one.
|
||||||
|
func applyAlpha() -> Support<UIImage>? {
|
||||||
|
return withCGImage { image in
|
||||||
|
let operation = ImageDrawingOperation(image: image,
|
||||||
|
newSize: base.size,
|
||||||
|
opaque: false)
|
||||||
|
|
||||||
|
return operation.imageFromNewContext(scale: base.scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a copy of the image with border of the given size added around its edges.
|
||||||
|
///
|
||||||
|
/// - Parameter padding: The padding amount.
|
||||||
|
/// - Returns: A new padded image or nil if something goes wrong.
|
||||||
|
func applyPadding(_ padding: CGFloat) -> Support<UIImage>? {
|
||||||
|
return withCGImage { image in
|
||||||
|
let operation = PaddingDrawingOperation(image: image,
|
||||||
|
imageSize: base.size,
|
||||||
|
padding: padding)
|
||||||
|
|
||||||
|
return operation.imageFromNewContext(scale: base.scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a copy of the image rotated by the given amount of degrees.
|
||||||
|
///
|
||||||
|
/// - Parameters:
|
||||||
|
/// - degrees: The number of degrees.
|
||||||
|
/// - clockwise: Should rotate image clockwise.
|
||||||
|
/// - Returns: A new rotated image or nil if something goes wrong.
|
||||||
|
func rotate(degrees: CGFloat, clockwise: Bool = true) -> Support<UIImage>? {
|
||||||
|
return withCGImage { image in
|
||||||
|
let radians = degrees.degreesToRadians()
|
||||||
|
|
||||||
|
let operation = RotateDrawingOperation(image: image,
|
||||||
|
imageSize: base.size,
|
||||||
|
radians: radians,
|
||||||
|
clockwise: clockwise)
|
||||||
|
|
||||||
|
guard let rotatedImage = operation.imageFromNewContext(scale: base.scale) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let flipOperation = rotatedImage.cgImage?.flipYOperation(size: rotatedImage.size)
|
||||||
|
|
||||||
|
return flipOperation?.imageFromNewContext(scale: rotatedImage.scale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func withCGImage(_ actionClosure: (CGImage) -> UIImage?) -> Support<UIImage>? {
|
||||||
|
guard let image = base.cgImage else {
|
||||||
|
return Support<UIImage>(base)
|
||||||
|
}
|
||||||
|
|
||||||
|
return actionClosure(image)?.support
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension CGImage {
|
||||||
|
|
||||||
|
func flipYOperation(size: CGSize) -> ImageDrawingOperation {
|
||||||
|
return ImageDrawingOperation(image: self,
|
||||||
|
newSize: size,
|
||||||
|
origin: .zero,
|
||||||
|
opaque: false,
|
||||||
|
flipY: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension DrawingOperation {
|
||||||
|
|
||||||
|
func cgImageFromNewContext(scale: CGFloat) -> CGImage? {
|
||||||
|
let ctxSize = contextSize
|
||||||
|
|
||||||
|
let intScale = Int(scale)
|
||||||
|
|
||||||
|
let context = CGContext.create(width: ctxSize.width * intScale,
|
||||||
|
height: ctxSize.height * intScale,
|
||||||
|
bitmapInfo: opaque ? .opaqueBitmapInfo : .alphaBitmapInfo)
|
||||||
|
|
||||||
|
guard let ctx = context else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.scaleBy(x: scale, y: scale)
|
||||||
|
|
||||||
|
apply(in: ctx)
|
||||||
|
|
||||||
|
return ctx.makeImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
func imageFromNewContext(scale: CGFloat) -> UIImage? {
|
||||||
|
guard let image = cgImageFromNewContext(scale: scale) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return UIImage(cgImage: image, scale: scale, orientation: .up)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ import RxSwift
|
||||||
public extension Error {
|
public extension Error {
|
||||||
|
|
||||||
var requestError: RequestError? {
|
var requestError: RequestError? {
|
||||||
self as? RequestError
|
return self as? RequestError
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Method that tries to serialize response from a mapping request error to a model
|
/// Method that tries to serialize response from a mapping request error to a model
|
||||||
|
|
@ -34,7 +34,7 @@ public extension Error {
|
||||||
/// - Returns: optional target object
|
/// - Returns: optional target object
|
||||||
/// - Throws: an error during decoding
|
/// - Throws: an error during decoding
|
||||||
func handleMappingError<T: Decodable>(with decoder: JSONDecoder = JSONDecoder()) throws -> T? {
|
func handleMappingError<T: Decodable>(with decoder: JSONDecoder = JSONDecoder()) throws -> T? {
|
||||||
guard let self = requestError, case .mapping(_, let response, _) = self else {
|
guard let self = requestError, case .mapping(_, let response) = self else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,8 +51,8 @@ public extension ObservableType {
|
||||||
/// - handler: closure that recieves serialized response
|
/// - handler: closure that recieves serialized response
|
||||||
/// - Returns: Observable on caller
|
/// - Returns: Observable on caller
|
||||||
func handleMappingError<T: Decodable>(with decoder: JSONDecoder = JSONDecoder(),
|
func handleMappingError<T: Decodable>(with decoder: JSONDecoder = JSONDecoder(),
|
||||||
handler: @escaping ParameterClosure<T>) -> Observable<Element> {
|
handler: @escaping ParameterClosure<T>) -> Observable<E> {
|
||||||
self.do(onError: { error in
|
return self.do(onError: { error in
|
||||||
guard let errorModel = try error.handleMappingError(with: decoder) as T? else {
|
guard let errorModel = try error.handleMappingError(with: decoder) as T? else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +72,7 @@ public extension PrimitiveSequence where Trait == SingleTrait {
|
||||||
/// - Returns: Single on caller
|
/// - Returns: Single on caller
|
||||||
func handleMappingError<T: Decodable>(with decoder: JSONDecoder = JSONDecoder(),
|
func handleMappingError<T: Decodable>(with decoder: JSONDecoder = JSONDecoder(),
|
||||||
handler: @escaping ParameterClosure<T>) -> PrimitiveSequence<Trait, Element> {
|
handler: @escaping ParameterClosure<T>) -> PrimitiveSequence<Trait, Element> {
|
||||||
self.do(onError: { error in
|
return self.do(onError: { error in
|
||||||
guard let errorModel = try error.handleMappingError(with: decoder) as T? else {
|
guard let errorModel = try error.handleMappingError(with: decoder) as T? else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +92,7 @@ public extension PrimitiveSequence where Trait == CompletableTrait, Element == N
|
||||||
/// - Returns: Completable
|
/// - Returns: Completable
|
||||||
func handleMappingError<T: Decodable>(with decoder: JSONDecoder = JSONDecoder(),
|
func handleMappingError<T: Decodable>(with decoder: JSONDecoder = JSONDecoder(),
|
||||||
handler: @escaping ParameterClosure<T>) -> Completable {
|
handler: @escaping ParameterClosure<T>) -> Completable {
|
||||||
self.do(onError: { error in
|
return self.do(onError: { error in
|
||||||
guard let errorModel = try error.handleMappingError(with: decoder) as T? else {
|
guard let errorModel = try error.handleMappingError(with: decoder) as T? else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,13 @@ public extension FloatingPoint {
|
||||||
///
|
///
|
||||||
/// - Returns: radians
|
/// - Returns: radians
|
||||||
func degreesToRadians() -> Self {
|
func degreesToRadians() -> Self {
|
||||||
self * .pi / 180
|
return self * .pi / 180
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts radians to degrees
|
/// Converts radians to degrees
|
||||||
///
|
///
|
||||||
/// - Returns: degrees
|
/// - Returns: degrees
|
||||||
func radiansToDegrees() -> Self {
|
func radiansToDegrees() -> Self {
|
||||||
self * 180 / .pi
|
return self * 180 / .pi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ public extension UserDefaults {
|
||||||
/// - Returns: The object with specified type associated with the specified key, or passed default value
|
/// - Returns: The object with specified type associated with the specified key, or passed default value
|
||||||
/// if there is no such value for specified key or if error occurred during mapping.
|
/// if there is no such value for specified key or if error occurred during mapping.
|
||||||
func object<T: Decodable>(forKey key: String, defaultValue: T, decoder: JSONDecoder = JSONDecoder()) -> T {
|
func object<T: Decodable>(forKey key: String, defaultValue: T, decoder: JSONDecoder = JSONDecoder()) -> T {
|
||||||
(try? object(forKey: key, decoder: decoder)) ?? defaultValue
|
return (try? object(forKey: key, decoder: decoder)) ?? defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set or remove the value of the specified default key in the standard application domain.
|
/// Set or remove the value of the specified default key in the standard application domain.
|
||||||
|
|
@ -58,7 +58,7 @@ public extension UserDefaults {
|
||||||
|
|
||||||
subscript<T: Codable>(key: String) -> T? {
|
subscript<T: Codable>(key: String) -> T? {
|
||||||
get {
|
get {
|
||||||
try? object(forKey: key)
|
return try? object(forKey: key)
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
try? set(object: newValue, forKey: key)
|
try? set(object: newValue, forKey: key)
|
||||||
|
|
@ -75,7 +75,7 @@ public extension Reactive where Base: UserDefaults {
|
||||||
/// - decoder: JSON decoder to decode stored data.
|
/// - decoder: JSON decoder to decode stored data.
|
||||||
/// - Returns: Single of specified model type.
|
/// - Returns: Single of specified model type.
|
||||||
func object<T: Decodable>(forKey key: String, decoder: JSONDecoder = JSONDecoder()) -> Single<T> {
|
func object<T: Decodable>(forKey key: String, decoder: JSONDecoder = JSONDecoder()) -> Single<T> {
|
||||||
.deferredJust { try self.base.object(forKey: key, decoder: decoder) }
|
return .deferredJust { try self.base.object(forKey: key, decoder: decoder) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reactive version of object<T>(forKey:defaultValue:decoder:) -> T.
|
/// Reactive version of object<T>(forKey:defaultValue:decoder:) -> T.
|
||||||
|
|
@ -87,7 +87,7 @@ public extension Reactive where Base: UserDefaults {
|
||||||
/// - decoder: JSON decoder to decode stored data.
|
/// - decoder: JSON decoder to decode stored data.
|
||||||
/// - Returns: Single of specified model type.
|
/// - Returns: Single of specified model type.
|
||||||
func object<T: Decodable>(forKey key: String, defaultValue: T, decoder: JSONDecoder = JSONDecoder()) -> Single<T> {
|
func object<T: Decodable>(forKey key: String, defaultValue: T, decoder: JSONDecoder = JSONDecoder()) -> Single<T> {
|
||||||
.deferredJust { self.base.object(forKey: key, defaultValue: defaultValue, decoder: decoder) }
|
return .deferredJust { self.base.object(forKey: key, defaultValue: defaultValue, decoder: decoder) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reactive version of set<T>(object:forKey:encoder:).
|
/// Reactive version of set<T>(object:forKey:encoder:).
|
||||||
|
|
@ -98,7 +98,7 @@ public extension Reactive where Base: UserDefaults {
|
||||||
/// - encoder: JSON encoder to encode to encode passed object.
|
/// - encoder: JSON encoder to encode to encode passed object.
|
||||||
/// - Returns: Completable.
|
/// - Returns: Completable.
|
||||||
func set<T: Encodable>(object: T?, forKey key: String, encoder: JSONEncoder = JSONEncoder()) -> Completable {
|
func set<T: Encodable>(object: T?, forKey key: String, encoder: JSONEncoder = JSONEncoder()) -> Completable {
|
||||||
.deferredJust {
|
return .deferredJust {
|
||||||
try self.base.set(object: object, forKey: key, encoder: encoder)
|
try self.base.set(object: object, forKey: key, encoder: encoder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ public extension NSAttributedString {
|
||||||
|
|
||||||
/// Mutable copy of attributed string.
|
/// Mutable copy of attributed string.
|
||||||
var mutable: NSMutableAttributedString {
|
var mutable: NSMutableAttributedString {
|
||||||
NSMutableAttributedString(attributedString: self)
|
return NSMutableAttributedString(attributedString: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,6 +51,6 @@ public extension NSMutableAttributedString {
|
||||||
|
|
||||||
/// Immutable copy of attributed string.
|
/// Immutable copy of attributed string.
|
||||||
var immutable: NSAttributedString {
|
var immutable: NSAttributedString {
|
||||||
NSAttributedString(attributedString: self)
|
return NSAttributedString(attributedString: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,41 +25,41 @@ import Foundation
|
||||||
extension NSNumber: NSNumberConvertible {
|
extension NSNumber: NSNumberConvertible {
|
||||||
|
|
||||||
public func asNSNumber() -> NSNumber {
|
public func asNSNumber() -> NSNumber {
|
||||||
self
|
return self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Decimal: NSNumberConvertible {
|
extension Decimal: NSNumberConvertible {
|
||||||
|
|
||||||
public func asNSNumber() -> NSNumber {
|
public func asNSNumber() -> NSNumber {
|
||||||
NSDecimalNumber(decimal: self)
|
return NSDecimalNumber(decimal: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Int: NSNumberConvertible {
|
extension Int: NSNumberConvertible {
|
||||||
|
|
||||||
public func asNSNumber() -> NSNumber {
|
public func asNSNumber() -> NSNumber {
|
||||||
NSNumber(value: self)
|
return NSNumber(value: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Int64: NSNumberConvertible {
|
extension Int64: NSNumberConvertible {
|
||||||
|
|
||||||
public func asNSNumber() -> NSNumber {
|
public func asNSNumber() -> NSNumber {
|
||||||
NSNumber(value: self)
|
return NSNumber(value: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Double: NSNumberConvertible {
|
extension Double: NSNumberConvertible {
|
||||||
|
|
||||||
public func asNSNumber() -> NSNumber {
|
public func asNSNumber() -> NSNumber {
|
||||||
NSNumber(value: self)
|
return NSNumber(value: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Float: NSNumberConvertible {
|
extension Float: NSNumberConvertible {
|
||||||
|
|
||||||
public func asNSNumber() -> NSNumber {
|
public func asNSNumber() -> NSNumber {
|
||||||
NSNumber(value: self)
|
return NSNumber(value: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ public extension NumberFormattingService {
|
||||||
|
|
||||||
/// Computed static property. Use only once for `formatters` field implementation!
|
/// Computed static property. Use only once for `formatters` field implementation!
|
||||||
static var computedFormatters: [NumberFormatType: NumberFormatter] {
|
static var computedFormatters: [NumberFormatType: NumberFormatter] {
|
||||||
Dictionary(uniqueKeysWithValues: NumberFormatType.allCases.map { ($0, $0.numberFormatter) })
|
return Dictionary(uniqueKeysWithValues: NumberFormatType.allCases.map { ($0, $0.numberFormatter) })
|
||||||
}
|
}
|
||||||
|
|
||||||
func numberFormatter(for format: NumberFormatType) -> NumberFormatter {
|
func numberFormatter(for format: NumberFormatType) -> NumberFormatter {
|
||||||
|
|
@ -38,21 +38,21 @@ public extension NumberFormattingService {
|
||||||
}
|
}
|
||||||
|
|
||||||
func string(from number: NSNumberConvertible, format: NumberFormatType, defaultString: String = "") -> String {
|
func string(from number: NSNumberConvertible, format: NumberFormatType, defaultString: String = "") -> String {
|
||||||
numberFormatter(for: format).string(from: number.asNSNumber()) ?? defaultString
|
return numberFormatter(for: format).string(from: number.asNSNumber()) ?? defaultString
|
||||||
}
|
}
|
||||||
|
|
||||||
func number(from string: String, format: NumberFormatType) -> NSNumber? {
|
func number(from string: String, format: NumberFormatType) -> NSNumber? {
|
||||||
numberFormatter(for: format).number(from: string)
|
return numberFormatter(for: format).number(from: string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension NumberFormattingService where Self: Singleton {
|
public extension NumberFormattingService where Self: Singleton {
|
||||||
|
|
||||||
static func string(from number: NSNumberConvertible, format: NumberFormatType, defaultString: String = "") -> String {
|
static func string(from number: NSNumberConvertible, format: NumberFormatType, defaultString: String = "") -> String {
|
||||||
shared.string(from: number, format: format, defaultString: defaultString)
|
return shared.string(from: number, format: format, defaultString: defaultString)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func number(from string: String, format: NumberFormatType) -> NSNumber? {
|
static func number(from string: String, format: NumberFormatType) -> NSNumber? {
|
||||||
shared.number(from: string, format: format)
|
return shared.number(from: string, format: format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ public extension ObservableType {
|
||||||
/// - Parameter elementFactory: Element factory function to invoke for each observer
|
/// - Parameter elementFactory: Element factory function to invoke for each observer
|
||||||
/// that subscribes to the resulting sequence.
|
/// that subscribes to the resulting sequence.
|
||||||
/// - Returns: An observable sequence whose observers trigger an invocation of the given element factory function.
|
/// - Returns: An observable sequence whose observers trigger an invocation of the given element factory function.
|
||||||
static func deferredJust(_ elementFactory: @escaping () throws -> Element) -> Observable<Element> {
|
static func deferredJust(_ elementFactory: @escaping () throws -> E) -> Observable<E> {
|
||||||
.create { observer in
|
return .create { observer in
|
||||||
do {
|
do {
|
||||||
observer.onNext(try elementFactory())
|
observer.onNext(try elementFactory())
|
||||||
observer.onCompleted()
|
observer.onCompleted()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2022 Touch Instinct
|
// Copyright (c) 2019 Touch Instinct
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
@ -20,21 +20,20 @@
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import RxSwift
|
||||||
|
|
||||||
/// Protocol which ensures that specific type can return string reuse identifier for view
|
public extension Observable {
|
||||||
public protocol ReuseIdentifierProtocol {
|
|
||||||
static var reuseIdentifier: String { get }
|
|
||||||
}
|
|
||||||
|
|
||||||
extension UICollectionViewCell: ReuseIdentifierProtocol {
|
/// Method that handles error with given type
|
||||||
public static var reuseIdentifier: String {
|
///
|
||||||
.init(describing: Self.self)
|
/// - Parameters:
|
||||||
}
|
/// - type: network error handling type
|
||||||
}
|
/// - handler: handler for alert type
|
||||||
|
/// - Returns: Observable on caller
|
||||||
extension UITableViewCell: ReuseIdentifierProtocol {
|
func handleNetworkError<Handler: NetworkErrorHandler>(type: NetworkErrorHandlingType<Handler>,
|
||||||
public static var reuseIdentifier: String {
|
handler: Handler? = nil) -> Observable<Element> {
|
||||||
.init(describing: Self.self)
|
return self.do(onError: { [weak handler] error in
|
||||||
|
type.handle(error: error, with: handler)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue