69 Commits
v0.9 ... 2.1.0

Author SHA1 Message Date
166026a766 feat(RES-43): Fix du warning magick convert (#16)
All checks were successful
gitea-openium/resgen.swift/pipeline/head This commit looks good
Reviewed-on: #16
2025-05-05 10:36:51 +02:00
ccda606af5 feat(RES-35): Force JSONEncoder output formatting with .sortedKeys (#15)
All checks were successful
gitea-openium/resgen.swift/pipeline/head This commit looks good
Reviewed-on: #15
2025-05-05 10:07:58 +02:00
756de4f1de feat(RES-34): Fix plist font filename (#14)
All checks were successful
gitea-openium/resgen.swift/pipeline/head This commit looks good
Reviewed-on: #14
2025-05-05 09:53:05 +02:00
8442c89944 feat(RES-33): Generation de l'architecture compatible Swift 6 (#13)
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Reviewed-on: #13
2025-04-30 10:22:34 +02:00
57cedd37bb Update rsvgConvertNotFound error to update brew install command line
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2025-04-08 15:27:10 +02:00
09556ba6e0 [DEVTOOLS-186] Exporter les images de resgen en svg
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Reviewed-on: #12
Reviewed-by: Thibaut Schmitt <t.schmitt@openium.fr>
2024-07-17 15:18:13 +02:00
dea57dc1e2 Maj du readme
Some checks failed
gitea-openium/resgen.swift/pipeline/pr-master There was a failure building this commit
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2024-07-11 10:29:32 +02:00
07575bd2bf DEVTOOLS-195 Ne pas générer les svg en template par défaut
Some checks failed
gitea-openium/resgen.swift/pipeline/pr-master There was a failure building this commit
2024-07-11 10:08:47 +02:00
8686ae974c Suppression des anciens assets si svg
Some checks failed
gitea-openium/resgen.swift/pipeline/pr-master There was a failure building this commit
2024-06-21 14:54:20 +02:00
be4c561ea8 DEVTOOLS-192 Resgen iOS vector
Some checks failed
gitea-openium/resgen.swift/pipeline/pr-master There was a failure building this commit
2024-06-21 09:18:51 +02:00
2357a40fff DEVTOOLS-186 Exporter les images de resgen en svg
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
gitea-openium/resgen.swift/pipeline/pr-master There was a failure building this commit
2024-04-22 12:05:24 +02:00
d4afa9c9e9 Maj du Readme suite aux devs sur le fichier string catalog
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2024-04-22 09:48:21 +02:00
76ef0a2d59 Merge pull request 'DEVTOOLS-185 Remplacer le json en dur des images resgen' (#11) from DEVTOOLS-186/SVG_resgen into master
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Reviewed-on: #11
Reviewed-by: Thibaut Schmitt <t.schmitt@openium.fr>
2024-04-19 17:02:26 +02:00
129eb135f1 DEVTOOLS-185 Remplacer le json en dur des images resgen
Some checks are pending
gitea-openium/resgen.swift/pipeline/pr-master Build started...
2024-04-19 17:02:00 +02:00
4ad15fcded Merge pull request 'xcstrings' (#10) from xcstrings into master
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Reviewed-on: #10
Reviewed-by: Thibaut Schmitt <t.schmitt@openium.fr>
2024-04-19 16:59:03 +02:00
fb2ddb2227 DEVTOOLS-181 Gérer le tag noTranslation pour les xcstrings 2024-04-17 09:44:09 +02:00
27f86f5c4d Correction de l'option pour le fichier xcstrings 2024-04-15 16:51:18 +02:00
209ba49e3f Gestion des commentaires 2024-04-12 17:15:15 +02:00
ba07005b13 Fix equatable properties for arrays 2024-04-12 16:45:09 +02:00
6c3f3a8982 Correction du test testGenerateXcStringsRootObject 2024-04-12 16:25:10 +02:00
0d651b810f Première implémentation des xcstrings 2024-04-12 16:09:54 +02:00
1d7fc76340 Changed the condition for moe visibility 2024-04-11 15:49:07 +02:00
5d4e461933 Affichage du commentaire même si nil ou empty 2024-04-11 14:20:54 +02:00
55264d61ad Modification de l'affichage des commentaires
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
gitea-openium/resgen.swift/pipeline/pr-master There was a failure building this commit
2024-04-11 11:18:57 +02:00
d21ad9d1ea Update JenkinsFile Xcode version
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2024-04-11 10:19:10 +02:00
0bd6c3c2d4 Correction des commentaires des strings
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2024-04-11 10:16:28 +02:00
eed20367b9 fix: Edit for NSObject in Firebase
Some checks failed
gitea-openium/resgen.swift/pipeline/pr-master There was a failure building this commit
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
PixeeBox/resgen.swift/pipeline/head There was a failure building this commit
2023-12-13 11:24:21 +01:00
43b5111d79 Actualiser Sources/ResgenSwift/Analytics/Generator/AnalyticsGenerator.swift
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-13 10:39:12 +01:00
2983093a9c Add Swiftlint 2023-12-13 10:39:12 +01:00
b4bbaa3bfd Fix Image 2023-12-13 10:39:12 +01:00
498c8fa4ae Fix Font 2023-12-13 10:39:12 +01:00
2957da6233 Fix Color 2023-12-13 10:39:12 +01:00
d79af06c38 docs: Add Analytics section in README
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-13 10:27:35 +01:00
d8937f2de6 docs: Add Analytics section in README 2023-12-13 10:23:31 +01:00
9b27f24197 docs: Add Analytics section in README 2023-12-13 10:20:53 +01:00
1d58fd5510 Edit sample file
Some checks failed
gitea-openium/resgen.swift/pipeline/pr-master There was a failure building this commit
2023-12-12 16:58:25 +01:00
f6c49bf626 Add parse error
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-11 11:19:19 +01:00
f1b62d83c4 Add missing print error
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-11 10:29:19 +01:00
ee5055efa5 Retours sur la structure du code
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-11 10:24:42 +01:00
6f8e3b6664 Add error handling
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-11 10:09:24 +01:00
1f2933950b Add \n at the end of R.swift
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-08 15:16:50 +01:00
3b90387e10 fix: Import + empty parameters
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-08 15:03:28 +01:00
1ee4998ec6 test: Edit test
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-08 14:22:17 +01:00
ca763cd5d0 fix: Rebase tags
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-08 11:30:05 +01:00
3fc2fd9bac fix: Tags -> Anlytics 2023-12-08 11:30:05 +01:00
09c153ba65 Actualiser Jenkinsfile
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-06 14:51:01 +01:00
2a144fc00e Test Tags generation
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-06 14:48:47 +01:00
6aef8bc2de Add FirebaseManager 2023-12-06 11:23:26 +01:00
3e133773a9 Add Manager + MatomoManager
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-06 10:34:27 +01:00
5fd680110c Fix forgotten code
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-05 17:09:24 +01:00
ce274219fc Add new tag generation
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-12-05 16:56:44 +01:00
fa5bf192e8 Delete lang option and add target option 2023-12-05 16:55:45 +01:00
1a45ec7b0d New version of tags.txt 2023-12-05 16:54:44 +01:00
7d6bb4fcb9 Merge pull request 'v1.2.2' (#5) from v1.2.2 into master
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Reviewed-on: #5
2023-06-07 09:53:38 +02:00
844a8aec45 Add availability to get keyPath from generated strings Key enumeration
Some checks are pending
gitea-openium/resgen.swift/pipeline/head Build started...
2023-06-07 09:52:56 +02:00
beb28e652d Add availability to get keyPath from generated strings Key enumeration 2023-06-07 09:52:36 +02:00
78be15d57d Merge pull request 'v1.2.1' (#4) from v1.2.1 into master
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Reviewed-on: #4
2023-06-05 09:33:14 +02:00
d6c4702390 Make R2String string Key enum unique by adding extnesion suffix (+ make extension suffix required)
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-05-12 11:59:46 +02:00
1e073af5df Fix architecture generation and add enum key of each string in R2String
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2023-05-12 11:33:36 +02:00
188178fe6a Update Changelog with v1.2
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2022-11-24 09:13:30 +01:00
c31d0b1618 Fix typo in CHANGELOG 2022-11-22 17:55:32 +01:00
b662fc64f3 Update Readme
Populate CHANGELOG.md based on previous versions
2022-11-22 17:54:20 +01:00
9ab7e74991 Renaming errors property: localizedDescription -> description
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Re enabling generation of ressources on commond
Architecture will now generate property of subobject as non-static. It will allow usage like R.sub_object.sub_property.property
2022-11-22 17:37:24 +01:00
fc427733ee Fix error/warning message to be shown in Xcode.IssueNavigator
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2022-11-22 17:14:13 +01:00
5a3d273acc Passage version en 1.2
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Ajout de la définition d'une architecture de classe pour éviter de définir manuellement les classes R/R2Image/R2Fonts.... (optionel)
2022-11-18 17:20:21 +01:00
a7a850799d Update Readme to add install/uninstall steps 2022-11-07 11:15:38 +01:00
7d3652f1f9 Update version to 1.1
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
2022-11-07 10:47:26 +01:00
41733d2680 Squashed commit of the following:
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
commit aa59ef28ea56315eb421ba044ddaf0c4066bfff8
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Mon Nov 7 10:26:28 2022 +0100

    Add trailing carrier at the end of generated extension files

commit e985950aa1e39d81d4938e15f8724c0f7723b003
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Fri Nov 4 16:37:34 2022 +0100

    Replace installation script by script that install completion file
    Setup a Makefile to install resgen

commit d574384c151259610a4c2f837b14068bb7716e44
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Fri Nov 4 14:33:39 2022 +0100

    Refactor
    Improve testability
    Add tests on SwiftUI generated code
    Add tests on  command

commit d9e76632c3037da0ed9e1dd37056685416579da9
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Thu Nov 3 15:43:47 2022 +0100

    Fixing bad merge on FontOptions

commit 76b5ebfcd1cde7a7d4c83f516a4fc937841e7715
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Thu Nov 3 15:37:28 2022 +0100

    Squashed commit of the following:

    commit 085f1ffc33
    Author: Thibaut Schmitt <t.schmitt@openium.fr>
    Date:   Thu Nov 3 15:00:27 2022 +0100

        Refactor SwiftUI extension generation and generation SwiftUI extension for images

    commit 4f7d7e18b1
    Author: Thibaut Schmitt <t.schmitt@openium.fr>
    Date:   Mon Oct 31 16:21:32 2022 +0100

        Génération de composant SwiftUI: Color et Image

    commit 0797667b25
    Author: Thibaut Schmitt <t.schmitt@openium.fr>
    Date:   Mon Oct 31 16:21:12 2022 +0100

        Génération de composant SwiftUI: Color et Image

commit 417a2630925841dd486ae1d684d28ab7dca240e0
Author: Thibaut Schmitt <t.schmitt@openium.fr>
Date:   Wed Oct 19 17:13:03 2022 +0200

    Update Info.plist UIAppFonts key when generating fonts (if plist path if defined)
2022-11-07 10:32:17 +01:00
6203700b0c Publish v1.0
Some checks failed
gitea-openium/resgen.swift/pipeline/head There was a failure building this commit
Reviewed-on: #1
2022-10-17 11:24:27 +02:00
202 changed files with 11336 additions and 3519 deletions

View File

@ -1,43 +1,276 @@
disabled_rules: # rule identifiers to exclude from running
- leading_whitespace
- trailing_whitespace
- identifier_name
- large_tuple
- file_length
- line_length
- force_try
- shorthand_operator
- type_body_length
- function_body_length
- function_parameter_count
- redundant_string_enum_value
- unused_closure_parameter
- cyclomatic_complexity
- syntactic_sugar
- empty_enum_arguments
- force_cast
- multiple_closures_with_trailing_closure
- private_over_fileprivate
- trailing_comma
- comment_spacing
excluded: # paths to ignore during linting. Takes precedence over `included`.
- DerivedData
- Carthage
- Pods
- vendor
- Vendor
- "*/R2Tag+tags.swift"
type_name:
min_length: 1 # only warning
max_length: # warning and error
warning: 50
error: 60
allowed_symbols: ["_"]
nesting:
type_level:
warning: 3
error: 6
statement_level:
warning: 5
error: 10
# All rules here : https://realm.github.io/SwiftLint/rule-directory.html
analyzer_rules:
- capture_variable
- typesafe_array_init
- unused_declaration
- unused_import
included:
- Sources
## Rules configuration
attributes:
always_on_line_above: ["@InjectedValue", "@ViewBuilder", "@IBOutlet"]
always_on_same_line: ["@Environment", "@EnvironmentObject", "@StateObject", "@State"]
identifier_name:
min_length:
- 2
max_length:
- 60
excluded:
- x
- y
type_name:
min_length: 3
max_length: 60
excluded:
- T
allowed_symbols:
- _
# line_length:
# warning: 150
disabled_rules:
- blanket_disable_command # do not warn when rule is not re-enable later in the file
- type_contents_order
- legacy_objc_type
- indentation_width
- function_parameter_count
- line_length
- function_body_length
- cyclomatic_complexity
- optional_data_string_conversion
opt_in_rules:
# Default rules :
- block_based_kvo
- class_delegate_protocol
- closing_brace
- closure_parameter_position
- colon
- comma
- comment_spacing
- compiler_protocol_init
- computed_accessors_order
- control_statement
- custom_rules
# - cyclomatic_complexity
- deployment_target
- discouraged_direct_init
- duplicate_enum_cases
- duplicate_imports
- duplicated_key_in_dictionary_literal
- dynamic_inline
- empty_enum_arguments
- empty_parameters
- empty_parentheses_with_trailing_closure
- file_length
- for_where
- force_unwrapping
- force_cast
- force_try
- trailing_whitespace
# - function_body_length
# - function_parameter_count
- generic_type_name
- identifier_name
- implicit_getter
- inclusive_language
- is_disjoint
- large_tuple
- leading_whitespace
- legacy_cggeometry_functions
- legacy_constant
- legacy_constructor
- legacy_hashing
- legacy_nsgeometry_functions
- legacy_random
# - line_length
- mark
- multiple_closures_with_trailing_closure
- nesting
- no_fallthrough_only
- no_space_in_method_call
- notification_center_detachment
- ns_number_init_as_function_reference
- nsobject_prefer_isequal
- opening_brace
- operator_whitespace
- orphaned_doc_comment
- private_over_fileprivate
- private_unit_test
- protocol_property_accessors_order
- reduce_boolean
- redundant_discardable_let
- redundant_objc_attribute
- redundant_optional_initialization
- redundant_set_access_control
- redundant_string_enum_value
- redundant_void_return
- return_arrow_whitespace
- self_in_property_initialization
- shorthand_operator
- statement_position
- superfluous_disable_command
- switch_case_alignment
- syntactic_sugar
- todo
- trailing_comma
- trailing_newline
- trailing_semicolon
- type_body_length
- type_name
- unavailable_condition
- unneeded_break_in_switch
- unused_closure_parameter
- unused_control_flow_label
- unused_enumerated
- unused_optional_binding
- unused_setter_value
- valid_ibinspectable
- vertical_parameter_alignment
- vertical_whitespace
- void_function_in_ternary
- void_return
- xctfail_message
- accessibility_trait_for_button
- array_init
- attributes
- closure_body_length
- closure_end_indentation
- closure_spacing
- collection_alignment
- comma_inheritance
- contains_over_filter_count
- contains_over_filter_is_empty
- contains_over_first_not_nil
- contains_over_range_nil_comparison
- convenience_type
- discarded_notification_center_observer
- discouraged_assert
- empty_count
- empty_string
- empty_xctest_method
- enum_case_associated_values_count
- explicit_init
- fallthrough
- fatal_error_message
- file_header
- first_where
- flatmap_over_map_reduce
- ibinspectable_in_extension
- implicit_return
- implicitly_unwrapped_optional
- joined_default_parameter
- last_where
- legacy_multiple
- let_var_whitespace
- literal_expression_end_indentation
- lower_acl_than_parent
# - missing_docs
- modifier_order
- multiline_arguments
- multiline_arguments_brackets
- multiline_function_chains
- multiline_literal_brackets
- multiline_parameters
- multiline_parameters_brackets
- nimble_operator
- no_extension_access_modifier
- no_grouping_extension
- nslocalizedstring_key
- nslocalizedstring_require_bundle
- number_separator
- operator_usage_whitespace
- optional_enum_case_matching
- overridden_super_call
- override_in_extension
- pattern_matching_keywords
- prefer_self_in_static_references
- prefer_self_type_over_type_of_self
- prefer_zero_over_explicit_init
- prefixed_toplevel_constant
- private_action
- private_outlet
- prohibited_interface_builder
- prohibited_super_call
- quick_discouraged_call
- quick_discouraged_focused_test
- quick_discouraged_pending_test
- redundant_nil_coalescing
- redundant_type_annotation
- required_enum_case
- return_value_from_void_function
- self_binding
- shorthand_optional_binding
- single_test_class
- sorted_first_last
- sorted_imports
- strong_iboutlet
- test_case_accessibility
- toggle_bool
- trailing_closure
- unavailable_function
- unneeded_parentheses_in_closure_argument
- unowned_variable_capture
- untyped_error_in_catch
- vertical_parameter_alignment_on_call
- vertical_whitespace_between_cases
- vertical_whitespace_closing_braces
- weak_delegate
- xct_specific_matcher
custom_rules:
# Empty line before and after MARK -------------------------------------------
# mark_spacing:
# name: "Surround MARK by empty lines"
# regex: '\n[^\n]([^\n]*\/\/ MARK[^\n]*)\n[^\n]'
# message: "Surround MARK by empty lines"
# severity: warning
# Empty line -----------------------------------------------------------------
# no_empty_line_after_func:
# name: "No empty line after init or func"
# regex: '(func|init|let\s|var\s)[^\n]*\{[^\n\{\}]*\n\n'
# message: "No empty line after init or func"
# severity: warning
# Empty line after canImport -----------------------------------------------------------------
no_empty_line_after_can_import:
name: "Add empty line after #if canImport"
regex: '#if canImport\(.*\)\n[^\n]*(import|class|struct|enum|extension|protocol)'
message: "Add empty line after #if canImport"
severity: warning
# Spacings -------------------------------------------------------------------
empty_line_required:
name: "Add empty line after class, struct, enum, extension or protocol"
regex: '(class |struct |enum |extension |protocol )[^\n]*\{\n[^\n]*(class|struct|enum|extension|protocol|func|let|var|weak|private|internal|public|open|static|final|\/\/|init|case|@)'
message: "Add empty line after class, struct, enum, extension or protocol"
severity: warning
match_kinds:
- argument
- attribute.builtin
- attribute.id
- buildconfig.id
- buildconfig.keyword
- comment
- comment.mark
- comment.url
- identifier
- keyword
- number
- objectliteral
- parameter
- placeholder
- string
- string_interpolation_anchor
- typeidentifier

View File

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ColorToolCore"
BuildableName = "ColorToolCore"
BlueprintName = "ColorToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ColorToolCore"
BuildableName = "ColorToolCore"
BlueprintName = "ColorToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ColorToolCore"
BuildableName = "ColorToolCore"
BlueprintName = "ColorToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FontToolCore"
BuildableName = "FontToolCore"
BlueprintName = "FontToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FontToolCore"
BuildableName = "FontToolCore"
BlueprintName = "FontToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FontToolCore"
BuildableName = "FontToolCore"
BlueprintName = "FontToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,78 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Imagium"
BuildableName = "Imagium"
BlueprintName = "Imagium"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Imagium"
BuildableName = "Imagium"
BlueprintName = "Imagium"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Imagium"
BuildableName = "Imagium"
BlueprintName = "Imagium"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,237 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1310"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ColorToolCore"
BuildableName = "ColorToolCore"
BlueprintName = "ColorToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FontToolCore"
BuildableName = "FontToolCore"
BlueprintName = "FontToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ResgenSwift"
BuildableName = "ResgenSwift"
BlueprintName = "ResgenSwift"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ResgenSwiftTests"
BuildableName = "ResgenSwiftTests"
BlueprintName = "ResgenSwiftTests"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CLIToolCore"
BuildableName = "CLIToolCore"
BlueprintName = "CLIToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "StringToolCore"
BuildableName = "StringToolCore"
BlueprintName = "StringToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "TwineToolCore"
BuildableName = "TwineToolCore"
BlueprintName = "TwineToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Strings"
BuildableName = "Strings"
BlueprintName = "Strings"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FontTool"
BuildableName = "FontTool"
BlueprintName = "FontTool"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Imagium"
BuildableName = "Imagium"
BlueprintName = "Imagium"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ToolCore"
BuildableName = "ToolCore"
BlueprintName = "ToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ResgenSwiftTests"
BuildableName = "ResgenSwiftTests"
BlueprintName = "ResgenSwiftTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Imagium"
BuildableName = "Imagium"
BlueprintName = "Imagium"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ColorToolCore"
BuildableName = "ColorToolCore"
BlueprintName = "ColorToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Imagium"
BuildableName = "Imagium"
BlueprintName = "Imagium"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -34,6 +34,34 @@
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ToolCore"
BuildableName = "ToolCore"
BlueprintName = "ToolCore"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ResgenSwift_ResgenSwift"
BuildableName = "ResgenSwift_ResgenSwift"
BlueprintName = "ResgenSwift_ResgenSwift"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
@ -74,6 +102,20 @@
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "generate"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;$(PROJECT_DIR)/../SampleFiles/resgenConfiguration.yml&quot;"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "--project-directory &quot;$(PROJECT_DIR)&quot;"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View File

@ -0,0 +1,34 @@
# v1.2 - Architecture generation
## New
- New section in configuration file: `architecture`. Define your ressources accessors achitecture and let ResgenSwift generate it for you. Check out Readme to know more.
## Fixes
- Errors and Warnings are now shown in Xcode Issue Navigator
---
# v1.1 - SwiftUI compatibility
## New
- Update plist `UIAppFonts` when generated fonts (use plistBuddy)
- New parameter: `infoPlistPaths`
- Generate SwiftUI extensions for colors, fonts and images
- New parameter: `extensionNameUIKit`
- Adding Makefile to install, unsintall and create man page.
## Fixes
Fix SwiftLint rule `trailing_newline`
---
# v1.0 - Configuration file
## Major
- A new command has been added: `generate`. Instead of runnning every single command, it will run all necessary command based on a `yaml` configuration file. Check out Readme to know more.
## Minors
- Code refactoring
- Huge performance improvements
- Readme.md update
- Add option to generate static properties/methods (`staticMembers`)
- Add option to specify the project directory (`--project-directory`). It allows to run ResgenSwift from anywhere
- Add `install.sh` script to install ResgenSwift in `/usr/local/bin`

8
Jenkinsfile vendored
View File

@ -1,6 +1,10 @@
library "openiumpipeline"
//env.DEVELOPER_DIR="/Applications/Xcode_12.4.app/Contents/Developer"
//env.SIMULATOR_DEVICE_TYPES="iPad--7th-generation-"
env.DEVELOPER_DIR="/Applications/Xcode-16.3.0.app/Contents/Developer"
// env.SIMULATOR_DEVICE_TYPES="iPhone-14-Pro"
// env.SLACK_CHANNEL = "prj-skdevkit"
env.IS_PACKAGE_SWIFT=1
env.TARGETS_MACOS=1
env.PACKAGE_NAME="ResgenSwift" // xcodebuild -list => Only 1 scheme
iOSpipeline()

63
Makefile Normal file
View File

@ -0,0 +1,63 @@
SHELL = /bin/zsh
#INSTALL_DIR ?= /usr/local/bin
INSTALL_DIR = /tmp/ResgenYolo
MAN_DIR := /usr/local/share/man
MAN_PAGE_NAME = resgen-swift.1
REPO_DIR = $(shell pwd)
BUILD_DIR = $(REPO_DIR)/.build
#
# Man pages
#
# create-man-files:
# swift package plugin generate-manual
# cp $(BUILDDIR)/plugins/GenerateManualPlugin/outputs/ResgenSwift/resgen-swift.1 $(REPODIR)/man/resgen-swift.1
# install-man-files:
# mkdir -p ${DESTDIR}${mandir}/man1
# cp $(REPODIR)/man/resgen-swift.1 ${DESTDIR}${mandir}/man1/resgen-swift.1
create-and-install-man-files:
swift package plugin generate-manual
mkdir -p ${MAN_DIR}/man1
cp $(BUILD_DIR)/plugins/GenerateManualPlugin/outputs/ResgenSwift/${MAN_PAGE_NAME} ${MAN_DIR}/man1/${MAN_PAGE_NAME}
#
# Build and install
#
build-debug:
@swift build \
-c debug \
--build-path "$(BUILD_DIR)"
build-release:
@swift build \
-c release \
--build-path "$(BUILD_DIR)"
.PHONY: install
install: build-release
@install -d "$(INSTALL_DIR)"
@install "$(wildcard $(BUILD_DIR)/**/release/ResgenSwift)" "$(INSTALL_DIR)/resgen-swift"
@make create-and-install-man-files
#
# Uninstall and cleaning
#
.PHONY: uninstall
uninstall:
@rm -rf "$(INSTALL_DIR)/resgen-swift"
@rm -rf ${MAN_DIR}/man1/${MAN_PAGE_NAME}
.PHONY: clean
distclean:
@rm -f $(BUILD_DIR)/release
.PHONY: clean
clean: distclean
@rm -rf $(BUILD_DIR)

View File

@ -1,16 +1,32 @@
{
"object": {
"pins": [
"pins" : [
{
"package": "swift-argument-parser",
"repositoryURL": "https://github.com/apple/swift-argument-parser",
"state": {
"branch": null,
"revision": "e1465042f195f374b94f915ba8ca49de24300a0d",
"version": "1.0.2"
"identity" : "swift-argument-parser",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser",
"state" : {
"revision" : "41982a3656a71c768319979febd796c6fd111d5c",
"version" : "1.5.0"
}
}
]
},
"version": 1
{
"identity" : "swiftlintplugin",
"kind" : "remoteSourceControl",
"location" : "https://github.com/lukepistrol/SwiftLintPlugin",
"state" : {
"revision" : "87454f5c9ff4d644086aec2a0df1ffba678e7f3c",
"version" : "0.57.1"
}
},
{
"identity" : "yams",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams.git",
"state" : {
"revision" : "0d9ee7ea8c4ebd4a489ad7a73d5c6cad55d6fed3",
"version" : "5.0.6"
}
}
],
"version" : 2
}

View File

@ -1,53 +1,47 @@
// swift-tools-version:5.3
// swift-tools-version:5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "ResgenSwift",
platforms: [.macOS(.v10_12)],
platforms: [.macOS(.v14), .iOS(.v15)],
dependencies: [
// 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.5.0"
),
.package(
url: "https://github.com/jpsim/Yams.git",
from: "5.0.1"
),
.package(
url: "https://github.com/lukepistrol/SwiftLintPlugin",
exact: "0.57.1"
),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
.executableTarget(
name: "ResgenSwift",
dependencies: ["FontTool", "ColorTool", "Strings", "Imagium"]
),
.target(
name: "FontTool",
dependencies: [
"ToolCore",
.product(name: "ArgumentParser", package: "swift-argument-parser")
]
),
.target(
name: "ColorTool",
dependencies: [
"ToolCore",
.product(name: "ArgumentParser", package: "swift-argument-parser")
]
),
.target(
name: "Strings",
dependencies: [
"ToolCore",
.product(name: "ArgumentParser", package: "swift-argument-parser")
"Yams",
.product(
name: "ArgumentParser",
package: "swift-argument-parser"
)
],
sources: ["."] // Force include all subdirectories
),
.target(
name: "Imagium",
dependencies: [
"ToolCore",
.product(name: "ArgumentParser", package: "swift-argument-parser")
plugins: [
// .plugin(name: "SwiftLint", package: "SwiftLintPlugin")
]
),
// Helper targets
.target(name: "ToolCore"),
// Test targets
.testTarget(
name: "ResgenSwiftTests",

353
README.md
View File

@ -4,18 +4,22 @@ ResgenSwift is a package, fully written in Swift, to help you automatize ressour
> 🧐 For all commands, see samples files in `SampleFiles`
# Fonts
## Fonts
Font generator generates an extension of `UIFont` (or a custom class). It also prints `UIAppFonts` to put in your project `.plist`.
iOS required to use the **real name** of the font, this name can be different from its filename. To get the **real name**, it uses `fc-scan`.
Font generator generates an extension of `UIFont` and `Font` (or custom classes). It also prints content of `UIAppFonts` from your project `.plist`. If project `.plist` is specified, it will update `UIAppFonts` content of all `.plist`.
iOS required to use the **real name** of the font, this name can be different from its filename. To get the **real name**, it uses `fc-scan`. So, be sure that the `$PATH` contains path of `fc-scan`.
**Example**
```
swift run -c release FontTool $FORCE_FLAG "./Fonts/fonts.txt" \
```sh
swift run -c release ResgenSwift fonts $FORCE_FLAG "./Fonts/fonts.txt" \
--extension-output-path "./Fonts/Generated" \
--extension-name "AppFont" \
--extension-suffix "GreatApp"
--extension-name-ui-kit "UIAppFont" \
--extension-suffix "GreatApp" \
--static-members true \
--info-plist-paths "./path/one/to/Info.plist ./path/two/to/Info.plist"
```
**Parameters**
@ -23,23 +27,26 @@ swift run -c release FontTool $FORCE_FLAG "./Fonts/fonts.txt" \
1. `-f`: force generation
2. Font input folder, it will search for every `.ttf` and `.otf` files specified in `fonts.txt`
3. `--extension-output-path`: path where to generate generated extension
4. `--extension-name` *(optional)* : name of thee class to add the extension
5. `--extension-suffix` *(optional)* : additional text which is added to the filename (ex: `AppFont+GreatApp.swift`)
> ⚠️ If extension name is not set or is `UIFont`, it will generate static property on `UIFont` instead of method in your custom class.
4. `--extension-name` *(optional)* : name of the class to add SwiftUI getters
5. `--extension-name-ui-kit` *(optional)* : name of the class to add UIKit getters
6. `--extension-suffix` *(optional)* : additional text which is added to the filename (ex: `AppFont+GreatApp.swift`)
7. `--static-members` *(optional)*: generate static properties or not
8. `--info-plist-paths` *(optional)*: array of `.plist`, you can specify multiple `Info.plist` for multiple targets
# Colors
## Colors
Colors generator generates an extension of `UIColor` (or a custom class) along with colorsets in specified xcassets.
```
swift run -c release ColorTool $FORCE_FLAG "./Colors/colors.txt" \
```sh
swift run -c release ResgenSwift colors $FORCE_FLAG "./Colors/colors.txt" \
--style all \
--xcassets-path "./Colors/colors.xcassets" \
--extension-output-path "./Colors/Generated/" \
--extension-name "AppColor" \
--extension-suffix "GreatApp"
--extension-name-ui-kit "UIAppColor" \
--extension-suffix "GreatApp" \
--static-members true
```
**Parameters**
@ -48,25 +55,25 @@ swift run -c release ColorTool $FORCE_FLAG "./Colors/colors.txt" \
2. Input colors file
3. `--style` can be `all` or `light`
4. `--extension-output-path`: path where to generate generated extension
5. `--extension-name` *(optional)* : name of class to add the extension
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppColor+GreatApp.swift`)
> ⚠️ If extension name is not set or is `UIColor`, it will generate static property on `UIColor`.
5. `--extension-name` *(optional)* : name of the class to add SwiftUI getters
6. `--extension-name-ui-kit` *(optional)* : name of the class to add UIKit getters
7. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppColor+GreatApp.swift`)
8. `--static-members` *(optional)*: generate static properties or not
# Strings
## Strings
Strings command allows to generate `strings` files along with extensions to access those strings easily. It can do it 2 ways: Twine and Stringium. It is not recommended to use Twine except on legacy projects or while migrating to ResgenSwift, because it use https://github.com/openium/twine. Using Stringium is recommended because it does not required external dependency and allow more customisation.
## Twine (not recommended)
### Twine (not recommended)
```
swift run -c release Strings twine $FORCE_FLAG "./Twine/strings.txt" \
```sh
swift run -c release ResgenSwift strings twine $FORCE_FLAG "./Twine/strings.txt" \
--output-path "./Twine/Generated" \
--langs "fr en en-us" \
--default-lang "en" \
--extension-output-path "./Twine/Generated"
```
```
**Parameters**
@ -74,18 +81,20 @@ swift run -c release Strings twine $FORCE_FLAG "./Twine/strings.txt" \
2. Input translations file (must be Twine formatted)
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. `--extension-output-path`: path where to generate generated extension
5. `--extension-output-path`: path where to generate generated extension
## Stringium (recommended)
### Stringium (recommended)
```
swift run -c release Strings stringium $FORCE_FLAG "./Strings/strings.txt" \
```sh
swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/strings.txt" \
--output-path "./Strings/Generated" \
--langs "fr en en-us" \
--default-lang "en" \
--extension-output-path "./Strings/Generated" \
--extension-name "AppString" \
--extension-suffix "GreatApp"
--extension-suffix "GreatApp" \
--xcStrings true
--static-members true
```
**Parameters**
@ -97,19 +106,21 @@ swift run -c release Strings stringium $FORCE_FLAG "./Strings/strings.txt" \
4. `--extension-output-path`: path where to generate generated 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. `--xcStrings`*(optional)* : generate string catalog
7. `--static-members` *(optional)*: generate static properties or not
> ⚠️ If extension name is not set or is `String`, it will generate static property on `String`.
# Tags
## Tags
Tags is also a subcommand of `Strings`. Input files are formatted the same way. Tags will generate properties which return exactly what is specified in the input file. It was designed to be used for analytics purpose and to be shared with any other platform to have the same analytics keys.
```
swift run -c release Strings tags $FORCE_FLAG "./Tags/tags.txt" \
```sh
swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
--lang "ium" \
--extension-output-path "./Tags/Generated" \
--extension-name "AppTags" \
--extension-suffix "GreatApp"
--extension-suffix "GreatApp" \
--static-members true
```
**Parameters**
@ -120,19 +131,87 @@ swift run -c release Strings tags $FORCE_FLAG "./Tags/tags.txt" \
4. `--extension-output-path`: path where to generate generated extension
5. `--extension-name` *(optional)* : name of class to add the extension
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppTags+GreatApp.swift`)
7. `--static-members` *(optional)*: generate static properties or not
> ⚠️ If extension name is not set or is `Tags`, it will generate static property on `Tags`. This class may not exists in your project, just create an empty class named `Tags` is necessary.
> ⚠️ If extension name is not set or is `Tags`, it will generate the following typaloas `typealias Tags = String`.
# Images
## Analytics
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
swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/tags.txt" \
--target "matomo firebase" \
--extension-output-path "./Analytics/Generated" \
--extension-name "AppAnalytics" \
--extension-suffix "GreatApp" \
--static-members true
```
**Parameters**
1. `-f`: force generation
2. Input tags file (must be YAML formatted)
3. `--target`: target with you will log UX
4. `--extension-output-path`: path where to generate generated extension
5. `--extension-name` *(optional)* : name of class to add the extension
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppAnalytics+GreatApp.swift`)
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`.
### YAML
```
- id: s1_def_one
name: s1 def one _TITLE_
path: s1_def_one/_TITLE_
action: Tap
category: User
tags: ios,droid
comments:
parameters:
- name: title
type: String
replaceIn: name,path
```
1. `id`: name of the method (method name will be composed of `log` + `Event|Screen` + `id`)
2. `name`: name of the tag
3. `path` *(optional with firebase)* : needed for matomo but not with firebase (log screen)
4. `action` *(optional with firebase)* : needed for matomo but not with firebase (log event)
5. `category` *(optional with firebase)* : needed for matomo but not with firebase (log event)
6. `tags`: which platform target
7. `comments` *(optional)*
8. `parameters` *(optional)*
**Parameters**
You can use parameters in generate methods.
1. `name`: name of the parameter
2. `type`: type of the parameter (Int, String, Bool, Double)
3. `replaceIn` *(optional)*
**Replace in**
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)
## Images
Images generator will generate images assets along with extensions to access those images easily.
```
swift run -c release Imagium $FORCE_FLAG "./Images/images.txt" \
```sh
swift run -c release ResgenSwift images $FORCE_FLAG "./Images/images.txt" \
--xcassets-path "./Images/app.xcassets" \
--extension-output-path "./Images/Generated" \
--extension-name "AppImage" \
--extension-suffix "GreatApp"
--extension-name-ui-kit "UIAppImage" \
--extension-suffix "GreatApp" \
--static-members true
```
**Parameters**
@ -141,11 +220,201 @@ swift run -c release Imagium $FORCE_FLAG "./Images/images.txt" \
2. Input images definitions file
3. `--xcassets-path`: xcasset path where to generate imagesets
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 the class to add SwiftUI getters
6. `--extension-name-ui-kit` *(optional)* : name of the class to add UIKit getters
6. `--extension-suffix` *(optional)* : additional text which is added to filename (ex: `AppImage+GreatApp.swift`)
7. `--static-members` *(optional)*: generate static properties or not
> ⚠️ If extension name is not set or is `UIImage`, it will generate static property on `UIImage`.
> ⚠️ 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
# TODO
## All at once
[ ] Allow static variable generation on custom extension
Another command exists to generate all ressources at the same time: `generate`. It use the following commands: `Fonts`, `Colors`, `Strings/Stringium`, `Strings/Tags`, `Images`.
All parameters can be specified in a configuration file in `Yaml`:
> Order of configuration types does not matter. Order them to fit your needs.
```yaml
---
colors:
-
inputFile: String
style: [light/all]
xcassetsPath: String
extensionOutputPath: String
extensionName: String?
extensionNameUIKit: String?
extensionSuffix: String?
staticMembers: Bool?
fonts:
-
inputFile: String
extensionOutputPath: String
extensionName: String?
extensionNameUIKit: String?
extensionSuffix: String?
staticMembers: Bool?
infoPlistPaths: [String]
images:
-
inputFile: String
xcassetsPath: String
extensionOutputPath: String
extensionName: String?
extensionNameUIKit: String?
extensionSuffix: String?
staticMembers: Bool?
strings:
-
inputFile: String
outputPath: String
langs: String
defaultLang: String
extensionOutputPath: String
extensionName: String?
extensionSuffix: String?
staticMembers: Bool?
tags:
-
inputFile: String
lang: String
extensionOutputPath: String
extensionName: String?
extensionSuffix: String?
staticMembers: Bool?
```
### Multiple configurations
In some case, you may need to have 2 colors files in your projects. You will need 2 colors configurations. Every configuration type is an array and can contains as many configurations as you need.
Sample for 2 colors configurations:
```yaml
...
colors:
-
inputFile: String
style: [light/all]
xcassetsPath: String
extensionOutputPath: String
extensionName: String?
extensionNameUIKit: String?
extensionSuffix: String?
staticMembers: Bool?
-
inputFile: String
style: [light/all]
xcassetsPath: String
extensionOutputPath: String
extensionName: String?
extensionNameUIKit: String?
extensionSuffix: String?
staticMembers: Bool?
...
```
### No configuration
In some case, you may not need to generate tags for example. You must specified `tags` as an empty array :
```yaml
...
tags: []
...
```
### File architecture
ResgenSwift generate extension of classes. Those classes must exists in your project. You can create them yourself OR you can let ResgenSwift create them by specifying what you want. Do as follow:
```
architecture:
  property: R *(required but not used)*
  classname: R
  path: ./path/to/generate
  children:
    - property: images
      classname: R2Image
    - property: strings
      classname: R2String
    - property: fonts
      classname: R2Font
    - property: images
      classname: R2Image
    - property: uikit
      classname: R2UI
      children:
        - property: images
          classname: R2UIImage
        - property: fonts
          classname: R2UIFont
        - property: images
          classname: R2UIImage
```
This will generate a file named as the architecture classname: `R.swift`. Based on the previous architecture, it will generate:
```
class R {
static let images = R2Image()
static let strings = R2String()
static let fonts = R2Font()
static let images = R2Image()
static let uikit = R2UI()
}
class R2Image {}
class R2String {}
class R2Font {}
class R2Image {}
class R2UI {
let images = R2UIImage()
let fonts = R2UIFont()
let images = R2UIImage()
}
class R2UIImage {}
class R2UIFont {}
class R2UIImage {}
```
### Usage
```sh
swift run -c release ResgenSwift generate path/to/configuration.yml --project-directory ${PROJECT_DIR}
```
> ⚠️ Every path in `configuration.yml` will be prepended by content of `--project-directory` if they are relative path (not starting with `/`)
## Binary usage
### Installation
Run `make install`. Binary will be install in `/usr/local/bin`.
Usage:
```sh
resgen-swift generate path/to/configuration.yml --project-directory ${PROJECT_DIR}
```
### Man page
Commands parameters and details can be find by running `resgen-swift --help`. If you prefer, a man page is also available. Run `man resgen-swift`. Man page is installed on `make install` but you can install manually by running `make create-and-install-man-file`.
### Uninstallation
To uninstall ResgenSwift: `make uninstall`.

View File

@ -0,0 +1,21 @@
// Generated by ResgenSwift.Color 2.1.0
import SwiftUI
extension ColorYolo {
/// Color red is #FF0000 (light) or #FF0000 (dark)"
var red: Color {
Color("red")
}
/// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
var green_alpha_50: Color {
Color("green_alpha_50")
}
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
var blue_light_dark: Color {
Color("blue_light_dark")
}
}

View File

@ -1,21 +0,0 @@
// Generated from ColorToolCore at 2021-12-20 15:16:18 +0000
import UIKit
extension UIColor {
/// Color red is #FF0000 (light) or #FF0000 (dark)"
static var red: UIColor {
UIColor(named: "red")!
}
/// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
static var green_alpha_50: UIColor {
UIColor(named: "green_alpha_50")!
}
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
static var blue_light_dark: UIColor {
UIColor(named: "blue_light_dark")!
}
}

View File

@ -1,21 +0,0 @@
// Generated from ColorToolCore at 2022-02-14 09:30:19 +0000
import UIKit
extension UIColor {
/// Color red is #FF0000 (light) or #FF0000 (dark)"
static var red: UIColor {
UIColor(named: "red")!
}
/// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
static var green_alpha_50: UIColor {
UIColor(named: "green_alpha_50")!
}
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
static var blue_light_dark: UIColor {
UIColor(named: "blue_light_dark")!
}
}

View File

@ -1,21 +0,0 @@
// Generated from ColorToolCore at 2021-12-20 15:17:10 +0000
import UIKit
extension UIColor {
/// Color red is #FF0000 (light) or #FF0000 (dark)"
static var red: UIColor {
UIColor(named: "red")!
}
/// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
static var green_alpha_50: UIColor {
UIColor(named: "green_alpha_50")!
}
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
static var blue_light_dark: UIColor {
UIColor(named: "blue_light_dark")!
}
}

View File

@ -1,8 +1,8 @@
// Generated from ColorToolCore at 2021-12-20 15:34:55 +0000
// Generated by ResgenSwift.Color 1.2
import UIKit
extension R2Color {
extension UIColorYolo {
/// Color red is #FF0000 (light) or #FF0000 (dark)"
@objc var red: UIColor {
@ -14,7 +14,7 @@ extension R2Color {
UIColor(named: "green_alpha_50")!
}
/// Color blue_light_dark is #0000FF (light) or #0000FF (dark)"
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
@objc var blue_light_dark: UIColor {
UIColor(named: "blue_light_dark")!
}

View File

@ -1,21 +1,21 @@
// Generated by ResgenSwift.ColorTool 1.0.0
// Generated by ResgenSwift.Color 2.1.0
import UIKit
extension UIColor {
extension UIhkjhkColorYolo {
/// Color red is #FF0000 (light) or #FF0000 (dark)"
static var red: UIColor {
@objc var red: UIColor {
UIColor(named: "red")!
}
/// Color green_alpha_50 is #A000FF00 (light) or #A000FF00 (dark)"
static var green_alpha_50: UIColor {
@objc var green_alpha_50: UIColor {
UIColor(named: "green_alpha_50")!
}
/// Color blue_light_dark is #0000FF (light) or #0000AA (dark)"
static var blue_light_dark: UIColor {
@objc var blue_light_dark: UIColor {
UIColor(named: "blue_light_dark")!
}
}

View File

@ -0,0 +1,61 @@
// Generated by ResgenSwift.Fonts 2.1.0
import SwiftUI
extension FontYolo {
enum FontName: String {
case LatoItalic = "Lato-Italic"
case LatoLightItalic = "Lato-LightItalic"
case LatoHairline = "Lato-Hairline"
case LatoBold = "Lato-Bold"
case LatoBlack = "Lato-Black"
case LatoRegular = "Lato-Regular"
case LatoBlackItalic = "Lato-BlackItalic"
case LatoBoldItalic = "Lato-BoldItalic"
case LatoLight = "Lato-Light"
case LatoHairlineItalic = "Lato-HairlineItalic"
}
// MARK: - Getter
func LatoItalic(withSize size: CGFloat) -> Font {
Font.custom(FontName.LatoItalic.rawValue, size: size)
}
func LatoLightItalic(withSize size: CGFloat) -> Font {
Font.custom(FontName.LatoLightItalic.rawValue, size: size)
}
func LatoHairline(withSize size: CGFloat) -> Font {
Font.custom(FontName.LatoHairline.rawValue, size: size)
}
func LatoBold(withSize size: CGFloat) -> Font {
Font.custom(FontName.LatoBold.rawValue, size: size)
}
func LatoBlack(withSize size: CGFloat) -> Font {
Font.custom(FontName.LatoBlack.rawValue, size: size)
}
func LatoRegular(withSize size: CGFloat) -> Font {
Font.custom(FontName.LatoRegular.rawValue, size: size)
}
func LatoBlackItalic(withSize size: CGFloat) -> Font {
Font.custom(FontName.LatoBlackItalic.rawValue, size: size)
}
func LatoBoldItalic(withSize size: CGFloat) -> Font {
Font.custom(FontName.LatoBoldItalic.rawValue, size: size)
}
func LatoLight(withSize size: CGFloat) -> Font {
Font.custom(FontName.LatoLight.rawValue, size: size)
}
func LatoHairlineItalic(withSize size: CGFloat) -> Font {
Font.custom(FontName.LatoHairlineItalic.rawValue, size: size)
}
}

View File

@ -1,62 +0,0 @@
// Generated from FontToolCore
import UIKit
extension R2Font {
enum FontName: String {
case LatoItalic = "Lato-Italic"
case LatoLightItalic = "Lato-LightItalic"
case LatoHairline = "Lato-Hairline"
case LatoBold = "Lato-Bold"
case LatoBlack = "Lato-Black"
case LatoRegular = "Lato-Regular"
case LatoBlackItalic = "Lato-BlackItalic"
case LatoBoldItalic = "Lato-BoldItalic"
case LatoLight = "Lato-Light"
case LatoHairlineItalic = "Lato-HairlineItalic"
}
// MARK: - Getter
func LatoItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoItalic.rawValue, size: size)!
}
func LatoLightItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoLightItalic.rawValue, size: size)!
}
func LatoHairline(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoHairline.rawValue, size: size)!
}
func LatoBold(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBold.rawValue, size: size)!
}
func LatoBlack(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBlack.rawValue, size: size)!
}
func LatoRegular(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoRegular.rawValue, size: size)!
}
func LatoBlackItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBlackItalic.rawValue, size: size)!
}
func LatoBoldItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBoldItalic.rawValue, size: size)!
}
func LatoLight(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoLight.rawValue, size: size)!
}
func LatoHairlineItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoHairlineItalic.rawValue, size: size)!
}
}

View File

@ -1,62 +0,0 @@
// Generated from FontToolCore
import UIKit
extension R2Font {
enum FontName: String {
case LatoItalic = "Lato-Italic"
case LatoLightItalic = "Lato-LightItalic"
case LatoHairline = "Lato-Hairline"
case LatoBold = "Lato-Bold"
case LatoBlack = "Lato-Black"
case LatoRegular = "Lato-Regular"
case LatoBlackItalic = "Lato-BlackItalic"
case LatoBoldItalic = "Lato-BoldItalic"
case LatoLight = "Lato-Light"
case LatoHairlineItalic = "Lato-HairlineItalic"
}
// MARK: - Getter
func LatoItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoItalic.rawValue, size: size)!
}
func LatoLightItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoLightItalic.rawValue, size: size)!
}
func LatoHairline(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoHairline.rawValue, size: size)!
}
func LatoBold(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBold.rawValue, size: size)!
}
func LatoBlack(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBlack.rawValue, size: size)!
}
func LatoRegular(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoRegular.rawValue, size: size)!
}
func LatoBlackItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBlackItalic.rawValue, size: size)!
}
func LatoBoldItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBoldItalic.rawValue, size: size)!
}
func LatoLight(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoLight.rawValue, size: size)!
}
func LatoHairlineItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoHairlineItalic.rawValue, size: size)!
}
}

View File

@ -1,63 +0,0 @@
// Lato/Lato-Italic.ttf Lato/Lato-LightItalic.ttf Lato/Lato-Thin.ttf Lato/Lato-Bold.ttf Lato/Lato-Black.ttf Lato/Lato-Regular.ttf Lato/Lato-BlackItalic.ttf Lato/Lato-BoldItalic.ttf Lato/Lato-Light.ttf Lato/Lato-ThinItalic.ttf
// Generated from FontToolCore
import UIKit
extension UIFont {
enum FontName: String {
case LatoItalic = "Lato-Italic"
case LatoLightItalic = "Lato-LightItalic"
case LatoHairline = "Lato-Hairline"
case LatoBold = "Lato-Bold"
case LatoBlack = "Lato-Black"
case LatoRegular = "Lato-Regular"
case LatoBlackItalic = "Lato-BlackItalic"
case LatoBoldItalic = "Lato-BoldItalic"
case LatoLight = "Lato-Light"
case LatoHairlineItalic = "Lato-HairlineItalic"
}
// MARK: - Getter
static let LatoItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoItalic.rawValue, size: size)!
}
static let LatoLightItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoLightItalic.rawValue, size: size)!
}
static let LatoHairline: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoHairline.rawValue, size: size)!
}
static let LatoBold: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBold.rawValue, size: size)!
}
static let LatoBlack: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBlack.rawValue, size: size)!
}
static let LatoRegular: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoRegular.rawValue, size: size)!
}
static let LatoBlackItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBlackItalic.rawValue, size: size)!
}
static let LatoBoldItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBoldItalic.rawValue, size: size)!
}
static let LatoLight: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoLight.rawValue, size: size)!
}
static let LatoHairlineItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoHairlineItalic.rawValue, size: size)!
}
}

View File

@ -1,62 +0,0 @@
// Generated from FontToolCore
import UIKit
extension UIFont {
enum FontName: String {
case LatoItalic = "Lato-Italic"
case LatoLightItalic = "Lato-LightItalic"
case LatoHairline = "Lato-Hairline"
case LatoBold = "Lato-Bold"
case LatoBlack = "Lato-Black"
case LatoRegular = "Lato-Regular"
case LatoBlackItalic = "Lato-BlackItalic"
case LatoBoldItalic = "Lato-BoldItalic"
case LatoLight = "Lato-Light"
case LatoHairlineItalic = "Lato-HairlineItalic"
}
// MARK: - Getter
static let LatoItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoItalic.rawValue, size: size)!
}
static let LatoLightItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoLightItalic.rawValue, size: size)!
}
static let LatoHairline: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoHairline.rawValue, size: size)!
}
static let LatoBold: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBold.rawValue, size: size)!
}
static let LatoBlack: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBlack.rawValue, size: size)!
}
static let LatoRegular: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoRegular.rawValue, size: size)!
}
static let LatoBlackItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBlackItalic.rawValue, size: size)!
}
static let LatoBoldItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBoldItalic.rawValue, size: size)!
}
static let LatoLight: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoLight.rawValue, size: size)!
}
static let LatoHairlineItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoHairlineItalic.rawValue, size: size)!
}
}

View File

@ -1,61 +0,0 @@
// Generated by ResgenSwift.FontTool 1.0.0
import UIKit
extension UIFont {
enum FontName: String {
case LatoItalic = "Lato-Italic"
case LatoLightItalic = "Lato-LightItalic"
case LatoHairline = "Lato-Hairline"
case LatoBold = "Lato-Bold"
case LatoBlack = "Lato-Black"
case LatoRegular = "Lato-Regular"
case LatoBlackItalic = "Lato-BlackItalic"
case LatoBoldItalic = "Lato-BoldItalic"
case LatoLight = "Lato-Light"
case LatoHairlineItalic = "Lato-HairlineItalic"
}
// MARK: - Getter
static let LatoItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoItalic.rawValue, size: size)!
}
static let LatoLightItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoLightItalic.rawValue, size: size)!
}
static let LatoHairline: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoHairline.rawValue, size: size)!
}
static let LatoBold: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBold.rawValue, size: size)!
}
static let LatoBlack: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBlack.rawValue, size: size)!
}
static let LatoRegular: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoRegular.rawValue, size: size)!
}
static let LatoBlackItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBlackItalic.rawValue, size: size)!
}
static let LatoBoldItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBoldItalic.rawValue, size: size)!
}
static let LatoLight: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoLight.rawValue, size: size)!
}
static let LatoHairlineItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoHairlineItalic.rawValue, size: size)!
}
}

View File

@ -0,0 +1,61 @@
// Generated by ResgenSwift.Fonts 2.1.0
import UIKit
extension UIFontYolo {
enum FontName: String {
case LatoItalic = "Lato-Italic"
case LatoLightItalic = "Lato-LightItalic"
case LatoHairline = "Lato-Hairline"
case LatoBold = "Lato-Bold"
case LatoBlack = "Lato-Black"
case LatoRegular = "Lato-Regular"
case LatoBlackItalic = "Lato-BlackItalic"
case LatoBoldItalic = "Lato-BoldItalic"
case LatoLight = "Lato-Light"
case LatoHairlineItalic = "Lato-HairlineItalic"
}
// MARK: - Getter
func LatoItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoItalic.rawValue, size: size)!
}
func LatoLightItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoLightItalic.rawValue, size: size)!
}
func LatoHairline(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoHairline.rawValue, size: size)!
}
func LatoBold(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBold.rawValue, size: size)!
}
func LatoBlack(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBlack.rawValue, size: size)!
}
func LatoRegular(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoRegular.rawValue, size: size)!
}
func LatoBlackItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBlackItalic.rawValue, size: size)!
}
func LatoBoldItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoBoldItalic.rawValue, size: size)!
}
func LatoLight(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoLight.rawValue, size: size)!
}
func LatoHairlineItalic(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.LatoHairlineItalic.rawValue, size: size)!
}
}

View File

@ -1,62 +0,0 @@
// Generated from FontToolCore
import UIKit
extension UIFont {
enum FontName: String {
case LatoItalic = "Lato-Italic"
case LatoLightItalic = "Lato-LightItalic"
case LatoHairline = "Lato-Hairline"
case LatoBold = "Lato-Bold"
case LatoBlack = "Lato-Black"
case LatoRegular = "Lato-Regular"
case LatoBlackItalic = "Lato-BlackItalic"
case LatoBoldItalic = "Lato-BoldItalic"
case LatoLight = "Lato-Light"
case LatoHairlineItalic = "Lato-HairlineItalic"
}
// MARK: - Getter
static let LatoItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoItalic.rawValue, size: size)!
}
static let LatoLightItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoLightItalic.rawValue, size: size)!
}
static let LatoHairline: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoHairline.rawValue, size: size)!
}
static let LatoBold: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBold.rawValue, size: size)!
}
static let LatoBlack: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBlack.rawValue, size: size)!
}
static let LatoRegular: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoRegular.rawValue, size: size)!
}
static let LatoBlackItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBlackItalic.rawValue, size: size)!
}
static let LatoBoldItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoBoldItalic.rawValue, size: size)!
}
static let LatoLight: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoLight.rawValue, size: size)!
}
static let LatoHairlineItalic: ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.LatoHairlineItalic.rawValue, size: size)!
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NewArr</key>
<array/>
<key>UIAppFonts</key>
<array>
<string>Lato-Italic.ttf</string>
<string>Lato-LightItalic.ttf</string>
<string>Lato-Thin.ttf</string>
<string>Lato-Bold.ttf</string>
<string>Lato-Black.ttf</string>
<string>Lato-Regular.ttf</string>
<string>Lato-BlackItalic.ttf</string>
<string>Lato-BoldItalic.ttf</string>
<string>Lato-Light.ttf</string>
<string>Lato-ThinItalic.ttf</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NewArr</key>
<array/>
<key>UIAppFonts</key>
<array>
<string>Lato-Italic.ttf</string>
<string>Lato-LightItalic.ttf</string>
<string>Lato-Thin.ttf</string>
<string>Lato-Bold.ttf</string>
<string>Lato-Black.ttf</string>
<string>Lato-Regular.ttf</string>
<string>Lato-BlackItalic.ttf</string>
<string>Lato-BoldItalic.ttf</string>
<string>Lato-Light.ttf</string>
<string>Lato-ThinItalic.ttf</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,31 @@
// Generated by ResgenSwift.Images 2.1.0
// Images from sampleImages
import SwiftUI
extension ImageYolo {
var article_notification_pull_detail: Image {
Image("article_notification_pull_detail")
}
var article_notification_pull: Image {
Image("article_notification_pull")
}
var new_article: Image {
Image("new_article")
}
var welcome_background: Image {
Image("welcome_background")
}
var article_trash: Image {
Image("article_trash")
}
var ic_close_article: Image {
Image("ic_close_article")
}
}

View File

@ -1,32 +1,31 @@
// Generated by ResgenSwift.Imagium 1.0.0
// Generated by ResgenSwift.Images 1.2
// Images from sampleImages
import UIKit
extension UIImage {
static var article_notification_pull_detail: UIImage {
var article_notification_pull_detail: UIImage {
UIImage(named: "article_notification_pull_detail")!
}
static var article_notification_pull: UIImage {
var article_notification_pull: UIImage {
UIImage(named: "article_notification_pull")!
}
static var new_article: UIImage {
var new_article: UIImage {
UIImage(named: "new_article")!
}
static var welcome_background: UIImage {
var welcome_background: UIImage {
UIImage(named: "welcome_background")!
}
static var article_trash: UIImage {
var article_trash: UIImage {
UIImage(named: "article_trash")!
}
static var ic_close_article: UIImage {
var ic_close_article: UIImage {
UIImage(named: "ic_close_article")!
}
}

View File

@ -1,32 +0,0 @@
// Generated from Imagium at 2022-02-14 09:30:23 +0000
// Images from sampleImages
import UIKit
extension UIImage {
static var article_notification_pull_detail: UIImage {
UIImage(named: "article_notification_pull_detail")!
}
static var article_notification_pull: UIImage {
UIImage(named: "article_notification_pull")!
}
static var new_article: UIImage {
UIImage(named: "new_article")!
}
static var welcome_background: UIImage {
UIImage(named: "welcome_background")!
}
static var article_trash: UIImage {
UIImage(named: "article_trash")!
}
static var ic_close_article: UIImage {
UIImage(named: "ic_close_article")!
}
}

View File

@ -0,0 +1,31 @@
// Generated by ResgenSwift.Images 2.1.0
// Images from sampleImages
import UIKit
extension UIImageYolo {
var article_notification_pull_detail: UIImage {
UIImage(named: "article_notification_pull_detail")!
}
var article_notification_pull: UIImage {
UIImage(named: "article_notification_pull")!
}
var new_article: UIImage {
UIImage(named: "new_article")!
}
var welcome_background: UIImage {
UIImage(named: "welcome_background")!
}
var article_trash: UIImage {
UIImage(named: "article_trash")!
}
var ic_close_article: UIImage {
UIImage(named: "ic_close_article")!
}
}

View File

@ -1,23 +1,16 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "article_notification_pull.png"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "article_notification_pull@2x.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "article_notification_pull@3x.png"
"filename" : "article_notification_pull.svg",
"idiom" : "universal"
}
],
"info" : {
"version" : 1,
"author" : "ResgenSwift-Imagium"
"author" : "ResgenSwift-Imagium",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "original"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="111px" height="69px" viewBox="0 0 111 69" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>article_notification_pull</title>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="article_notification_pull">
<path d="M81.130223,39.5772 C81.130223,39.5772 99.360223,32.4231 102.116223,33.2806 C104.871223,34.1381 111.204223,51.339 110.013223,51.8526 C108.758223,52.4481 102.001223,47.0974 102.001223,47.0974 C102.001223,47.0974 100.834223,50.2797 98.387023,49.5337 C95.939623,48.7877 92.897623,44.9219 92.897623,44.9219 C92.897623,44.9219 92.488923,47.0487 89.986323,46.4577 C87.483723,45.8667 83.726623,41.567 83.726623,41.567 L81.130223,39.5772 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
<path d="M99.259223,10.5629 C97.894023,10.5629 96.788623,9.4412 96.788623,8.0557 C96.788623,7.4619 96.333423,7 95.748223,7 C95.163023,7 94.707823,7.4619 94.707823,8.0557 C94.707823,9.4412 93.602423,10.5629 92.237023,10.5629 C91.651723,10.5629 91.196623,11.0247 91.196623,11.6185 C91.196623,12.2124 91.651723,12.6742 92.237023,12.6742 C93.602423,12.6742 94.707823,13.7959 94.707823,15.1814 C94.707823,15.7752 95.163023,16.2371 95.748223,16.2371 C96.333423,16.2371 96.788623,15.7752 96.788623,15.1814 C96.788623,13.7959 97.894023,12.6742 99.259223,12.6742 C99.844223,12.6742 100.300223,12.2124 100.300223,11.6185 C100.365223,11.0907 99.844223,10.5629 99.259223,10.5629 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
<path d="M81.193523,11.2243 C80.403523,10.8878 79.962423,9.9515 80.333423,9.0805 C80.502023,8.6847 80.287223,8.3125 79.971223,8.1779 C79.576223,8.0096 79.204323,8.2254 79.069423,8.5421 C78.732123,9.3338 77.796523,9.7772 76.927523,9.407 C76.532523,9.2387 76.160623,9.4544 76.025723,9.7711 C75.857023,10.167 76.071823,10.5391 76.387823,10.6738 C77.177923,11.0103 77.619023,11.9466 77.248023,12.8175 C77.079423,13.2134 77.294223,13.5855 77.610223,13.7201 C78.005223,13.8884 78.377123,13.6727 78.512023,13.356 C78.849323,12.5642 79.784923,12.1209 80.653923,12.4911 C81.048923,12.6594 81.420823,12.4436 81.555723,12.1269 C81.769623,11.8439 81.588623,11.3926 81.193523,11.2243 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
<line x1="12.845223" y1="48.192" x2="16.110123" y2="42" id="Path" stroke-opacity="0.8" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round"></line>
<ellipse id="Oval" fill-opacity="0.1" fill="#000000" fill-rule="nonzero" cx="50.345223" cy="67.5" rx="17.5" ry="1.5"></ellipse>
<line x1="14.517923" y1="53.5959" x2="17.782723" y2="47.404" id="Path" stroke-opacity="0.8" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round"></line>
<line x1="20.806323" y1="52.3897" x2="23.604823" y2="47.0823" id="Path" stroke-opacity="0.8" stroke="#FFFFFF" stroke-width="2" stroke-linecap="round"></line>
<path d="M79.876623,1.78144 C79.226423,1.78144 78.641223,1.2536 78.641223,0.52783 C78.641223,0.19794 78.381123,0 78.121023,0 C77.795923,0 77.600823,0.26392 77.600823,0.52783 C77.600823,1.18763 77.080623,1.78144 76.365423,1.78144 C76.040323,1.78144 75.845223,2.04535 75.845223,2.30927 C75.845223,2.63917 76.105323,2.8371 76.365423,2.8371 C77.015623,2.8371 77.600823,3.3649 77.600823,4.0907 C77.600823,4.4206 77.860923,4.6185 78.121023,4.6185 C78.446123,4.6185 78.641223,4.3546 78.641223,4.0907 C78.641223,3.4309 79.161423,2.8371 79.876623,2.8371 C80.201823,2.8371 80.396823,2.57319 80.396823,2.30927 C80.461923,2.04535 80.201823,1.78144 79.876623,1.78144 Z" id="Path" fill="#FFFFFF" fill-rule="nonzero"></path>
<path d="M31.021323,19.8983 C31.021323,19.8983 19.126423,4.2537 16.379623,3.4694 C13.568923,2.76686 -0.694914027,14.1215 0.0264229726,15.2225 C0.756502973,16.3967 9.32942297,15.3706 9.32942297,15.3706 C9.32942297,15.3706 8.62499297,18.7201 11.136323,19.3843 C13.647723,20.0484 18.238723,18.3857 18.238723,18.3857 C18.238723,18.3857 17.521923,20.401 19.905523,21.2288 C22.289123,22.0567 27.760723,20.3628 27.760723,20.3628 L31.021323,19.8983 Z" id="Path" fill="#E0EDF3" fill-rule="nonzero"></path>
<path d="M89.710223,24.4503 L77.707723,58.391 C77.385623,59.3943 76.267023,59.8992 75.270023,59.5733 L21.900823,40.3589 C20.903823,40.033 20.400423,38.9059 20.722523,37.9026 L32.788923,3.88 C32.835323,3.6518 32.954323,3.4149 33.154823,3.2425 C33.674723,2.66083 34.456323,2.41884 35.299323,2.689 L88.604623,21.9853 C89.374923,22.2641 89.834523,23.0254 89.849423,23.7658 C89.875623,23.9852 89.829323,24.2134 89.710223,24.4503 Z" id="Path" fill="#FFD100" fill-rule="nonzero"></path>
<path d="M23.390523,38.0285 L52.772523,31.6916 C54.280623,31.3626 55.821223,31.9203 56.778023,33.1416 L75.925523,57.0459 L57.901923,31.4487 C56.910123,29.9348 55.061323,29.2655 53.361523,29.84 L23.390523,38.0285 Z" id="Path" fill="#DA9135" fill-rule="nonzero"></path>
<path d="M89.803023,23.9939 L54.122423,34.35 L33.108423,3.4707 C33.610823,2.74268 34.529023,2.41014 35.299323,2.68899 L88.604623,21.9853 C89.374923,22.2641 89.770623,23.1073 89.803023,23.9939 Z" id="Path" fill="#FFDF4F" fill-rule="nonzero"></path>
<path d="M34.370723,5.3975 L52.679723,32.148 C53.572623,33.4511 55.113223,34.0088 56.685323,33.598 L87.402923,24.8749 L56.375623,35.9356 C54.611823,36.592 52.771823,35.9959 51.835123,34.327 L34.370723,5.3975 Z" id="Path" fill="#DA9135" fill-rule="nonzero"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,23 +1,16 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "article_notification_pull_detail.png"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "article_notification_pull_detail@2x.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "article_notification_pull_detail@3x.png"
"filename" : "article_notification_pull_detail.svg",
"idiom" : "universal"
}
],
"info" : {
"version" : 1,
"author" : "ResgenSwift-Imagium"
"author" : "ResgenSwift-Imagium",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "original"
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="111px" height="69px" viewBox="0 0 111 69" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>article_notification_pull_detail</title>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="article_notification_pull_detail" transform="translate(0.000000, 0.000000)">
<path d="M81.1301131,39.5772 C81.1301131,39.5772 99.3602131,32.4231 102.116213,33.2806 C104.871213,34.1381 111.204213,51.339 110.013213,51.8526 C108.758213,52.4481 102.001213,47.0974 102.001213,47.0974 C102.001213,47.0974 100.834213,50.2797 98.3869131,49.5337 C95.9395131,48.7877 92.8975131,44.9219 92.8975131,44.9219 C92.8975131,44.9219 92.4888131,47.0487 89.9862131,46.4577 C87.4836131,45.8667 83.7265131,41.567 83.7265131,41.567 L81.1301131,39.5772 Z" id="Path" fill="#E0EDF3" fill-rule="nonzero"></path>
<path d="M99.2592131,10.5629 C97.8940131,10.5629 96.7886131,9.4412 96.7886131,8.0557 C96.7886131,7.4619 96.3334131,7 95.7482131,7 C95.1630131,7 94.7078131,7.4619 94.7078131,8.0557 C94.7078131,9.4412 93.6024131,10.5629 92.2370131,10.5629 C91.6517131,10.5629 91.1966131,11.0247 91.1966131,11.6185 C91.1966131,12.2124 91.6517131,12.6742 92.2370131,12.6742 C93.6024131,12.6742 94.7078131,13.7959 94.7078131,15.1814 C94.7078131,15.7752 95.1630131,16.2371 95.7482131,16.2371 C96.3334131,16.2371 96.7886131,15.7752 96.7886131,15.1814 C96.7886131,13.7959 97.8940131,12.6742 99.2592131,12.6742 C99.8442131,12.6742 100.300213,12.2124 100.300213,11.6185 C100.365213,11.0907 99.8442131,10.5629 99.2592131,10.5629 Z" id="Path" fill="#E0EDF3" fill-rule="nonzero"></path>
<path d="M81.1934131,11.2243 C80.4034131,10.8878 79.9623131,9.9515 80.3333131,9.0805 C80.5019131,8.6847 80.2871131,8.3125 79.9711131,8.1779 C79.5761131,8.0096 79.2042131,8.2254 79.0693131,8.5421 C78.7320131,9.3338 77.7964131,9.7772 76.9274131,9.407 C76.5324131,9.2387 76.1605131,9.4544 76.0256131,9.7711 C75.8569131,10.167 76.0717131,10.5391 76.3877131,10.6738 C77.1778131,11.0103 77.6189131,11.9466 77.2479131,12.8175 C77.0793131,13.2134 77.2941131,13.5855 77.6101131,13.7201 C78.0051131,13.8884 78.3770131,13.6727 78.5119131,13.356 C78.8492131,12.5642 79.7848131,12.1209 80.6538131,12.4911 C81.0488131,12.6594 81.4207131,12.4436 81.5556131,12.1269 C81.7695131,11.8439 81.5885131,11.3926 81.1934131,11.2243 Z" id="Path" fill="#E0EDF3" fill-rule="nonzero"></path>
<line x1="12.8452131" y1="48.192" x2="16.1101131" y2="42" id="Path" stroke-opacity="0.8" stroke="#E0EDF3" stroke-width="2" stroke-linecap="round"></line>
<path d="M50.3452131,69 C60.0102131,69 67.8452131,68.3284 67.8452131,67.5 C67.8452131,66.6716 60.0102131,66 50.3452131,66 C40.6802131,66 32.8452131,66.6716 32.8452131,67.5 C32.8452131,68.3284 40.6802131,69 50.3452131,69 Z" id="Path" fill-opacity="0.1" fill="#000000" fill-rule="nonzero"></path>
<line x1="14.5178131" y1="53.5959" x2="17.7826131" y2="47.404" id="Path" stroke-opacity="0.8" stroke="#E0EDF3" stroke-width="2" stroke-linecap="round"></line>
<line x1="20.8064131" y1="52.3897" x2="23.6049131" y2="47.0823" id="Path" stroke-opacity="0.8" stroke="#E0EDF3" stroke-width="2" stroke-linecap="round"></line>
<path d="M79.8766131,1.78144 C79.2264131,1.78144 78.6412131,1.2536 78.6412131,0.52783 C78.6412131,0.19794 78.3811131,0 78.1210131,0 C77.7959131,0 77.6008131,0.26392 77.6008131,0.52783 C77.6008131,1.18763 77.0806131,1.78144 76.3654131,1.78144 C76.0403131,1.78144 75.8452131,2.04535 75.8452131,2.30927 C75.8452131,2.63917 76.1053131,2.8371 76.3654131,2.8371 C77.0156131,2.8371 77.6008131,3.3649 77.6008131,4.0907 C77.6008131,4.4206 77.8609131,4.6185 78.1210131,4.6185 C78.4461131,4.6185 78.6412131,4.3546 78.6412131,4.0907 C78.6412131,3.4309 79.1614131,2.8371 79.8766131,2.8371 C80.2018131,2.8371 80.3968131,2.57319 80.3968131,2.30927 C80.4619131,2.04535 80.2018131,1.78144 79.8766131,1.78144 Z" id="Path" fill="#E0EDF3" fill-rule="nonzero"></path>
<path d="M31.0213131,19.8983 C31.0213131,19.8983 19.1264131,4.2537 16.3796131,3.4694 C13.5689131,2.76686 -0.694915869,14.1215 0.0264231309,15.2225 C0.756503131,16.3967 9.32941313,15.3706 9.32941313,15.3706 C9.32941313,15.3706 8.62499313,18.7201 11.1363131,19.3843 C13.6477131,20.0484 18.2387131,18.3857 18.2387131,18.3857 C18.2387131,18.3857 17.5219131,20.401 19.9055131,21.2288 C22.2891131,22.0567 27.7607131,20.3628 27.7607131,20.3628 L31.0213131,19.8983 Z" id="Path" fill="#E0EDF3" fill-rule="nonzero"></path>
<path d="M89.7103131,24.4503 L77.7078131,58.391 C77.3857131,59.3943 76.2671131,59.8992 75.2701131,59.5733 L21.9009131,40.3589 C20.9039131,40.033 20.4005131,38.9059 20.7226131,37.9026 L32.7890131,3.88 C32.8354131,3.6518 32.9544131,3.4149 33.1549131,3.2425 C33.6748131,2.66083 34.4564131,2.41884 35.2994131,2.689 L88.6047131,21.9853 C89.3750131,22.2641 89.8346131,23.0254 89.8495131,23.7658 C89.8757131,23.9852 89.8294131,24.2134 89.7103131,24.4503 Z" id="Path" fill="#FFD100" fill-rule="nonzero"></path>
<path d="M23.3906131,38.0285 L52.7726131,31.6916 C54.2807131,31.3626 55.8213131,31.9203 56.7781131,33.1416 L75.9256131,57.0459 L57.9020131,31.4487 C56.9102131,29.9348 55.0614131,29.2655 53.3616131,29.84 L23.3906131,38.0285 Z" id="Path" fill="#DA9135" fill-rule="nonzero"></path>
<path d="M89.8030131,23.9939 L54.1224131,34.35 L33.1084131,3.4707 C33.6108131,2.74268 34.5290131,2.41014 35.2993131,2.68899 L88.6046131,21.9853 C89.3749131,22.2641 89.7706131,23.1073 89.8030131,23.9939 Z" id="Path" fill="#FFDF4F" fill-rule="nonzero"></path>
<path d="M34.3706131,5.3975 L52.6796131,32.148 C53.5725131,33.4511 55.1131131,34.0088 56.6852131,33.598 L87.4028131,24.8749 L56.3755131,35.9356 C54.6117131,36.592 52.7717131,35.9959 51.8350131,34.327 L34.3706131,5.3975 Z" id="Path" fill="#DA9135" fill-rule="nonzero"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -1,23 +1,16 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "article_trash.png"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "article_trash@2x.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "article_trash@3x.png"
"filename" : "article_trash.svg",
"idiom" : "universal"
}
],
"info" : {
"version" : 1,
"author" : "ResgenSwift-Imagium"
"author" : "ResgenSwift-Imagium",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "original"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 977 B

View File

@ -0,0 +1,4 @@
<svg width="37" height="41" viewBox="0 0 37 41" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 4.87183L5.45856 32.1227C5.68952 33.5346 6.30709 34.8549 7.24275 35.9371C8.17841 37.0194 9.3956 37.8213 10.7593 38.2539L11.3943 38.4553C15.9682 39.9073 20.8795 39.9073 25.4534 38.4553L26.0884 38.2539C27.4518 37.8215 28.6688 37.0199 29.6044 35.938C30.5401 34.8561 31.1578 33.5362 31.3891 32.1246L35.8476 4.87183" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18.4238 8.74392C28.0467 8.74392 35.8476 7.01039 35.8476 4.87196C35.8476 2.73354 28.0467 1 18.4238 1C8.80091 1 1 2.73354 1 4.87196C1 7.01039 8.80091 8.74392 18.4238 8.74392Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,23 +1,16 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "ic_close_article.png"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "ic_close_article@2x.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "ic_close_article@3x.png"
"filename" : "ic_close_article.svg",
"idiom" : "universal"
}
],
"info" : {
"version" : 1,
"author" : "ResgenSwift-Imagium"
"author" : "ResgenSwift-Imagium",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "original"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 B

View File

@ -0,0 +1,4 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.41 1.41L10 0L5.705 4.295L1.41 0L0 1.41L4.295 5.705L0 10L1.41 11.41L5.705 7.115L10 11.41L11.41 10L7.115 5.705L11.41 1.41Z"
fill="#EFF2F4" />
</svg>

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 B

View File

@ -1,23 +1,16 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "new_article.png"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "new_article@2x.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "new_article@3x.png"
"filename" : "new_article.svg",
"idiom" : "universal"
}
],
"info" : {
"version" : 1,
"author" : "ResgenSwift-Imagium"
"author" : "ResgenSwift-Imagium",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "original"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -0,0 +1,54 @@
<svg width="102" height="69" viewBox="0 0 102 69" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M100.089 35.765H72.7522V66.626H100.089V35.765Z" fill="#DEF1F8"/>
<path d="M89.1215 46.2884H56.9285V66.6806H89.1215V46.2884Z" fill="#FAFAFA"/>
<path d="M100.089 46.2883H89.1216V66.6805H100.089V46.2883Z" fill="#DEF1F8"/>
<path d="M84.9199 49.5053H82.8464V53.1039H84.9199V49.5053Z" fill="#DEF1F8"/>
<path d="M80.8276 49.5053H78.7542V53.1039H80.8276V49.5053Z" fill="#DEF1F8"/>
<path d="M62.8759 60.3557H60.8025V63.9543H62.8759V60.3557Z" fill="#DEF1F8"/>
<path d="M97.7973 37.7279H95.7239V41.3266H97.7973V37.7279Z" fill="#FAFAFA"/>
<path d="M76.9538 37.7279H74.8804V41.3266H76.9538V37.7279Z" fill="#FAFAFA"/>
<path d="M36.4457 27.1985H101.509C101.728 25.2457 100.03 23.1303 98.1679 22.4794C96.251 21.8285 94.1699 21.72 92.4721 20.6351C90.3362 19.2791 89.1861 16.5127 86.7216 15.8076C84.3666 15.1566 82.0117 16.7839 79.5472 16.8924C74.5086 17.1094 70.6202 10.8715 65.6364 11.7394C62.2956 12.336 60.3788 15.8076 57.3666 17.3263C54.8473 18.6282 51.8352 18.3569 48.9873 18.7366C44.1678 19.4418 39.2388 23.3472 36.4457 27.1985Z" fill="#DEF1F8"/>
<path d="M0.455092 25.2296L32.2995 0.974118C33.9893 -0.324706 36.3288 -0.324706 38.0185 0.974118L69.8305 25.2296C70.1229 25.4569 70.2854 25.8141 70.2854 26.1713V67.7661C70.2854 68.4155 69.7655 68.9351 69.1156 68.9351H1.20246C0.552574 68.9351 0.0326646 68.4155 0.0326646 67.7661V26.1713C0.0001703 25.8141 0.162643 25.4569 0.455092 25.2296Z" fill="url(#paint0_linear)"/>
<path d="M53.973 13.183H16.3121L10.5281 17.5666V68.935H59.7245V17.5666L53.973 13.183Z" fill="#FDB918"/>
<path d="M55.9878 6.55914H14.2651C12.8353 6.55914 11.6655 7.72808 11.6655 9.15679V64.7789C11.6655 66.2076 12.8353 67.3765 14.2651 67.3765H55.9878C57.4176 67.3765 58.5874 66.2076 58.5874 64.7789V9.15679C58.5874 7.72808 57.4176 6.55914 55.9878 6.55914Z" fill="#FAFAFA"/>
<path d="M35.1265 47.2773L68.4657 67.8312C69.2455 68.3182 70.2528 67.7662 70.2528 66.8246V27.6975C70.2528 26.7883 69.2455 26.2039 68.4657 26.6909L35.1265 47.2773Z" fill="url(#paint1_linear)"/>
<path d="M0 27.6974V66.8245C0 67.7336 1.00732 68.3181 1.78719 67.831L35.1264 47.2772L1.78719 26.6908C1.00732 26.2038 0 26.7882 0 27.6974Z" fill="url(#paint2_linear)"/>
<path d="M40.3255 44.0627L38.1808 42.4392C36.3611 41.0429 33.8591 41.0429 32.0394 42.4392L29.8948 44.0627L35.0939 47.2773L40.3255 44.0627Z" fill="#E6E6E6"/>
<path d="M0 67.1491L35.1264 47.2771L29.9273 44.0626L0 67.1491Z" fill="#FDB918"/>
<path d="M70.2528 67.1491L35.1265 47.2771L40.3256 44.0626L70.2528 67.1491Z" fill="#FDB918"/>
<path d="M29.1147 17.3064C29.1147 17.3064 28.8872 19.969 35.1262 21.4627L33.7939 21.3977C33.7939 21.3977 29.6996 20.9756 28.7573 19.2547C27.8149 17.5337 29.1147 17.3064 29.1147 17.3064Z" fill="#FDB918"/>
<path d="M30.1545 15.9104C33.079 13.053 34.9312 21.4304 34.9637 21.4629C35.0287 21.4629 35.0937 21.4629 35.1587 21.4629C35.1587 21.4629 33.014 9.90333 29.4396 14.709C25.6053 19.7744 30.0245 21.3654 35.1262 21.4629C30.7719 21.333 26.8076 19.1574 30.1545 15.9104Z" fill="#FFE368"/>
<path d="M40.9753 17.3064C40.9753 17.3064 41.2028 19.969 34.9639 21.4627L36.2961 21.3977C36.2961 21.3977 40.3904 20.9756 41.3328 19.2547C42.2426 17.5337 40.9753 17.3064 40.9753 17.3064Z" fill="#FDB918"/>
<path d="M39.9353 15.9104C37.0108 13.053 35.1586 21.4304 35.1261 21.4629C35.0611 21.4629 34.9961 21.4629 34.9312 21.4629C34.9312 21.4629 37.0758 9.90333 40.6502 14.709C44.452 19.7744 40.0328 21.3654 34.9312 21.4629C39.3179 21.333 43.2497 19.1574 39.9353 15.9104Z" fill="#FFE368"/>
<path d="M27.3926 36.237V22.0798C27.3926 21.7226 27.685 21.4304 28.0425 21.4304H42.21C42.5674 21.4304 42.8599 21.7226 42.8599 22.0798V36.237C42.8599 36.5941 42.5674 36.8864 42.21 36.8864H28.0425C27.685 36.8864 27.3926 36.5941 27.3926 36.237Z" fill="#063881"/>
<path d="M26.3528 24.645V22.0798C26.3528 21.7226 26.6452 21.4304 27.0027 21.4304H43.2499C43.6073 21.4304 43.8997 21.7226 43.8997 22.0798V24.645C43.8997 25.0021 43.6073 25.2944 43.2499 25.2944H27.0027C26.6452 25.2944 26.3528 25.0021 26.3528 24.645Z" fill="#0B559E"/>
<path d="M37.5959 21.4304H32.6567V25.2944H37.5959V21.4304Z" fill="#FFE368"/>
<path d="M37.3035 25.2943H32.9492V36.8863H37.3035V25.2943Z" fill="#FDB918"/>
<path d="M1.5437 69H68.8777C70.1371 69 70.6539 67.4136 69.6204 66.6839L38.0042 44.6961C36.3248 43.427 33.9673 43.427 32.2557 44.6961L0.736338 66.6839C-0.232496 67.4136 0.284216 69 1.5437 69Z" fill="url(#paint3_linear)"/>
<defs>
<linearGradient id="paint0_linear" x1="-0.00678347" y1="34.4878" x2="70.2659" y2="34.4878" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFE368"/>
<stop offset="0.3174" stop-color="#FFE265"/>
<stop offset="0.5172" stop-color="#FFDD5D"/>
<stop offset="0.6845" stop-color="#FED54E"/>
<stop offset="0.8339" stop-color="#FECB39"/>
<stop offset="0.9701" stop-color="#FDBD1F"/>
<stop offset="1" stop-color="#FDB918"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="9.77743" y1="11.1302" x2="102.999" y2="68.0143" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFE368"/>
<stop offset="0.3387" stop-color="#FED750"/>
<stop offset="1" stop-color="#FDB918"/>
</linearGradient>
<linearGradient id="paint2_linear" x1="-8.63037" y1="41.2967" x2="84.5914" y2="98.1808" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFE368"/>
<stop offset="0.3387" stop-color="#FED750"/>
<stop offset="1" stop-color="#FDB918"/>
</linearGradient>
<linearGradient id="paint3_linear" x1="-10.5945" y1="38.7503" x2="87.7585" y2="99.7918" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFE368"/>
<stop offset="0.3387" stop-color="#FED750"/>
<stop offset="1" stop-color="#FDB918"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,23 +1,23 @@
{
"images" : [
{
"filename" : "welcome_background.png",
"idiom" : "universal",
"scale" : "1x",
"filename" : "welcome_background.png"
"scale" : "1x"
},
{
"filename" : "welcome_background@2x.png",
"idiom" : "universal",
"scale" : "2x",
"filename" : "welcome_background@2x.png"
"scale" : "2x"
},
{
"filename" : "welcome_background@3x.png",
"idiom" : "universal",
"scale" : "3x",
"filename" : "welcome_background@3x.png"
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "ResgenSwift-Imagium"
"author" : "ResgenSwift-Imagium",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 281 KiB

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 813 KiB

After

Width:  |  Height:  |  Size: 813 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@ -1,37 +0,0 @@
// Generated from StringToolCore at 2022-01-10 08:27:11 +0000
import UIKit
fileprivate let kStringsFileName = "sampleStrings"
extension MyString {
// MARK: - Webservice
/// Translation in en :
/// en
var param_lang: String {
NSLocalizedString("param_lang", tableName: kStringsFileName, bundle: Bundle.main, value: "en", comment: "")
}
// MARK: - Generic
/// Translation in en :
/// Back
var generic_back: String {
NSLocalizedString("generic_back", tableName: kStringsFileName, bundle: Bundle.main, value: "Back", comment: "")
}
/// Translation in en :
/// Loading data...
var generic_loading_data: String {
NSLocalizedString("generic_loading_data", tableName: kStringsFileName, bundle: Bundle.main, value: "Loading data...", comment: "")
}
/// Translation in en :
/// Welcome %@ !
var generic_welcome_firstname_format: String {
NSLocalizedString("generic_welcome_firstname_format", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome %@ !", comment: "")
}
}

View File

@ -1,4 +1,4 @@
// Generated by ResgenSwift.Strings.Stringium 1.0.0
// Generated by ResgenSwift.Strings.Stringium 2.1.0
import UIKit
@ -6,11 +6,34 @@ fileprivate let kStringsFileName = "sampleStrings"
extension String {
enum KeyGenAllScript: String {
case param_lang = "param_lang"
case generic_back = "generic_back"
case generic_loading_data = "generic_loading_data"
case generic_welcome_firstname_format = "generic_welcome_firstname_format"
case test_equal_symbol = "test_equal_symbol"
case placeholders_test_one = "placeholders_test_one"
var keyPath: KeyPath<String, String> {
switch self {
case .param_lang: return \String.param_lang
case .generic_back: return \String.generic_back
case .generic_loading_data: return \String.generic_loading_data
case .generic_welcome_firstname_format: return \String.generic_welcome_firstname_format
case .test_equal_symbol: return \String.test_equal_symbol
case .placeholders_test_one: return \String.placeholders_test_one
}
}
}
// MARK: - Webservice
/// Translation in en :
/// en
static var param_lang: String {
///
/// Comment :
/// No comment
var param_lang: String {
NSLocalizedString("param_lang", tableName: kStringsFileName, bundle: Bundle.main, value: "en", comment: "")
}
@ -18,33 +41,47 @@ extension String {
/// Translation in en :
/// Back
static var generic_back: String {
///
/// Comment :
/// No comment
var generic_back: String {
NSLocalizedString("generic_back", tableName: kStringsFileName, bundle: Bundle.main, value: "Back", comment: "")
}
/// Translation in en :
/// Loading data...
static var generic_loading_data: String {
///
/// Comment :
/// No comment
var generic_loading_data: String {
NSLocalizedString("generic_loading_data", tableName: kStringsFileName, bundle: Bundle.main, value: "Loading data...", comment: "")
}
/// Translation in en :
/// Welcome \"%@\" !
static var generic_welcome_firstname_format: String {
///
/// Comment :
/// No comment
var generic_welcome_firstname_format: String {
NSLocalizedString("generic_welcome_firstname_format", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" !", comment: "")
}
/// Translation in en :
/// Welcome \"%@\" !
static func generic_welcome_firstname_format(arg0: String) -> String {
String(format: Self.generic_welcome_firstname_format, arg0)
///
/// Comment :
/// No comment
func generic_welcome_firstname_format(arg0: String) -> String {
String(format: self.generic_welcome_firstname_format, arg0)
}
// MARK: - EqualSymbol
/// Translation in en :
/// 1 = 1 point !
static var test_equal_symbol: String {
///
/// Comment :
/// No comment
var test_equal_symbol: String {
NSLocalizedString("test_equal_symbol", tableName: kStringsFileName, bundle: Bundle.main, value: "1€ = 1 point !", comment: "")
}
@ -52,14 +89,18 @@ extension String {
/// Translation in en :
/// You %%: %2$@ %1$@ Age: %3$d
static var placeholders_test_one: String {
///
/// Comment :
/// No comment
var placeholders_test_one: String {
NSLocalizedString("placeholders_test_one", tableName: kStringsFileName, bundle: Bundle.main, value: "You %%: %2$@ %1$@ Age: %3$d", comment: "")
}
/// Translation in en :
/// You %%: %2$@ %1$@ Age: %3$d
static func placeholders_test_one(arg0: String, arg1: String, arg2: Int) -> String {
String(format: Self.placeholders_test_one, arg0, arg1, arg2)
///
/// Comment :
/// No comment
func placeholders_test_one(arg0: String, arg1: String, arg2: Int) -> String {
String(format: self.placeholders_test_one, arg0, arg1, arg2)
}
}

View File

@ -1,57 +0,0 @@
// Generated from Strings-Stringium at 2022-03-07 11:02:15 +0000
import UIKit
fileprivate let kStringsFileName = "sampleStrings"
extension String {
// MARK: - Webservice
/// Translation in en :
/// en
static var param_lang: String {
NSLocalizedString("param_lang", tableName: kStringsFileName, bundle: Bundle.main, value: "en", comment: "")
}
// MARK: - Generic
/// Translation in en :
/// Back
static var generic_back: String {
NSLocalizedString("generic_back", tableName: kStringsFileName, bundle: Bundle.main, value: "Back", comment: "")
}
/// Translation in en :
/// Loading data...
static var generic_loading_data: String {
NSLocalizedString("generic_loading_data", tableName: kStringsFileName, bundle: Bundle.main, value: "Loading data...", comment: "")
}
/// Translation in en :
/// Welcome \"%@\" !
static var generic_welcome_firstname_format: String {
NSLocalizedString("generic_welcome_firstname_format", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" !", comment: "")
}
/// Translation in en :
/// Welcome \"%@\" !
static func generic_welcome_firstname_format(arg0: String) -> String {
String(format: Self.generic_welcome_firstname_format, arg0)
}
// MARK: - Placeholders
/// Translation in en :
/// You %%: %2$@ %1$@ Age: %3$d
static var placeholders_test_one: String {
NSLocalizedString("placeholders_test_one", tableName: kStringsFileName, bundle: Bundle.main, value: "You %%: %2$@ %1$@ Age: %3$d", comment: "")
}
/// Translation in en :
/// You %%: %2$@ %1$@ Age: %3$d
static func placeholders_test_one(arg0: String, arg1: String, arg2: Int) -> String {
String(format: Self.placeholders_test_one, arg0, arg1, arg2)
}
}

View File

@ -1,37 +0,0 @@
// Generated from StringToolCore at 2022-01-10 08:39:52 +0000
import UIKit
fileprivate let kStringsFileName = "sampleStrings"
extension String {
// MARK: - Webservice
/// Translation in en :
/// en
static var param_lang: String {
NSLocalizedString("param_lang", tableName: kStringsFileName, bundle: Bundle.main, value: "en", comment: "")
}
// MARK: - Generic
/// Translation in en :
/// Back
static var generic_back: String {
NSLocalizedString("generic_back", tableName: kStringsFileName, bundle: Bundle.main, value: "Back", comment: "")
}
/// Translation in en :
/// Loading data...
static var generic_loading_data: String {
NSLocalizedString("generic_loading_data", tableName: kStringsFileName, bundle: Bundle.main, value: "Loading data...", comment: "")
}
/// Translation in en :
/// Welcome \"%@\" !
static var generic_welcome_firstname_format: String {
NSLocalizedString("generic_welcome_firstname_format", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" !", comment: "")
}
}

View File

@ -1,57 +0,0 @@
// Generated from Strings-Stringium at 2022-03-07 11:00:52 +0000
import UIKit
fileprivate let kStringsFileName = "sampleStrings"
extension StringTest {
// MARK: - Webservice
/// Translation in en :
/// en
var param_lang: String {
NSLocalizedString("param_lang", tableName: kStringsFileName, bundle: Bundle.main, value: "en", comment: "")
}
// MARK: - Generic
/// Translation in en :
/// Back
var generic_back: String {
NSLocalizedString("generic_back", tableName: kStringsFileName, bundle: Bundle.main, value: "Back", comment: "")
}
/// Translation in en :
/// Loading data...
var generic_loading_data: String {
NSLocalizedString("generic_loading_data", tableName: kStringsFileName, bundle: Bundle.main, value: "Loading data...", comment: "")
}
/// Translation in en :
/// Welcome \"%@\" !
var generic_welcome_firstname_format: String {
NSLocalizedString("generic_welcome_firstname_format", tableName: kStringsFileName, bundle: Bundle.main, value: "Welcome \"%@\" !", comment: "")
}
/// Translation in en :
/// Welcome \"%@\" !
func generic_welcome_firstname_format(arg0: String) -> String {
String(format: self.generic_welcome_firstname_format, arg0)
}
// MARK: - Placeholders
/// Translation in en :
/// You %%: %2$@ %1$@ Age: %3$d
var placeholders_test_one: String {
NSLocalizedString("placeholders_test_one", tableName: kStringsFileName, bundle: Bundle.main, value: "You %%: %2$@ %1$@ Age: %3$d", comment: "")
}
/// Translation in en :
/// You %%: %2$@ %1$@ Age: %3$d
func placeholders_test_one(arg0: String, arg1: String, arg2: Int) -> String {
String(format: self.placeholders_test_one, arg0, arg1, arg2)
}
}

View File

@ -1,6 +1,6 @@
/**
* Apple Strings File
* Generated by ResgenSwift 1.0.0
* Generated by ResgenSwift 2.1.0
* Language: en-us
*/

View File

@ -1,6 +1,6 @@
/**
* Apple Strings File
* Generated by ResgenSwift 1.0.0
* Generated by ResgenSwift 2.1.0
* Language: en
*/

View File

@ -1,6 +1,6 @@
/**
* Apple Strings File
* Generated by ResgenSwift 1.0.0
* Generated by ResgenSwift 2.1.0
* Language: fr
*/

View File

@ -0,0 +1,207 @@
// Generated by ResgenSwift.Analytics 2.1.0
import MatomoTracker
import FirebaseAnalytics
// MARK: - Protocol
protocol AnalyticsManagerProtocol {
func logScreen(name: String, path: String)
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
)
}
// MARK: - Matomo
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Properties
private var tracker: MatomoTracker
// MARK: - Init
init(siteId: String, url: String) {
debugPrint("[Matomo service] Server URL: \(url)")
debugPrint("[Matomo service] Site ID: \(siteId)")
tracker = MatomoTracker(
siteId: siteId,
baseURL: URL(string: url)!
)
#if DEBUG
tracker.dispatchInterval = 5
#endif
#if DEBUG
tracker.logger = DefaultLogger(minLevel: .verbose)
#endif
debugPrint("[Matomo service] Configured with content base: \(tracker.contentBase?.absoluteString ?? "-")")
debugPrint("[Matomo service] Opt out: \(tracker.isOptedOut)")
}
// MARK: - Methods
func logScreen(name: String, path: String) {
guard !tracker.isOptedOut else { return }
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
let urlString = URL(string: "\(trackerUrl)" + "/" + "\(path)" + "iOS")
tracker.track(
view: [name],
url: urlString
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard !tracker.isOptedOut else { return }
tracker.track(
eventWithCategory: category,
action: action,
name: name,
number: nil,
url: nil
)
}
}
// MARK: - Firebase
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
func logScreen(name: String, path: String) {
var parameters = [
AnalyticsParameterScreenName: name as NSObject
]
Analytics.logEvent(
AnalyticsEventScreenView,
parameters: parameters
)
}
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
var parameters: [String:NSObject] = [
"action": action as NSObject,
"category": category 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(
name.replacingOccurrences(of: [" "], with: "_"),
parameters: parameters
)
}
}
// MARK: - Manager
class AnalyticsManager {
static var shared = AnalyticsManager()
// MARK: - Properties
var managers: [AnalyticsManagerProtocol] = []
private var isEnabled: Bool = true
// MARK: - Methods
func setAnalyticsEnabled(_ enable: Bool) {
isEnabled = enable
}
func configure(siteId: String, url: String) {
managers.append(
MatomoAnalyticsManager(
siteId: siteId,
url: url
)
)
managers.append(FirebaseAnalyticsManager())
}
private func logScreen(name: String, path: String) {
guard isEnabled else { return }
managers.forEach { manager in
manager.logScreen(name: name, path: path)
}
}
private func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard isEnabled else { return }
managers.forEach { manager in
manager.logEvent(
name: name,
action: action,
category: category,
params: params
)
}
}
// MARK: - section_one
func logScreenS1DefOne(title: String) {
logScreen(
name: "s1 def one \(title)",
path: "s1_def_one/\(title)"
)
}
func logEventS1DefTwo(title: String, count: String) {
logEvent(
name: "s1 def two",
action: "test",
category: "test",
params: [
"title": title,
"count": count
]
)
}
// MARK: - section_two
func logScreenS2DefOne() {
logScreen(
name: "s2 def one",
path: "s2_def_one/"
)
}
}

View File

@ -1,6 +1,4 @@
// Generated by ResgenSwift.Strings.Tags 1.0.0
// typelias Tags = String
// Generated by ResgenSwift.Strings.Tags 2.1.0
import UIKit
@ -10,14 +8,21 @@ extension Tags {
/// Translation in ium :
/// Ecran un
static var screen_one: String {
///
/// Comment :
/// No comment
var screen_one: String {
"Ecran un"
}
/// Translation in ium :
/// Ecran deux
static var screen_two: String {
///
/// Comment :
/// No comment
var screen_two: String {
"Ecran deux"
}
}

View File

@ -1,23 +0,0 @@
// Generated from Strings-Tags at 2022-02-14 09:30:20 +0000
// typelias Tags = String
import UIKit
extension Tags {
// MARK: - ScreenTag
/// Translation in ium :
/// Ecran un
static var screen_one: String {
"Ecran un"
}
/// Translation in ium :
/// Ecran deux
static var screen_two: String {
"Ecran deux"
}
}

View File

@ -0,0 +1,52 @@
---
categories:
- id: section_one
screens:
- id: s1_def_one
name: s1 def one _TITLE_
path: s1_def_one/_TITLE_
tags: ios,droid
parameters:
- name: title
type: String
replaceIn: name,path
events:
- id: s1_def_two
name: s1 def two
action: test
category: test
tags: ios
parameters:
- name: title
type: String
- name: count
type: String
- id: section_two
screens:
- id: s2_def_one
name: s2 def one
path: s2_def_one/
tags: ios
events:
- id: s2_def_two
name: s2 def two
action: test
category: test
tags: droid
- id: section_three
screens:
- id: s3_def_one
name: s3 def one
path: s3_def_one/
tags: droid
events:
- id: s3_def_two
name: s3 def two
action: test
category: test
tags: droid

View File

@ -2,26 +2,29 @@
FORCE_FLAG="$1"
# Font
swift run -c release FontTool $FORCE_FLAG "./Fonts/sampleFontsAll.txt" \
## Font
swift run -c release ResgenSwift fonts $FORCE_FLAG "./Fonts/sampleFontsAll.txt" \
--extension-output-path "./Fonts/Generated" \
--extension-name "UIFont" \
--extension-suffix "GenAllScript"
--extension-name "FontYolo" \
--extension-name-ui-kit "UIFontYolo" \
--extension-suffix "GenAllScript" \
--info-plist-paths "./Fonts/Generated/test.plist ./Fonts/Generated/test2.plist"
echo "\n-------------------------\n"
# Color
swift run -c release ColorTool $FORCE_FLAG "./Colors/sampleColors1.txt" \
## Color
swift run -c release ResgenSwift colors $FORCE_FLAG "./Colors/sampleColors1.txt" \
--style all \
--xcassets-path "./Colors/colors.xcassets" \
--extension-output-path "./Colors/Generated/" \
--extension-name "UIColor" \
--extension-name "ColorYolo" \
--extension-name-ui-kit "UIhkjhkColorYolo" \
--extension-suffix "GenAllScript"
echo "\n-------------------------\n"
# Twine
swift run -c release Strings twine $FORCE_FLAG "./Twine/sampleStrings.txt" \
## Twine
swift run -c release ResgenSwift strings twine $FORCE_FLAG "./Twine/sampleStrings.txt" \
--output-path "./Twine/Generated" \
--langs "fr en en-us" \
--default-lang "en" \
@ -29,8 +32,8 @@ swift run -c release Strings twine $FORCE_FLAG "./Twine/sampleStrings.txt" \
echo "\n-------------------------\n"
# Strings
swift run -c release Strings stringium $FORCE_FLAG "./Strings/sampleStrings.txt" \
## Strings
swift run -c release ResgenSwift strings stringium $FORCE_FLAG "./Strings/sampleStrings.txt" \
--output-path "./Strings/Generated" \
--langs "fr en en-us" \
--default-lang "en" \
@ -40,18 +43,28 @@ swift run -c release Strings stringium $FORCE_FLAG "./Strings/sampleStrings.txt"
echo "\n-------------------------\n"
# Tags
swift run -c release Strings tags $FORCE_FLAG "./Tags/sampleTags.txt" \
## Tags
swift run -c release ResgenSwift strings tags $FORCE_FLAG "./Tags/sampleTags.txt" \
--lang "ium" \
--extension-output-path "./Tags/Generated" \
--extension-name "Tags" \
--extension-suffix "GenAllScript"
#echo "\n-------------------------\n"
# Analytics
swift run -c release ResgenSwift analytics $FORCE_FLAG "./Tags/sampleTags.yml" \
--target "matomo firebase" \
--extension-output-path "./Tags/Generated" \
--extension-name "Analytics" \
--extension-suffix "GenAllScript"
echo "\n-------------------------\n"
# Images
swift run -c release Imagium $FORCE_FLAG "./Images/sampleImages.txt" \
## Images
swift run -c release ResgenSwift images $FORCE_FLAG "./Images/sampleImages.txt" \
--xcassets-path "./Images/imagium.xcassets" \
--extension-output-path "./Images/Generated" \
--extension-name "UIImage" \
--extension-name "ImageYolo" \
--extension-name-ui-kit "UIImageYolo" \
--extension-suffix "GenAllScript"

View File

@ -0,0 +1,103 @@
---
#
# Class architecture
#
architecture:
property: R
classname: R
path: ./Tags
children:
- property: images
classname: R2Image
- property: strings
classname: R2String
- property: fonts
classname: R2Font
- property: images
classname: R2Image
- property: ui
classname: R2UI
children:
- property: images
classname: R2UIImage
- property: fonts
classname: R2UIFont
- property: images
classname: R2UIImage
#
# Strings
#
strings:
-
inputFile: ./Strings/sampleStrings.txt
outputPath: ./Strings/Generated
langs: "fr en en-us"
defaultLang: en
extensionOutputPath: ./Strings/Generated
extensionName: String
extensionSuffix: GenAllScript
#
# Images
#
images:
-
inputFile: ./Images/sampleImages.txt
xcassetsPath: ./Images/imagium.xcassets
extensionOutputPath: ./Images/Generated
extensionName: ImageYolo
extensionNameUIKit: UIImageYolo
extensionSuffix: GenAllScript
#
# Colors
#
colors:
-
inputFile: ./Colors/sampleColors1.txt
style: all
xcassetsPath: ./Colors/colors.xcassets
extensionOutputPath: ./Colors/Generated/
extensionName: ColorYolo
extensionNameUIKit: UIColorYolo
extensionSuffix: GenAllScript
#
# Tags
#
tags:
-
inputFile: ./Tags/sampleTags.txt
lang: ium
extensionOutputPath: ./Tags/Generated
extensionName: Tags
extensionSuffix: GenAllScript
#
# Analytics
#
analytics:
-
inputFile: ./Tags/sampleTags.yml
target: "matomo firebase"
extensionOutputPath: ./Tags/Generated
extensionName: Analytics
extensionSuffix: GenAllScript
#
# Fonts
#
fonts:
-
inputFile: ./Fonts/sampleFontsAll.txt
extensionOutputPath: ./Fonts/Generated
extensionName: FontYolo
extensionNameUIKit: UIFontYolo
extensionSuffix: GenAllScript
infoPlistPaths: "./Fonts/Generated/test.plist ./Fonts/Generated/test2.plist"

View File

@ -1,35 +0,0 @@
//
// ColorToolError.swift
//
//
// Created by Thibaut Schmitt on 20/12/2021.
//
import Foundation
enum ColorToolError: Error {
case badFormat(String)
case writeAsset(String)
case writeExtension(String, String)
case fileNotExists(String)
case badColorDefinition(String, String)
var description: String {
switch self {
case .badFormat(let info):
return "error:[ColorTool] Bad line format: \(info). Accepted format are: colorName=\"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\"; colorName \"#RGB/#ARGB\" \"#RGB/#ARGB\""
case .writeAsset(let info):
return "error:[ColorTool] An error occured while writing color in Xcasset: \(info)"
case .writeExtension(let filename, let info):
return "error:[ColorTool] An error occured while writing extension in \(filename): \(info)"
case .fileNotExists(let filename):
return "error:[ColorTool] File \(filename) does not exists"
case .badColorDefinition(let lightColor, let darkColor):
return "error:[ColorTool]One of these two colors has invalid synthax: -\(lightColor)- or -\(darkColor)-"
}
}
}

View File

@ -1,38 +0,0 @@
//
// ColorToolOptions.swift
//
//
// Created by Thibaut Schmitt on 17/01/2022.
//
import Foundation
import ArgumentParser
struct ColorToolOptions: ParsableArguments {
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
var forceGeneration = false
@Argument(help: "Input files where colors ared defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var inputFile: String
@Option(help: "Color style to generate: light for light colors only, or all for dark and light colors")
fileprivate var style: String
@Option(help: "Path of xcassets where to generate colors", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var xcassetsPath: String
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var extensionOutputPath: String
@Option(help: "Extension name. If not specified, it will generate an UIColor extension. Using default extension name will generate static property.")
var extensionName: String = ColorTool.defaultExtensionName
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+ColorsMyApp.swift")
var extensionSuffix: String = ""
}
extension ColorToolOptions {
var colorStyle: ColorStyle {
ColorStyle(rawValue: style) ?? .all
}
}

View File

@ -1,67 +0,0 @@
//
// ColorExtensionGenerator.swift
//
//
// Created by Thibaut Schmitt on 20/12/2021.
//
import Foundation
import ToolCore
struct ColorExtensionGenerator {
let colors: [ParsedColor]
let extensionClassname: String
static func writeExtensionFile(colors: [ParsedColor], staticVar: Bool, extensionName: String, extensionFilePath: String) {
// Create file if not exists
let fileManager = FileManager()
if fileManager.fileExists(atPath: extensionFilePath) == false {
Shell.shell("touch", "\(extensionFilePath)")
}
// Create extension content
let extensionContent = [
Self.getHeader(extensionClassname: extensionName),
Self.getProperties(for: colors, withStaticVar: staticVar),
Self.getFooter()
]
.joined(separator: "\n")
// Write content
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
do {
try extensionContent.write(to: extensionFilePathURL, atomically: true, encoding: .utf8)
} catch (let error) {
let error = ColorToolError.writeExtension(extensionFilePath, error.localizedDescription)
print(error.localizedDescription)
ColorTool.exit(withError: error)
}
}
private static func getHeader(extensionClassname: String) -> String {
"""
// Generated by ResgenSwift.\(ColorTool.toolName) \(ResgenSwiftVersion)
import UIKit
extension \(extensionClassname) {\n
"""
}
private static func getFooter() -> String {
"""
}
"""
}
private static func getProperties(for colors: [ParsedColor], withStaticVar staticVar: Bool) -> String {
colors.map {
if staticVar {
return $0.getColorStaticProperty()
}
return $0.getColorProperty()
}
.joined(separator: "\n\n")
}
}

View File

@ -1,13 +0,0 @@
//
// File.swift
//
//
// Created by Thibaut Schmitt on 29/08/2022.
//
import Foundation
enum ColorStyle: String, Decodable {
case light
case all
}

View File

@ -1,49 +0,0 @@
//
// File.swift
//
//
// Created by Thibaut Schmitt on 29/08/2022.
//
import Foundation
class ColorFileParser {
static func parse(_ inputFile: String, colorStyle: ColorStyle) -> [ParsedColor] {
// Get content of input file
let inputFileContent = try! String(contentsOfFile: inputFile, encoding: .utf8)
let colorsByLines = inputFileContent.components(separatedBy: CharacterSet.newlines)
// Iterate on each line of input file
return colorsByLines.enumerated().compactMap { lineNumber, colorLine in
// Required format:
// colorName="#RGB/#ARGB", colorName "#RGB/#ARGB", colorName "#RGB/#ARGB" "#RGB/#ARGB"
let colorLineCleanedUp = colorLine
.removeTrailingWhitespace()
.replacingOccurrences(of: "=", with: "") // Keep compat with current file format
guard colorLineCleanedUp.hasPrefix("#") == false, colorLineCleanedUp.isEmpty == false else {
print("[\(ColorTool.toolName)] ⚠️ BadFormat or empty line (line number: \(lineNumber + 1)). Skip this line")
return nil
}
let colorContent = colorLineCleanedUp.split(separator: " ")
guard colorContent.count >= 2 else {
let error = ColorToolError.badFormat(colorLine)
print(error.localizedDescription)
ColorTool.exit(withError: error)
}
switch colorStyle {
case .light:
return ParsedColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[1]))
case .all:
if colorContent.count == 3 {
return ParsedColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[2]))
}
return ParsedColor(name: String(colorContent[0]), light: String(colorContent[1]), dark: String(colorContent[1]))
}
}
}
}

View File

@ -1,123 +0,0 @@
//
// main.swift
//
//
// Created by Thibaut Schmitt on 20/12/2021.
//
import ToolCore
import Foundation
import ArgumentParser
struct ColorTool: ParsableCommand {
// MARK: - CommandConfiguration
static var configuration = CommandConfiguration(
abstract: "A utility for generate colors assets and their getters.",
version: ResgenSwiftVersion
)
// MARK: - Static
static let toolName = "ColorTool"
static let defaultExtensionName = "UIColor"
static let assetsColorsFolderName = "Colors"
// MARK: - Properties
var extensionFileName: String {
if options.extensionSuffix.isEmpty == false {
return "\(options.extensionName)+\(options.extensionSuffix).swift"
}
return "\(options.extensionName).swift"
}
var extensionFilePath: String { "\(options.extensionOutputPath)/\(extensionFileName)" }
var generateStaticVariable: Bool {
options.extensionName == Self.defaultExtensionName
}
// MARK: - Command options
@OptionGroup var options: ColorToolOptions
// MARK: - Run
public func run() throws {
print("[\(Self.toolName)] Starting colors generation")
print("[\(Self.toolName)] Will use inputFile \(options.inputFile) to generate \(options.colorStyle) colors in xcassets \(options.xcassetsPath)")
// Check requirements
guard checkRequirements() else { return }
print("[\(Self.toolName)] Will generate colors")
// Delete current colors
deleteCurrentColors()
// Get colors to generate
let parsedColors = ColorFileParser.parse(options.inputFile,
colorStyle: options.colorStyle)
// Generate all colors in xcassets
ColorXcassetHelper.generateXcassetColors(colors: parsedColors,
to: options.xcassetsPath)
// Generate extension
ColorExtensionGenerator.writeExtensionFile(colors: parsedColors,
staticVar: generateStaticVariable,
extensionName: options.extensionName,
extensionFilePath: extensionFilePath)
print("[\(Self.toolName)] Colors generated")
}
// MARK: - Requirements
private func checkRequirements() -> Bool {
let fileManager = FileManager()
// Check if input file exists
guard fileManager.fileExists(atPath: options.inputFile) else {
let error = ColorToolError.fileNotExists(options.inputFile)
print(error.localizedDescription)
ColorTool.exit(withError: error)
}
// Check if xcassets file exists
guard fileManager.fileExists(atPath: options.xcassetsPath) else {
let error = ColorToolError.fileNotExists(options.xcassetsPath)
print(error.localizedDescription)
ColorTool.exit(withError: error)
}
// Check if needed to regenerate
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration, inputFilePath: options.inputFile, extensionFilePath: extensionFilePath) else {
print("[\(Self.toolName)] Colors are already up to date :) ")
return false
}
return true
}
// MARK: - Helpers
private func deleteCurrentColors() {
Shell.shell("rm", "-rf", "\(options.xcassetsPath)/Colors/*")
}
}
ColorTool.main()
/*
Command samples:
1. UIColor extension without suffix
swift run -c release ColorToolCore -f ./SampleFiles/Colors/sampleColors1.txt --style all --xcassets-path "./SampleFiles/Colors/colors.xcassets" --extension-output-path "./SampleFiles/Colors/Generated/" --extension-name "UIColor"
2. UIColor extension with custom suffix
swift run -c release ColorToolCore -f ./SampleFiles/Colors/sampleColors1.txt --style all --xcassets-path "./SampleFiles/Colors/colors.xcassets" --extension-output-path "./SampleFiles/Colors/Generated/" --extension-name "UIColor" --extension-suffix "SampleApp"
3. Custom extension with only light theme colors (R2Color)
swift run -c release ColorToolCore -f ./SampleFiles/Colors/sampleColors1.txt --style light --xcassets-path "./SampleFiles/Colors/colors.xcassets" --extension-output-path "./SampleFiles/Colors/Generated/" --extension-name "R2Color"
*/

View File

@ -1,26 +0,0 @@
//
// FontOptions.swift
//
//
// Created by Thibaut Schmitt on 17/01/2022.
//
import Foundation
import ArgumentParser
struct FontOptions: ParsableArguments {
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
var forceGeneration = false
@Argument(help: "Input files where fonts ared defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var inputFile: String
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var extensionOutputPath: String
@Option(help: "Extension name. If not specified, it will generate an UIFont extension. Using default extension name will generate static property.")
var extensionName: String = FontTool.defaultExtensionName
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+FontsMyApp.swift")
var extensionSuffix: String = ""
}

View File

@ -1,31 +0,0 @@
//
// FontToolError.swift
//
//
// Created by Thibaut Schmitt on 13/12/2021.
//
import Foundation
enum FontToolError: Error {
case fcScan(String, Int32, String?)
case inputFolderNotFound(String)
case fileNotExists(String)
case writeExtension(String, String)
var localizedDescription: String {
switch self {
case .fcScan(let path, let code, let output):
return "error:[\(FontTool.toolName)] Error while getting fontName (fc-scan --format %{postscriptname} \(path). fc-scan exit with \(code) and output is: \(output ?? "no output")"
case .inputFolderNotFound(let inputFolder):
return " error:[\(FontTool.toolName)] Input folder not found: \(inputFolder)"
case .fileNotExists(let filename):
return " error:[\(FontTool.toolName)] File \(filename) does not exists"
case .writeExtension(let filename, let info):
return "error:[\(FontTool.toolName)] An error occured while writing extension in \(filename): \(info)"
}
}
}

View File

@ -1,22 +0,0 @@
//
// File.swift
//
//
// Created by Thibaut Schmitt on 29/08/2022.
//
import Foundation
class FontPlistGenerator {
static func generatePlistUIAppsFontContent(for fonts: [FontName]) -> String {
var plistData = "<key>UIAppFonts</key>\n\t<array>\n"
fonts
.compactMap { $0 }
.forEach {
plistData += "\t\t<string>\($0)</string>\n"
}
plistData += "\t</array>\n*/"
return plistData
}
}

View File

@ -1,83 +0,0 @@
//
// FontToolContentGenerator.swift
//
//
// Created by Thibaut Schmitt on 13/12/2021.
//
import Foundation
import ToolCore
class FontExtensionGenerator {
static func writeExtensionFile(fontsNames: [String], staticVar: Bool, extensionName: String, extensionFilePath: String) {
// Check file if not exists
let fileManager = FileManager()
if fileManager.fileExists(atPath: extensionFilePath) == false {
Shell.shell("touch", "\(extensionFilePath)")
}
// Create extension content
let extensionContent = [
Self.getHeader(extensionClassname: extensionName),
Self.getFontNameEnum(fontsNames: fontsNames),
Self.getFontMethods(fontsNames: fontsNames, staticVar: staticVar),
Self.getFooter()
]
.joined(separator: "\n")
// Write content
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
do {
try extensionContent.write(to: extensionFilePathURL, atomically: true, encoding: .utf8)
} catch (let error) {
let error = FontToolError.writeExtension(extensionFilePath, error.localizedDescription)
print(error.localizedDescription)
FontTool.exit(withError: error)
}
}
private static func getHeader(extensionClassname: String) -> String {
"""
// Generated by ResgenSwift.\(FontTool.toolName) \(ResgenSwiftVersion)
import UIKit
extension \(extensionClassname) {\n
"""
}
private static func getFontNameEnum(fontsNames: [String]) -> String {
var enumDefinition = "\tenum FontName: String {\n"
fontsNames.forEach {
enumDefinition += "\t\tcase \($0.removeCharacters(from: "[]+-_")) = \"\($0)\"\n"
}
enumDefinition += "\t}\n"
return enumDefinition
}
private static func getFontMethods(fontsNames: [FontName], staticVar: Bool) -> String {
let pragma = "\t// MARK: - Getter"
var propertiesOrMethods: [String] = fontsNames
.unique()
.map {
if staticVar {
return $0.staticProperty
} else {
return $0.method
}
}
propertiesOrMethods.insert(pragma, at: 0)
return propertiesOrMethods.joined(separator: "\n\n")
}
private static func getFooter() -> String {
"""
}
"""
}
}

View File

@ -1,32 +0,0 @@
//
// File.swift
//
//
// Created by Thibaut Schmitt on 29/08/2022.
//
import Foundation
typealias FontName = String
extension FontName {
var fontNameSanitize: String {
self.removeCharacters(from: "[]+-_")
}
var method: String {
"""
func \(fontNameSanitize)(withSize size: CGFloat) -> UIFont {
UIFont(name: FontName.\(fontNameSanitize).rawValue, size: size)!
}
"""
}
var staticProperty: String {
"""
static let \(fontNameSanitize): ((_ size: CGFloat) -> UIFont) = { size in
UIFont(name: FontName.\(fontNameSanitize).rawValue, size: size)!
}
"""
}
}

View File

@ -1,95 +0,0 @@
//
// FontTool.swift
//
//
// Created by Thibaut Schmitt on 13/12/2021.
//
import ToolCore
import Foundation
import ArgumentParser
struct FontTool: ParsableCommand {
// MARK: - CommandConfiguration
static var configuration = CommandConfiguration(
abstract: "A utility to generate an helpful etension to access your custom font from code and also Info.plist UIAppsFont content.",
version: ResgenSwiftVersion
)
// MARK: - Static
static let toolName = "FontTool"
static let defaultExtensionName = "UIFont"
// MARK: - Properties
var extensionFileName: String {
if options.extensionSuffix.isEmpty == false {
return "\(options.extensionName)+\(options.extensionSuffix).swift"
}
return "\(options.extensionName).swift"
}
var extensionFilePath: String { "\(options.extensionOutputPath)/\(extensionFileName)" }
var generateStaticVariable: Bool {
options.extensionName == Self.defaultExtensionName
}
// MARK: - Command Options
@OptionGroup var options: FontOptions
// MARK: - Run
public func run() throws {
print("[\(Self.toolName)] Starting fonts generation")
// Check requirements
guard checkRequirements() else { return }
print("[\(Self.toolName)] Will generate fonts")
// Get fonts to generate
let fontsToGenerate = FontFileParser.parse(options.inputFile)
// Get real font names
let inputFolder = URL(fileURLWithPath: options.inputFile).deletingLastPathComponent().relativePath
let fontsNames = FontToolHelper.getFontPostScriptName(for: fontsToGenerate,
inputFolder: inputFolder)
// Generate extension
FontExtensionGenerator.writeExtensionFile(fontsNames: fontsNames,
staticVar: generateStaticVariable,
extensionName: options.extensionName,
extensionFilePath: extensionFilePath)
print("Info.plist information:")
print("\(FontPlistGenerator.generatePlistUIAppsFontContent(for: fontsNames))")
print("[\(Self.toolName)] Fonts generated")
}
// MARK: - Requirements
private func checkRequirements() -> Bool {
let fileManager = FileManager()
// Check input file exists
guard fileManager.fileExists(atPath: options.inputFile) else {
let error = FontToolError.fileNotExists(options.inputFile)
print(error.localizedDescription)
FontTool.exit(withError: error)
}
// Check if needed to regenerate
guard GeneratorChecker.shouldGenerate(force: options.forceGeneration, inputFilePath: options.inputFile, extensionFilePath: extensionFilePath) else {
print("[\(Self.toolName)] Fonts are already up to date :) ")
return false
}
return true
}
}
FontTool.main()

View File

@ -1,87 +0,0 @@
//
// ImageExtensionGenerator.swift
//
//
// Created by Thibaut Schmitt on 14/02/2022.
//
import ToolCore
import Foundation
class ImageExtensionGenerator {
// MARK: - Extension files
static func writeStringsFiles(images: [ParsedImage], staticVar: Bool, inputFilename: String, extensionName: String, extensionFilePath: String) {
// Get header/footer
let extensionHeader = Self.getHeader(inputFilename: inputFilename, extensionClassname: extensionName)
let extensionFooter = Self.getFooter()
// Create content
let extensionContent: String = {
var content = ""
images.forEach { img in
if staticVar {
content += "\n\(img.getStaticImageProperty())"
} else {
content += "\n\(img.getImageProperty())"
}
content += "\n "
}
return content
}()
// Create file if not exists
let fileManager = FileManager()
if fileManager.fileExists(atPath: extensionFilePath) == false {
Shell.shell("touch", "\(extensionFilePath)")
}
// Generate extension
Self.generateExtensionFile(extensionFilePath: extensionFilePath, extensionHeader, extensionContent, extensionFooter)
}
// MARK: - pragm
private static func generateExtensionFile(extensionFilePath: String, _ args: String...) {
// Create file if not exists
let fileManager = FileManager()
if fileManager.fileExists(atPath: extensionFilePath) == false {
Shell.shell("touch", "\(extensionFilePath)")
}
// Create extension content
let extensionContent = args.joined(separator: "\n")
// Write content
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
do {
try extensionContent.write(to: extensionFilePathURL, atomically: true, encoding: .utf8)
} catch (let error) {
let error = ImagiumError.writeFile(extensionFilePath, error.localizedDescription)
print(error.localizedDescription)
Imagium.exit(withError: error)
}
}
private static func getHeader(inputFilename: String, extensionClassname: String) -> String {
"""
// Generated by ResgenSwift.Imagium \(ResgenSwiftVersion)
// Images from \(inputFilename)
import UIKit
extension \(extensionClassname) {
"""
}
private static func getFooter() -> String {
"""
}
"""
}
}
//@objc var onboarding_foreground3: UIImage {
// return UIImage(named: "onboarding_foreground3")!
// }

View File

@ -1,189 +0,0 @@
//
// File.swift
//
//
// Created by Thibaut Schmitt on 24/01/2022.
//
import Foundation
import ToolCore
class XcassetsGenerator {
static let outputImageExtension = "png"
let forceGeneration: Bool
// MARK: - Init
init(forceGeneration: Bool) {
self.forceGeneration = forceGeneration
}
// MARK: - Assets generation
func generateXcassets(inputPath: String, imagesToGenerate: [ParsedImage], xcassetsPath: String) {
let fileManager = FileManager()
let svgConverter = Imagium.getSvgConverterPath()
let allSubFiles = fileManager.getAllRegularFileIn(directory: inputPath)
var generatedAssetsPaths = [String]()
// Generate new assets
imagesToGenerate.forEach { parsedImage in
// Get image path
let imageData: (path: String, ext: String) = {
for subfile in allSubFiles {
if subfile.hasSuffix("/" + parsedImage.name + ".svg") {
return (subfile, "svg")
}
if subfile.hasSuffix("/" + parsedImage.name + ".png") {
return (subfile, "png")
}
if subfile.hasSuffix("/" + parsedImage.name + ".jpg") {
return (subfile, "jpg")
}
if subfile.hasSuffix("/" + parsedImage.name + ".jepg") {
return (subfile, "jepg")
}
}
let error = ImagiumError.unknownImageExtension(parsedImage.name)
print(error.localizedDescription)
Imagium.exit(withError: error)
}()
// Create imageset folder
let imagesetName = "\(parsedImage.name).imageset"
let imagesetPath = "\(xcassetsPath)/\(imagesetName)"
Shell.shell("mkdir", "-p", imagesetPath)
// Store managed images path
generatedAssetsPaths.append(imagesetName)
// Generate output images path
let output1x = "\(imagesetPath)/\(parsedImage.name).\(XcassetsGenerator.outputImageExtension)"
let output2x = "\(imagesetPath)/\(parsedImage.name)@2x.\(XcassetsGenerator.outputImageExtension)"
let output3x = "\(imagesetPath)/\(parsedImage.name)@3x.\(XcassetsGenerator.outputImageExtension)"
// Check if we need to convert image
if self.shouldBypassGeneration(for: parsedImage, xcassetImagePath: output1x) {
print("\(parsedImage.name) -> Not regenerating")
return
}
// Convert image
let convertArguments = parsedImage.convertArguments
if imageData.ext == "svg" {
// /usr/local/bin/rsvg-convert path/to/image.png -w 200 -h 300 -o path/to/output.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
var command1x = ["\(svgConverter)", "\(imageData.path)"]
var command2x = ["\(svgConverter)", "\(imageData.path)"]
var command3x = ["\(svgConverter)", "\(imageData.path)"]
self.addConvertArgument(command: &command1x, convertArgument: convertArguments.x1)
self.addConvertArgument(command: &command2x, convertArgument: convertArguments.x2)
self.addConvertArgument(command: &command3x, convertArgument: convertArguments.x3)
command1x.append(contentsOf: ["-o", output1x])
command2x.append(contentsOf: ["-o", output2x])
command3x.append(contentsOf: ["-o", output3x])
Shell.shell(command1x)
Shell.shell(command2x)
Shell.shell(command3x)
} else {
// 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 x300 path/to/output.png
Shell.shell("convert", "\(imageData.path)", "-resize", "\(convertArguments.x1.width ?? "")x\(convertArguments.x1.height ?? "")", output1x)
Shell.shell("convert", "\(imageData.path)", "-resize", "\(convertArguments.x2.width ?? "")x\(convertArguments.x2.height ?? "")", output2x)
Shell.shell("convert", "\(imageData.path)", "-resize", "\(convertArguments.x3.width ?? "")x\(convertArguments.x3.height ?? "")", output3x)
}
// Write Content.json
let imagesetContentJson = parsedImage.contentJson
let contentJsonFilePath = "\(imagesetPath)/Contents.json"
if fileManager.fileExists(atPath: contentJsonFilePath) == false {
Shell.shell("touch", "\(contentJsonFilePath)")
}
let contentJsonFilePathURL = URL(fileURLWithPath: contentJsonFilePath)
try! imagesetContentJson.write(to: contentJsonFilePathURL, atomically: true, encoding: .utf8)
print("\(parsedImage.name) -> Generated")
}
// Success info
let generatedAssetsCount = generatedAssetsPaths.count
print("Images generated: \(generatedAssetsCount)")
// Delete old assets
let allImagesetName = Set(fileManager.getAllImageSetFolderIn(directory: xcassetsPath))
let imagesetToRemove = allImagesetName.subtracting(Set(generatedAssetsPaths))
imagesetToRemove.forEach {
print("Will remove: \($0)")
}
imagesetToRemove.forEach { itemToRemove in
try! fileManager.removeItem(atPath: "\(xcassetsPath)/\(itemToRemove)")
}
print("Removed \(imagesetToRemove.count) images")
}
// MARK: - Helpers: SVG command
private func addConvertArgument(command: inout [String], convertArgument: ConvertArgument) {
if let width = convertArgument.width, width.isEmpty == false {
command.append("-w")
command.append("\(width)")
}
if let height = convertArgument.height, height.isEmpty == false {
command.append("-h")
command.append("\(height)")
}
}
// MARK: - Helpers: bypass generation
private func shouldBypassGeneration(for image: ParsedImage, xcassetImagePath: String) -> Bool {
guard forceGeneration == false else {
return false
}
let fileManager = FileManager()
// File not exists -> do not bypass
guard fileManager.fileExists(atPath: xcassetImagePath) else {
return false
}
// Info unavailable -> do not bypass
let taskWidth = Shell.shell("identify", "-format", "%w", xcassetImagePath)
let taskHeight = Shell.shell("identify", "-format", "%h", xcassetImagePath)
guard taskWidth.terminationStatus == 0,
taskHeight.terminationStatus == 0 else {
return false
}
let currentWidth = Int(taskWidth.output ?? "-1") ?? -1
let currentheight = Int(taskHeight.output ?? "-1") ?? -1
// Info unavailable -> do not bypass
guard currentWidth > 0 && currentheight > 0 else {
return false
}
// Check width and height
if image.width != -1 && currentWidth == image.width {
return true
}
if image.height != -1 && currentheight == image.height {
return true
}
return false
}
}

View File

@ -1,43 +0,0 @@
//
// ImagiumError.swift
//
//
// Created by Thibaut Schmitt on 24/01/2022.
//
import Foundation
enum ImagiumError: Error {
case inputFolderNotFound(String)
case fileNotExists(String)
case unknownImageExtension(String)
case getFileAttributed(String, String)
case rsvgConvertNotFound
case writeFile(String, String)
case unknown(String)
var localizedDescription: String {
switch self {
case .inputFolderNotFound(let inputFolder):
return " error:[\(Imagium.toolName)] Input folder not found: \(inputFolder)"
case .fileNotExists(let filename):
return " error:[\(Imagium.toolName)] File \(filename) does not exists"
case .unknownImageExtension(let filename):
return " error:[\(Imagium.toolName)] File \(filename) have an unhandled file extension. Cannot generate image."
case .getFileAttributed(let filename, let errorDescription):
return " error:[\(Imagium.toolName)] Getting file attributes of \(filename) failed with error: \(errorDescription)"
case .rsvgConvertNotFound:
return " error:[\(Imagium.toolName)] Can't find rsvg-convert (can be installed with 'brew remove imagemagick && brew install imagemagick --with-librsvg')"
case .writeFile(let subErrorDescription, let filename):
return " error:[\(Imagium.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
case .unknown(let errorDescription):
return " error:[\(Imagium.toolName)] Unknown error: \(errorDescription)"
}
}
}

View File

@ -1,41 +0,0 @@
//
// ImagiumOptions.swift
//
//
// Created by Thibaut Schmitt on 24/01/2022.
//
import Foundation
import ArgumentParser
struct ImagiumOptions: ParsableArguments {
@Flag(name: .customShort("f"), help: "Should force script execution")
var forceExecution = false
@Flag(name: .customShort("F"), help: "Regenerate all images")
var forceExecutionAndGeneration = false
@Argument(help: "Input files where strings ared defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var inputFile: String
@Option(help: "Xcassets path where to generate images.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var xcassetsPath: String
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var extensionOutputPath: String
@Option(help: "Extension name. If not specified, it will generate an UIImage extension. Using default extension name will generate static property.")
var extensionName: String = Imagium.defaultExtensionName
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Image{extensionSuffix}.swift")
var extensionSuffix: String = ""
}
/*
swift run -c release Imagium $FORCE_FLAG "./Images/sampleImages.txt" \
--xcassets-path "./Images/imagium.xcassets" \
--extension-output-path "./Images/Generated" \
--extension-name "UIImage" \
--extension-suffix "GenAllScript"
*/

View File

@ -1,90 +0,0 @@
//
// ParsedImage.swift
//
//
// Created by Thibaut Schmitt on 24/01/2022.
//
import Foundation
struct ParsedImage {
let name: String
let tags: String
let width: Int
let height: Int
// MARK: - Convert
var convertArguments: (x1: ConvertArgument, x2: ConvertArgument, x3: ConvertArgument) {
var width1x = ""
var height1x = ""
var width2x = ""
var height2x = ""
var width3x = ""
var height3x = ""
if width != -1 {
width1x = "\(width)"
width2x = "\(width * 2)"
width3x = "\(width * 3)"
}
if height != -1 {
height1x = "\(height)"
height2x = "\(height * 2)"
height3x = "\(height * 3)"
}
return (x1: ConvertArgument(width: width1x, height: height1x),
x2: ConvertArgument(width: width2x, height: height2x),
x3: ConvertArgument(width: width3x, height: height3x))
}
// MARK: - Assets
var contentJson: String {
"""
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "\(name).\(XcassetsGenerator.outputImageExtension)"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "\(name)@2x.\(XcassetsGenerator.outputImageExtension)"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "\(name)@3x.\(XcassetsGenerator.outputImageExtension)"
}
],
"info" : {
"version" : 1,
"author" : "ResgenSwift-Imagium"
}
}
"""
}
// MARK: - Extension property
func getImageProperty() -> String {
"""
var \(name): UIImage {
UIImage(named: "\(name)")!
}
"""
}
func getStaticImageProperty() -> String {
"""
static var \(name): UIImage {
UIImage(named: "\(name)")!
}
"""
}
}

View File

@ -1,116 +0,0 @@
//
// Imagium.swift
//
//
// Created by Thibaut Schmitt on 24/01/2022.
//
import ToolCore
import Foundation
import ArgumentParser
struct Imagium: ParsableCommand {
// MARK: - CommandConfiguration
static var configuration = CommandConfiguration(
abstract: "A utility for generate images and an extension to access them easily.",
version: ResgenSwiftVersion
)
// MARK: - Static
static let toolName = "Imagium"
static let defaultExtensionName = "UIImage"
// MARK: - Properties
var extensionFileName: String { "\(options.extensionName)+\(options.extensionSuffix).swift" }
var extensionFilePath: String { "\(options.extensionOutputPath)/\(extensionFileName)" }
var inputFilenameWithoutExt: String {
URL(fileURLWithPath: options.inputFile)
.deletingPathExtension()
.lastPathComponent
}
// MARK: - Command Options
@OptionGroup var options: ImagiumOptions
// MARK: - Run
mutating func run() {
print("[\(Self.toolName)] Starting images generation")
// Check requirements
guard checkRequirements() else { return }
print("[\(Self.toolName)] Will generate images")
// Parse input file
let imagesToGenerate = ImageFileParser.parse(options.inputFile, platform: PlatormTag.ios)
// Generate xcassets files
let inputFolder = URL(fileURLWithPath: options.inputFile)
.deletingLastPathComponent()
.relativePath
let xcassetsGenerator = XcassetsGenerator(forceGeneration: options.forceExecutionAndGeneration)
xcassetsGenerator.generateXcassets(inputPath: inputFolder,
imagesToGenerate: imagesToGenerate,
xcassetsPath: options.xcassetsPath)
// Generate extension
ImageExtensionGenerator.writeStringsFiles(images: imagesToGenerate,
staticVar: options.extensionName == Self.defaultExtensionName,
inputFilename: inputFilenameWithoutExt,
extensionName: options.extensionName,
extensionFilePath: extensionFilePath)
print("[\(Self.toolName)] Images generated")
}
// MARK: - Requirements
private func checkRequirements() -> Bool {
guard options.forceExecutionAndGeneration == false else {
return true
}
let fileManager = FileManager()
// Input file
guard fileManager.fileExists(atPath: options.inputFile) else {
let error = ImagiumError.fileNotExists(options.inputFile)
print(error.localizedDescription)
Imagium.exit(withError: error)
}
// RSVG-Converter
_ = Imagium.getSvgConverterPath()
// Check if needed to regenerate
guard GeneratorChecker.shouldGenerate(force: options.forceExecution, inputFilePath: options.inputFile, extensionFilePath: extensionFilePath) else {
print("[\(Self.toolName)] Images are already up to date :) ")
return false
}
return true
}
// MARK: - Helpers
@discardableResult
static func getSvgConverterPath() -> String {
let taskSvgConverter = Shell.shell("which", "rsvg-convert")
if taskSvgConverter.terminationStatus == 0 {
return taskSvgConverter.output!.removeCharacters(from: CharacterSet.whitespacesAndNewlines)
}
let error = ImagiumError.rsvgConvertNotFound
print(error.localizedDescription)
Imagium.exit(withError: error)
}
}
Imagium.main()

View File

@ -0,0 +1,90 @@
//
// Analytics.swift
//
//
// Created by Loris Perret on 08/12/2023.
//
import ArgumentParser
import Foundation
import ToolCore
struct Analytics: ParsableCommand {
// MARK: - Command Configuration
static var configuration = CommandConfiguration(
abstract: "Generate analytics extension file.",
version: ResgenSwiftVersion
)
// MARK: - Static
static let toolName = "Analytics"
static let defaultExtensionName = "Analytics"
// MARK: - Command Options
@OptionGroup var options: AnalyticsOptions
// MARK: - Run
mutating func run() {
print("[\(Self.toolName)] Starting analytics generation")
print("[\(Self.toolName)] Will use inputFile \(options.inputFile) to generate analytics for target: \(options.target)")
// Check requirements
guard checkRequirements() else { return }
print("[\(Self.toolName)] Will generate analytics")
// Check requirements
guard checkRequirements() else { return }
// Parse input file
let sections = AnalyticsFileParser().parse(options.inputFile, target: options.target)
// Generate extension
AnalyticsGenerator.writeExtensionFiles(
sections: sections,
target: options.target,
tags: ["ios", "iosonly"],
staticVar: options.staticMembers,
extensionName: options.extensionName,
extensionFilePath: options.extensionFilePath
)
print("[\(Self.toolName)] Analytics generated")
}
// MARK: - Requirements
private func checkRequirements() -> Bool {
let fileManager = FileManager()
// Input file
guard fileManager.fileExists(atPath: options.inputFile) else {
let error = AnalyticsError.fileNotExists(options.inputFile)
print(error.description)
Self.exit(withError: error)
}
guard TrackerType.hasValidTarget(in: options.target) else {
let error = AnalyticsError.noValidTracker(options.target)
print(error.description)
Self.exit(withError: error)
}
// Check if needed to regenerate
guard GeneratorChecker.shouldGenerate(
force: options.forceGeneration,
inputFilePath: options.inputFile,
extensionFilePath: options.extensionFilePath
) else {
print("[\(Self.toolName)] Analytics are already up to date :) ")
return false
}
return true
}
}

View File

@ -0,0 +1,40 @@
//
// AnalyticsError.swift
//
//
// Created by Loris Perret on 11/12/2023.
//
import Foundation
enum AnalyticsError: Error {
case noValidTracker(String)
case fileNotExists(String)
case missingElement(String)
case invalidParameter(String)
case parseFailed(String)
case writeFile(String, String)
var description: String {
switch self {
case .noValidTracker(let inputTargets):
return "error: [\(Analytics.toolName)] '\(inputTargets)' ne contient aucun tracker valid"
case .fileNotExists(let filename):
return "error: [\(Analytics.toolName)] File \(filename) does not exists"
case .missingElement(let element):
return "error: [\(Analytics.toolName)] Missing \(element) for Matomo"
case .invalidParameter(let reason):
return "error: [\(Analytics.toolName)] Invalid parameter \(reason)"
case .parseFailed(let baseError):
return "error: [\(Analytics.toolName)] Parse input file failed: \(baseError)"
case let .writeFile(subErrorDescription, filename):
return "error: [\(Analytics.toolName)] An error occured while writing content to \(filename): \(subErrorDescription)"
}
}
}

View File

@ -0,0 +1,51 @@
//
// AnalyticsOptions.swift
//
//
// Created by Loris Perret on 08/12/2023.
//
import ArgumentParser
import Foundation
// swiftlint:disable no_grouping_extension
struct AnalyticsOptions: ParsableArguments {
@Flag(name: [.customShort("f"), .customShort("F")], help: "Should force generation")
var forceGeneration = false
@Argument(help: "Input files where tags ared defined.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var inputFile: String
@Option(help: "Target(s) analytics to generate. (\"matomo\" | \"firebase\")")
var target: String
@Option(help: "Path where to generate the extension.", transform: { $0.replaceTiltWithHomeDirectoryPath() })
var extensionOutputPath: String
@Option(help: "Tell if it will generate static properties or not")
var staticMembers: Bool = false
@Option(help: "Extension name. If not specified, it will generate a Analytics extension.")
var extensionName: String = Analytics.defaultExtensionName
@Option(help: "Extension suffix. Ex: MyApp, it will generate {extensionName}+Analytics{extensionSuffix}.swift")
var extensionSuffix: String?
}
// MARK: - Computed var
extension AnalyticsOptions {
var extensionFileName: String {
if let extensionSuffix {
return "\(extensionName)+\(extensionSuffix).swift"
}
return "\(extensionName).swift"
}
var extensionFilePath: String {
"\(extensionOutputPath)/\(extensionFileName)"
}
}

View File

@ -0,0 +1,267 @@
//
// AnalyticsGenerator.swift
//
//
// Created by Loris Perret on 08/12/2023.
//
import CoreVideo
import Foundation
import ToolCore
// Disabled cause it's a pain to handle in generated string
enum AnalyticsGenerator {
// MARK: - Write content
static func writeExtensionFiles(
sections: [AnalyticsCategory],
target: String,
tags: [String],
staticVar: Bool,
extensionName: String,
extensionFilePath: String
) {
// Get target type from enum
let targetsString: [String] = target.components(separatedBy: " ")
let targets = {
var targets = [TrackerType]()
TrackerType.allCases.forEach { enumTarget in
if targetsString.contains(enumTarget.value) {
targets.append(enumTarget)
}
}
return targets
}()
// Get extension content
let extensionFileContent = getExtensionContent(
targets: targets,
sections: sections,
tags: tags,
staticVar: staticVar,
extensionName: extensionName
)
// Write content
let extensionFilePathURL = URL(fileURLWithPath: extensionFilePath)
do {
try extensionFileContent.write(to: extensionFilePathURL, atomically: false, encoding: .utf8)
} catch {
let error = AnalyticsError.writeFile(extensionFilePath, error.localizedDescription)
print(error.description)
Analytics.exit(withError: error)
}
}
// MARK: - Extension content
static func getExtensionContent(
targets: [TrackerType],
sections: [AnalyticsCategory],
tags: [String],
staticVar: Bool,
extensionName: String
) -> String {
[
getHeader(
targets: targets,
extensionClassname: extensionName,
staticVar: staticVar
),
getProperties(
sections: sections,
tags: tags,
staticVar: staticVar
),
getFooter()
]
.joined(separator: "\n")
}
// MARK: - Extension part
private static func getHeader(
targets: [TrackerType],
extensionClassname: String,
staticVar: Bool
) -> String {
"""
// Generated by ResgenSwift.\(Analytics.toolName) \(ResgenSwiftVersion)
\(getImport(targets: targets))
\(getAnalyticsProtocol(targets: targets))
// MARK: - Manager
class AnalyticsManager {
static var shared = AnalyticsManager()
// MARK: - Properties
var managers: [AnalyticsManagerProtocol] = []
\(getEnabledContent())
\(getAnalyticsProperties(targets: targets))
\(getPrivateLogFunction())
"""
}
private static func getEnabledContent() -> String {
"""
private var isEnabled: Bool = true
// MARK: - Methods
func setAnalyticsEnabled(_ enable: Bool) {
isEnabled = enable
}
"""
}
private static func getImport(targets: [TrackerType]) -> String {
var result: [String] = []
if targets.contains(TrackerType.matomo) {
result.append("import MatomoTracker")
}
if targets.contains(TrackerType.firebase) {
result.append("import FirebaseAnalytics")
}
return result.joined(separator: "\n")
}
private static func getPrivateLogFunction() -> String {
"""
private func logScreen(name: String, path: String) {
guard isEnabled else { return }
managers.forEach { manager in
manager.logScreen(name: name, path: path)
}
}
private func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard isEnabled else { return }
managers.forEach { manager in
manager.logEvent(
name: name,
action: action,
category: category,
params: params
)
}
}
"""
}
private static func getAnalyticsProperties(targets: [TrackerType]) -> String {
var header = ""
var content: [String] = []
let footer = " }"
if targets.contains(TrackerType.matomo) {
header = "func configure(siteId: String, url: String) {"
} else if targets.contains(TrackerType.firebase) {
header = "func configure() {"
}
if targets.contains(TrackerType.matomo) {
content.append("""
managers.append(
MatomoAnalyticsManager(
siteId: siteId,
url: url
)
)
""")
}
if targets.contains(TrackerType.firebase) {
content.append(" managers.append(FirebaseAnalyticsManager())")
}
return [
header,
content.joined(separator: "\n"),
footer
]
.joined(separator: "\n")
}
private static func getAnalyticsProtocol(targets: [TrackerType]) -> String {
let proto = """
// MARK: - Protocol
protocol AnalyticsManagerProtocol {
func logScreen(name: String, path: String)
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
)
}
"""
var result: [String] = [proto]
if targets.contains(TrackerType.matomo) {
result.append(MatomoGenerator.service)
}
if targets.contains(TrackerType.firebase) {
result.append(FirebaseGenerator.service)
}
return result.joined(separator: "\n")
}
private static func getProperties(
sections: [AnalyticsCategory],
tags: [String],
staticVar: Bool
) -> String {
sections
.compactMap { section in
// Check that at least one string will be generated
guard section.hasOneOrMoreMatchingTags(tags: tags) else {
return nil// Go to next section
}
var res = "\n // MARK: - \(section.id)"
section.definitions.forEach { definition in
guard definition.hasOneOrMoreMatchingTags(inputTags: tags) == true else {
return // Go to next definition
}
if staticVar {
res += "\n\n\(definition.getStaticProperty())"
} else {
res += "\n\n\(definition.getProperty())"
}
}
return res
}
.joined(separator: "\n")
}
private static func getFooter() -> String {
"""
}
"""
}
}

View File

@ -0,0 +1,91 @@
//
// FirebaseGenerator.swift
//
//
// Created by Loris Perret on 05/12/2023.
//
// CPD-OFF
import Foundation
enum FirebaseGenerator {
static var service: String {
[
Self.header,
Self.logScreen,
Self.logEvent,
Self.footer
]
.joined(separator: "\n")
}
// MARK: - Private vars
private static var header: String {
"""
// MARK: - Firebase
class FirebaseAnalyticsManager: AnalyticsManagerProtocol {
"""
}
private static var logScreen: String {
"""
func logScreen(name: String, path: String) {
var parameters = [
AnalyticsParameterScreenName: name as NSObject
]
Analytics.logEvent(
AnalyticsEventScreenView,
parameters: parameters
)
}
"""
}
private static var logEvent: String {
"""
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
var parameters: [String:NSObject] = [
"action": action as NSObject,
"category": category 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(
name.replacingOccurrences(of: [" "], with: "_"),
parameters: parameters
)
}
"""
}
private static var footer: String {
"""
}
"""
}
}
// CPD-ON

View File

@ -0,0 +1,110 @@
//
// MatomoGenerator.swift
//
//
// Created by Loris Perret on 05/12/2023.
//
import Foundation
enum MatomoGenerator {
static var service: String {
[
Self.header,
Self.setup,
Self.logScreen,
Self.logEvent,
Self.footer
]
.joined(separator: "\n")
}
// MARK: - Private vars
private static var header: String {
"""
// MARK: - Matomo
class MatomoAnalyticsManager: AnalyticsManagerProtocol {
// MARK: - Properties
private var tracker: MatomoTracker
"""
}
private static var setup: String {
"""
// MARK: - Init
init(siteId: String, url: String) {
debugPrint("[Matomo service] Server URL: \\(url)")
debugPrint("[Matomo service] Site ID: \\(siteId)")
tracker = MatomoTracker(
siteId: siteId,
baseURL: URL(string: url)!
)
#if DEBUG
tracker.dispatchInterval = 5
#endif
#if DEBUG
tracker.logger = DefaultLogger(minLevel: .verbose)
#endif
debugPrint("[Matomo service] Configured with content base: \\(tracker.contentBase?.absoluteString ?? "-")")
debugPrint("[Matomo service] Opt out: \\(tracker.isOptedOut)")
}
// MARK: - Methods
"""
}
private static var logScreen: String {
"""
func logScreen(name: String, path: String) {
guard !tracker.isOptedOut else { return }
guard let trackerUrl = tracker.contentBase?.absoluteString else { return }
let urlString = URL(string: "\\(trackerUrl)" + "/" + "\\(path)" + "iOS")
tracker.track(
view: [name],
url: urlString
)
}
"""
}
private static var logEvent: String {
"""
func logEvent(
name: String,
action: String,
category: String,
params: [String: Any]?
) {
guard !tracker.isOptedOut else { return }
tracker.track(
eventWithCategory: category,
action: action,
name: name,
number: nil,
url: nil
)
}
"""
}
private static var footer: String {
"""
}
"""
}
}

View File

@ -0,0 +1,35 @@
//
// AnalyticsCategory.swift
//
//
// Created by Loris Perret on 05/12/2023.
//
import Foundation
class AnalyticsCategory {
// MARK: - Properties
let id: String // OnBoarding
var definitions = [AnalyticsDefinition]()
// MARK: - Init
init(id: String) {
self.id = id
}
// MARK: - Methods
func hasOneOrMoreMatchingTags(tags: [String]) -> Bool {
let allTags = definitions.flatMap { $0.tags }
let allTagsSet = Set(allTags)
let intersection = Set(tags).intersection(allTagsSet)
if intersection.isEmpty {
return false
}
return true
}
}

Some files were not shown because too many files have changed in this diff Show More