Compare commits
17 Commits
129eb135f1
...
analytics
Author | SHA1 | Date | |
---|---|---|---|
239deb2b91 | |||
9a05ce29b8 | |||
2ec4ebcc66 | |||
6ea31a8030 | |||
df173406d4 | |||
922ed56959 | |||
ab91c1c277 | |||
aa64ce5cf7 | |||
23bf3c3a82 | |||
09556ba6e0 | |||
dea57dc1e2 | |||
07575bd2bf | |||
8686ae974c | |||
be4c561ea8 | |||
2357a40fff | |||
d4afa9c9e9 | |||
76ef0a2d59 |
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
@ -1,6 +1,6 @@
|
|||||||
library "openiumpipeline"
|
library "openiumpipeline"
|
||||||
|
|
||||||
env.DEVELOPER_DIR="/Applications/Xcode-15.3.0.app/Contents/Developer"
|
env.DEVELOPER_DIR="/Applications/Xcode-15.4.0.app/Contents/Developer"
|
||||||
//env.SIMULATOR_DEVICE_TYPES="iPad--7th-generation-"
|
//env.SIMULATOR_DEVICE_TYPES="iPad--7th-generation-"
|
||||||
env.IS_PACKAGE_SWIFT=1
|
env.IS_PACKAGE_SWIFT=1
|
||||||
env.TARGETS_MACOS=1
|
env.TARGETS_MACOS=1
|
||||||
|
@ -1,32 +1,5 @@
|
|||||||
{
|
{
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
|
||||||
"identity" : "collectionconcurrencykit",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95",
|
|
||||||
"version" : "0.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "cryptoswift",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "c9c3df6ab812de32bae61fc0cd1bf6d45170ebf0",
|
|
||||||
"version" : "1.8.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "sourcekitten",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/jpsim/SourceKitten.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56",
|
|
||||||
"version" : "0.34.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"identity" : "swift-argument-parser",
|
"identity" : "swift-argument-parser",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
@ -37,39 +10,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"identity" : "swift-syntax",
|
"identity" : "swiftlintplugin",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-syntax.git",
|
"location" : "https://github.com/lukepistrol/SwiftLintPlugin",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036",
|
"revision" : "5a65f4074975f811da666dfe31a19850950b1ea4",
|
||||||
"version" : "509.0.2"
|
"version" : "0.56.2"
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "swiftlint",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/realm/SwiftLint.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "f17a4f9dfb6a6afb0408426354e4180daaf49cee",
|
|
||||||
"version" : "0.54.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "swiftytexttable",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/scottrhoyt/SwiftyTextTable.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3",
|
|
||||||
"version" : "0.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "swxmlhash",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/drmohundro/SWXMLHash.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f",
|
|
||||||
"version" : "7.0.2"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -10,7 +10,7 @@ let package = Package(
|
|||||||
// Dependencies declare other packages that this package depends on.
|
// Dependencies declare other packages that this package depends on.
|
||||||
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"),
|
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"),
|
||||||
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.1"),
|
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.1"),
|
||||||
.package(url: "https://github.com/realm/SwiftLint.git", .upToNextMajor(from: "0.54.0")),
|
.package(url: "https://github.com/lukepistrol/SwiftLintPlugin", exact: "0.56.2"),
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||||
@ -22,7 +22,9 @@ let package = Package(
|
|||||||
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
.product(name: "ArgumentParser", package: "swift-argument-parser"),
|
||||||
"Yams"
|
"Yams"
|
||||||
],
|
],
|
||||||
plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")]
|
plugins: [
|
||||||
|
.plugin(name: "SwiftLint", package: "SwiftLintPlugin")
|
||||||
|
]
|
||||||
),
|
),
|
||||||
|
|
||||||
// Helper targets
|
// Helper targets
|
||||||
|
90
README.md
90
README.md
@ -81,7 +81,7 @@ swift run -c release ResgenSwift strings twine $FORCE_FLAG "./Twine/strings.txt"
|
|||||||
2. Input translations file (must be Twine formatted)
|
2. Input translations file (must be Twine formatted)
|
||||||
3. `--langs`: langs to generate (string with space between each lang)
|
3. `--langs`: langs to generate (string with space between each lang)
|
||||||
4. `--default-lang`: default lang that will be in `Base.lproj`. It must be in `langs` as well
|
4. `--default-lang`: default lang that will be in `Base.lproj`. It must be in `langs` as well
|
||||||
4. `--extension-output-path`: path where to generate generated extension
|
5. `--extension-output-path`: path where to generate generated extension
|
||||||
|
|
||||||
### Stringium (recommended)
|
### Stringium (recommended)
|
||||||
|
|
||||||
@ -93,6 +93,7 @@ swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/string
|
|||||||
--extension-output-path "./Strings/Generated" \
|
--extension-output-path "./Strings/Generated" \
|
||||||
--extension-name "AppString" \
|
--extension-name "AppString" \
|
||||||
--extension-suffix "GreatApp" \
|
--extension-suffix "GreatApp" \
|
||||||
|
--xcStrings true
|
||||||
--static-members true
|
--static-members true
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -105,6 +106,7 @@ swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/string
|
|||||||
4. `--extension-output-path`: path where to generate generated extension
|
4. `--extension-output-path`: path where to generate generated extension
|
||||||
5. `--extension-name` *(optional)* : name of class to add the extension
|
5. `--extension-name` *(optional)* : name of class to add the extension
|
||||||
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppString+GreatApp.swift`)
|
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppString+GreatApp.swift`)
|
||||||
|
6. `--xcStrings`*(optional)* : generate string catalog
|
||||||
7. `--static-members` *(optional)*: generate static properties or not
|
7. `--static-members` *(optional)*: generate static properties or not
|
||||||
|
|
||||||
|
|
||||||
@ -131,7 +133,7 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
|||||||
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppTags+GreatApp.swift`)
|
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppTags+GreatApp.swift`)
|
||||||
7. `--static-members` *(optional)*: generate static properties or not
|
7. `--static-members` *(optional)*: generate static properties or not
|
||||||
|
|
||||||
> ⚠️ If extension name is not set or is `Tags`, it will generate the following typaloas `typealias Tags = String`.
|
> ⚠️ If extension name is not set or is `Tags`, it will generate the following typealias `typealias Tags = String`.
|
||||||
|
|
||||||
|
|
||||||
## Analytics
|
## Analytics
|
||||||
@ -139,7 +141,7 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
|||||||
Analytics will generate all you need to analyze UX with Matomo or Firebase Analytics. Input files are formatted in YAML. This command will generate a manager for each target and an AnalyticsManager. This is this one you will need to use. And it will generate a method for all tags you have declared in the YAML file. Next, you will need to use the `configure()` method of AnalyticsManager and if you want to use matomo to set up the `siteId` and the `url` of the site.
|
Analytics will generate all you need to analyze UX with Matomo or Firebase Analytics. Input files are formatted in YAML. This command will generate a manager for each target and an AnalyticsManager. This is this one you will need to use. And it will generate a method for all tags you have declared in the YAML file. Next, you will need to use the `configure()` method of AnalyticsManager and if you want to use matomo to set up the `siteId` and the `url` of the site.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/analytics.yml" \
|
||||||
--target "matomo firebase" \
|
--target "matomo firebase" \
|
||||||
--extension-output-path "./Analytics/Generated" \
|
--extension-output-path "./Analytics/Generated" \
|
||||||
--extension-name "AppAnalytics" \
|
--extension-name "AppAnalytics" \
|
||||||
@ -157,7 +159,7 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
|||||||
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppAnalytics+GreatApp.swift`)
|
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppAnalytics+GreatApp.swift`)
|
||||||
7. `--static-members` *(optional)*: generate static properties or not
|
7. `--static-members` *(optional)*: generate static properties or not
|
||||||
|
|
||||||
> ⚠️ If extension name is not set or is `Analytics`, it will generate the following typaloas `typealias Analytics = String`.
|
> ⚠️ If extension name is not set or is `Analytics`, it will generate the following typealias `typealias Analytics = String`.
|
||||||
|
|
||||||
### YAML
|
### YAML
|
||||||
|
|
||||||
@ -184,23 +186,87 @@ swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
|
|||||||
7. `comments` *(optional)*
|
7. `comments` *(optional)*
|
||||||
8. `parameters` *(optional)*
|
8. `parameters` *(optional)*
|
||||||
|
|
||||||
**Parameters**
|
**Parameters**
|
||||||
|
|
||||||
You can use parameters in generate methods.
|
You can use parameters in generate methods.
|
||||||
|
|
||||||
1. `name`: name of the parameter
|
1. `name`: name of the parameter
|
||||||
2. `type`: type of the parameter (Int, String, Bool, Double)
|
2. `type`: type of the parameter (Int, String, Bool, Double)
|
||||||
|
3. `value`: value of the parameter
|
||||||
|
4. `defaultValue`: defaultValue of the parameter
|
||||||
3. `replaceIn` *(optional)*
|
3. `replaceIn` *(optional)*
|
||||||
|
|
||||||
|
**Value**
|
||||||
|
|
||||||
|
If you want to send another parameter with a static value. For example, you want to send to which screen the event is triggered.
|
||||||
|
You can add the parameter 'screenName' for example and its 'value' is 'Home'. With this, you do not need to specify the value in the function call.
|
||||||
|
|
||||||
|
**DefaultValue**
|
||||||
|
|
||||||
|
If you want ta add a parameter in the call of the function but you want to make it optionnal with a default value you need to use this property.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
events:
|
||||||
|
id: id_of_tag
|
||||||
|
name: _TITLE_
|
||||||
|
tags: ios,droid
|
||||||
|
parameters:
|
||||||
|
- name: title
|
||||||
|
type: String
|
||||||
|
defaultValue: someTitle
|
||||||
|
```
|
||||||
|
|
||||||
|
The generated method will be:
|
||||||
|
```
|
||||||
|
logIdOfTag(title: String = "someTitle")
|
||||||
|
```
|
||||||
|
|
||||||
**Replace in**
|
**Replace in**
|
||||||
|
|
||||||
This is section is equivalent of `%s | %d | %f | %@`. You can put the content of the parameter in *name*, *path*, *action*, *category*.
|
This is section is equivalent of `%s | %d | %f | %@`. You can put the content of the parameter in *name*, *path*, *action*, *category*.
|
||||||
You need to put `_` + `NAME OF THE PARAMETER` + `_` in the target and which target you want in the value of `replaceIn`. (name need to be in uppercase)
|
You need to put `_` + `NAME OF THE PARAMETER` + `_` in the target and which target you want in the value of `replaceIn`. (name need to be in uppercase).
|
||||||
|
You can't use `value`and `replaceIn`in thge same time.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
events:
|
||||||
|
id: id_of_tag
|
||||||
|
name: _TITLE_
|
||||||
|
tags: ios,droid
|
||||||
|
parameters:
|
||||||
|
- name: title
|
||||||
|
type: String
|
||||||
|
replaceIn: name
|
||||||
|
```
|
||||||
|
|
||||||
|
In this sample, we want to add the parameter `title` in the field `name`. So, we need to place `_TITLE_` in the field `name`.
|
||||||
|
|
||||||
|
The generated method will be:
|
||||||
|
```
|
||||||
|
logIdOfTag(title: String)
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also want to replace a parameter in an other parameter. You can do this with the `replaceIn` property. The condition is that the parameter which will use the `replaceIn`need to have the `value`property
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
events:
|
||||||
|
id: id_of_tag
|
||||||
|
name: title
|
||||||
|
tags: ios,droid
|
||||||
|
parameters:
|
||||||
|
- name: something
|
||||||
|
type: String
|
||||||
|
value: test _TEXT_
|
||||||
|
- name: text
|
||||||
|
type: String
|
||||||
|
replaceIn: something
|
||||||
|
```
|
||||||
|
|
||||||
## Images
|
## Images
|
||||||
|
|
||||||
Images generator will generate images assets along with extensions to access those images easily.
|
Images generator will generate images assets along with extensions to access those images easily.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
swift run -c release ResgenSwift images $FORCE_FLAG "./Images/images.txt" \
|
swift run -c release ResgenSwift images $FORCE_FLAG "./Images/images.txt" \
|
||||||
@ -223,6 +289,7 @@ swift run -c release ResgenSwift images $FORCE_FLAG "./Images/images.txt" \
|
|||||||
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppImage+GreatApp.swift`)
|
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppImage+GreatApp.swift`)
|
||||||
7. `--static-members` *(optional)*: generate static properties or not
|
7. `--static-members` *(optional)*: generate static properties or not
|
||||||
|
|
||||||
|
> ⚠️ Svg images will be copied in the assets and rendered as "Original", however if those images are not rendered correctly you can force the png generation by adding the key word "png" like this: id arrow_back 15 ? png
|
||||||
|
|
||||||
## All at once
|
## All at once
|
||||||
|
|
||||||
@ -284,6 +351,15 @@ tags:
|
|||||||
extensionName: String?
|
extensionName: String?
|
||||||
extensionSuffix: String?
|
extensionSuffix: String?
|
||||||
staticMembers: Bool?
|
staticMembers: Bool?
|
||||||
|
|
||||||
|
analytics:
|
||||||
|
-
|
||||||
|
inputFile: String
|
||||||
|
target: String
|
||||||
|
extensionOutputPath: String
|
||||||
|
extensionName: String?
|
||||||
|
extensionSuffix: String?
|
||||||
|
staticMembers: Bool?
|
||||||
```
|
```
|
||||||
|
|
||||||
### Multiple configurations
|
### Multiple configurations
|
||||||
|
@ -6,13 +6,20 @@ import FirebaseAnalytics
|
|||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
func logScreen(name: String, path: String)
|
func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
)
|
||||||
|
|
||||||
func logEvent(
|
func logEvent(
|
||||||
name: String,
|
name: String,
|
||||||
action: String,
|
action: String,
|
||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func setEnable(_ enable: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Matomo
|
// MARK: - Matomo
|
||||||
@ -47,8 +54,11 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
|
|
||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
|
|
||||||
func logScreen(name: String, path: String) {
|
func logScreen(
|
||||||
guard !tracker.isOptedOut else { return }
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
||||||
|
|
||||||
let urlString = URL(string: "\(trackerUrl)" + "/" + "\(path)" + "iOS")
|
let urlString = URL(string: "\(trackerUrl)" + "/" + "\(path)" + "iOS")
|
||||||
@ -64,8 +74,6 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
guard !tracker.isOptedOut else { return }
|
|
||||||
|
|
||||||
tracker.track(
|
tracker.track(
|
||||||
eventWithCategory: category,
|
eventWithCategory: category,
|
||||||
action: action,
|
action: action,
|
||||||
@ -74,16 +82,40 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
url: nil
|
url: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setEnable(_ enable: Bool) {
|
||||||
|
tracker.isOptedOut = !enable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Firebase
|
// MARK: - Firebase
|
||||||
|
|
||||||
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
||||||
func logScreen(name: String, path: String) {
|
func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
var parameters = [
|
var parameters = [
|
||||||
AnalyticsParameterScreenName: name as NSObject
|
AnalyticsParameterScreenName: name as NSObject
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if path.isEmpty == false {
|
||||||
|
parameters["path"] = path + "/iOS" as NSObject
|
||||||
|
}
|
||||||
|
|
||||||
|
if let supplementaryParameters = params {
|
||||||
|
for (newKey, newValue) in supplementaryParameters {
|
||||||
|
if parameters.contains(where: { (key: String, value: NSObject) in
|
||||||
|
key == newKey
|
||||||
|
}) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters[newKey] = newValue as? NSObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Analytics.logEvent(
|
Analytics.logEvent(
|
||||||
AnalyticsEventScreenView,
|
AnalyticsEventScreenView,
|
||||||
parameters: parameters
|
parameters: parameters
|
||||||
@ -97,9 +129,16 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
var parameters: [String:NSObject] = [
|
var parameters: [String:NSObject] = [
|
||||||
"action": action as NSObject,
|
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
||||||
"category": category as NSObject,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if category.isEmpty == false {
|
||||||
|
parameters["AnalyticsParameterItemCategory"] = category as NSObject
|
||||||
|
}
|
||||||
|
|
||||||
|
if action.isEmpty == false {
|
||||||
|
parameters["action"] = action as NSObject
|
||||||
|
}
|
||||||
|
|
||||||
if let supplementaryParameters = params {
|
if let supplementaryParameters = params {
|
||||||
for (newKey, newValue) in supplementaryParameters {
|
for (newKey, newValue) in supplementaryParameters {
|
||||||
@ -114,10 +153,13 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Analytics.logEvent(
|
Analytics.logEvent(
|
||||||
name.replacingOccurrences(of: [" "], with: "_"),
|
AnalyticsEventSelectContent,
|
||||||
parameters: parameters
|
parameters: parameters
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
func setEnable(_ enable: Bool) {
|
||||||
|
Analytics.setAnalyticsCollectionEnabled(enable)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
@ -127,31 +169,57 @@ class AnalyticsManager {
|
|||||||
|
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
|
|
||||||
var managers: [AnalyticsManagerProtocol] = []
|
var managers: [TargetType: AnalyticsManagerProtocol] = []
|
||||||
|
|
||||||
private var isEnabled: Bool = true
|
private var isEnabled: Bool {
|
||||||
|
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
|
|
||||||
func setAnalyticsEnabled(_ enable: Bool) {
|
private func setAnalytics(enable: Bool) {
|
||||||
isEnabled = enable
|
managers.forEach { (key, value) in
|
||||||
|
if analytics.contains(where: { type in
|
||||||
|
type == key
|
||||||
|
}) {
|
||||||
|
value.setEnable(enable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func enableAnalytics(_ analytics: [TargetType] = TargetType.allCases) {
|
||||||
|
setAnalytics(enable: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func disableAnalytics(_ analytics: [TargetType] = TargetType.allCases) {
|
||||||
|
setAnalytics(enable: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func configure(siteId: String, url: String) {
|
func configure(siteId: String, url: String) {
|
||||||
managers.append(
|
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||||||
MatomoAnalyticsManager(
|
siteId: siteId,
|
||||||
siteId: siteId,
|
url: url
|
||||||
url: url
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
managers.append(FirebaseAnalyticsManager())
|
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func logScreen(name: String, path: String) {
|
private func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logScreen(name: name, path: path)
|
manager.logScreen(
|
||||||
|
name: name,
|
||||||
|
path: path,
|
||||||
|
params: params
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +231,7 @@ class AnalyticsManager {
|
|||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logEvent(
|
manager.logEvent(
|
||||||
name: name,
|
name: name,
|
||||||
action: action,
|
action: action,
|
||||||
@ -175,31 +243,39 @@ class AnalyticsManager {
|
|||||||
|
|
||||||
// MARK: - section_one
|
// MARK: - section_one
|
||||||
|
|
||||||
func logScreenS1DefOne(title: String) {
|
static func logScreenS1DefOne(title: String) {
|
||||||
logScreen(
|
AnalyticsManager.shared.logScreen(
|
||||||
name: "s1 def one \(title)",
|
name: "s1 def one \(title)",
|
||||||
path: "s1_def_one/\(title)"
|
path: "s1_def_one/\(title)",
|
||||||
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func logEventS1DefTwo(title: String, count: String) {
|
static func logEventS1DefTwo(
|
||||||
logEvent(
|
title: String,
|
||||||
|
count: String,
|
||||||
|
test2: String = "test"
|
||||||
|
) {
|
||||||
|
AnalyticsManager.shared.logEvent(
|
||||||
name: "s1 def two",
|
name: "s1 def two",
|
||||||
action: "test",
|
action: "test",
|
||||||
category: "test",
|
category: "test",
|
||||||
params: [
|
params: [
|
||||||
"title": title,
|
"title": title,
|
||||||
"count": count
|
"count": count,
|
||||||
|
"test": "test",
|
||||||
|
"test2": test2
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - section_two
|
// MARK: - section_two
|
||||||
|
|
||||||
func logScreenS2DefOne() {
|
static func logScreenS2DefOne() {
|
||||||
logScreen(
|
AnalyticsManager.shared.logScreen(
|
||||||
name: "s2 def one",
|
name: "s2 def one",
|
||||||
path: "s2_def_one/"
|
path: "s2_def_one/",
|
||||||
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,12 @@ categories:
|
|||||||
type: String
|
type: String
|
||||||
- name: count
|
- name: count
|
||||||
type: String
|
type: String
|
||||||
|
- name: test
|
||||||
|
type: String
|
||||||
|
value: test
|
||||||
|
- name: test2
|
||||||
|
type: String
|
||||||
|
defaultValue: test
|
||||||
|
|
||||||
- id: section_two
|
- id: section_two
|
||||||
screens:
|
screens:
|
||||||
|
@ -54,10 +54,11 @@ FORCE_FLAG="$1"
|
|||||||
|
|
||||||
# Analytics
|
# Analytics
|
||||||
swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \
|
swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \
|
||||||
--target "matomo firebase" \
|
--target "firebase matomo" \
|
||||||
--extension-output-path "./Tags/Generated" \
|
--extension-output-path "./Tags/Generated" \
|
||||||
--extension-name "Analytics" \
|
--extension-name "Analytics" \
|
||||||
--extension-suffix "GenAllScript"
|
--extension-suffix "GenAllScript" \
|
||||||
|
--static-members true
|
||||||
|
|
||||||
#echo "\n-------------------------\n"
|
#echo "\n-------------------------\n"
|
||||||
#
|
#
|
||||||
|
@ -59,14 +59,18 @@ class AnalyticsGenerator {
|
|||||||
\(Self.getImport())
|
\(Self.getImport())
|
||||||
|
|
||||||
\(Self.getAnalyticsProtocol())
|
\(Self.getAnalyticsProtocol())
|
||||||
|
|
||||||
|
\(Self.getTrackerTypeEnum())
|
||||||
|
|
||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
|
|
||||||
class AnalyticsManager {
|
class AnalyticsManager {
|
||||||
|
|
||||||
static var shared = AnalyticsManager()
|
static var shared = AnalyticsManager()
|
||||||
|
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
|
|
||||||
var managers: [AnalyticsManagerProtocol] = []
|
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
||||||
|
|
||||||
\(Self.getEnabledContent())
|
\(Self.getEnabledContent())
|
||||||
|
|
||||||
@ -76,14 +80,49 @@ class AnalyticsGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static func getTrackerTypeEnum() -> String {
|
||||||
|
var result: [String] = []
|
||||||
|
TrackerType.allCases.forEach { type in
|
||||||
|
result.append(" case \(type)")
|
||||||
|
}
|
||||||
|
|
||||||
|
return """
|
||||||
|
// MARK: - Traker Type
|
||||||
|
|
||||||
|
enum TrackerType: CaseIterable {
|
||||||
|
\(result.joined(separator: "\n"))
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
private static func getEnabledContent() -> String {
|
private static func getEnabledContent() -> String {
|
||||||
"""
|
"""
|
||||||
private var isEnabled: Bool = true
|
private var isEnabled: Bool {
|
||||||
|
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Methods
|
// MARK: - Methods
|
||||||
|
|
||||||
func setAnalyticsEnabled(_ enable: Bool) {
|
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||||
isEnabled = enable
|
managers.forEach { (key, value) in
|
||||||
|
if analytics.contains(where: { type in
|
||||||
|
type == key
|
||||||
|
}) {
|
||||||
|
value.setEnable(enable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||||
|
setAnalytics(enable: true, analytics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||||
|
setAnalytics(enable: false, analytics)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
@ -103,11 +142,19 @@ class AnalyticsGenerator {
|
|||||||
|
|
||||||
private static func getPrivateLogFunction() -> String {
|
private static func getPrivateLogFunction() -> String {
|
||||||
"""
|
"""
|
||||||
private func logScreen(name: String, path: String) {
|
private func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logScreen(name: name, path: path)
|
manager.logScreen(
|
||||||
|
name: name,
|
||||||
|
path: path,
|
||||||
|
params: params
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +166,7 @@ class AnalyticsGenerator {
|
|||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else { return }
|
||||||
|
|
||||||
managers.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
manager.logEvent(
|
manager.logEvent(
|
||||||
name: name,
|
name: name,
|
||||||
action: action,
|
action: action,
|
||||||
@ -144,16 +191,14 @@ class AnalyticsGenerator {
|
|||||||
|
|
||||||
if targets.contains(TrackerType.matomo) {
|
if targets.contains(TrackerType.matomo) {
|
||||||
content.append("""
|
content.append("""
|
||||||
managers.append(
|
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||||||
MatomoAnalyticsManager(
|
siteId: siteId,
|
||||||
siteId: siteId,
|
url: url
|
||||||
url: url
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
if targets.contains(TrackerType.firebase) {
|
if targets.contains(TrackerType.firebase) {
|
||||||
content.append(" managers.append(FirebaseAnalyticsManager())")
|
content.append(" managers[TrackerType.firebase] = FirebaseAnalyticsManager()")
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -169,13 +214,20 @@ class AnalyticsGenerator {
|
|||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
protocol AnalyticsManagerProtocol {
|
protocol AnalyticsManagerProtocol {
|
||||||
func logScreen(name: String, path: String)
|
func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
)
|
||||||
|
|
||||||
func logEvent(
|
func logEvent(
|
||||||
name: String,
|
name: String,
|
||||||
action: String,
|
action: String,
|
||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func setEnable(_ enable: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -14,6 +14,7 @@ enum FirebaseGenerator {
|
|||||||
FirebaseGenerator.header,
|
FirebaseGenerator.header,
|
||||||
FirebaseGenerator.logScreen,
|
FirebaseGenerator.logScreen,
|
||||||
FirebaseGenerator.logEvent,
|
FirebaseGenerator.logEvent,
|
||||||
|
FirebaseGenerator.enable,
|
||||||
FirebaseGenerator.footer
|
FirebaseGenerator.footer
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
@ -31,11 +32,31 @@ enum FirebaseGenerator {
|
|||||||
|
|
||||||
private static var logScreen: String {
|
private static var logScreen: String {
|
||||||
"""
|
"""
|
||||||
func logScreen(name: String, path: String) {
|
func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
var parameters = [
|
var parameters = [
|
||||||
AnalyticsParameterScreenName: name as NSObject
|
AnalyticsParameterScreenName: name as NSObject
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if path.isEmpty == false {
|
||||||
|
parameters["path"] = path + "/iOS" as NSObject
|
||||||
|
}
|
||||||
|
|
||||||
|
if let supplementaryParameters = params {
|
||||||
|
for (newKey, newValue) in supplementaryParameters {
|
||||||
|
if parameters.contains(where: { (key: String, value: NSObject) in
|
||||||
|
key == newKey
|
||||||
|
}) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters[newKey] = newValue as? NSObject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Analytics.logEvent(
|
Analytics.logEvent(
|
||||||
AnalyticsEventScreenView,
|
AnalyticsEventScreenView,
|
||||||
parameters: parameters
|
parameters: parameters
|
||||||
@ -54,9 +75,16 @@ enum FirebaseGenerator {
|
|||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
var parameters: [String:NSObject] = [
|
var parameters: [String:NSObject] = [
|
||||||
"action": action as NSObject,
|
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
||||||
"category": category as NSObject,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if category.isEmpty == false {
|
||||||
|
parameters["AnalyticsParameterItemCategory"] = category as NSObject
|
||||||
|
}
|
||||||
|
|
||||||
|
if action.isEmpty == false {
|
||||||
|
parameters["action"] = action as NSObject
|
||||||
|
}
|
||||||
|
|
||||||
if let supplementaryParameters = params {
|
if let supplementaryParameters = params {
|
||||||
for (newKey, newValue) in supplementaryParameters {
|
for (newKey, newValue) in supplementaryParameters {
|
||||||
@ -71,13 +99,21 @@ enum FirebaseGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Analytics.logEvent(
|
Analytics.logEvent(
|
||||||
name.replacingOccurrences(of: [" "], with: "_"),
|
AnalyticsEventSelectContent,
|
||||||
parameters: parameters
|
parameters: parameters
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static var enable: String {
|
||||||
|
"""
|
||||||
|
func setEnable(_ enable: Bool) {
|
||||||
|
Analytics.setAnalyticsCollectionEnabled(enable)
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
private static var footer: String {
|
private static var footer: String {
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ enum MatomoGenerator {
|
|||||||
MatomoGenerator.setup,
|
MatomoGenerator.setup,
|
||||||
MatomoGenerator.logScreen,
|
MatomoGenerator.logScreen,
|
||||||
MatomoGenerator.logEvent,
|
MatomoGenerator.logEvent,
|
||||||
|
MatomoGenerator.enable,
|
||||||
MatomoGenerator.footer
|
MatomoGenerator.footer
|
||||||
]
|
]
|
||||||
.joined(separator: "\n")
|
.joined(separator: "\n")
|
||||||
@ -66,8 +67,11 @@ enum MatomoGenerator {
|
|||||||
|
|
||||||
private static var logScreen: String {
|
private static var logScreen: String {
|
||||||
"""
|
"""
|
||||||
func logScreen(name: String, path: String) {
|
func logScreen(
|
||||||
guard !tracker.isOptedOut else { return }
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
|
||||||
|
|
||||||
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
|
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
|
||||||
@ -88,8 +92,6 @@ enum MatomoGenerator {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
guard !tracker.isOptedOut else { return }
|
|
||||||
|
|
||||||
tracker.track(
|
tracker.track(
|
||||||
eventWithCategory: category,
|
eventWithCategory: category,
|
||||||
action: action,
|
action: action,
|
||||||
@ -98,6 +100,15 @@ enum MatomoGenerator {
|
|||||||
url: nil
|
url: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
private static var enable: String {
|
||||||
|
"""
|
||||||
|
func setEnable(_ enable: Bool) {
|
||||||
|
tracker.isOptedOut = !enable
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,17 +48,23 @@ class AnalyticsDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func getParameters() -> String {
|
private func getParameters() -> String {
|
||||||
var params = parameters
|
|
||||||
var result: String
|
var result: String
|
||||||
|
|
||||||
if type == .screen {
|
let paramsString = parameters.compactMap { parameter -> String? in
|
||||||
params = params.filter { param in
|
guard parameter.value.isEmpty else { return nil }
|
||||||
!param.replaceIn.isEmpty
|
|
||||||
|
let defaultValue: String
|
||||||
|
switch parameter.type {
|
||||||
|
case .bool:
|
||||||
|
defaultValue = "\(parameter.defaultValue.lowercased())"
|
||||||
|
case .int, .double:
|
||||||
|
defaultValue = "\(parameter.defaultValue)"
|
||||||
|
case .string:
|
||||||
|
defaultValue = "\"\(parameter.defaultValue)\""
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
let defaultValueString = parameter.defaultValue.isEmpty ? "" : " = \(defaultValue)"
|
||||||
let paramsString = params.map { parameter in
|
return "\(parameter.name): \(parameter.type.rawValue)\(defaultValueString)"
|
||||||
"\(parameter.name): \(parameter.type)"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if paramsString.count > 2 {
|
if paramsString.count > 2 {
|
||||||
@ -84,7 +90,10 @@ class AnalyticsDefinition {
|
|||||||
case "path": path = path.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
case "path": path = path.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
case "category": category = category.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
case "category": category = category.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
case "action": action = action.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
case "action": action = action.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
default: break
|
default:
|
||||||
|
if let param = parameters.first(where: { $0.name == rep }), param.value.isEmpty == false {
|
||||||
|
param.value = param.value.replacingFirstOccurrence(of: "_\(parameter.name.uppercased())_", with: "\\(\(parameter.name))")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,7 +108,18 @@ class AnalyticsDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
supplementaryParams.forEach { param in
|
supplementaryParams.forEach { param in
|
||||||
params.append("\"\(param.name)\": \(param.name)")
|
if param.value.isEmpty {
|
||||||
|
params.append("\"\(param.name)\": \(param.name)")
|
||||||
|
} else {
|
||||||
|
switch param.type {
|
||||||
|
case .bool:
|
||||||
|
params.append("\"\(param.name)\": \(param.value.lowercased())")
|
||||||
|
case .int, .double:
|
||||||
|
params.append("\"\(param.name)\": \(param.value)")
|
||||||
|
case .string:
|
||||||
|
params.append("\"\(param.name)\": \"\(param.value)\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.count > 1 {
|
if params.count > 1 {
|
||||||
@ -113,14 +133,15 @@ class AnalyticsDefinition {
|
|||||||
[\(params.joined(separator: ", "))]
|
[\(params.joined(separator: ", "))]
|
||||||
"""
|
"""
|
||||||
} else {
|
} else {
|
||||||
result = "[:]"
|
result = "nil"
|
||||||
}
|
}
|
||||||
|
|
||||||
if type == .screen {
|
if type == .screen {
|
||||||
return """
|
return """
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "\(name)",
|
name: "\(name)",
|
||||||
path: "\(path)"
|
path: "\(path)",
|
||||||
|
params: \(result)
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
} else {
|
} else {
|
||||||
@ -150,7 +171,7 @@ class AnalyticsDefinition {
|
|||||||
replaceIn()
|
replaceIn()
|
||||||
return """
|
return """
|
||||||
static func \(getFuncName())\(getParameters()) {
|
static func \(getFuncName())\(getParameters()) {
|
||||||
\(getlogFunction())
|
AnalyticsManager.shared.\(getlogFunction())
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
@ -41,5 +41,7 @@ struct AnalyticsDefinitionEventDTO: Codable {
|
|||||||
struct AnalyticsParameterDTO: Codable {
|
struct AnalyticsParameterDTO: Codable {
|
||||||
var name: String
|
var name: String
|
||||||
var type: String
|
var type: String
|
||||||
|
var value: String?
|
||||||
|
var defaultValue: String?
|
||||||
var replaceIn: String?
|
var replaceIn: String?
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,17 @@ import Foundation
|
|||||||
|
|
||||||
class AnalyticsParameter {
|
class AnalyticsParameter {
|
||||||
var name: String
|
var name: String
|
||||||
var type: String
|
var type: ParameterType
|
||||||
|
var value: String
|
||||||
|
var defaultValue: String
|
||||||
var replaceIn: [String] = []
|
var replaceIn: [String] = []
|
||||||
|
|
||||||
// MARK: - Init
|
// MARK: - Init
|
||||||
|
|
||||||
init(name: String, type: String) {
|
init(name: String, type: ParameterType, value: String, defaultValue: String) {
|
||||||
self.name = name
|
self.name = name
|
||||||
self.type = type
|
self.type = type
|
||||||
|
self.value = value
|
||||||
|
self.defaultValue = defaultValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
Sources/ResgenSwift/Analytics/Model/ParameterType.swift
Normal file
15
Sources/ResgenSwift/Analytics/Model/ParameterType.swift
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// File.swift
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Created by Loris Perret on 17/07/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum ParameterType: String {
|
||||||
|
case string = "String"
|
||||||
|
case int = "Int"
|
||||||
|
case double = "Double"
|
||||||
|
case bool = "Bool"
|
||||||
|
}
|
@ -30,25 +30,58 @@ class AnalyticsFileParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
private static func getParameters(from parameters: [AnalyticsParameterDTO]) -> [AnalyticsParameter] {
|
||||||
parameters.map { dtoParameter in
|
func verify(value: String?, for type: ParameterType) {
|
||||||
|
guard let value, value.isEmpty == false else { return }
|
||||||
|
|
||||||
|
switch type {
|
||||||
|
case .int:
|
||||||
|
if Int(value) == nil {
|
||||||
|
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||||
|
print(error.description)
|
||||||
|
Analytics.exit(withError: error)
|
||||||
|
}
|
||||||
|
case .bool:
|
||||||
|
if Bool(value.lowercased()) == nil {
|
||||||
|
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||||
|
print(error.description)
|
||||||
|
Analytics.exit(withError: error)
|
||||||
|
}
|
||||||
|
case .double:
|
||||||
|
if Double(value) == nil {
|
||||||
|
let error = AnalyticsError.invalidParameter("type of \(value) is not \(type)")
|
||||||
|
print(error.description)
|
||||||
|
Analytics.exit(withError: error)
|
||||||
|
}
|
||||||
|
case .string:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters.map { dtoParameter in
|
||||||
// Type
|
// Type
|
||||||
|
|
||||||
let type = dtoParameter.type.uppercasedFirst()
|
let type = dtoParameter.type.uppercasedFirst()
|
||||||
|
|
||||||
guard
|
guard let typeEnum = ParameterType(rawValue: type) else {
|
||||||
type == "String" ||
|
|
||||||
type == "Int" ||
|
|
||||||
type == "Double" ||
|
|
||||||
type == "Bool"
|
|
||||||
else {
|
|
||||||
let error = AnalyticsError.invalidParameter("type of \(dtoParameter.name)")
|
let error = AnalyticsError.invalidParameter("type of \(dtoParameter.name)")
|
||||||
print(error.description)
|
print(error.description)
|
||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dtoParameter.value != nil, dtoParameter.replaceIn != nil {
|
||||||
|
let error = AnalyticsError.invalidParameter("you can't set 'value' and 'replaceIn' for \(dtoParameter.name)")
|
||||||
|
print(error.description)
|
||||||
|
Analytics.exit(withError: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
verify(value: dtoParameter.value, for: typeEnum)
|
||||||
|
verify(value: dtoParameter.defaultValue, for: typeEnum)
|
||||||
|
|
||||||
let parameter = AnalyticsParameter(
|
let parameter = AnalyticsParameter(
|
||||||
name: dtoParameter.name,
|
name: dtoParameter.name,
|
||||||
type: type
|
type: typeEnum,
|
||||||
|
value: dtoParameter.value ?? "",
|
||||||
|
defaultValue: dtoParameter.defaultValue ?? ""
|
||||||
)
|
)
|
||||||
|
|
||||||
if let replaceIn = dtoParameter.replaceIn {
|
if let replaceIn = dtoParameter.replaceIn {
|
||||||
@ -103,6 +136,8 @@ class AnalyticsFileParser {
|
|||||||
Analytics.exit(withError: error)
|
Analytics.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
definition.path = path
|
||||||
|
} else if let path = screen.path {
|
||||||
definition.path = path
|
definition.path = path
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,6 +174,14 @@ class AnalyticsFileParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
definition.action = action
|
definition.action = action
|
||||||
|
} else {
|
||||||
|
if let category = event.category {
|
||||||
|
definition.category = category
|
||||||
|
}
|
||||||
|
|
||||||
|
if let action = event.action {
|
||||||
|
definition.action = action
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return definition
|
return definition
|
||||||
|
@ -8,10 +8,13 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import ToolCore
|
import ToolCore
|
||||||
|
|
||||||
|
enum OutputImageExtension: String {
|
||||||
|
case png
|
||||||
|
case svg
|
||||||
|
}
|
||||||
|
|
||||||
class XcassetsGenerator {
|
class XcassetsGenerator {
|
||||||
|
|
||||||
static let outputImageExtension = "png"
|
|
||||||
|
|
||||||
let forceGeneration: Bool
|
let forceGeneration: Bool
|
||||||
|
|
||||||
// MARK: - Init
|
// MARK: - Init
|
||||||
@ -60,13 +63,20 @@ class XcassetsGenerator {
|
|||||||
generatedAssetsPaths.append(imagesetName)
|
generatedAssetsPaths.append(imagesetName)
|
||||||
|
|
||||||
// Generate output images path
|
// Generate output images path
|
||||||
let output1x = "\(imagesetPath)/\(parsedImage.name).\(XcassetsGenerator.outputImageExtension)"
|
let output1x = "\(imagesetPath)/\(parsedImage.name).\(OutputImageExtension.png.rawValue)"
|
||||||
let output2x = "\(imagesetPath)/\(parsedImage.name)@2x.\(XcassetsGenerator.outputImageExtension)"
|
let output2x = "\(imagesetPath)/\(parsedImage.name)@2x.\(OutputImageExtension.png.rawValue)"
|
||||||
let output3x = "\(imagesetPath)/\(parsedImage.name)@3x.\(XcassetsGenerator.outputImageExtension)"
|
let output3x = "\(imagesetPath)/\(parsedImage.name)@3x.\(OutputImageExtension.png.rawValue)"
|
||||||
|
|
||||||
// Check if we need to convert image
|
// Check if we need to convert image
|
||||||
guard self.shouldGenerate(inputImagePath: imageData.path, xcassetImagePath: output1x) else {
|
|
||||||
//print("\(parsedImage.name) -> Not regenerating")
|
var needToGenerateForSvg = false
|
||||||
|
|
||||||
|
if imageData.ext == "svg" && !parsedImage.imageExtensions.contains(.png) {
|
||||||
|
needToGenerateForSvg = true
|
||||||
|
}
|
||||||
|
|
||||||
|
guard self.shouldGenerate(inputImagePath: imageData.path, xcassetImagePath: output1x, needToGenerateForSvg: needToGenerateForSvg) else {
|
||||||
|
print("\(parsedImage.name) -> Not regenerating")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,29 +90,55 @@ class XcassetsGenerator {
|
|||||||
print(error.description)
|
print(error.description)
|
||||||
Images.exit(withError: error)
|
Images.exit(withError: error)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
let documentsDirectory = try fileManager.contentsOfDirectory(atPath: imagesetPath)
|
||||||
|
for filePath in documentsDirectory {
|
||||||
|
try fileManager.removeItem(atPath: "\(imagesetPath)/\(filePath)")
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print("Error deleting previous assets")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert image
|
|
||||||
let convertArguments = parsedImage.convertArguments
|
let convertArguments = parsedImage.convertArguments
|
||||||
|
|
||||||
if imageData.ext == "svg" {
|
if imageData.ext == "svg" {
|
||||||
// /usr/local/bin/rsvg-convert path/to/image.png -w 200 -h 300 -o path/to/output.png
|
if parsedImage.imageExtensions.contains(.png) {
|
||||||
// /usr/local/bin/rsvg-convert path/to/image.png -w 200 -o path/to/output.png
|
|
||||||
// /usr/local/bin/rsvg-convert path/to/image.png -h 300 -o path/to/output.png
|
// /usr/local/bin/rsvg-convert path/to/image.png -w 200 -h 300 -o path/to/output.png
|
||||||
var command1x = ["\(svgConverter)", "\(imageData.path)"]
|
// /usr/local/bin/rsvg-convert path/to/image.png -w 200 -o path/to/output.png
|
||||||
var command2x = ["\(svgConverter)", "\(imageData.path)"]
|
// /usr/local/bin/rsvg-convert path/to/image.png -h 300 -o path/to/output.png
|
||||||
var command3x = ["\(svgConverter)", "\(imageData.path)"]
|
var command1x = ["\(svgConverter)", "\(imageData.path)"]
|
||||||
|
var command2x = ["\(svgConverter)", "\(imageData.path)"]
|
||||||
self.addConvertArgument(command: &command1x, convertArgument: convertArguments.x1)
|
var command3x = ["\(svgConverter)", "\(imageData.path)"]
|
||||||
self.addConvertArgument(command: &command2x, convertArgument: convertArguments.x2)
|
|
||||||
self.addConvertArgument(command: &command3x, convertArgument: convertArguments.x3)
|
self.addConvertArgument(command: &command1x, convertArgument: convertArguments.x1)
|
||||||
|
self.addConvertArgument(command: &command2x, convertArgument: convertArguments.x2)
|
||||||
command1x.append(contentsOf: ["-o", output1x])
|
self.addConvertArgument(command: &command3x, convertArgument: convertArguments.x3)
|
||||||
command2x.append(contentsOf: ["-o", output2x])
|
|
||||||
command3x.append(contentsOf: ["-o", output3x])
|
command1x.append(contentsOf: ["-o", output1x])
|
||||||
|
command2x.append(contentsOf: ["-o", output2x])
|
||||||
Shell.shell(command1x)
|
command3x.append(contentsOf: ["-o", output3x])
|
||||||
Shell.shell(command2x)
|
|
||||||
Shell.shell(command3x)
|
Shell.shell(command1x)
|
||||||
|
Shell.shell(command2x)
|
||||||
|
Shell.shell(command3x)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
let output = "\(imagesetPath)/\(parsedImage.name).\(OutputImageExtension.svg.rawValue)"
|
||||||
|
let tempURL = URL(fileURLWithPath: output)
|
||||||
|
|
||||||
|
do {
|
||||||
|
if FileManager.default.fileExists(atPath: tempURL.path) {
|
||||||
|
try FileManager.default.removeItem(atPath: tempURL.path)
|
||||||
|
}
|
||||||
|
try FileManager.default.copyItem(atPath: imageData.path, toPath: tempURL.path)
|
||||||
|
} catch {
|
||||||
|
print(error.localizedDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// convert path/to/image.png -resize 200x300 path/to/output.png
|
// convert path/to/image.png -resize 200x300 path/to/output.png
|
||||||
// convert path/to/image.png -resize 200x path/to/output.png
|
// convert path/to/image.png -resize 200x path/to/output.png
|
||||||
@ -119,7 +155,7 @@ class XcassetsGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write Content.json
|
// Write Content.json
|
||||||
guard let imagesetContentJson = parsedImage.contentJson else { return }
|
guard let imagesetContentJson = parsedImage.generateContentJson(isVector: imageData.ext == "svg") else { return }
|
||||||
let contentJsonFilePath = "\(imagesetPath)/Contents.json"
|
let contentJsonFilePath = "\(imagesetPath)/Contents.json"
|
||||||
|
|
||||||
let contentJsonFilePathURL = URL(fileURLWithPath: contentJsonFilePath)
|
let contentJsonFilePathURL = URL(fileURLWithPath: contentJsonFilePath)
|
||||||
@ -161,8 +197,8 @@ class XcassetsGenerator {
|
|||||||
|
|
||||||
// MARK: - Helpers: bypass generation
|
// MARK: - Helpers: bypass generation
|
||||||
|
|
||||||
private func shouldGenerate(inputImagePath: String, xcassetImagePath: String) -> Bool {
|
private func shouldGenerate(inputImagePath: String, xcassetImagePath: String, needToGenerateForSvg: Bool) -> Bool {
|
||||||
if forceGeneration {
|
if forceGeneration || needToGenerateForSvg {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,14 +7,30 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
enum TemplateRenderingIntent: String, Codable {
|
||||||
|
case template
|
||||||
|
case original
|
||||||
|
}
|
||||||
|
|
||||||
struct AssetContent: Codable, Equatable {
|
struct AssetContent: Codable, Equatable {
|
||||||
let images: [AssetImageDescription]
|
let images: [AssetImageDescription]
|
||||||
let info: AssetInfo
|
let info: AssetInfo
|
||||||
|
let properties: AssetProperties?
|
||||||
|
|
||||||
|
init(
|
||||||
|
images: [AssetImageDescription],
|
||||||
|
info: AssetInfo,
|
||||||
|
properties: AssetProperties? = nil
|
||||||
|
) {
|
||||||
|
self.images = images
|
||||||
|
self.info = info
|
||||||
|
self.properties = properties
|
||||||
|
}
|
||||||
|
|
||||||
static func == (lhs: AssetContent, rhs: AssetContent) -> Bool {
|
static func == (lhs: AssetContent, rhs: AssetContent) -> Bool {
|
||||||
guard lhs.images.count == rhs.images.count else { return false }
|
guard lhs.images.count == rhs.images.count else { return false }
|
||||||
let lhsImages = lhs.images.sorted(by: { $0.scale < $1.scale })
|
let lhsImages = lhs.images.sorted(by: { $0.filename < $1.filename })
|
||||||
let rhsImages = rhs.images.sorted(by: { $0.scale < $1.scale })
|
let rhsImages = rhs.images.sorted(by: { $0.filename < $1.filename })
|
||||||
|
|
||||||
return lhsImages == rhsImages
|
return lhsImages == rhsImages
|
||||||
}
|
}
|
||||||
@ -22,11 +38,39 @@ struct AssetContent: Codable, Equatable {
|
|||||||
|
|
||||||
struct AssetImageDescription: Codable, Equatable {
|
struct AssetImageDescription: Codable, Equatable {
|
||||||
let idiom: String
|
let idiom: String
|
||||||
let scale: String
|
let scale: String?
|
||||||
let filename: String
|
let filename: String
|
||||||
|
|
||||||
|
init(
|
||||||
|
idiom: String,
|
||||||
|
scale: String? = nil,
|
||||||
|
filename: String
|
||||||
|
) {
|
||||||
|
self.idiom = idiom
|
||||||
|
self.scale = scale
|
||||||
|
self.filename = filename
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AssetInfo: Codable, Equatable {
|
struct AssetInfo: Codable, Equatable {
|
||||||
let version: Int
|
let version: Int
|
||||||
let author: String
|
let author: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AssetProperties: Codable, Equatable {
|
||||||
|
let preservesVectorRepresentation: Bool
|
||||||
|
let templateRenderingIntent: TemplateRenderingIntent?
|
||||||
|
|
||||||
|
init(
|
||||||
|
preservesVectorRepresentation: Bool,
|
||||||
|
templateRenderingIntent: TemplateRenderingIntent? = nil
|
||||||
|
) {
|
||||||
|
self.preservesVectorRepresentation = preservesVectorRepresentation
|
||||||
|
self.templateRenderingIntent = templateRenderingIntent
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case preservesVectorRepresentation = "preserves-vector-representation"
|
||||||
|
case templateRenderingIntent = "template-rendering-intent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,12 +7,31 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
enum ImageExtension: String {
|
||||||
|
case png
|
||||||
|
}
|
||||||
|
|
||||||
struct ParsedImage {
|
struct ParsedImage {
|
||||||
let name: String
|
let name: String
|
||||||
let tags: String
|
let tags: String
|
||||||
let width: Int
|
let width: Int
|
||||||
let height: Int
|
let height: Int
|
||||||
|
let imageExtensions: [ImageExtension]
|
||||||
|
|
||||||
|
init(
|
||||||
|
name: String,
|
||||||
|
tags: String,
|
||||||
|
width: Int,
|
||||||
|
height: Int,
|
||||||
|
imageExtensions: [ImageExtension] = []
|
||||||
|
) {
|
||||||
|
self.name = name
|
||||||
|
self.tags = tags
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self.imageExtensions = imageExtensions
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Convert
|
// MARK: - Convert
|
||||||
|
|
||||||
var convertArguments: (x1: ConvertArgument, x2: ConvertArgument, x3: ConvertArgument) {
|
var convertArguments: (x1: ConvertArgument, x2: ConvertArgument, x3: ConvertArgument) {
|
||||||
@ -42,10 +61,12 @@ struct ParsedImage {
|
|||||||
|
|
||||||
// MARK: - Assets
|
// MARK: - Assets
|
||||||
|
|
||||||
var contentJson: String? {
|
func generateContentJson(isVector: Bool) -> String? {
|
||||||
let encoder = JSONEncoder()
|
let encoder = JSONEncoder()
|
||||||
encoder.outputFormatting = .prettyPrinted
|
encoder.outputFormatting = .prettyPrinted
|
||||||
|
|
||||||
|
let imageContent = generateImageContent(isVector: isVector)
|
||||||
|
|
||||||
guard let data = try? encoder.encode(imageContent) else {
|
guard let data = try? encoder.encode(imageContent) else {
|
||||||
let error = ImagesError.writeFile("Contents.json", "Error encoding json file")
|
let error = ImagesError.writeFile("Contents.json", "Error encoding json file")
|
||||||
print(error.description)
|
print(error.description)
|
||||||
@ -55,30 +76,52 @@ struct ParsedImage {
|
|||||||
return String(data: data, encoding: .utf8)
|
return String(data: data, encoding: .utf8)
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageContent: AssetContent {
|
func generateImageContent(isVector: Bool) -> AssetContent {
|
||||||
return AssetContent(
|
|
||||||
images: [
|
if !imageExtensions.contains(.png) && isVector {
|
||||||
AssetImageDescription(
|
//Generate svg
|
||||||
idiom: "universal",
|
return AssetContent(
|
||||||
scale: "1x",
|
images: [
|
||||||
filename: "\(name).\(XcassetsGenerator.outputImageExtension)"
|
AssetImageDescription(
|
||||||
|
idiom: "universal",
|
||||||
|
filename: "\(name).\(OutputImageExtension.svg.rawValue)"
|
||||||
|
)
|
||||||
|
],
|
||||||
|
info: AssetInfo(
|
||||||
|
version: 1,
|
||||||
|
author: "ResgenSwift-Imagium"
|
||||||
),
|
),
|
||||||
AssetImageDescription(
|
properties: AssetProperties(
|
||||||
idiom: "universal",
|
preservesVectorRepresentation: true,
|
||||||
scale: "2x",
|
templateRenderingIntent: .original
|
||||||
filename: "\(name)@2x.\(XcassetsGenerator.outputImageExtension)"
|
|
||||||
),
|
|
||||||
AssetImageDescription(
|
|
||||||
idiom: "universal",
|
|
||||||
scale: "3x",
|
|
||||||
filename: "\(name)@3x.\(XcassetsGenerator.outputImageExtension)"
|
|
||||||
)
|
)
|
||||||
],
|
|
||||||
info: AssetInfo(
|
|
||||||
version: 1,
|
|
||||||
author: "ResgenSwift-Imagium"
|
|
||||||
)
|
)
|
||||||
)
|
} else {
|
||||||
|
//Generate png
|
||||||
|
return AssetContent(
|
||||||
|
images: [
|
||||||
|
AssetImageDescription(
|
||||||
|
idiom: "universal",
|
||||||
|
scale: "1x",
|
||||||
|
filename: "\(name).\(OutputImageExtension.png.rawValue)"
|
||||||
|
),
|
||||||
|
AssetImageDescription(
|
||||||
|
idiom: "universal",
|
||||||
|
scale: "2x",
|
||||||
|
filename: "\(name)@2x.\(OutputImageExtension.png.rawValue)"
|
||||||
|
),
|
||||||
|
AssetImageDescription(
|
||||||
|
idiom: "universal",
|
||||||
|
scale: "3x",
|
||||||
|
filename: "\(name)@3x.\(OutputImageExtension.png.rawValue)"
|
||||||
|
)
|
||||||
|
],
|
||||||
|
info: AssetInfo(
|
||||||
|
version: 1,
|
||||||
|
author: "ResgenSwift-Imagium"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Extension property
|
// MARK: - Extension property
|
||||||
|
@ -38,11 +38,21 @@ class ImageFileParser {
|
|||||||
}
|
}
|
||||||
return Int(splittedLine[3])!
|
return Int(splittedLine[3])!
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let image = ParsedImage(name: String(splittedLine[1]), tags: String(splittedLine[0]), width: width, height: height)
|
var imageExtensions: [ImageExtension] = []
|
||||||
|
|
||||||
|
splittedLine.forEach { stringExtension in
|
||||||
|
if let imageExtension = ImageExtension(rawValue: String(stringExtension)) {
|
||||||
|
imageExtensions.append(imageExtension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let image = ParsedImage(name: String(splittedLine[1]), tags: String(splittedLine[0]), width: width, height: height, imageExtensions: imageExtensions)
|
||||||
imagesToGenerate.append(image)
|
imagesToGenerate.append(image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print(imagesToGenerate)
|
||||||
|
|
||||||
return imagesToGenerate.filter {
|
return imagesToGenerate.filter {
|
||||||
$0.tags.contains(platform.rawValue)
|
$0.tags.contains(platform.rawValue)
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@ class ImageFileParserTests: XCTestCase {
|
|||||||
#
|
#
|
||||||
# SMAAS Support
|
# SMAAS Support
|
||||||
#
|
#
|
||||||
id image_one 25 ?
|
id image_one 25 ? png
|
||||||
di image_two ? 50
|
di image_two ? 50 webp png
|
||||||
d image_three 25 ?
|
d image_three 25 ?
|
||||||
d image_four 75 ?
|
d image_four 75 ?
|
||||||
"""
|
"""
|
||||||
@ -38,13 +38,15 @@ class ImageFileParserTests: XCTestCase {
|
|||||||
XCTAssertEqual(firstImage!.tags, "id")
|
XCTAssertEqual(firstImage!.tags, "id")
|
||||||
XCTAssertEqual(firstImage!.width, 25)
|
XCTAssertEqual(firstImage!.width, 25)
|
||||||
XCTAssertEqual(firstImage!.height, -1)
|
XCTAssertEqual(firstImage!.height, -1)
|
||||||
|
XCTAssertEqual(firstImage!.imageExtensions, [.png])
|
||||||
|
|
||||||
let secondImage = parsedImages.first {
|
let secondImage = parsedImages.first {
|
||||||
$0.name == "image_two"
|
$0.name == "image_two"
|
||||||
}
|
}
|
||||||
XCTAssertEqual(secondImage!.name, "image_two")
|
XCTAssertEqual(secondImage!.name, "image_two")
|
||||||
XCTAssertEqual(secondImage!.tags, "di")
|
XCTAssertEqual(secondImage!.tags, "di")
|
||||||
XCTAssertEqual(secondImage!.width, -1)
|
XCTAssertEqual(secondImage!.width, -1)
|
||||||
XCTAssertEqual(secondImage!.height, 50)
|
XCTAssertEqual(secondImage!.height, 50)
|
||||||
|
XCTAssertEqual(firstImage!.imageExtensions, [.png])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ final class ParsedImageTests: XCTestCase {
|
|||||||
height: 10)
|
height: 10)
|
||||||
|
|
||||||
// When
|
// When
|
||||||
let property = parsedImage.imageContent
|
let property = parsedImage.generateImageContent(isVector: false)
|
||||||
|
|
||||||
// Expect
|
// Expect
|
||||||
let expect = AssetContent(
|
let expect = AssetContent(
|
||||||
@ -135,17 +135,17 @@ final class ParsedImageTests: XCTestCase {
|
|||||||
AssetImageDescription(
|
AssetImageDescription(
|
||||||
idiom: "universal",
|
idiom: "universal",
|
||||||
scale: "1x",
|
scale: "1x",
|
||||||
filename: "\(parsedImage.name).\(XcassetsGenerator.outputImageExtension)"
|
filename: "\(parsedImage.name).\(OutputImageExtension.png.rawValue)"
|
||||||
),
|
),
|
||||||
AssetImageDescription(
|
AssetImageDescription(
|
||||||
idiom: "universal",
|
idiom: "universal",
|
||||||
scale: "2x",
|
scale: "2x",
|
||||||
filename: "\(parsedImage.name)@2x.\(XcassetsGenerator.outputImageExtension)"
|
filename: "\(parsedImage.name)@2x.\(OutputImageExtension.png.rawValue)"
|
||||||
),
|
),
|
||||||
AssetImageDescription(
|
AssetImageDescription(
|
||||||
idiom: "universal",
|
idiom: "universal",
|
||||||
scale: "3x",
|
scale: "3x",
|
||||||
filename: "\(parsedImage.name)@3x.\(XcassetsGenerator.outputImageExtension)"
|
filename: "\(parsedImage.name)@3x.\(OutputImageExtension.png.rawValue)"
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
info: AssetInfo(
|
info: AssetInfo(
|
||||||
@ -156,4 +156,48 @@ final class ParsedImageTests: XCTestCase {
|
|||||||
|
|
||||||
XCTAssertEqual(property, expect)
|
XCTAssertEqual(property, expect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testAssetPng() {
|
||||||
|
// Given
|
||||||
|
let imageName = "the_name"
|
||||||
|
let parsedImage = ParsedImage(name: imageName,
|
||||||
|
tags: "id",
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
imageExtensions: [.png])
|
||||||
|
|
||||||
|
// When
|
||||||
|
let property = parsedImage.generateImageContent(isVector: false)
|
||||||
|
|
||||||
|
// Expect
|
||||||
|
|
||||||
|
let expect = AssetContent(
|
||||||
|
images: [
|
||||||
|
AssetImageDescription(
|
||||||
|
idiom: "universal",
|
||||||
|
scale: "1x",
|
||||||
|
filename: "\(parsedImage.name).\(OutputImageExtension.png.rawValue)"
|
||||||
|
),
|
||||||
|
AssetImageDescription(
|
||||||
|
idiom: "universal",
|
||||||
|
scale: "2x",
|
||||||
|
filename: "\(parsedImage.name)@2x.\(OutputImageExtension.png.rawValue)"
|
||||||
|
),
|
||||||
|
AssetImageDescription(
|
||||||
|
idiom: "universal",
|
||||||
|
scale: "3x",
|
||||||
|
filename: "\(parsedImage.name)@3x.\(OutputImageExtension.png.rawValue)"
|
||||||
|
)
|
||||||
|
],
|
||||||
|
info: AssetInfo(
|
||||||
|
version: 1,
|
||||||
|
author: "ResgenSwift-Imagium"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
debugPrint(property)
|
||||||
|
debugPrint(expect)
|
||||||
|
|
||||||
|
XCTAssertEqual(property, expect)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user