Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
SSD_Swift_ServicesPackage
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Safina Elmira
SSD_Swift_ServicesPackage
Commits
173dbbb3
Commit
173dbbb3
authored
Feb 21, 2023
by
Eli Safina
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial commit
parents
Pipeline
#3766
failed with stages
in 2 seconds
Changes
17
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
900 additions
and
0 deletions
+900
-0
.gitignore
.gitignore
+9
-0
IDEWorkspaceChecks.plist
...package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+8
-0
Package.swift
Package.swift
+28
-0
README.md
README.md
+3
-0
Array+Extensions.swift
...D_Swift_ServicesPackage/extensions/Array+Extensions.swift
+23
-0
Bundle+Extension.swift
...D_Swift_ServicesPackage/extensions/Bundle+Extension.swift
+24
-0
Color+Extension.swift
...SD_Swift_ServicesPackage/extensions/Color+Extension.swift
+44
-0
Date+Extension.swift
...SSD_Swift_ServicesPackage/extensions/Date+Extension.swift
+55
-0
Dictionary+Extension.swift
...ift_ServicesPackage/extensions/Dictionary+Extension.swift
+22
-0
Int+Extensions.swift
...SSD_Swift_ServicesPackage/extensions/Int+Extensions.swift
+20
-0
Numeric+Extensions.swift
...Swift_ServicesPackage/extensions/Numeric+Extensions.swift
+90
-0
String+Extension.swift
...D_Swift_ServicesPackage/extensions/String+Extension.swift
+77
-0
UIDevice+Extensions.swift
...wift_ServicesPackage/extensions/UIDevice+Extensions.swift
+109
-0
StringFormatter.swift
...SSD_Swift_ServicesPackage/formators/StringFormatter.swift
+105
-0
TextFieldFormatter.swift
..._Swift_ServicesPackage/formators/TextFieldFormatter.swift
+69
-0
Validators.swift
...ces/SSD_Swift_ServicesPackage/validators/Validators.swift
+89
-0
SSD_Swift_ServicesPackageTests.swift
...ServicesPackageTests/SSD_Swift_ServicesPackageTests.swift
+125
-0
No files found.
.gitignore
0 → 100644
View file @
173dbbb3
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
0 → 100644
View file @
173dbbb3
<
?xml
v
e
rsion="
1
.
0
"
e
n
c
o
d
ing="UT
F
-
8
"?
>
<
!
D
O
C
TYP
E
plist
PU
B
LI
C
"-//
A
ppl
e
//
D
T
D
PLIST
1
.
0
//
E
N"
"http://www.
a
ppl
e
.
c
om/
D
T
D
s/Prop
e
rtyList-
1
.
0
.
d
t
d
"
>
<
plist
v
e
rsion="
1
.
0
"
>
<
d
i
c
t
>
<
k
e
y
>
IDEDidComputeMac32BitWarning
<
/k
e
y
>
<
tru
e
/
>
<
/
d
i
c
t
>
<
/plist
>
Package.swift
0 → 100644
View file @
173dbbb3
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.
import
PackageDescription
let
package
=
Package
(
name
:
"SSD_Swift_ServicesPackage"
,
products
:
[
// Products define the executables and libraries a package produces, and make them visible to other packages.
.
library
(
name
:
"SSD_Swift_ServicesPackage"
,
targets
:
[
"SSD_Swift_ServicesPackage"
]),
],
dependencies
:
[
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets
:
[
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.
target
(
name
:
"SSD_Swift_ServicesPackage"
,
dependencies
:
[]),
.
testTarget
(
name
:
"SSD_Swift_ServicesPackageTests"
,
dependencies
:
[
"SSD_Swift_ServicesPackage"
]),
]
)
README.md
0 → 100644
View file @
173dbbb3
# SSD_Swift_ServicesPackage
A description of this package.
Sources/SSD_Swift_ServicesPackage/extensions/Array+Extensions.swift
0 → 100644
View file @
173dbbb3
//
// Array+Extensions.swift
// QIWI
//
// Created by Ilkhom on 31/03/22.
//
import
Foundation
extension
Array
where
Element
==
String
{
static
func
ofUZBmonths
()
->
[
String
]
{
[
"January"
,
"February"
,
"March"
,
"April"
,
"May"
,
"June"
,
"July"
,
"August"
,
"September"
,
"October"
,
"November"
,
"December"
]
}
static
func
ofENGmonths
()
->
[
String
]
{
[
"January"
,
"February"
,
"March"
,
"April"
,
"May"
,
"June"
,
"July"
,
"August"
,
"September"
,
"October"
,
"November"
,
"December"
]
}
static
func
ofRUSmonths
()
->
[
String
]
{
[
"Январь"
,
"Февраль"
,
"Март"
,
"Апрель"
,
"Май"
,
"Июнь"
,
"Июль"
,
"Август"
,
"Сентябрь"
,
"Октябрь"
,
"Ноябрь"
,
"Декабрь"
]
}
}
Sources/SSD_Swift_ServicesPackage/extensions/Bundle+Extension.swift
0 → 100644
View file @
173dbbb3
//
// Bundle+Extension.swift
// QIWI
//
// Created by Ilkhom on 13/06/22.
//
import
Foundation
extension
Bundle
{
public
var
appName
:
String
{
getInfo
(
"CFBundleName"
)
}
public
var
displayName
:
String
{
getInfo
(
"CFBundleDisplayName"
)}
public
var
language
:
String
{
getInfo
(
"CFBundleDevelopmentRegion"
)}
public
var
identifier
:
String
{
getInfo
(
"CFBundleIdentifier"
)}
public
var
copyright
:
String
{
getInfo
(
"NSHumanReadableCopyright"
)
.
replacingOccurrences
(
of
:
"
\\\\
n"
,
with
:
"
\n
"
)
}
public
var
appBuild
:
String
{
getInfo
(
"CFBundleVersion"
)
}
public
var
appVersionLong
:
String
{
getInfo
(
"CFBundleShortVersionString"
)
}
//public var appVersionShort: String { getInfo("CFBundleShortVersion") }
fileprivate
func
getInfo
(
_
str
:
String
)
->
String
{
infoDictionary
?[
str
]
as?
String
??
"⚠️"
}
}
Sources/SSD_Swift_ServicesPackage/extensions/Color+Extension.swift
0 → 100644
View file @
173dbbb3
//
// Color+Extension.swift
//
//
// Created by Ilkhom on 01/03/22.
//
#if os(iOS)
import
SwiftUI
extension
Color
{
init
(
hex
:
String
)
{
let
hex
=
hex
.
trimmingCharacters
(
in
:
CharacterSet
.
alphanumerics
.
inverted
)
var
int
:
UInt64
=
0
Scanner
(
string
:
hex
)
.
scanHexInt64
(
&
int
)
let
a
,
r
,
g
,
b
:
UInt64
switch
hex
.
count
{
case
3
:
// RGB (12-bit)
(
a
,
r
,
g
,
b
)
=
(
255
,
(
int
>>
8
)
*
17
,
(
int
>>
4
&
0xF
)
*
17
,
(
int
&
0xF
)
*
17
)
case
6
:
// RGB (24-bit)
(
a
,
r
,
g
,
b
)
=
(
255
,
int
>>
16
,
int
>>
8
&
0xFF
,
int
&
0xFF
)
case
8
:
// ARGB (32-bit)
(
a
,
r
,
g
,
b
)
=
(
int
>>
24
,
int
>>
16
&
0xFF
,
int
>>
8
&
0xFF
,
int
&
0xFF
)
default
:
(
a
,
r
,
g
,
b
)
=
(
1
,
1
,
1
,
0
)
}
self
.
init
(
.
sRGB
,
red
:
Double
(
r
)
/
255
,
green
:
Double
(
g
)
/
255
,
blue
:
Double
(
b
)
/
255
,
opacity
:
Double
(
a
)
/
255
)
}
}
extension
Color
{
var
uiColor
:
UIColor
{
return
UIColor
(
cgColor
:
self
.
cgColor
!
)
}
}
#endif
Sources/SSD_Swift_ServicesPackage/extensions/Date+Extension.swift
0 → 100644
View file @
173dbbb3
//
// Date+Extension.swift
// QIWI
//
// Created by Ilkhom on 04/03/22.
//
import
Foundation
extension
Date
{
func
getDateComponent
(
_
components
:
Calendar
.
Component
...
,
calendar
:
Calendar
=
Calendar
.
current
)
->
DateComponents
{
return
calendar
.
dateComponents
(
Set
(
components
),
from
:
self
)
}
func
getDateComponent
(
_
component
:
Calendar
.
Component
,
calendar
:
Calendar
=
Calendar
.
current
)
->
Int
{
return
calendar
.
component
(
component
,
from
:
self
)
}
func
startOfMonth
()
->
Date
{
return
Calendar
.
current
.
date
(
from
:
Calendar
.
current
.
dateComponents
([
.
year
,
.
month
],
from
:
Calendar
.
current
.
startOfDay
(
for
:
self
)))
!
}
func
endOfMonth
()
->
Date
{
return
Calendar
.
current
.
date
(
byAdding
:
DateComponents
(
month
:
1
,
day
:
-
1
),
to
:
self
.
startOfMonth
())
!
}
func
isInPastWeek
()
->
Bool
{
let
week
=
Calendar
(
identifier
:
.
gregorian
)
.
date
(
byAdding
:
.
day
,
value
:
-
7
,
to
:
Date
())
??
Date
()
return
(
week
...
Date
())
.
contains
(
self
)
}
func
isInPastMonth
()
->
Bool
{
let
month
=
Calendar
(
identifier
:
.
gregorian
)
.
date
(
byAdding
:
.
month
,
value
:
-
1
,
to
:
Date
())
??
Date
()
return
(
month
...
Date
())
.
contains
(
self
)
}
func
convertToLocalTime
(
fromTimeZone
timeZoneAbbreviation
:
String
)
->
Date
?
{
if
let
timeZone
=
TimeZone
(
abbreviation
:
timeZoneAbbreviation
)
{
let
targetOffset
=
TimeInterval
(
timeZone
.
secondsFromGMT
(
for
:
self
))
let
localOffeset
=
TimeInterval
(
TimeZone
.
autoupdatingCurrent
.
secondsFromGMT
(
for
:
self
))
return
self
.
addingTimeInterval
(
targetOffset
-
localOffeset
)
}
return
nil
}
func
toString
(
format
:
String
,
timeZone
:
String
?
=
"GMT"
)
->
String
{
let
formatter
=
DateFormatter
()
formatter
.
timeZone
=
TimeZone
(
identifier
:
timeZone
??
"GMT"
)
formatter
.
dateFormat
=
format
return
formatter
.
string
(
from
:
self
)
}
}
Sources/SSD_Swift_ServicesPackage/extensions/Dictionary+Extension.swift
0 → 100644
View file @
173dbbb3
//
// Dictionary+Extension.swift
// QIWI
//
// Created by Ilkhom on 02/03/22.
//
import
Foundation
extension
Dictionary
{
func
asData
()
->
Data
{
do
{
let
data
=
try
JSONSerialization
.
data
(
withJSONObject
:
self
,
options
:
.
fragmentsAllowed
)
return
data
}
catch
let
error
{
print
(
error
.
localizedDescription
)
}
return
Data
()
}
}
Sources/SSD_Swift_ServicesPackage/extensions/Int+Extensions.swift
0 → 100644
View file @
173dbbb3
//
// Int+Extensions.swift
// QIWI
//
// Created by admin on 16.08.2022.
//
import
Foundation
extension
Int
{
func
fromTimeIntervalToDateString
(
format
:
String
)
->
String
{
let
timeInterval
=
TimeInterval
(
self
)
let
date
=
Date
(
timeIntervalSince1970
:
timeInterval
)
let
formatter
=
DateFormatter
()
formatter
.
dateFormat
=
format
return
formatter
.
string
(
from
:
date
)
}
}
Sources/SSD_Swift_ServicesPackage/extensions/Numeric+Extensions.swift
0 → 100644
View file @
173dbbb3
//
// Numeric+Extensions.swift
// QIWI
//
// Created by Ilkhom on 05/04/22.
//
#if os(iOS)
import
UIKit
//MARK: - Part below converts 1000000 -> 1 000 000
extension
Formatter
{
static
let
withSeparator
:
NumberFormatter
=
{
let
formatter
=
NumberFormatter
()
formatter
.
numberStyle
=
.
decimal
formatter
.
groupingSeparator
=
" "
return
formatter
}()
}
extension
Numeric
{
var
separated
:
String
{
Formatter
.
withSeparator
.
string
(
for
:
self
)
??
""
}
}
//MARK: - Dynamic Fonts Sizes
fileprivate
let
baseDeviceHeight
:
CGFloat
=
UIScreen
.
main
.
bounds
.
height
fileprivate
let
baseDeviceWidth
:
CGFloat
=
UIScreen
.
main
.
bounds
.
width
public
extension
CGFloat
{
var
dfs
:
CGFloat
{
return
CGFloat
.
getDynamicFontSize
(
size
:
self
)
}
var
dvs
:
CGFloat
{
return
CGFloat
.
getDynamicVerticalSize
(
size
:
self
)
}
var
dhs
:
CGFloat
{
return
CGFloat
.
getDynamicHorizontalSize
(
size
:
self
)
}
// Minimum visible font size is 11
fileprivate
static
func
getDynamicFontSize
(
size
:
CGFloat
)
->
CGFloat
{
return
(
CGFloat
.
maximum
(
11
,
size
*
UIScreen
.
main
.
bounds
.
height
/
baseDeviceHeight
))
}
fileprivate
static
func
getDynamicVerticalSize
(
size
:
CGFloat
)
->
CGFloat
{
return
(
size
*
UIScreen
.
main
.
bounds
.
height
/
baseDeviceHeight
)
}
fileprivate
static
func
getDynamicHorizontalSize
(
size
:
CGFloat
)
->
CGFloat
{
return
(
size
*
UIScreen
.
main
.
bounds
.
width
/
baseDeviceWidth
)
}
}
public
extension
Int
{
var
dfs
:
CGFloat
{
return
CGFloat
.
getDynamicFontSize
(
size
:
CGFloat
(
self
))
}
var
dvs
:
CGFloat
{
return
CGFloat
.
getDynamicVerticalSize
(
size
:
CGFloat
(
self
))
}
var
dhs
:
CGFloat
{
return
CGFloat
.
getDynamicHorizontalSize
(
size
:
CGFloat
(
self
))
}
}
public
extension
Double
{
var
dfs
:
CGFloat
{
return
CGFloat
.
getDynamicFontSize
(
size
:
CGFloat
(
self
))
}
var
dvs
:
CGFloat
{
return
CGFloat
.
getDynamicVerticalSize
(
size
:
CGFloat
(
self
))
}
var
dhs
:
CGFloat
{
return
CGFloat
.
getDynamicHorizontalSize
(
size
:
CGFloat
(
self
))
}
}
#endif
Sources/SSD_Swift_ServicesPackage/extensions/String+Extension.swift
0 → 100644
View file @
173dbbb3
//
// String+Extension.swift
// test
//
// Created by Ilkhom on 01/03/22.
//
import
Foundation
public
extension
String
{
var
alphabetic
:
String
{
components
(
separatedBy
:
CharacterSet
.
decimalDigits
)
.
joined
()
}
var
alphanumeric
:
String
{
components
(
separatedBy
:
CharacterSet
.
alphanumerics
.
inverted
)
.
joined
()
}
var
digits
:
String
{
components
(
separatedBy
:
CharacterSet
.
decimalDigits
.
inverted
)
.
joined
()
}
var
trimmed
:
String
{
self
.
trimmingCharacters
(
in
:
.
whitespacesAndNewlines
)
}
}
//MARK: - DATEs
extension
String
{
func
toDate
(
format
:
String
,
locale
:
String
=
"en_US"
,
timeZone
:
String
=
"GMT"
)
->
Date
{
let
formatter
=
DateFormatter
()
formatter
.
locale
=
Locale
(
identifier
:
locale
)
formatter
.
timeZone
=
TimeZone
(
identifier
:
timeZone
)
formatter
.
dateFormat
=
format
let
date
=
(
formatter
.
date
(
from
:
self
)
??
Date
())
.
convertToLocalTime
(
fromTimeZone
:
timeZone
)
return
date
??
Date
()
}
func
convertDate
(
_
fromFormat
:
String
,
to
format
:
String
)
->
String
{
let
date
=
self
.
toDate
(
format
:
fromFormat
)
let
dateFormatter
=
DateFormatter
()
dateFormatter
.
dateFormat
=
format
return
dateFormatter
.
string
(
from
:
date
)
}
}
//MARK: - URL encoding String it contains nonlatin letters
extension
String
{
var
encodeUrl
:
String
{
return
self
.
addingPercentEncoding
(
withAllowedCharacters
:
NSCharacterSet
.
urlQueryAllowed
)
!
}
var
decodeUrl
:
String
{
return
self
.
removingPercentEncoding
!
}
}
//MARK: - encoding if String contains emojis
extension
String
{
var
encode
:
String
{
let
data
=
self
.
data
(
using
:
.
nonLossyASCII
,
allowLossyConversion
:
true
)
??
Data
()
return
String
(
data
:
data
,
encoding
:
.
utf8
)
??
""
}
var
decode
:
String
{
let
data
=
self
.
data
(
using
:
.
utf8
)
??
Data
()
return
String
(
data
:
data
,
encoding
:
.
nonLossyASCII
)
??
""
}
}
Sources/SSD_Swift_ServicesPackage/extensions/UIDevice+Extensions.swift
0 → 100644
View file @
173dbbb3
//
// UIDevice+Extensions.swift
// QIWI
//
// Created by admin on 17.08.2022.
//
#if os(iOS)
import
UIKit
public
extension
UIDevice
{
static
let
modelName
:
String
=
{
var
systemInfo
=
utsname
()
uname
(
&
systemInfo
)
let
machineMirror
=
Mirror
(
reflecting
:
systemInfo
.
machine
)
let
identifier
=
machineMirror
.
children
.
reduce
(
""
)
{
identifier
,
element
in
guard
let
value
=
element
.
value
as?
Int8
,
value
!=
0
else
{
return
identifier
}
return
identifier
+
String
(
UnicodeScalar
(
UInt8
(
value
)))
}
func
mapToDevice
(
identifier
:
String
)
->
String
{
// swiftlint:disable:this cyclomatic_complexity
#if os(iOS)
switch
identifier
{
case
"iPod5,1"
:
return
"iPod touch (5th generation)"
case
"iPod7,1"
:
return
"iPod touch (6th generation)"
case
"iPod9,1"
:
return
"iPod touch (7th generation)"
case
"iPhone3,1"
,
"iPhone3,2"
,
"iPhone3,3"
:
return
"iPhone 4"
case
"iPhone4,1"
:
return
"iPhone 4s"
case
"iPhone5,1"
,
"iPhone5,2"
:
return
"iPhone 5"
case
"iPhone5,3"
,
"iPhone5,4"
:
return
"iPhone 5c"
case
"iPhone6,1"
,
"iPhone6,2"
:
return
"iPhone 5s"
case
"iPhone7,2"
:
return
"iPhone 6"
case
"iPhone7,1"
:
return
"iPhone 6 Plus"
case
"iPhone8,1"
:
return
"iPhone 6s"
case
"iPhone8,2"
:
return
"iPhone 6s Plus"
case
"iPhone8,4"
:
return
"iPhone SE"
case
"iPhone9,1"
,
"iPhone9,3"
:
return
"iPhone 7"
case
"iPhone9,2"
,
"iPhone9,4"
:
return
"iPhone 7 Plus"
case
"iPhone10,1"
,
"iPhone10,4"
:
return
"iPhone 8"
case
"iPhone10,2"
,
"iPhone10,5"
:
return
"iPhone 8 Plus"
case
"iPhone10,3"
,
"iPhone10,6"
:
return
"iPhone X"
case
"iPhone11,2"
:
return
"iPhone XS"
case
"iPhone11,4"
,
"iPhone11,6"
:
return
"iPhone XS Max"
case
"iPhone11,8"
:
return
"iPhone XR"
case
"iPhone12,1"
:
return
"iPhone 11"
case
"iPhone12,3"
:
return
"iPhone 11 Pro"
case
"iPhone12,5"
:
return
"iPhone 11 Pro Max"
case
"iPhone12,8"
:
return
"iPhone SE (2nd generation)"
case
"iPhone13,1"
:
return
"iPhone 12 mini"
case
"iPhone13,2"
:
return
"iPhone 12"
case
"iPhone13,3"
:
return
"iPhone 12 Pro"
case
"iPhone13,4"
:
return
"iPhone 12 Pro Max"
case
"iPhone14,4"
:
return
"iPhone 13 mini"
case
"iPhone14,5"
:
return
"iPhone 13"
case
"iPhone14,2"
:
return
"iPhone 13 Pro"
case
"iPhone14,3"
:
return
"iPhone 13 Pro Max"
case
"iPad2,1"
,
"iPad2,2"
,
"iPad2,3"
,
"iPad2,4"
:
return
"iPad 2"
case
"iPad3,1"
,
"iPad3,2"
,
"iPad3,3"
:
return
"iPad (3rd generation)"
case
"iPad3,4"
,
"iPad3,5"
,
"iPad3,6"
:
return
"iPad (4th generation)"
case
"iPad6,11"
,
"iPad6,12"
:
return
"iPad (5th generation)"
case
"iPad7,5"
,
"iPad7,6"
:
return
"iPad (6th generation)"
case
"iPad7,11"
,
"iPad7,12"
:
return
"iPad (7th generation)"
case
"iPad11,6"
,
"iPad11,7"
:
return
"iPad (8th generation)"
case
"iPad12,1"
,
"iPad12,2"
:
return
"iPad (9th generation)"
case
"iPad4,1"
,
"iPad4,2"
,
"iPad4,3"
:
return
"iPad Air"
case
"iPad5,3"
,
"iPad5,4"
:
return
"iPad Air 2"
case
"iPad11,3"
,
"iPad11,4"
:
return
"iPad Air (3rd generation)"
case
"iPad13,1"
,
"iPad13,2"
:
return
"iPad Air (4th generation)"
case
"iPad2,5"
,
"iPad2,6"
,
"iPad2,7"
:
return
"iPad mini"
case
"iPad4,4"
,
"iPad4,5"
,
"iPad4,6"
:
return
"iPad mini 2"
case
"iPad4,7"
,
"iPad4,8"
,
"iPad4,9"
:
return
"iPad mini 3"
case
"iPad5,1"
,
"iPad5,2"
:
return
"iPad mini 4"
case
"iPad11,1"
,
"iPad11,2"
:
return
"iPad mini (5th generation)"
case
"iPad14,1"
,
"iPad14,2"
:
return
"iPad mini (6th generation)"
case
"iPad6,3"
,
"iPad6,4"
:
return
"iPad Pro (9.7-inch)"
case
"iPad7,3"
,
"iPad7,4"
:
return
"iPad Pro (10.5-inch)"
case
"iPad8,1"
,
"iPad8,2"
,
"iPad8,3"
,
"iPad8,4"
:
return
"iPad Pro (11-inch) (1st generation)"
case
"iPad8,9"
,
"iPad8,10"
:
return
"iPad Pro (11-inch) (2nd generation)"
case
"iPad13,4"
,
"iPad13,5"
,
"iPad13,6"
,
"iPad13,7"
:
return
"iPad Pro (11-inch) (3rd generation)"
case
"iPad6,7"
,
"iPad6,8"
:
return
"iPad Pro (12.9-inch) (1st generation)"
case
"iPad7,1"
,
"iPad7,2"
:
return
"iPad Pro (12.9-inch) (2nd generation)"
case
"iPad8,5"
,
"iPad8,6"
,
"iPad8,7"
,
"iPad8,8"
:
return
"iPad Pro (12.9-inch) (3rd generation)"
case
"iPad8,11"
,
"iPad8,12"
:
return
"iPad Pro (12.9-inch) (4th generation)"
case
"iPad13,8"
,
"iPad13,9"
,
"iPad13,10"
,
"iPad13,11"
:
return
"iPad Pro (12.9-inch) (5th generation)"
case
"AppleTV5,3"
:
return
"Apple TV"
case
"AppleTV6,2"
:
return
"Apple TV 4K"
case
"AudioAccessory1,1"
:
return
"HomePod"
case
"AudioAccessory5,1"
:
return
"HomePod mini"
case
"i386"
,
"x86_64"
,
"arm64"
:
return
"Simulator
\(
mapToDevice
(
identifier
:
ProcessInfo
()
.
environment
[
"SIMULATOR_MODEL_IDENTIFIER"
]
??
"iOS"
)
)
"
default
:
return
identifier
}
#elseif os(tvOS)
switch
identifier
{
case
"AppleTV5,3"
:
return
"Apple TV 4"
case
"AppleTV6,2"
:
return
"Apple TV 4K"
case
"i386"
,
"x86_64"
:
return
"Simulator
\(
mapToDevice
(
identifier
:
ProcessInfo
()
.
environment
[
"SIMULATOR_MODEL_IDENTIFIER"
]
??
"tvOS"
)
)
"
default
:
return
identifier
}
#endif
}
return
mapToDevice
(
identifier
:
identifier
)
}()
}
#endif
Sources/SSD_Swift_ServicesPackage/formators/StringFormatter.swift
0 → 100644
View file @
173dbbb3
//
// StringFormatter.swift
// QIWI
//
// Created by Ilkhom on 15/03/22.
//
import
Foundation
extension
String
{
func
toTiins
()
->
Int
{
self
.
toInt
()
*
100
}
func
toInt
()
->
Int
{
return
(
self
.
noSpaces
()
as
NSString
)
.
integerValue
}
func
toDouble
()
->
Double
{
return
(
self
.
noSpaces
()
.
replacingOccurrences
(
of
:
","
,
with
:
"."
)
as
NSString
)
.
doubleValue
}
func
noSpaces
()
->
String
{
self
.
replacingOccurrences
(
of
:
" "
,
with
:
""
)
}
}
//MARK: - PHONE
extension
String
{
func
addUzbekPrefixIfNeeded
()
->
String
{
let
digits
=
self
.
digits
if
digits
.
count
==
9
{
return
"998"
+
digits
}
return
digits
}
func
removeUzbekPrefixIfNeeded
()
->
String
{
let
digits
=
self
.
digits
if
digits
.
count
==
12
{
return
String
(
digits
.
dropFirst
(
3
))
}
return
digits
}
var
isUzPhoneNumber
:
Bool
{
self
.
digits
.
count
==
9
||
self
.
digits
.
count
==
12
&&
self
.
starts
(
with
:
"998"
)
}
var
isRuPhoneNumber
:
Bool
{
self
.
digits
.
count
==
11
&&
self
.
digits
.
starts
(
with
:
"7"
)
}
func
asPhone
(
masks
:
[
String
])
->
String
{
let
formatter
=
TextFieldFormatter
()
return
formatter
.
formatString
(
ofNumbers
:
self
,
withMasks
:
masks
)
}
}
//MARK: - CARD
extension
String
{
func
asCardNumber
()
->
String
{
self
.
replacingOccurrences
(
of
:
"(
\\
d{4})(
\\
d{4})(
\\
d{4})(
\\
d+)"
,
with
:
"$1 $2 $3 $4"
,
options
:
.
regularExpression
,
range
:
nil
)
}
func
asMaskedCardNumber
()
->
String
{
var
result
=
""
self
.
enumerated
()
.
forEach
{
(
index
,
character
)
in
if
index
>
6
&&
index
<
12
{
result
+=
"*"
}
else
{
result
.
append
(
character
)
}
}
return
result
}
func
asSeparatedMaskedCardNumber
()
->
String
{
var
result
=
""
self
.
asMaskedCardNumber
()
.
enumerated
()
.
forEach
{
(
index
,
character
)
in
if
index
%
4
==
0
&&
index
>
0
{
result
+=
" "
}
result
.
append
(
character
)
}
return
result
}
func
asCardExpiry
()
->
String
{
var
result
=
""
self
.
enumerated
()
.
forEach
{
(
index
,
character
)
in
if
index
%
2
==
0
&&
index
>
0
{
result
+=
"/"
}
result
.
append
(
character
)
}
return
result
}
}
Sources/SSD_Swift_ServicesPackage/formators/TextFieldFormatter.swift
0 → 100644
View file @
173dbbb3
//
// TextFieldFormatter.swift
// QIWI
//
// Created by Ilkhom on 02/03/22.
//
import
Foundation
class
TextFieldFormatter
{
func
formatString
(
ofNumbers
string
:
String
,
withMasks
masks
:
[
String
])
->
String
{
let
numbers
=
getNumbers
(
string
)
guard
let
mask
=
masks
.
first
(
where
:
{
$0
.
count
(
of
:
"X"
)
==
numbers
.
count
||
$0
.
count
(
of
:
"#"
)
==
numbers
.
count
})
else
{
return
numbers
}
return
formatStringInternal
(
numbers
:
numbers
,
mask
:
mask
)
}
func
formatString
(
ofNumbers
string
:
String
,
withMask
mask
:
String
)
->
String
{
let
numbers
=
getNumbers
(
string
)
return
formatStringInternal
(
numbers
:
numbers
,
mask
:
mask
)
}
private
func
formatStringInternal
(
numbers
:
String
,
mask
:
String
)
->
String
{
var
result
=
""
var
index
=
numbers
.
startIndex
for
ch
in
mask
where
index
<
numbers
.
endIndex
{
if
ch
==
"X"
||
ch
==
"#"
{
result
.
append
(
numbers
[
index
])
index
=
numbers
.
index
(
after
:
index
)
}
else
{
result
.
append
(
ch
)
}
}
return
result
}
private
func
getNumbers
(
_
string
:
String
)
->
String
{
string
.
noSpaces
()
.
replacingOccurrences
(
of
:
"[^0-9 || A-Za-z]"
,
with
:
""
,
options
:
.
regularExpression
)
}
///ex. passport data `AAXXXXXXX` - A - seria X - number
func
format
(
with
mask
:
String
,
passport
:
String
)
->
String
{
var
result
=
""
var
index
=
passport
.
startIndex
for
ch
in
mask
where
index
<
passport
.
endIndex
{
if
ch
==
"X"
&&
passport
[
index
]
.
isNumber
{
result
.
append
(
passport
[
index
])
index
=
passport
.
index
(
after
:
index
)
}
else
if
ch
==
"A"
&&
passport
[
index
]
.
isASCII
&&
passport
[
index
]
.
isLetter
{
result
.
append
(
passport
[
index
]
.
uppercased
())
index
=
passport
.
index
(
after
:
index
)
}
else
{
break
}
}
return
result
}
}
private
extension
String
{
func
count
(
of
char
:
Character
)
->
Int
{
return
reduce
(
0
)
{
$1
==
char
?
$0
+
1
:
$0
}
}
}
Sources/SSD_Swift_ServicesPackage/validators/Validators.swift
0 → 100644
View file @
173dbbb3
//
// Validators.swift
// QIWI
//
// Created by Ilkhom on 03/03/22.
//
import
Foundation
public
extension
String
{
func
isValidEmail
()
->
Bool
{
let
regex
=
try!
NSRegularExpression
(
pattern
:
"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+
\\
.[A-Za-z]{2,64}"
,
options
:
.
caseInsensitive
)
return
regex
.
firstMatch
(
in
:
self
,
options
:
[],
range
:
NSRange
(
location
:
0
,
length
:
count
))
!=
nil
}
func
isValidShortUzPhone
()
->
Bool
{
let
regex
=
"^[0-9]{9}$"
let
test
=
NSPredicate
(
format
:
"SELF MATCHES %@"
,
regex
)
return
test
.
evaluate
(
with
:
self
.
digits
)
}
func
isValidPhone
()
->
Bool
{
let
regex
=
"^[0-9]{12}$"
let
test
=
NSPredicate
(
format
:
"SELF MATCHES %@"
,
regex
)
return
test
.
evaluate
(
with
:
self
.
digits
)
}
func
isValidPassword
()
->
Bool
{
do
{
let
regex
=
try
NSRegularExpression
(
pattern
:
"^[a-zA-Z_0-9
\\
-_,;.:#+*?=!§$%&/()@]+$"
,
options
:
.
caseInsensitive
)
if
(
regex
.
firstMatch
(
in
:
self
,
options
:
NSRegularExpression
.
MatchingOptions
(
rawValue
:
0
),
range
:
NSMakeRange
(
0
,
self
.
count
))
!=
nil
){
return
self
.
count
>=
6
&&
self
.
count
<=
20
}
else
{
return
false
}
}
catch
{
return
false
}
}
func
isValidPassportSeria
()
->
Bool
{
self
.
alphabetic
.
count
==
2
}
func
isValidPassportNumber
()
->
Bool
{
self
.
digits
.
count
==
7
}
func
isValidPassportPinfl
()
->
Bool
{
self
.
digits
.
count
==
14
}
func
isValidPassport
()
->
Bool
{
self
.
noSpaces
()
.
count
==
9
}
func
isValidDate
(
format
:
String
)
->
Bool
{
let
formatter
=
DateFormatter
()
formatter
.
dateFormat
=
format
let
date
=
formatter
.
date
(
from
:
self
)
guard
let
date
=
date
else
{
return
false
}
return
date
.
getDateComponent
(
.
day
)
<=
31
&&
date
.
getDateComponent
(
.
month
)
<=
12
&&
(
1900
...
Date
()
.
getDateComponent
(
.
year
))
.
contains
(
date
.
getDateComponent
(
.
year
))
}
func
isValidAmount
(
max
:
Int
,
min
:
Int
)
->
Bool
{
if
self
.
isEmpty
||
min
>
max
{
return
false
}
let
range
=
min
...
max
return
range
.
contains
(
self
.
digits
.
toInt
())
}
func
isValidCardNumber
()
->
Bool
{
self
.
noSpaces
()
.
digits
.
count
==
16
}
func
isValidCardExpiry
()
->
Bool
{
self
.
digits
.
count
==
4
}
func
isValidCardCVV
()
->
Bool
{
self
.
digits
.
count
==
3
}
}
Tests/SSD_Swift_ServicesPackageTests/SSD_Swift_ServicesPackageTests.swift
0 → 100644
View file @
173dbbb3
import
XCTest
@testable
import
SSD_Swift_ServicesPackage
final
class
SSD_Swift_ServicesPackageTests
:
XCTestCase
{
var
formatter
=
DateFormatter
()
func
testAsPhone
()
throws
{
let
mock1
=
"+7(999)000-00-33"
let
result1
=
mock1
.
asPhone
(
masks
:
[
"+X(XXX)XXX-XX-XX"
])
let
mock2
=
"800000000"
let
result2
=
mock2
.
asPhone
(
masks
:
[
"XX XXX XX XX"
])
let
mock3
=
"988800000000"
let
result3
=
mock3
.
asPhone
(
masks
:
[
"+XXX(XX)XXX-XX-XX"
])
XCTAssertEqual
(
result1
,
"+7(999)000-00-33"
)
XCTAssertEqual
(
result2
,
"80 000 00 00"
)
XCTAssertEqual
(
result3
,
"+988(80)000-00-00"
)
}
func
test_toTiins
()
throws
{
let
mock1
=
"1000"
let
mock2
=
"1 000"
XCTAssertEqual
(
mock1
.
toTiins
(),
100000
)
XCTAssertEqual
(
mock2
.
toTiins
(),
100000
)
}
func
test_alphabetic
()
throws
{
let
mock
=
"test123test"
XCTAssertEqual
(
mock
.
alphabetic
,
"testtest"
)
}
func
test_alphanumeric
()
throws
{
let
mock
=
"test123_()_123"
XCTAssertEqual
(
mock
.
alphanumeric
,
"test123123"
)
}
func
test_digits
()
throws
{
let
mock
=
"test123_()_123"
XCTAssertEqual
(
mock
.
digits
,
"123123"
)
}
func
test_trimmed
()
throws
{
let
mock
=
"test "
XCTAssertEqual
(
mock
.
trimmed
,
"test"
)
}
func
test_toInt_int
()
throws
{
let
mock1
=
"1234"
let
mock2
=
"1234,123"
let
mock3
=
"1234.123"
let
mock4
=
"test1234.123test"
let
mock5
=
"1234 5"
XCTAssertEqual
(
mock1
.
toInt
(),
1234
)
XCTAssertEqual
(
mock2
.
toInt
(),
1234
)
XCTAssertEqual
(
mock3
.
toInt
(),
1234
)
XCTAssertEqual
(
mock4
.
toInt
(),
0
)
XCTAssertEqual
(
mock5
.
toInt
(),
12345
)
}
func
test_toDouble
()
throws
{
let
mock1
=
"1234,5"
let
mock2
=
"1234.5"
let
mock3
=
"test1234.5"
let
mock4
=
"test 1234.5"
XCTAssertEqual
(
mock1
.
toDouble
(),
1234.5
)
XCTAssertEqual
(
mock2
.
toDouble
(),
1234.5
)
XCTAssertEqual
(
mock3
.
toDouble
(),
0.0
)
XCTAssertEqual
(
mock4
.
toDouble
(),
0.0
)
}
func
test_noSpaces
()
throws
{
let
mock
=
"test 123 test"
XCTAssertEqual
(
mock
.
noSpaces
(),
"test123test"
)
}
func
test_toDate
()
throws
{
let
mock
=
"28.11.1991"
let
mockFormat
=
"dd.MM.yyyy"
formatter
.
dateFormat
=
mockFormat
let
result
=
formatter
.
date
(
from
:
mock
)
XCTAssertEqual
(
mock
.
toDate
(
format
:
mockFormat
),
result
)
}
func
test_toTiins_round
()
throws
{
let
mock1
=
"100"
let
mock2
=
"100,00"
let
mock3
=
"100.00"
XCTAssertEqual
(
mock1
.
toTiins
(),
10000
)
XCTAssertEqual
(
mock2
.
toTiins
(),
10000
)
XCTAssertEqual
(
mock3
.
toTiins
(),
10000
)
}
func
test_addUzbekPrefixIfNeeded_withPrefix
()
throws
{
let
mock1
=
"998901281289"
let
mock2
=
"901281289"
XCTAssertEqual
(
mock1
.
addUzbekPrefixIfNeeded
(),
"998901281289"
)
XCTAssertEqual
(
mock2
.
addUzbekPrefixIfNeeded
(),
"998901281289"
)
}
func
test_removeUzbekPrefixIfNeeded
()
throws
{
let
mock
=
"998901281289"
let
mock2
=
"+998901281289"
let
mock3
=
"901281289"
let
mock4
=
"998 90 128 12 89"
let
mock5
=
"90 128 12 89"
let
expectedResult
=
"901281289"
XCTAssertEqual
(
mock
.
removeUzbekPrefixIfNeeded
(),
expectedResult
)
XCTAssertEqual
(
mock2
.
removeUzbekPrefixIfNeeded
(),
expectedResult
)
XCTAssertEqual
(
mock3
.
removeUzbekPrefixIfNeeded
(),
expectedResult
)
XCTAssertEqual
(
mock4
.
removeUzbekPrefixIfNeeded
(),
expectedResult
)
XCTAssertEqual
(
mock5
.
removeUzbekPrefixIfNeeded
(),
expectedResult
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment