Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fdd23f4378 | |||
| 8d37744373 | |||
| b9aac55a76 | |||
| 7bbb702861 | |||
| 0118492162 | |||
| 6debae8162 | |||
| 434d427136 | |||
| 052f416741 | |||
| 4b944ed8c7 | |||
| 1f9af76b40 | |||
| 7247d20ae4 | |||
| 63404f8f20 | |||
| c4a3aa54d6 | |||
| b9e610a6d9 | |||
| 7c6a8d2ac3 | |||
| f0aac3a91b | |||
| f1ca8e92b7 | |||
|
|
436bc4b2af | ||
| e0e561ff7f | |||
| ed4e9849e7 | |||
| ddf1d2509f |
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
@@ -1,6 +1,6 @@
|
|||||||
library "openiumpipeline"
|
library "openiumpipeline"
|
||||||
|
|
||||||
env.DEVELOPER_DIR="/Applications/Xcode-16.3.0.app/Contents/Developer"
|
env.DEVELOPER_DIR="/Applications/Xcode-26.2.0.app/Contents/Developer"
|
||||||
// env.SIMULATOR_DEVICE_TYPES="iPhone-14-Pro"
|
// env.SIMULATOR_DEVICE_TYPES="iPhone-14-Pro"
|
||||||
// env.SLACK_CHANNEL = "prj-skdevkit"
|
// env.SLACK_CHANNEL = "prj-skdevkit"
|
||||||
env.IS_PACKAGE_SWIFT=1
|
env.IS_PACKAGE_SWIFT=1
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -1,7 +1,6 @@
|
|||||||
SHELL = /bin/zsh
|
SHELL = /bin/zsh
|
||||||
|
|
||||||
#INSTALL_DIR ?= /usr/local/bin
|
INSTALL_DIR = /usr/local/bin
|
||||||
INSTALL_DIR = /tmp/ResgenYolo
|
|
||||||
|
|
||||||
MAN_DIR := /usr/local/share/man
|
MAN_DIR := /usr/local/share/man
|
||||||
MAN_PAGE_NAME = resgen-swift.1
|
MAN_PAGE_NAME = resgen-swift.1
|
||||||
@@ -14,7 +13,7 @@ BUILD_DIR = $(REPO_DIR)/.build
|
|||||||
|
|
||||||
# create-man-files:
|
# create-man-files:
|
||||||
# swift package plugin generate-manual
|
# swift package plugin generate-manual
|
||||||
# cp $(BUILDDIR)/plugins/GenerateManualPlugin/outputs/ResgenSwift/resgen-swift.1 $(REPODIR)/man/resgen-swift.1
|
# cp $(BUILDDIR)/plugins/GenerateManual/outputs/ResgenSwift/resgen-swift.1 $(REPODIR)/man/resgen-swift.1
|
||||||
|
|
||||||
# install-man-files:
|
# install-man-files:
|
||||||
# mkdir -p ${DESTDIR}${mandir}/man1
|
# mkdir -p ${DESTDIR}${mandir}/man1
|
||||||
@@ -23,7 +22,7 @@ BUILD_DIR = $(REPO_DIR)/.build
|
|||||||
create-and-install-man-files:
|
create-and-install-man-files:
|
||||||
swift package plugin generate-manual
|
swift package plugin generate-manual
|
||||||
mkdir -p ${MAN_DIR}/man1
|
mkdir -p ${MAN_DIR}/man1
|
||||||
cp $(BUILD_DIR)/plugins/GenerateManualPlugin/outputs/ResgenSwift/${MAN_PAGE_NAME} ${MAN_DIR}/man1/${MAN_PAGE_NAME}
|
cp $(BUILD_DIR)/plugins/GenerateManual/outputs/ResgenSwift/${MAN_PAGE_NAME} ${MAN_DIR}/man1/${MAN_PAGE_NAME}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Build and install
|
# Build and install
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"originHash" : "fae67d9ce14b6664edc4151ad1a55b74d50d7281499f09eeca50b0376d0f837f",
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
{
|
||||||
"identity" : "swift-argument-parser",
|
"identity" : "swift-argument-parser",
|
||||||
@@ -14,8 +15,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/lukepistrol/SwiftLintPlugin",
|
"location" : "https://github.com/lukepistrol/SwiftLintPlugin",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "87454f5c9ff4d644086aec2a0df1ffba678e7f3c",
|
"revision" : "8e785a9801fc7961fef3d41ccb81acb3bd3d9735",
|
||||||
"version" : "0.57.1"
|
"version" : "0.60.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -28,5 +29,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version" : 2
|
"version" : 3
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// swift-tools-version:5.9
|
// swift-tools-version:6.1
|
||||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
import PackageDescription
|
import PackageDescription
|
||||||
@@ -18,7 +18,7 @@ let package = Package(
|
|||||||
),
|
),
|
||||||
.package(
|
.package(
|
||||||
url: "https://github.com/lukepistrol/SwiftLintPlugin",
|
url: "https://github.com/lukepistrol/SwiftLintPlugin",
|
||||||
exact: "0.57.1"
|
exact: "0.60.0"
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
|
|||||||
@@ -6,16 +6,16 @@ extension ColorYolo {
|
|||||||
|
|
||||||
/// Color red is #FF0000 (light) or #FF0000 (dark)"
|
/// Color red is #FF0000 (light) or #FF0000 (dark)"
|
||||||
public var red: Color {
|
public var red: Color {
|
||||||
Color("red")
|
Color("red", bundle: Bundle.main)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
|
/// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
|
||||||
public var green_alpha_50: Color {
|
public var green_alpha_50: Color {
|
||||||
Color("green_alpha_50")
|
Color("green_alpha_50", bundle: Bundle.main)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
|
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
|
||||||
public var blue_light_dark: Color {
|
public var blue_light_dark: Color {
|
||||||
Color("blue_light_dark")
|
Color("blue_light_dark", bundle: Bundle.main)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,16 @@ extension UIColorYolo {
|
|||||||
|
|
||||||
/// Color red is #FF0000 (light) or #FF0000 (dark)"
|
/// Color red is #FF0000 (light) or #FF0000 (dark)"
|
||||||
@objc public var red: UIColor {
|
@objc public var red: UIColor {
|
||||||
UIColor(named: "red")!
|
UIColor(named: "red", in: Bundle.main, compatibleWith: nil)!
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
|
/// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
|
||||||
@objc public var green_alpha_50: UIColor {
|
@objc public var green_alpha_50: UIColor {
|
||||||
UIColor(named: "green_alpha_50")!
|
UIColor(named: "green_alpha_50", in: Bundle.main, compatibleWith: nil)!
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
|
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
|
||||||
@objc public var blue_light_dark: UIColor {
|
@objc public var blue_light_dark: UIColor {
|
||||||
UIColor(named: "blue_light_dark")!
|
UIColor(named: "blue_light_dark", in: Bundle.main, compatibleWith: nil)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,26 +6,26 @@ import SwiftUI
|
|||||||
extension ImageYolo {
|
extension ImageYolo {
|
||||||
|
|
||||||
public var article_notification_pull_detail: Image {
|
public var article_notification_pull_detail: Image {
|
||||||
Image("article_notification_pull_detail")
|
Image("article_notification_pull_detail", bundle: Bundle.main)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var article_notification_pull: Image {
|
public var article_notification_pull: Image {
|
||||||
Image("article_notification_pull")
|
Image("article_notification_pull", bundle: Bundle.main)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var new_article: Image {
|
public var new_article: Image {
|
||||||
Image("new_article")
|
Image("new_article", bundle: Bundle.main)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var welcome_background: Image {
|
public var welcome_background: Image {
|
||||||
Image("welcome_background")
|
Image("welcome_background", bundle: Bundle.main)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var article_trash: Image {
|
public var article_trash: Image {
|
||||||
Image("article_trash")
|
Image("article_trash", bundle: Bundle.main)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var ic_close_article: Image {
|
public var ic_close_article: Image {
|
||||||
Image("ic_close_article")
|
Image("ic_close_article", bundle: Bundle.main)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,26 +6,26 @@ import UIKit
|
|||||||
extension UIImageYolo {
|
extension UIImageYolo {
|
||||||
|
|
||||||
public var article_notification_pull_detail: UIImage {
|
public var article_notification_pull_detail: UIImage {
|
||||||
UIImage(named: "article_notification_pull_detail")!
|
UIImage(named: "article_notification_pull_detail", in: Bundle.main, with: nil)!
|
||||||
}
|
}
|
||||||
|
|
||||||
public var article_notification_pull: UIImage {
|
public var article_notification_pull: UIImage {
|
||||||
UIImage(named: "article_notification_pull")!
|
UIImage(named: "article_notification_pull", in: Bundle.main, with: nil)!
|
||||||
}
|
}
|
||||||
|
|
||||||
public var new_article: UIImage {
|
public var new_article: UIImage {
|
||||||
UIImage(named: "new_article")!
|
UIImage(named: "new_article", in: Bundle.main, with: nil)!
|
||||||
}
|
}
|
||||||
|
|
||||||
public var welcome_background: UIImage {
|
public var welcome_background: UIImage {
|
||||||
UIImage(named: "welcome_background")!
|
UIImage(named: "welcome_background", in: Bundle.main, with: nil)!
|
||||||
}
|
}
|
||||||
|
|
||||||
public var article_trash: UIImage {
|
public var article_trash: UIImage {
|
||||||
UIImage(named: "article_trash")!
|
UIImage(named: "article_trash", in: Bundle.main, with: nil)!
|
||||||
}
|
}
|
||||||
|
|
||||||
public var ic_close_article: UIImage {
|
public var ic_close_article: UIImage {
|
||||||
UIImage(named: "ic_close_article")!
|
UIImage(named: "ic_close_article", in: Bundle.main, with: nil)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ fileprivate let kStringsFileName = "sampleStrings"
|
|||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
|
|
||||||
internal enum KeyGenAllScript: String {
|
public enum KeyGenAllScript: String {
|
||||||
case param_lang = "param_lang"
|
case param_lang = "param_lang"
|
||||||
case generic_back = "generic_back"
|
case generic_back = "generic_back"
|
||||||
case generic_loading_data = "generic_loading_data"
|
case generic_loading_data = "generic_loading_data"
|
||||||
@@ -14,7 +14,7 @@ extension String {
|
|||||||
case test_equal_symbol = "test_equal_symbol"
|
case test_equal_symbol = "test_equal_symbol"
|
||||||
case placeholders_test_one = "placeholders_test_one"
|
case placeholders_test_one = "placeholders_test_one"
|
||||||
|
|
||||||
internal var keyPath: KeyPath<String, String> {
|
public var keyPath: KeyPath<String, String> {
|
||||||
switch self {
|
switch self {
|
||||||
case .param_lang: return \String.param_lang
|
case .param_lang: return \String.param_lang
|
||||||
case .generic_back: return \String.generic_back
|
case .generic_back: return \String.generic_back
|
||||||
@@ -33,7 +33,7 @@ extension String {
|
|||||||
///
|
///
|
||||||
/// Comment :
|
/// Comment :
|
||||||
/// No comment
|
/// No comment
|
||||||
internal var param_lang: String {
|
public var param_lang: String {
|
||||||
NSLocalizedString("param_lang", tableName: kStringsFileName, bundle: Bundle.main, value: "en", comment: "")
|
NSLocalizedString("param_lang", tableName: kStringsFileName, bundle: Bundle.main, value: "en", comment: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ extension String {
|
|||||||
///
|
///
|
||||||
/// Comment :
|
/// Comment :
|
||||||
/// No comment
|
/// No comment
|
||||||
internal var generic_back: String {
|
public var generic_back: String {
|
||||||
NSLocalizedString("generic_back", tableName: kStringsFileName, bundle: Bundle.main, value: "Back", comment: "")
|
NSLocalizedString("generic_back", tableName: kStringsFileName, bundle: Bundle.main, value: "Back", comment: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ extension String {
|
|||||||
///
|
///
|
||||||
/// Comment :
|
/// Comment :
|
||||||
/// No comment
|
/// No comment
|
||||||
internal var generic_loading_data: String {
|
public var generic_loading_data: String {
|
||||||
NSLocalizedString("generic_loading_data", tableName: kStringsFileName, bundle: Bundle.main, value: "Loading\ndata...", comment: "")
|
NSLocalizedString("generic_loading_data", tableName: kStringsFileName, bundle: Bundle.main, value: "Loading\ndata...", comment: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ extension String {
|
|||||||
///
|
///
|
||||||
/// Comment :
|
/// Comment :
|
||||||
/// No comment
|
/// No comment
|
||||||
internal var generic_welcome_firstname_format: String {
|
public var generic_welcome_firstname_format: String {
|
||||||
NSLocalizedString("generic_welcome_firstname_format", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" !", comment: "")
|
NSLocalizedString("generic_welcome_firstname_format", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" !", comment: "")
|
||||||
}
|
}
|
||||||
/// Translation in en :
|
/// Translation in en :
|
||||||
@@ -70,7 +70,7 @@ extension String {
|
|||||||
///
|
///
|
||||||
/// Comment :
|
/// Comment :
|
||||||
/// No comment
|
/// No comment
|
||||||
internal func generic_welcome_firstname_format(arg0: String) -> String {
|
public func generic_welcome_firstname_format(arg0: String) -> String {
|
||||||
String(format: self.generic_welcome_firstname_format, arg0)
|
String(format: self.generic_welcome_firstname_format, arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ extension String {
|
|||||||
///
|
///
|
||||||
/// Comment :
|
/// Comment :
|
||||||
/// No comment
|
/// No comment
|
||||||
internal var test_equal_symbol: String {
|
public var test_equal_symbol: String {
|
||||||
NSLocalizedString("test_equal_symbol", tableName: kStringsFileName, bundle: Bundle.main, value: "1€ = 1 point !", comment: "")
|
NSLocalizedString("test_equal_symbol", tableName: kStringsFileName, bundle: Bundle.main, value: "1€ = 1 point !", comment: "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ extension String {
|
|||||||
///
|
///
|
||||||
/// Comment :
|
/// Comment :
|
||||||
/// No comment
|
/// No comment
|
||||||
internal var placeholders_test_one: String {
|
public var placeholders_test_one: String {
|
||||||
NSLocalizedString("placeholders_test_one", tableName: kStringsFileName, bundle: Bundle.main, value: "You %%: %2$@ %1$@ Age: %3$d", comment: "")
|
NSLocalizedString("placeholders_test_one", tableName: kStringsFileName, bundle: Bundle.main, value: "You %%: %2$@ %1$@ Age: %3$d", comment: "")
|
||||||
}
|
}
|
||||||
/// Translation in en :
|
/// Translation in en :
|
||||||
@@ -100,7 +100,7 @@ extension String {
|
|||||||
///
|
///
|
||||||
/// Comment :
|
/// Comment :
|
||||||
/// No comment
|
/// No comment
|
||||||
internal func placeholders_test_one(arg0: String, arg1: String, arg2: Int) -> String {
|
public func placeholders_test_one(arg0: String, arg1: String, arg2: Int) -> String {
|
||||||
String(format: self.placeholders_test_one, arg0, arg1, arg2)
|
String(format: self.placeholders_test_one, arg0, arg1, arg2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import MatomoTracker
|
import MatomoTracker
|
||||||
import FirebaseAnalytics
|
import FirebaseAnalytics
|
||||||
|
import os
|
||||||
|
|
||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
|
|
||||||
public protocol AnalyticsManagerProtocol {
|
internal protocol AnalyticsManagerProtocol {
|
||||||
|
|
||||||
func logScreen(
|
func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
@@ -63,7 +64,7 @@ class MatomoAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
) {
|
) {
|
||||||
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)" + "/yolo")
|
||||||
tracker.track(
|
tracker.track(
|
||||||
view: [name],
|
view: [name],
|
||||||
url: urlString
|
url: urlString
|
||||||
@@ -106,7 +107,7 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
]
|
]
|
||||||
|
|
||||||
if path.isEmpty == false {
|
if path.isEmpty == false {
|
||||||
parameters["path"] = path + "/iOS" as NSObject
|
parameters["path"] = path + "/yolo" as NSObject
|
||||||
}
|
}
|
||||||
|
|
||||||
if let supplementaryParameters = params {
|
if let supplementaryParameters = params {
|
||||||
@@ -133,7 +134,7 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
var parameters: [String:NSObject] = [
|
var parameters: [String: NSObject] = [
|
||||||
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -170,7 +171,7 @@ class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
|
|||||||
|
|
||||||
// MARK: - Traker Type
|
// MARK: - Traker Type
|
||||||
|
|
||||||
public enum TrackerType: CaseIterable {
|
internal enum TrackerType: CaseIterable {
|
||||||
|
|
||||||
case matomo
|
case matomo
|
||||||
case firebase
|
case firebase
|
||||||
@@ -178,9 +179,10 @@ public enum TrackerType: CaseIterable {
|
|||||||
|
|
||||||
// MARK: - Manager
|
// MARK: - Manager
|
||||||
|
|
||||||
public class AnalyticsManager {
|
internal class AnalyticsManager {
|
||||||
|
|
||||||
public static var shared = AnalyticsManager()
|
@MainActor
|
||||||
|
internal static var shared = AnalyticsManager()
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
|
|
||||||
@@ -188,6 +190,8 @@ public class AnalyticsManager {
|
|||||||
|
|
||||||
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
||||||
|
|
||||||
|
private var isDebugMode: Bool = false
|
||||||
|
|
||||||
private var isEnabled: Bool {
|
private var isEnabled: Bool {
|
||||||
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||||||
false
|
false
|
||||||
@@ -196,6 +200,8 @@ public class AnalyticsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let logger = Logger(subsystem: "resgen", category: "analytics")
|
||||||
|
|
||||||
// MARK: - Enable Methods
|
// MARK: - Enable Methods
|
||||||
|
|
||||||
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||||
@@ -208,15 +214,16 @@ public class AnalyticsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
internal func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||||
setAnalytics(enable: true, analytics)
|
setAnalytics(enable: true, analytics)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
internal func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||||
setAnalytics(enable: false, analytics)
|
setAnalytics(enable: false, analytics)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func configure(siteId: String, url: String) {
|
internal func configure(siteId: String, url: String, isDebugMode: Bool = false) {
|
||||||
|
self.isDebugMode = isDebugMode
|
||||||
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||||||
siteId: siteId,
|
siteId: siteId,
|
||||||
url: url
|
url: url
|
||||||
@@ -226,14 +233,40 @@ public class AnalyticsManager {
|
|||||||
|
|
||||||
// MARK: - Private Log Methods
|
// MARK: - Private Log Methods
|
||||||
|
|
||||||
|
private func formattedParams(_ params: [String: Any]?) -> String {
|
||||||
|
guard let params = params, !params.isEmpty else { return "-" }
|
||||||
|
|
||||||
|
let formattedParams = params.map { key, value in
|
||||||
|
" \(key): \(value)"
|
||||||
|
}
|
||||||
|
.joined(separator: "\n")
|
||||||
|
|
||||||
|
return "\n" + formattedParams
|
||||||
|
}
|
||||||
|
|
||||||
private func logScreen(
|
private func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else {
|
||||||
|
if isDebugMode {
|
||||||
|
logger.log("Analytics disabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
|
|
||||||
|
if isDebugMode {
|
||||||
|
logger.debug("""
|
||||||
|
🖥️ Screen:
|
||||||
|
Name: \(name, privacy: .public)
|
||||||
|
Path: \(path, privacy: .public)
|
||||||
|
Params: \(self.formattedParams(params), privacy: .public)
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
manager.logScreen(
|
manager.logScreen(
|
||||||
name: name,
|
name: name,
|
||||||
path: path,
|
path: path,
|
||||||
@@ -248,9 +281,25 @@ public class AnalyticsManager {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else {
|
||||||
|
if isDebugMode {
|
||||||
|
logger.log("Analytics disabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
|
|
||||||
|
if isDebugMode {
|
||||||
|
logger.debug("""
|
||||||
|
📊 Event:
|
||||||
|
Name: \(name, privacy: .public)
|
||||||
|
Action: \(action.isEmpty ? "-" : action, privacy: .public)
|
||||||
|
Category: \(category.isEmpty ? "-" : category, privacy: .public)
|
||||||
|
Params: \(self.formattedParams(params), privacy: .public)
|
||||||
|
""")
|
||||||
|
}
|
||||||
|
|
||||||
manager.logEvent(
|
manager.logEvent(
|
||||||
name: name,
|
name: name,
|
||||||
action: action,
|
action: action,
|
||||||
@@ -262,7 +311,7 @@ public class AnalyticsManager {
|
|||||||
|
|
||||||
// MARK: - section_one
|
// MARK: - section_one
|
||||||
|
|
||||||
public func logScreenS1DefOne(title: String) {
|
internal func logScreenS1DefOne(title: String) {
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "s1 def one \(title)",
|
name: "s1 def one \(title)",
|
||||||
path: "s1_def_one/\(title)",
|
path: "s1_def_one/\(title)",
|
||||||
@@ -270,7 +319,7 @@ public class AnalyticsManager {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func logEventS1DefTwo(
|
internal func logEventS1DefTwo(
|
||||||
title: String,
|
title: String,
|
||||||
count: String,
|
count: String,
|
||||||
test2: String = "test"
|
test2: String = "test"
|
||||||
@@ -290,10 +339,10 @@ public class AnalyticsManager {
|
|||||||
|
|
||||||
// MARK: - section_two
|
// MARK: - section_two
|
||||||
|
|
||||||
public func logScreenS2DefOne() {
|
internal func logScreenS2DefOne() {
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "s2 def one",
|
name: "s2 def one",
|
||||||
path: "s2_def_one/",
|
path: "s2_def_one",
|
||||||
params: nil
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
29
SampleFiles/Tags/R.swift
Normal file
29
SampleFiles/Tags/R.swift
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Generated by ResgenSwift.Generate 2.2.0
|
||||||
|
|
||||||
|
class R: Sendable {
|
||||||
|
static let images = R2Image()
|
||||||
|
static let strings = R2String()
|
||||||
|
static let fonts = R2Font()
|
||||||
|
static let images = R2Image()
|
||||||
|
static let ui = R2UI()
|
||||||
|
}
|
||||||
|
|
||||||
|
final class R2Image: Sendable {}
|
||||||
|
|
||||||
|
final class R2String: Sendable {}
|
||||||
|
|
||||||
|
final class R2Font: Sendable {}
|
||||||
|
|
||||||
|
final class R2Image: Sendable {}
|
||||||
|
|
||||||
|
class R2UI: Sendable {
|
||||||
|
let images = R2UIImage()
|
||||||
|
let fonts = R2UIFont()
|
||||||
|
let images = R2UIImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
final class R2UIImage: Sendable {}
|
||||||
|
|
||||||
|
final class R2UIFont: Sendable {}
|
||||||
|
|
||||||
|
final class R2UIImage: Sendable {}
|
||||||
@@ -33,7 +33,7 @@ categories:
|
|||||||
screens:
|
screens:
|
||||||
- id: s2_def_one
|
- id: s2_def_one
|
||||||
name: s2 def one
|
name: s2 def one
|
||||||
path: s2_def_one/
|
path: s2_def_one///
|
||||||
tags: ios
|
tags: ios
|
||||||
|
|
||||||
events:
|
events:
|
||||||
|
|||||||
@@ -33,13 +33,13 @@ FORCE_FLAG="$1"
|
|||||||
#echo "\n-------------------------\n"
|
#echo "\n-------------------------\n"
|
||||||
|
|
||||||
## Strings
|
## Strings
|
||||||
swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/sampleStrings.txt" \
|
#swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/sampleStrings.txt" \
|
||||||
--output-path "./Strings/Generated" \
|
# --output-path "./Strings/Generated" \
|
||||||
--langs "fr en en-us" \
|
# --langs "fr en en-us" \
|
||||||
--default-lang "en" \
|
# --default-lang "en" \
|
||||||
--extension-output-path "./Strings/Generated" \
|
# --extension-output-path "./Strings/Generated" \
|
||||||
--extension-name "String" \
|
# --extension-name "String" \
|
||||||
--extension-suffix "GenAllScript"
|
# --extension-suffix "GenAllScript"
|
||||||
|
|
||||||
#echo "\n-------------------------\n"
|
#echo "\n-------------------------\n"
|
||||||
#
|
#
|
||||||
@@ -53,12 +53,10 @@ swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/sample
|
|||||||
#echo "\n-------------------------\n"
|
#echo "\n-------------------------\n"
|
||||||
#
|
#
|
||||||
## Analytics
|
## Analytics
|
||||||
#swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \
|
swift run -c release ResgenSwift analytics -f "./Tags/sampleTags.yml" \
|
||||||
# --target "firebase" \
|
--target "firebase matomo" \
|
||||||
# --extension-output-path "./Tags/Generated" \
|
--output-file "./Tags/Generated/Analytics+GenAllScript.swift" \
|
||||||
# --extension-name "Analytics" \
|
--path-suffix "sampleApp"
|
||||||
# --extension-suffix "GenAllScript" \
|
|
||||||
# --static-members true
|
|
||||||
#
|
#
|
||||||
#echo "\n-------------------------\n"
|
#echo "\n-------------------------\n"
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -90,7 +90,8 @@ analytics:
|
|||||||
inputFile: ./Tags/sampleTags.yml
|
inputFile: ./Tags/sampleTags.yml
|
||||||
target: "matomo firebase"
|
target: "matomo firebase"
|
||||||
outputFile: ./Tags/Generated/Analytics+GenAllScript.swift
|
outputFile: ./Tags/Generated/Analytics+GenAllScript.swift
|
||||||
visibility: public
|
visibility: internal
|
||||||
|
pathSuffix: "yolo"
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct Analytics: ParsableCommand {
|
|||||||
|
|
||||||
// MARK: - Command Configuration
|
// MARK: - Command Configuration
|
||||||
|
|
||||||
static var configuration = CommandConfiguration(
|
static let configuration = CommandConfiguration(
|
||||||
abstract: "Generate analytics extension file.",
|
abstract: "Generate analytics extension file.",
|
||||||
version: ResgenSwiftVersion
|
version: ResgenSwiftVersion
|
||||||
)
|
)
|
||||||
@@ -38,11 +38,11 @@ struct Analytics: ParsableCommand {
|
|||||||
|
|
||||||
print("[\(Self.toolName)] Will generate analytics")
|
print("[\(Self.toolName)] Will generate analytics")
|
||||||
|
|
||||||
// Check requirements
|
|
||||||
guard checkRequirements() else { return }
|
|
||||||
|
|
||||||
// Parse input file
|
// Parse input file
|
||||||
let sections = AnalyticsFileParser().parse(options.inputFile, target: options.target)
|
let sections = AnalyticsFileParser().parse(
|
||||||
|
options.inputFile,
|
||||||
|
target: options.target
|
||||||
|
)
|
||||||
|
|
||||||
// Generate extension
|
// Generate extension
|
||||||
AnalyticsGenerator.writeExtensionFiles(
|
AnalyticsGenerator.writeExtensionFiles(
|
||||||
@@ -51,7 +51,8 @@ struct Analytics: ParsableCommand {
|
|||||||
tags: ["ios", "iosonly"],
|
tags: ["ios", "iosonly"],
|
||||||
isStatic: options.staticMembers,
|
isStatic: options.staticMembers,
|
||||||
outputFile: options.outputFile,
|
outputFile: options.outputFile,
|
||||||
visibility: options.extensionVisibility
|
visibility: options.extensionVisibility,
|
||||||
|
pathSuffix: options.pathSuffix
|
||||||
)
|
)
|
||||||
|
|
||||||
print("[\(Self.toolName)] Analytics generated")
|
print("[\(Self.toolName)] Analytics generated")
|
||||||
|
|||||||
@@ -44,4 +44,9 @@ struct AnalyticsOptions: ParsableArguments {
|
|||||||
completion: .list(["public", "private", "package", "internal"])
|
completion: .list(["public", "private", "package", "internal"])
|
||||||
)
|
)
|
||||||
var extensionVisibility: ExtensionVisibility = .internal
|
var extensionVisibility: ExtensionVisibility = .internal
|
||||||
|
|
||||||
|
@Option(
|
||||||
|
help: "Suffix to add to every path parameters. Default is 'iOS'."
|
||||||
|
)
|
||||||
|
var pathSuffix: String = "iOS"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ enum AnalyticsGenerator {
|
|||||||
tags: [String],
|
tags: [String],
|
||||||
isStatic: Bool,
|
isStatic: Bool,
|
||||||
outputFile: String,
|
outputFile: String,
|
||||||
visibility: ExtensionVisibility
|
visibility: ExtensionVisibility,
|
||||||
|
pathSuffix: String
|
||||||
) {
|
) {
|
||||||
// Get target type from enum
|
// Get target type from enum
|
||||||
let targetsString: [String] = target.components(separatedBy: " ")
|
let targetsString: [String] = target.components(separatedBy: " ")
|
||||||
@@ -44,7 +45,8 @@ enum AnalyticsGenerator {
|
|||||||
sections: sections,
|
sections: sections,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
isStatic: isStatic,
|
isStatic: isStatic,
|
||||||
visibility: visibility
|
visibility: visibility,
|
||||||
|
pathSuffix: pathSuffix
|
||||||
)
|
)
|
||||||
|
|
||||||
// Write content
|
// Write content
|
||||||
@@ -65,13 +67,15 @@ enum AnalyticsGenerator {
|
|||||||
sections: [AnalyticsCategory],
|
sections: [AnalyticsCategory],
|
||||||
tags: [String],
|
tags: [String],
|
||||||
isStatic: Bool,
|
isStatic: Bool,
|
||||||
visibility: ExtensionVisibility
|
visibility: ExtensionVisibility,
|
||||||
|
pathSuffix: String
|
||||||
) -> String {
|
) -> String {
|
||||||
[
|
[
|
||||||
getHeader(
|
getHeader(
|
||||||
targets: targets,
|
targets: targets,
|
||||||
isStatic: isStatic,
|
isStatic: isStatic,
|
||||||
visibility: visibility
|
visibility: visibility,
|
||||||
|
pathSuffix: pathSuffix
|
||||||
),
|
),
|
||||||
getProperties(
|
getProperties(
|
||||||
sections: sections,
|
sections: sections,
|
||||||
@@ -89,14 +93,15 @@ enum AnalyticsGenerator {
|
|||||||
private static func getHeader(
|
private static func getHeader(
|
||||||
targets: [TrackerType],
|
targets: [TrackerType],
|
||||||
isStatic: Bool,
|
isStatic: Bool,
|
||||||
visibility: ExtensionVisibility
|
visibility: ExtensionVisibility,
|
||||||
|
pathSuffix: String
|
||||||
) -> String {
|
) -> String {
|
||||||
"""
|
"""
|
||||||
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
|
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
|
||||||
|
|
||||||
\(Self.getImport(targets: targets))
|
\(Self.getImport(targets: targets))
|
||||||
|
|
||||||
\(Self.getAnalyticsProtocol(targets: targets, visibility: visibility))
|
\(Self.getAnalyticsProtocol(targets: targets, visibility: visibility, pathSuffix: pathSuffix))
|
||||||
|
|
||||||
\(Self.getTrackerTypeEnum(targets: targets, visibility: visibility))
|
\(Self.getTrackerTypeEnum(targets: targets, visibility: visibility))
|
||||||
|
|
||||||
@@ -104,6 +109,7 @@ enum AnalyticsGenerator {
|
|||||||
|
|
||||||
\(visibility) class AnalyticsManager {
|
\(visibility) class AnalyticsManager {
|
||||||
|
|
||||||
|
@MainActor
|
||||||
\(visibility) static var shared = AnalyticsManager()
|
\(visibility) static var shared = AnalyticsManager()
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
@@ -143,6 +149,8 @@ enum AnalyticsGenerator {
|
|||||||
visibility: ExtensionVisibility
|
visibility: ExtensionVisibility
|
||||||
) -> String {
|
) -> String {
|
||||||
"""
|
"""
|
||||||
|
private var isDebugMode: Bool = false
|
||||||
|
|
||||||
private var isEnabled: Bool {
|
private var isEnabled: Bool {
|
||||||
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||||||
false
|
false
|
||||||
@@ -151,6 +159,8 @@ enum AnalyticsGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let logger = Logger(subsystem: "resgen", category: "analytics")
|
||||||
|
|
||||||
// MARK: - Enable Methods
|
// MARK: - Enable Methods
|
||||||
|
|
||||||
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||||
@@ -186,6 +196,8 @@ enum AnalyticsGenerator {
|
|||||||
result.append("import FirebaseAnalytics")
|
result.append("import FirebaseAnalytics")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.append("import os")
|
||||||
|
|
||||||
return result.joined(separator: "\n")
|
return result.joined(separator: "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,14 +205,40 @@ enum AnalyticsGenerator {
|
|||||||
"""
|
"""
|
||||||
// MARK: - Private Log Methods
|
// MARK: - Private Log Methods
|
||||||
|
|
||||||
|
private func formattedParams(_ params: [String: Any]?) -> String {
|
||||||
|
guard let params = params, !params.isEmpty else { return "-" }
|
||||||
|
|
||||||
|
let formattedParams = params.map { key, value in
|
||||||
|
" \\(key): \\(value)"
|
||||||
|
}
|
||||||
|
.joined(separator: "\\n")
|
||||||
|
|
||||||
|
return "\\n" + formattedParams
|
||||||
|
}
|
||||||
|
|
||||||
private func logScreen(
|
private func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else {
|
||||||
|
if isDebugMode {
|
||||||
|
logger.log("Analytics disabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
|
|
||||||
|
if isDebugMode {
|
||||||
|
logger.debug(\"""
|
||||||
|
🖥️ Screen:
|
||||||
|
Name: \\(name, privacy: .public)
|
||||||
|
Path: \\(path, privacy: .public)
|
||||||
|
Params: \\(self.formattedParams(params), privacy: .public)
|
||||||
|
\""")
|
||||||
|
}
|
||||||
|
|
||||||
manager.logScreen(
|
manager.logScreen(
|
||||||
name: name,
|
name: name,
|
||||||
path: path,
|
path: path,
|
||||||
@@ -215,9 +253,25 @@ enum AnalyticsGenerator {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else {
|
||||||
|
if isDebugMode {
|
||||||
|
logger.log("Analytics disabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
|
|
||||||
|
if isDebugMode {
|
||||||
|
logger.debug(\"""
|
||||||
|
📊 Event:
|
||||||
|
Name: \\(name, privacy: .public)
|
||||||
|
Action: \\(action.isEmpty ? "-" : action, privacy: .public)
|
||||||
|
Category: \\(category.isEmpty ? "-" : category, privacy: .public)
|
||||||
|
Params: \\(self.formattedParams(params), privacy: .public)
|
||||||
|
\""")
|
||||||
|
}
|
||||||
|
|
||||||
manager.logEvent(
|
manager.logEvent(
|
||||||
name: name,
|
name: name,
|
||||||
action: action,
|
action: action,
|
||||||
@@ -238,11 +292,13 @@ enum AnalyticsGenerator {
|
|||||||
let footer = " }"
|
let footer = " }"
|
||||||
|
|
||||||
if targets.contains(TrackerType.matomo) {
|
if targets.contains(TrackerType.matomo) {
|
||||||
header = "\(visibility) func configure(siteId: String, url: String) {"
|
header = "\(visibility) func configure(siteId: String, url: String, isDebugMode: Bool = false) {"
|
||||||
} else if targets.contains(TrackerType.firebase) {
|
} else if targets.contains(TrackerType.firebase) {
|
||||||
header = "\(visibility) func configure() {"
|
header = "\(visibility) func configure(isDebugMode: Bool = false) {"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
content.append(" self.isDebugMode = isDebugMode")
|
||||||
|
|
||||||
if targets.contains(TrackerType.matomo) {
|
if targets.contains(TrackerType.matomo) {
|
||||||
content.append("""
|
content.append("""
|
||||||
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||||||
@@ -266,7 +322,8 @@ enum AnalyticsGenerator {
|
|||||||
|
|
||||||
private static func getAnalyticsProtocol(
|
private static func getAnalyticsProtocol(
|
||||||
targets: [TrackerType],
|
targets: [TrackerType],
|
||||||
visibility: ExtensionVisibility
|
visibility: ExtensionVisibility,
|
||||||
|
pathSuffix: String
|
||||||
) -> String {
|
) -> String {
|
||||||
let proto = """
|
let proto = """
|
||||||
// MARK: - Protocol
|
// MARK: - Protocol
|
||||||
@@ -293,11 +350,11 @@ enum AnalyticsGenerator {
|
|||||||
var result: [String] = [proto]
|
var result: [String] = [proto]
|
||||||
|
|
||||||
if targets.contains(TrackerType.matomo) {
|
if targets.contains(TrackerType.matomo) {
|
||||||
result.append(MatomoGenerator.service)
|
result.append(MatomoGenerator.service(pathSuffix: pathSuffix))
|
||||||
}
|
}
|
||||||
|
|
||||||
if targets.contains(TrackerType.firebase) {
|
if targets.contains(TrackerType.firebase) {
|
||||||
result.append(FirebaseGenerator.service)
|
result.append(FirebaseGenerator.service(pathSuffix: pathSuffix))
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.joined(separator: "\n\n")
|
return result.joined(separator: "\n\n")
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ import Foundation
|
|||||||
|
|
||||||
enum FirebaseGenerator {
|
enum FirebaseGenerator {
|
||||||
|
|
||||||
static var service: String {
|
static func service(pathSuffix: String) -> String {
|
||||||
[
|
[
|
||||||
Self.header,
|
Self.header,
|
||||||
Self.logScreen,
|
Self.logScreen(pathSuffix: pathSuffix),
|
||||||
Self.logEvent,
|
Self.logEvent,
|
||||||
Self.enable,
|
Self.enable,
|
||||||
Self.footer
|
Self.footer
|
||||||
@@ -35,8 +35,14 @@ enum FirebaseGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var logScreen: String {
|
private static func logScreen(pathSuffix: String) -> String {
|
||||||
"""
|
let pathSuffixCode: String = if pathSuffix.isEmpty == false {
|
||||||
|
" + \"/\(pathSuffix)\""
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
return """
|
||||||
func logScreen(
|
func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
@@ -47,7 +53,7 @@ enum FirebaseGenerator {
|
|||||||
]
|
]
|
||||||
|
|
||||||
if path.isEmpty == false {
|
if path.isEmpty == false {
|
||||||
parameters["path"] = path + "/iOS" as NSObject
|
parameters["path"] = path\(pathSuffixCode) as NSObject
|
||||||
}
|
}
|
||||||
|
|
||||||
if let supplementaryParameters = params {
|
if let supplementaryParameters = params {
|
||||||
@@ -79,7 +85,7 @@ enum FirebaseGenerator {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
var parameters: [String:NSObject] = [
|
var parameters: [String: NSObject] = [
|
||||||
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ import Foundation
|
|||||||
|
|
||||||
enum MatomoGenerator {
|
enum MatomoGenerator {
|
||||||
|
|
||||||
static var service: String {
|
static func service(pathSuffix: String) -> String {
|
||||||
[
|
[
|
||||||
Self.header,
|
Self.header,
|
||||||
Self.setup,
|
Self.setup,
|
||||||
Self.logScreen,
|
Self.logScreen(pathSuffix: pathSuffix),
|
||||||
Self.logEvent,
|
Self.logEvent,
|
||||||
Self.enable,
|
Self.enable,
|
||||||
Self.footer
|
Self.footer
|
||||||
@@ -67,8 +67,14 @@ enum MatomoGenerator {
|
|||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
private static var logScreen: String {
|
private static func logScreen(pathSuffix: String) -> String {
|
||||||
"""
|
let pathSuffixCode: String = if pathSuffix.isEmpty == false {
|
||||||
|
" + \"/\(pathSuffix)\""
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
return """
|
||||||
func logScreen(
|
func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
@@ -76,7 +82,7 @@ enum MatomoGenerator {
|
|||||||
) {
|
) {
|
||||||
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)"\(pathSuffixCode))
|
||||||
tracker.track(
|
tracker.track(
|
||||||
view: [name],
|
view: [name],
|
||||||
url: urlString
|
url: urlString
|
||||||
|
|||||||
@@ -169,7 +169,6 @@ class AnalyticsFileParser {
|
|||||||
|
|
||||||
if target.contains(TrackerType.matomo.value) {
|
if target.contains(TrackerType.matomo.value) {
|
||||||
// Path
|
// Path
|
||||||
|
|
||||||
guard let path = screen.path else {
|
guard let path = screen.path else {
|
||||||
let error = AnalyticsError.missingElement("screen path")
|
let error = AnalyticsError.missingElement("screen path")
|
||||||
print(error.description)
|
print(error.description)
|
||||||
@@ -181,6 +180,10 @@ class AnalyticsFileParser {
|
|||||||
definition.path = path
|
definition.path = path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while definition.path.last == "/" {
|
||||||
|
definition.path = String(definition.path.dropLast())
|
||||||
|
}
|
||||||
|
|
||||||
return definition
|
return definition
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct Fonts: ParsableCommand {
|
|||||||
|
|
||||||
// MARK: - CommandConfiguration
|
// MARK: - CommandConfiguration
|
||||||
|
|
||||||
static var configuration = CommandConfiguration(
|
static let configuration = CommandConfiguration(
|
||||||
abstract: "A utility to generate an helpful etension to access your custom font from code and also Info.plist UIAppsFont content.",
|
abstract: "A utility to generate an helpful etension to access your custom font from code and also Info.plist UIAppsFont content.",
|
||||||
version: ResgenSwiftVersion
|
version: ResgenSwiftVersion
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct Generate: ParsableCommand {
|
|||||||
|
|
||||||
// MARK: - CommandConfiguration
|
// MARK: - CommandConfiguration
|
||||||
|
|
||||||
static var configuration = CommandConfiguration(
|
static let configuration = CommandConfiguration(
|
||||||
abstract: "A utility to generate ressources based on a configuration file",
|
abstract: "A utility to generate ressources based on a configuration file",
|
||||||
version: ResgenSwiftVersion
|
version: ResgenSwiftVersion
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,12 +16,14 @@ struct GenerateOptions: ParsableArguments {
|
|||||||
@Argument(help: "Configuration file.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
@Argument(help: "Configuration file.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
|
||||||
var configurationFile: String
|
var configurationFile: String
|
||||||
|
|
||||||
@Option(help: "Project directory. It will be added to every relative path (path that does not start with `/`",
|
@Option(
|
||||||
|
help: "Project directory. It will be added to every relative path (path that does not start with `/`",
|
||||||
transform: {
|
transform: {
|
||||||
if $0.last == "/" {
|
if $0.last == "/" {
|
||||||
return $0
|
return $0
|
||||||
}
|
}
|
||||||
return $0 + "/"
|
return $0 + "/"
|
||||||
})
|
}
|
||||||
|
)
|
||||||
var projectDirectory: String
|
var projectDirectory: String
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ struct ConfigurationArchitecture: Codable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let classDefinition = [
|
let classDefinition = [
|
||||||
"class \(classname) {",
|
"class \(classname): Sendable {",
|
||||||
children?.map { $0.getProperty(isStatic: generateStaticProperty) }.joined(separator: "\n"),
|
children?.map { $0.getProperty(isStatic: generateStaticProperty) }.joined(separator: "\n"),
|
||||||
"}"
|
"}"
|
||||||
]
|
]
|
||||||
@@ -89,19 +89,22 @@ struct AnalyticsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
let outputFile: String
|
let outputFile: String
|
||||||
let visibility: String?
|
let visibility: String?
|
||||||
let staticMembers: Bool?
|
let staticMembers: Bool?
|
||||||
|
let pathSuffix: String?
|
||||||
|
|
||||||
internal init(
|
internal init(
|
||||||
inputFile: String,
|
inputFile: String,
|
||||||
target: String,
|
target: String,
|
||||||
outputFile: String,
|
outputFile: String,
|
||||||
visibility: String?,
|
visibility: String?,
|
||||||
staticMembers: Bool?
|
staticMembers: Bool?,
|
||||||
|
pathSuffix: String?
|
||||||
) {
|
) {
|
||||||
self.inputFile = inputFile
|
self.inputFile = inputFile
|
||||||
self.target = target
|
self.target = target
|
||||||
self.outputFile = outputFile
|
self.outputFile = outputFile
|
||||||
self.visibility = visibility
|
self.visibility = visibility
|
||||||
self.staticMembers = staticMembers
|
self.staticMembers = staticMembers
|
||||||
|
self.pathSuffix = pathSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
var debugDescription: String {
|
var debugDescription: String {
|
||||||
@@ -112,6 +115,7 @@ struct AnalyticsConfiguration: Codable, CustomDebugStringConvertible {
|
|||||||
- Output file: \(outputFile)
|
- Output file: \(outputFile)
|
||||||
- Visiblity: \(visibility ?? "default")
|
- Visiblity: \(visibility ?? "default")
|
||||||
- Static members: \(staticMembers != nil ? "\(String(describing: staticMembers))" : "default")
|
- Static members: \(staticMembers != nil ? "\(String(describing: staticMembers))" : "default")
|
||||||
|
- Path suffix: \(pathSuffix != nil ? "\(String(describing: pathSuffix))" : "default")
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ extension AnalyticsConfiguration: Runnable {
|
|||||||
// Add optional parameters
|
// Add optional parameters
|
||||||
[
|
[
|
||||||
("--visibility", visibility),
|
("--visibility", visibility),
|
||||||
("--static-members", staticMembers?.description)
|
("--static-members", staticMembers?.description),
|
||||||
|
("--path-suffix", pathSuffix)
|
||||||
].forEach { argumentName, argumentValue in
|
].forEach { argumentName, argumentValue in
|
||||||
if let argumentValue {
|
if let argumentValue {
|
||||||
args += [
|
args += [
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ extension StringsConfiguration: Runnable {
|
|||||||
("--extension-suffix", extensionSuffix),
|
("--extension-suffix", extensionSuffix),
|
||||||
("--visibility", visibility),
|
("--visibility", visibility),
|
||||||
("--asset-bundle", assetBundle),
|
("--asset-bundle", assetBundle),
|
||||||
("--xc-strings", staticMembers?.description),
|
("--xc-strings", xcStrings?.description),
|
||||||
("--static-members", xcStrings?.description)
|
("--static-members", staticMembers?.description)
|
||||||
].forEach { argumentName, argumentValue in
|
].forEach { argumentName, argumentValue in
|
||||||
if let argumentValue {
|
if let argumentValue {
|
||||||
args += [
|
args += [
|
||||||
|
|||||||
@@ -186,8 +186,6 @@ class XcassetsGenerator {
|
|||||||
atomically: false,
|
atomically: false,
|
||||||
encoding: .utf8
|
encoding: .utf8
|
||||||
)
|
)
|
||||||
|
|
||||||
print("\(parsedImage.name) -> Generated")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success info
|
// Success info
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct Images: ParsableCommand {
|
|||||||
|
|
||||||
// MARK: - CommandConfiguration
|
// MARK: - CommandConfiguration
|
||||||
|
|
||||||
static var configuration = CommandConfiguration(
|
static let configuration = CommandConfiguration(
|
||||||
abstract: "A utility for generate images and an extension to access them easily.",
|
abstract: "A utility for generate images and an extension to access them easily.",
|
||||||
version: ResgenSwiftVersion
|
version: ResgenSwiftVersion
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -176,21 +176,21 @@ enum StringsFileGenerator {
|
|||||||
return // Go to next section
|
return // Go to next section
|
||||||
}
|
}
|
||||||
|
|
||||||
section.definitions.forEach { definition in // swiftlint:disable:this closure_body_length
|
section
|
||||||
var skipDefinition = false
|
.definitions
|
||||||
|
.forEach { definition in // swiftlint:disable:this closure_body_length
|
||||||
var isNoTranslation = false
|
var isNoTranslation = false
|
||||||
|
|
||||||
var localizationTab: [XCStringLocalization] = []
|
var localizationTab: [XCStringLocalization] = []
|
||||||
|
|
||||||
if definition.hasOneOrMoreMatchingTags(inputTags: inputTags) == false {
|
guard definition.hasOneOrMoreMatchingTags(inputTags: inputTags) else {
|
||||||
skipDefinition = true
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if definition.tags.contains(Stringium.noTranslationTag) {
|
if definition.tags.contains(Stringium.noTranslationTag) {
|
||||||
isNoTranslation = true
|
isNoTranslation = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !skipDefinition {
|
|
||||||
if isNoTranslation {
|
if isNoTranslation {
|
||||||
// Search for langs in yaml
|
// Search for langs in yaml
|
||||||
for lang in langs {
|
for lang in langs {
|
||||||
@@ -209,7 +209,8 @@ enum StringsFileGenerator {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Search for langs in twine
|
// Search for langs in twine
|
||||||
for (lang, value) in definition.translations where !value.isEmpty {
|
for (lang, value) in definition.translations
|
||||||
|
where langs.contains(lang) && !value.isEmpty {
|
||||||
let localization = XCStringLocalization(
|
let localization = XCStringLocalization(
|
||||||
lang: lang,
|
lang: lang,
|
||||||
content: XCStringLocalizationLangContent(
|
content: XCStringLocalizationLangContent(
|
||||||
@@ -219,7 +220,6 @@ enum StringsFileGenerator {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
print("VALUE: \(value)")
|
|
||||||
localizationTab.append(localization)
|
localizationTab.append(localization)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,7 +238,6 @@ enum StringsFileGenerator {
|
|||||||
xcStringDefinitionTab.append(xcStringDefinition)
|
xcStringDefinitionTab.append(xcStringDefinition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let xcStringContainer = XCStringDefinitionContainer(strings: xcStringDefinitionTab)
|
let xcStringContainer = XCStringDefinitionContainer(strings: xcStringDefinitionTab)
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct Stringium: ParsableCommand {
|
|||||||
|
|
||||||
// MARK: - Command Configuration
|
// MARK: - Command Configuration
|
||||||
|
|
||||||
static var configuration = CommandConfiguration(
|
static let configuration = CommandConfiguration(
|
||||||
abstract: "Generate strings with custom scripts.",
|
abstract: "Generate strings with custom scripts.",
|
||||||
version: ResgenSwiftVersion
|
version: ResgenSwiftVersion
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import ToolCore
|
|||||||
|
|
||||||
struct Strings: ParsableCommand {
|
struct Strings: ParsableCommand {
|
||||||
|
|
||||||
static var configuration = CommandConfiguration(
|
static let configuration = CommandConfiguration(
|
||||||
abstract: "A utility for generate strings.",
|
abstract: "A utility for generate strings.",
|
||||||
version: ResgenSwiftVersion,
|
version: ResgenSwiftVersion,
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct Tags: ParsableCommand {
|
|||||||
|
|
||||||
// MARK: - Command Configuration
|
// MARK: - Command Configuration
|
||||||
|
|
||||||
static var configuration = CommandConfiguration(
|
static let configuration = CommandConfiguration(
|
||||||
abstract: "Generate tags extension file.",
|
abstract: "Generate tags extension file.",
|
||||||
version: ResgenSwiftVersion
|
version: ResgenSwiftVersion
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct Twine: ParsableCommand {
|
|||||||
|
|
||||||
// MARK: - Command Configuration
|
// MARK: - Command Configuration
|
||||||
|
|
||||||
static var configuration = CommandConfiguration(
|
static let configuration = CommandConfiguration(
|
||||||
abstract: "Generate strings with twine.",
|
abstract: "Generate strings with twine.",
|
||||||
version: ResgenSwiftVersion
|
version: ResgenSwiftVersion
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import ToolCore
|
|||||||
|
|
||||||
struct ResgenSwift: ParsableCommand {
|
struct ResgenSwift: ParsableCommand {
|
||||||
|
|
||||||
static var configuration = CommandConfiguration(
|
static let configuration = CommandConfiguration(
|
||||||
abstract: "A utility for generate ressources.",
|
abstract: "A utility for generate ressources.",
|
||||||
version: ResgenSwiftVersion,
|
version: ResgenSwiftVersion,
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
var parameters: [String:NSObject] = [
|
var parameters: [String: NSObject] = [
|
||||||
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
AnalyticsParameterItemName: name.replacingOccurrences(of: " ", with: "_") as NSObject
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
) {
|
) {
|
||||||
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")
|
||||||
tracker.track(
|
tracker.track(
|
||||||
view: [name],
|
view: [name],
|
||||||
url: urlString
|
url: urlString
|
||||||
@@ -234,7 +234,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
sections: [sectionOne, sectionTwo, sectionThree],
|
sections: [sectionOne, sectionTwo, sectionThree],
|
||||||
tags: ["ios", "iosonly"],
|
tags: ["ios", "iosonly"],
|
||||||
isStatic: false,
|
isStatic: false,
|
||||||
visibility: .public
|
visibility: .internal,
|
||||||
|
pathSuffix: "iOS"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Expect Analytics
|
// Expect Analytics
|
||||||
@@ -243,351 +244,16 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import FirebaseAnalytics
|
import FirebaseAnalytics
|
||||||
|
import os
|
||||||
\(protocolString(visibility: .public))
|
|
||||||
|
|
||||||
\(firebaseString())
|
|
||||||
|
|
||||||
// MARK: - Traker Type
|
|
||||||
|
|
||||||
public enum TrackerType: CaseIterable {
|
|
||||||
|
|
||||||
case firebase
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Manager
|
|
||||||
|
|
||||||
public class AnalyticsManager {
|
|
||||||
|
|
||||||
public static var shared = AnalyticsManager()
|
|
||||||
|
|
||||||
private init() {}
|
|
||||||
|
|
||||||
// MARK: - Properties
|
|
||||||
|
|
||||||
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
|
||||||
|
|
||||||
private var isEnabled: Bool {
|
|
||||||
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Enable Methods
|
|
||||||
|
|
||||||
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
|
||||||
managers.forEach { (key, value) in
|
|
||||||
if analytics.contains(where: { type in
|
|
||||||
type == key
|
|
||||||
}) {
|
|
||||||
value.setEnable(enable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
|
||||||
setAnalytics(enable: true, analytics)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
|
||||||
setAnalytics(enable: false, analytics)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func configure() {
|
|
||||||
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Private Log Methods
|
|
||||||
|
|
||||||
private func logScreen(
|
|
||||||
name: String,
|
|
||||||
path: String,
|
|
||||||
params: [String: Any]?
|
|
||||||
) {
|
|
||||||
guard isEnabled else { return }
|
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
|
||||||
manager.logScreen(
|
|
||||||
name: name,
|
|
||||||
path: path,
|
|
||||||
params: params
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func logEvent(
|
|
||||||
name: String,
|
|
||||||
action: String,
|
|
||||||
category: String,
|
|
||||||
params: [String: Any]?
|
|
||||||
) {
|
|
||||||
guard isEnabled else { return }
|
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
|
||||||
manager.logEvent(
|
|
||||||
name: name,
|
|
||||||
action: action,
|
|
||||||
category: category,
|
|
||||||
params: params
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - section_one
|
|
||||||
|
|
||||||
public func logScreenS1DefOne() {
|
|
||||||
logScreen(
|
|
||||||
name: "s1 def one",
|
|
||||||
path: "",
|
|
||||||
params: nil
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public func logEventS1DefTwo() {
|
|
||||||
logEvent(
|
|
||||||
name: "s1 def two",
|
|
||||||
action: "",
|
|
||||||
category: "",
|
|
||||||
params: nil
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - section_two
|
|
||||||
|
|
||||||
public func logScreenS2DefOne() {
|
|
||||||
logScreen(
|
|
||||||
name: "s2 def one",
|
|
||||||
path: "",
|
|
||||||
params: nil
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
if extensionContent != expect {
|
|
||||||
print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
|
|
||||||
}
|
|
||||||
XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGeneratedExtensionContentMatomo() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = AnalyticsCategory(id: "section_one")
|
|
||||||
sectionOne.definitions = [
|
|
||||||
getAnalyticsDefinition(id: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: .screen, tags: ["ios", "iosonly"]),
|
|
||||||
getAnalyticsDefinition(id: "s1_def_two", action: "test", category: "test", name: "s1 def two", type: .event, tags: ["ios", "iosonly"]),
|
|
||||||
]
|
|
||||||
|
|
||||||
let sectionTwo = AnalyticsCategory(id: "section_two")
|
|
||||||
sectionTwo.definitions = [
|
|
||||||
getAnalyticsDefinition(id: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: .screen, tags: ["ios","iosonly"]),
|
|
||||||
getAnalyticsDefinition(id: "s2_def_two", action: "test", category: "test", name: "s2 def two", type: .event, tags: ["droid","droidonly"]),
|
|
||||||
]
|
|
||||||
|
|
||||||
let sectionThree = AnalyticsCategory(id: "section_three")
|
|
||||||
sectionThree.definitions = [
|
|
||||||
getAnalyticsDefinition(id: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: .screen, tags: ["droid","droidonly"]),
|
|
||||||
getAnalyticsDefinition(id: "s3_def_two", action: "test", category: "test", name: "s3 def two", type: .event, tags: ["droid","droidonly"]),
|
|
||||||
]
|
|
||||||
|
|
||||||
// When
|
|
||||||
let extensionContent = AnalyticsGenerator.getExtensionContent(
|
|
||||||
targets: [TrackerType.matomo],
|
|
||||||
sections: [sectionOne, sectionTwo, sectionThree],
|
|
||||||
tags: ["ios", "iosonly"],
|
|
||||||
isStatic: false,
|
|
||||||
visibility: .package
|
|
||||||
)
|
|
||||||
// Expect Analytics
|
|
||||||
let expect = """
|
|
||||||
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import MatomoTracker
|
|
||||||
|
|
||||||
\(protocolString(visibility: .package))
|
|
||||||
|
|
||||||
\(matomoString())
|
|
||||||
|
|
||||||
// MARK: - Traker Type
|
|
||||||
|
|
||||||
package enum TrackerType: CaseIterable {
|
|
||||||
|
|
||||||
case matomo
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Manager
|
|
||||||
|
|
||||||
package class AnalyticsManager {
|
|
||||||
|
|
||||||
package static var shared = AnalyticsManager()
|
|
||||||
|
|
||||||
private init() {}
|
|
||||||
|
|
||||||
// MARK: - Properties
|
|
||||||
|
|
||||||
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
|
||||||
|
|
||||||
private var isEnabled: Bool {
|
|
||||||
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Enable Methods
|
|
||||||
|
|
||||||
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
|
||||||
managers.forEach { (key, value) in
|
|
||||||
if analytics.contains(where: { type in
|
|
||||||
type == key
|
|
||||||
}) {
|
|
||||||
value.setEnable(enable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
package func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
|
||||||
setAnalytics(enable: true, analytics)
|
|
||||||
}
|
|
||||||
|
|
||||||
package func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
|
||||||
setAnalytics(enable: false, analytics)
|
|
||||||
}
|
|
||||||
|
|
||||||
package func configure(siteId: String, url: String) {
|
|
||||||
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
|
||||||
siteId: siteId,
|
|
||||||
url: url
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Private Log Methods
|
|
||||||
|
|
||||||
private func logScreen(
|
|
||||||
name: String,
|
|
||||||
path: String,
|
|
||||||
params: [String: Any]?
|
|
||||||
) {
|
|
||||||
guard isEnabled else { return }
|
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
|
||||||
manager.logScreen(
|
|
||||||
name: name,
|
|
||||||
path: path,
|
|
||||||
params: params
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func logEvent(
|
|
||||||
name: String,
|
|
||||||
action: String,
|
|
||||||
category: String,
|
|
||||||
params: [String: Any]?
|
|
||||||
) {
|
|
||||||
guard isEnabled else { return }
|
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
|
||||||
manager.logEvent(
|
|
||||||
name: name,
|
|
||||||
action: action,
|
|
||||||
category: category,
|
|
||||||
params: params
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - section_one
|
|
||||||
|
|
||||||
package func logScreenS1DefOne() {
|
|
||||||
logScreen(
|
|
||||||
name: "s1 def one",
|
|
||||||
path: "s1_def_one/",
|
|
||||||
params: nil
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
package func logEventS1DefTwo() {
|
|
||||||
logEvent(
|
|
||||||
name: "s1 def two",
|
|
||||||
action: "test",
|
|
||||||
category: "test",
|
|
||||||
params: nil
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - section_two
|
|
||||||
|
|
||||||
package func logScreenS2DefOne() {
|
|
||||||
logScreen(
|
|
||||||
name: "s2 def one",
|
|
||||||
path: "s2_def_one/",
|
|
||||||
params: nil
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
if extensionContent != expect {
|
|
||||||
print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
|
|
||||||
}
|
|
||||||
XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGeneratedExtensionContentMatomoAndFirebase() {
|
|
||||||
// Given
|
|
||||||
let sectionOne = AnalyticsCategory(id: "section_one")
|
|
||||||
sectionOne.definitions = [
|
|
||||||
getAnalyticsDefinition(id: "s1_def_one", path: "s1_def_one/", name: "s1 def one", type: .screen, tags: ["ios", "iosonly"]),
|
|
||||||
getAnalyticsDefinition(id: "s1_def_two", action: "test", category: "test", name: "s1 def two", type: .event, tags: ["ios", "iosonly"]),
|
|
||||||
]
|
|
||||||
|
|
||||||
let sectionTwo = AnalyticsCategory(id: "section_two")
|
|
||||||
sectionTwo.definitions = [
|
|
||||||
getAnalyticsDefinition(id: "s2_def_one", path: "s2_def_one/", name: "s2 def one", type: .screen, tags: ["ios","iosonly"]),
|
|
||||||
getAnalyticsDefinition(id: "s2_def_two", action: "test", category: "test", name: "s2 def two", type: .event, tags: ["droid","droidonly"]),
|
|
||||||
]
|
|
||||||
|
|
||||||
let sectionThree = AnalyticsCategory(id: "section_three")
|
|
||||||
sectionThree.definitions = [
|
|
||||||
getAnalyticsDefinition(id: "s3_def_one", path: "s3_def_one/", name: "s3 def one", type: .screen, tags: ["droid","droidonly"]),
|
|
||||||
getAnalyticsDefinition(id: "s3_def_two", action: "test", category: "test", name: "s3 def two", type: .event, tags: ["droid","droidonly"]),
|
|
||||||
]
|
|
||||||
|
|
||||||
// When
|
|
||||||
let extensionContent = AnalyticsGenerator.getExtensionContent(
|
|
||||||
targets: [TrackerType.matomo, TrackerType.firebase],
|
|
||||||
sections: [sectionOne, sectionTwo, sectionThree],
|
|
||||||
tags: ["ios", "iosonly"],
|
|
||||||
isStatic: false,
|
|
||||||
visibility: .internal
|
|
||||||
)
|
|
||||||
|
|
||||||
// Expect Analytics
|
|
||||||
let expect = """
|
|
||||||
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import MatomoTracker
|
|
||||||
import FirebaseAnalytics
|
|
||||||
|
|
||||||
\(protocolString(visibility: .internal))
|
\(protocolString(visibility: .internal))
|
||||||
|
|
||||||
\(matomoString())
|
|
||||||
|
|
||||||
\(firebaseString())
|
\(firebaseString())
|
||||||
|
|
||||||
// MARK: - Traker Type
|
// MARK: - Traker Type
|
||||||
|
|
||||||
internal enum TrackerType: CaseIterable {
|
internal enum TrackerType: CaseIterable {
|
||||||
|
|
||||||
case matomo
|
|
||||||
case firebase
|
case firebase
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,6 +261,7 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
|
|
||||||
internal class AnalyticsManager {
|
internal class AnalyticsManager {
|
||||||
|
|
||||||
|
@MainActor
|
||||||
internal static var shared = AnalyticsManager()
|
internal static var shared = AnalyticsManager()
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
@@ -603,6 +270,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
|
|
||||||
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
||||||
|
|
||||||
|
private var isDebugMode: Bool = false
|
||||||
|
|
||||||
private var isEnabled: Bool {
|
private var isEnabled: Bool {
|
||||||
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||||||
false
|
false
|
||||||
@@ -611,6 +280,8 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let logger = Logger(subsystem: "resgen", category: "analytics")
|
||||||
|
|
||||||
// MARK: - Enable Methods
|
// MARK: - Enable Methods
|
||||||
|
|
||||||
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||||
@@ -631,24 +302,47 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
setAnalytics(enable: false, analytics)
|
setAnalytics(enable: false, analytics)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal func configure(siteId: String, url: String) {
|
internal func configure(isDebugMode: Bool = false) {
|
||||||
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
self.isDebugMode = isDebugMode
|
||||||
siteId: siteId,
|
|
||||||
url: url
|
|
||||||
)
|
|
||||||
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
|
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Private Log Methods
|
// MARK: - Private Log Methods
|
||||||
|
|
||||||
|
private func formattedParams(_ params: [String: Any]?) -> String {
|
||||||
|
guard let params = params, !params.isEmpty else { return "-" }
|
||||||
|
|
||||||
|
let formattedParams = params.map { key, value in
|
||||||
|
" \\(key): \\(value)"
|
||||||
|
}
|
||||||
|
.joined(separator: "\\n")
|
||||||
|
|
||||||
|
return "\\n" + formattedParams
|
||||||
|
}
|
||||||
|
|
||||||
private func logScreen(
|
private func logScreen(
|
||||||
name: String,
|
name: String,
|
||||||
path: String,
|
path: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else {
|
||||||
|
if isDebugMode {
|
||||||
|
logger.log("Analytics disabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
|
|
||||||
|
if isDebugMode {
|
||||||
|
logger.debug(\"""
|
||||||
|
🖥️ Screen:
|
||||||
|
Name: \\(name, privacy: .public)
|
||||||
|
Path: \\(path, privacy: .public)
|
||||||
|
Params: \\(self.formattedParams(params), privacy: .public)
|
||||||
|
\""")
|
||||||
|
}
|
||||||
|
|
||||||
manager.logScreen(
|
manager.logScreen(
|
||||||
name: name,
|
name: name,
|
||||||
path: path,
|
path: path,
|
||||||
@@ -663,9 +357,25 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
category: String,
|
category: String,
|
||||||
params: [String: Any]?
|
params: [String: Any]?
|
||||||
) {
|
) {
|
||||||
guard isEnabled else { return }
|
guard isEnabled else {
|
||||||
|
if isDebugMode {
|
||||||
|
logger.log("Analytics disabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
managers.values.forEach { manager in
|
managers.values.forEach { manager in
|
||||||
|
|
||||||
|
if isDebugMode {
|
||||||
|
logger.debug(\"""
|
||||||
|
📊 Event:
|
||||||
|
Name: \\(name, privacy: .public)
|
||||||
|
Action: \\(action.isEmpty ? "-" : action, privacy: .public)
|
||||||
|
Category: \\(category.isEmpty ? "-" : category, privacy: .public)
|
||||||
|
Params: \\(self.formattedParams(params), privacy: .public)
|
||||||
|
\""")
|
||||||
|
}
|
||||||
|
|
||||||
manager.logEvent(
|
manager.logEvent(
|
||||||
name: name,
|
name: name,
|
||||||
action: action,
|
action: action,
|
||||||
@@ -680,7 +390,224 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
internal func logScreenS1DefOne() {
|
internal func logScreenS1DefOne() {
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "s1 def one",
|
name: "s1 def one",
|
||||||
path: "s1_def_one/",
|
path: "",
|
||||||
|
params: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func logEventS1DefTwo() {
|
||||||
|
logEvent(
|
||||||
|
name: "s1 def two",
|
||||||
|
action: "",
|
||||||
|
category: "",
|
||||||
|
params: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - section_two
|
||||||
|
|
||||||
|
internal func logScreenS2DefOne() {
|
||||||
|
logScreen(
|
||||||
|
name: "s2 def one",
|
||||||
|
path: "",
|
||||||
|
params: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if extensionContent != expect {
|
||||||
|
print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
|
||||||
|
}
|
||||||
|
XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGeneratedExtensionContentMatomo() {
|
||||||
|
// Given
|
||||||
|
let sectionOne = AnalyticsCategory(id: "section_one")
|
||||||
|
sectionOne.definitions = [
|
||||||
|
getAnalyticsDefinition(id: "s1_def_one", path: "s1_def_one", name: "s1 def one", type: .screen, tags: ["ios", "iosonly"]),
|
||||||
|
getAnalyticsDefinition(id: "s1_def_two", action: "test", category: "test", name: "s1 def two", type: .event, tags: ["ios", "iosonly"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
let sectionTwo = AnalyticsCategory(id: "section_two")
|
||||||
|
sectionTwo.definitions = [
|
||||||
|
getAnalyticsDefinition(id: "s2_def_one", path: "s2_def_one", name: "s2 def one", type: .screen, tags: ["ios","iosonly"]),
|
||||||
|
getAnalyticsDefinition(id: "s2_def_two", action: "test", category: "test", name: "s2 def two", type: .event, tags: ["droid","droidonly"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
let sectionThree = AnalyticsCategory(id: "section_three")
|
||||||
|
sectionThree.definitions = [
|
||||||
|
getAnalyticsDefinition(id: "s3_def_one", path: "s3_def_one", name: "s3 def one", type: .screen, tags: ["droid","droidonly"]),
|
||||||
|
getAnalyticsDefinition(id: "s3_def_two", action: "test", category: "test", name: "s3 def two", type: .event, tags: ["droid","droidonly"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
// When
|
||||||
|
let extensionContent = AnalyticsGenerator.getExtensionContent(
|
||||||
|
targets: [TrackerType.matomo],
|
||||||
|
sections: [sectionOne, sectionTwo, sectionThree],
|
||||||
|
tags: ["ios", "iosonly"],
|
||||||
|
isStatic: false,
|
||||||
|
visibility: .internal,
|
||||||
|
pathSuffix: "iOS"
|
||||||
|
)
|
||||||
|
// Expect Analytics
|
||||||
|
let expect = """
|
||||||
|
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import MatomoTracker
|
||||||
|
import os
|
||||||
|
|
||||||
|
\(protocolString(visibility: .internal))
|
||||||
|
|
||||||
|
\(matomoString())
|
||||||
|
|
||||||
|
// MARK: - Traker Type
|
||||||
|
|
||||||
|
internal enum TrackerType: CaseIterable {
|
||||||
|
|
||||||
|
case matomo
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Manager
|
||||||
|
|
||||||
|
internal class AnalyticsManager {
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
internal static var shared = AnalyticsManager()
|
||||||
|
|
||||||
|
private init() {}
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
|
||||||
|
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
||||||
|
|
||||||
|
private var isDebugMode: Bool = false
|
||||||
|
|
||||||
|
private var isEnabled: Bool {
|
||||||
|
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private let logger = Logger(subsystem: "resgen", category: "analytics")
|
||||||
|
|
||||||
|
// MARK: - Enable Methods
|
||||||
|
|
||||||
|
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||||
|
managers.forEach { (key, value) in
|
||||||
|
if analytics.contains(where: { type in
|
||||||
|
type == key
|
||||||
|
}) {
|
||||||
|
value.setEnable(enable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||||
|
setAnalytics(enable: true, analytics)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||||
|
setAnalytics(enable: false, analytics)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func configure(siteId: String, url: String, isDebugMode: Bool = false) {
|
||||||
|
self.isDebugMode = isDebugMode
|
||||||
|
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||||||
|
siteId: siteId,
|
||||||
|
url: url
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private Log Methods
|
||||||
|
|
||||||
|
private func formattedParams(_ params: [String: Any]?) -> String {
|
||||||
|
guard let params = params, !params.isEmpty else { return "-" }
|
||||||
|
|
||||||
|
let formattedParams = params.map { key, value in
|
||||||
|
" \\(key): \\(value)"
|
||||||
|
}
|
||||||
|
.joined(separator: "\\n")
|
||||||
|
|
||||||
|
return "\\n" + formattedParams
|
||||||
|
}
|
||||||
|
|
||||||
|
private func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
|
guard isEnabled else {
|
||||||
|
if isDebugMode {
|
||||||
|
logger.log("Analytics disabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
managers.values.forEach { manager in
|
||||||
|
|
||||||
|
if isDebugMode {
|
||||||
|
logger.debug(\"""
|
||||||
|
🖥️ Screen:
|
||||||
|
Name: \\(name, privacy: .public)
|
||||||
|
Path: \\(path, privacy: .public)
|
||||||
|
Params: \\(self.formattedParams(params), privacy: .public)
|
||||||
|
\""")
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.logScreen(
|
||||||
|
name: name,
|
||||||
|
path: path,
|
||||||
|
params: params
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func logEvent(
|
||||||
|
name: String,
|
||||||
|
action: String,
|
||||||
|
category: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
|
guard isEnabled else {
|
||||||
|
if isDebugMode {
|
||||||
|
logger.log("Analytics disabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
managers.values.forEach { manager in
|
||||||
|
|
||||||
|
if isDebugMode {
|
||||||
|
logger.debug(\"""
|
||||||
|
📊 Event:
|
||||||
|
Name: \\(name, privacy: .public)
|
||||||
|
Action: \\(action.isEmpty ? "-" : action, privacy: .public)
|
||||||
|
Category: \\(category.isEmpty ? "-" : category, privacy: .public)
|
||||||
|
Params: \\(self.formattedParams(params), privacy: .public)
|
||||||
|
\""")
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.logEvent(
|
||||||
|
name: name,
|
||||||
|
action: action,
|
||||||
|
category: category,
|
||||||
|
params: params
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - section_one
|
||||||
|
|
||||||
|
internal func logScreenS1DefOne() {
|
||||||
|
logScreen(
|
||||||
|
name: "s1 def one",
|
||||||
|
path: "s1_def_one",
|
||||||
params: nil
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -699,7 +626,230 @@ final class AnalyticsGeneratorTests: XCTestCase {
|
|||||||
internal func logScreenS2DefOne() {
|
internal func logScreenS2DefOne() {
|
||||||
logScreen(
|
logScreen(
|
||||||
name: "s2 def one",
|
name: "s2 def one",
|
||||||
path: "s2_def_one/",
|
path: "s2_def_one",
|
||||||
|
params: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if extensionContent != expect {
|
||||||
|
print(prettyFirstDifferenceBetweenStrings(s1: extensionContent, s2: expect))
|
||||||
|
}
|
||||||
|
XCTAssertEqual(extensionContent.adaptForXCTest(), expect.adaptForXCTest())
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGeneratedExtensionContentMatomoAndFirebase() {
|
||||||
|
// Given
|
||||||
|
let sectionOne = AnalyticsCategory(id: "section_one")
|
||||||
|
sectionOne.definitions = [
|
||||||
|
getAnalyticsDefinition(id: "s1_def_one", path: "s1_def_one", name: "s1 def one", type: .screen, tags: ["ios", "iosonly"]),
|
||||||
|
getAnalyticsDefinition(id: "s1_def_two", action: "test", category: "test", name: "s1 def two", type: .event, tags: ["ios", "iosonly"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
let sectionTwo = AnalyticsCategory(id: "section_two")
|
||||||
|
sectionTwo.definitions = [
|
||||||
|
getAnalyticsDefinition(id: "s2_def_one", path: "s2_def_one", name: "s2 def one", type: .screen, tags: ["ios","iosonly"]),
|
||||||
|
getAnalyticsDefinition(id: "s2_def_two", action: "test", category: "test", name: "s2 def two", type: .event, tags: ["droid","droidonly"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
let sectionThree = AnalyticsCategory(id: "section_three")
|
||||||
|
sectionThree.definitions = [
|
||||||
|
getAnalyticsDefinition(id: "s3_def_one", path: "s3_def_one", name: "s3 def one", type: .screen, tags: ["droid","droidonly"]),
|
||||||
|
getAnalyticsDefinition(id: "s3_def_two", action: "test", category: "test", name: "s3 def two", type: .event, tags: ["droid","droidonly"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
// When
|
||||||
|
let extensionContent = AnalyticsGenerator.getExtensionContent(
|
||||||
|
targets: [TrackerType.matomo, TrackerType.firebase],
|
||||||
|
sections: [sectionOne, sectionTwo, sectionThree],
|
||||||
|
tags: ["ios", "iosonly"],
|
||||||
|
isStatic: false,
|
||||||
|
visibility: .internal,
|
||||||
|
pathSuffix: "iOS"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Expect Analytics
|
||||||
|
let expect = """
|
||||||
|
// Generated by ResgenSwift.Analytics \(ResgenSwiftVersion)
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import MatomoTracker
|
||||||
|
import FirebaseAnalytics
|
||||||
|
import os
|
||||||
|
|
||||||
|
\(protocolString(visibility: .internal))
|
||||||
|
|
||||||
|
\(matomoString())
|
||||||
|
|
||||||
|
\(firebaseString())
|
||||||
|
|
||||||
|
// MARK: - Traker Type
|
||||||
|
|
||||||
|
internal enum TrackerType: CaseIterable {
|
||||||
|
|
||||||
|
case matomo
|
||||||
|
case firebase
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Manager
|
||||||
|
|
||||||
|
internal class AnalyticsManager {
|
||||||
|
|
||||||
|
@MainActor
|
||||||
|
internal static var shared = AnalyticsManager()
|
||||||
|
|
||||||
|
private init() {}
|
||||||
|
|
||||||
|
// MARK: - Properties
|
||||||
|
|
||||||
|
var managers: [TrackerType: AnalyticsManagerProtocol] = [:]
|
||||||
|
|
||||||
|
private var isDebugMode: Bool = false
|
||||||
|
|
||||||
|
private var isEnabled: Bool {
|
||||||
|
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private let logger = Logger(subsystem: "resgen", category: "analytics")
|
||||||
|
|
||||||
|
// MARK: - Enable Methods
|
||||||
|
|
||||||
|
private func setAnalytics(enable: Bool, _ analytics: [TrackerType]) {
|
||||||
|
managers.forEach { (key, value) in
|
||||||
|
if analytics.contains(where: { type in
|
||||||
|
type == key
|
||||||
|
}) {
|
||||||
|
value.setEnable(enable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func enableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||||
|
setAnalytics(enable: true, analytics)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func disableAnalytics(_ analytics: [TrackerType] = TrackerType.allCases) {
|
||||||
|
setAnalytics(enable: false, analytics)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func configure(siteId: String, url: String, isDebugMode: Bool = false) {
|
||||||
|
self.isDebugMode = isDebugMode
|
||||||
|
managers[TrackerType.matomo] = MatomoAnalyticsManager(
|
||||||
|
siteId: siteId,
|
||||||
|
url: url
|
||||||
|
)
|
||||||
|
managers[TrackerType.firebase] = FirebaseAnalyticsManager()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private Log Methods
|
||||||
|
|
||||||
|
private func formattedParams(_ params: [String: Any]?) -> String {
|
||||||
|
guard let params = params, !params.isEmpty else { return "-" }
|
||||||
|
|
||||||
|
let formattedParams = params.map { key, value in
|
||||||
|
" \\(key): \\(value)"
|
||||||
|
}
|
||||||
|
.joined(separator: "\\n")
|
||||||
|
|
||||||
|
return "\\n" + formattedParams
|
||||||
|
}
|
||||||
|
|
||||||
|
private func logScreen(
|
||||||
|
name: String,
|
||||||
|
path: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
|
guard isEnabled else {
|
||||||
|
if isDebugMode {
|
||||||
|
logger.log("Analytics disabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
managers.values.forEach { manager in
|
||||||
|
|
||||||
|
if isDebugMode {
|
||||||
|
logger.debug(\"""
|
||||||
|
🖥️ Screen:
|
||||||
|
Name: \\(name, privacy: .public)
|
||||||
|
Path: \\(path, privacy: .public)
|
||||||
|
Params: \\(self.formattedParams(params), privacy: .public)
|
||||||
|
\""")
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.logScreen(
|
||||||
|
name: name,
|
||||||
|
path: path,
|
||||||
|
params: params
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func logEvent(
|
||||||
|
name: String,
|
||||||
|
action: String,
|
||||||
|
category: String,
|
||||||
|
params: [String: Any]?
|
||||||
|
) {
|
||||||
|
guard isEnabled else {
|
||||||
|
if isDebugMode {
|
||||||
|
logger.log("Analytics disabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
managers.values.forEach { manager in
|
||||||
|
|
||||||
|
if isDebugMode {
|
||||||
|
logger.debug(\"""
|
||||||
|
📊 Event:
|
||||||
|
Name: \\(name, privacy: .public)
|
||||||
|
Action: \\(action.isEmpty ? "-" : action, privacy: .public)
|
||||||
|
Category: \\(category.isEmpty ? "-" : category, privacy: .public)
|
||||||
|
Params: \\(self.formattedParams(params), privacy: .public)
|
||||||
|
\""")
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.logEvent(
|
||||||
|
name: name,
|
||||||
|
action: action,
|
||||||
|
category: category,
|
||||||
|
params: params
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - section_one
|
||||||
|
|
||||||
|
internal func logScreenS1DefOne() {
|
||||||
|
logScreen(
|
||||||
|
name: "s1 def one",
|
||||||
|
path: "s1_def_one",
|
||||||
|
params: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func logEventS1DefTwo() {
|
||||||
|
logEvent(
|
||||||
|
name: "s1 def two",
|
||||||
|
action: "test",
|
||||||
|
category: "test",
|
||||||
|
params: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - section_two
|
||||||
|
|
||||||
|
internal func logScreenS2DefOne() {
|
||||||
|
logScreen(
|
||||||
|
name: "s2 def one",
|
||||||
|
path: "s2_def_one",
|
||||||
params: nil
|
params: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ final class AnalyticsConfigurationTests: XCTestCase {
|
|||||||
target: "matomo firebase",
|
target: "matomo firebase",
|
||||||
outputFile: "Analytics/Generated/AnalyticsManager.swift",
|
outputFile: "Analytics/Generated/AnalyticsManager.swift",
|
||||||
visibility: nil,
|
visibility: nil,
|
||||||
staticMembers: nil
|
staticMembers: nil,
|
||||||
|
pathSuffix: nil
|
||||||
)
|
)
|
||||||
|
|
||||||
// When
|
// When
|
||||||
@@ -48,7 +49,8 @@ final class AnalyticsConfigurationTests: XCTestCase {
|
|||||||
target: "matomo firebase",
|
target: "matomo firebase",
|
||||||
outputFile: "Analytics/Generated/AnalyticsManager.swift",
|
outputFile: "Analytics/Generated/AnalyticsManager.swift",
|
||||||
visibility: "public",
|
visibility: "public",
|
||||||
staticMembers: false
|
staticMembers: false,
|
||||||
|
pathSuffix: "mySuffix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// When
|
// When
|
||||||
@@ -68,7 +70,9 @@ final class AnalyticsConfigurationTests: XCTestCase {
|
|||||||
"--visibility",
|
"--visibility",
|
||||||
"public",
|
"public",
|
||||||
"--static-members",
|
"--static-members",
|
||||||
"false"
|
"false",
|
||||||
|
"--path-suffix",
|
||||||
|
"mySuffix"
|
||||||
]
|
]
|
||||||
|
|
||||||
XCTAssertEqual(arguments, expectedArguments)
|
XCTAssertEqual(arguments, expectedArguments)
|
||||||
|
|||||||
Reference in New Issue
Block a user