solara 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/solara/lib/core/.DS_Store +0 -0
  3. data/solara/lib/core/aliases/alias_generator.rb +1 -0
  4. data/solara/lib/core/aliases/alias_generator_manager.rb +2 -1
  5. data/solara/lib/core/aliases/solara_terminal_setup.rb +1 -1
  6. data/solara/lib/core/brands/brand_font_switcher.rb +154 -0
  7. data/solara/lib/core/brands/brand_onboarder.rb +8 -6
  8. data/solara/lib/core/brands/brand_switcher.rb +232 -166
  9. data/solara/lib/core/brands/brands_manager.rb +15 -39
  10. data/solara/lib/core/dashboard/brand/BrandDetail.js +19 -0
  11. data/solara/lib/core/dashboard/brand/BrandDetailController.js +50 -8
  12. data/solara/lib/core/dashboard/brand/BrandDetailModel.js +9 -30
  13. data/solara/lib/core/dashboard/brand/BrandDetailView.js +49 -3
  14. data/solara/lib/core/dashboard/brand/InfoPlistStringCatalogManager.js +19 -0
  15. data/solara/lib/core/dashboard/brand/brand.html +209 -62
  16. data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +1 -1
  17. data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +38 -53
  18. data/solara/lib/core/dashboard/brands/BrandsController.js +6 -5
  19. data/solara/lib/core/dashboard/brands/BrandsModel.js +2 -2
  20. data/solara/lib/core/dashboard/brands/BrandsView.js +2 -2
  21. data/solara/lib/core/dashboard/brands/brands.html +3 -1
  22. data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +7 -5
  23. data/solara/lib/core/dashboard/dashboard_manager.rb +2 -0
  24. data/solara/lib/core/dashboard/dashboard_server.rb +13 -8
  25. data/solara/lib/core/dashboard/handler/brand_alisases_handler.rb +4 -11
  26. data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +11 -11
  27. data/solara/lib/core/dashboard/handler/{brand_configurations_handler.rb → brand_details_handler.rb} +4 -4
  28. data/solara/lib/core/dashboard/handler/brands_handler.rb +1 -1
  29. data/solara/lib/core/dashboard/handler/edit_section_handler.rb +8 -8
  30. data/solara/lib/core/doctor/brand_doctor.rb +31 -31
  31. data/solara/lib/core/doctor/doctor_manager.rb +0 -1
  32. data/solara/lib/core/doctor/project_doctor.rb +0 -1
  33. data/solara/lib/core/doctor/schema/platform/android/android_config.json +0 -4
  34. data/solara/lib/core/doctor/schema/platform/ios/InfoPlist.xcstrings +15 -0
  35. data/solara/lib/core/doctor/schema/platform/ios/ios_config.json +0 -5
  36. data/solara/lib/core/doctor/schema/platform/shared/brand_config.json +9 -0
  37. data/solara/lib/core/doctor/schema/platform/shared/theme.json +94 -9
  38. data/solara/lib/core/doctor/validator/brand_settings_validator.rb +6 -0
  39. data/solara/lib/core/doctor/validator/brand_settings_validator_manager.rb +9 -21
  40. data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +22 -4
  41. data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +22 -6
  42. data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +22 -4
  43. data/solara/lib/core/scripts/brand_config_generator.rb +1 -0
  44. data/solara/lib/core/scripts/brand_config_manager.rb +2 -4
  45. data/solara/lib/core/scripts/brand_exporter.rb +1 -1
  46. data/solara/lib/core/scripts/brand_importer.rb +2 -3
  47. data/solara/lib/core/scripts/brand_offboarder.rb +5 -0
  48. data/solara/lib/core/scripts/brand_resources_manager.rb +127 -54
  49. data/solara/lib/core/scripts/directory_creator.rb +2 -2
  50. data/solara/lib/core/scripts/file_manager.rb +53 -19
  51. data/solara/lib/core/scripts/file_path.rb +175 -30
  52. data/solara/lib/core/scripts/folder_copier.rb +3 -7
  53. data/solara/lib/core/scripts/gitignore_manager.rb +21 -10
  54. data/solara/lib/core/scripts/interactive_file_system_validator.rb +8 -2
  55. data/solara/lib/core/scripts/platform/android/android_manifest_switcher.rb +3 -3
  56. data/solara/lib/core/scripts/platform/android/android_strings_switcher.rb +26 -24
  57. data/solara/lib/core/scripts/platform/android/gradle_switcher.rb +7 -6
  58. data/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb +123 -0
  59. data/solara/lib/core/scripts/platform/ios/infoplist_switcher.rb +59 -0
  60. data/solara/lib/core/scripts/platform/ios/ios_plist_manager.rb +11 -20
  61. data/solara/lib/core/scripts/platform/ios/plist_font_manager.rb +33 -0
  62. data/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb +15 -3
  63. data/solara/lib/core/scripts/platform/ios/xcode_asset_manager.rb +2 -3
  64. data/solara/lib/core/scripts/platform/ios/xcode_project_manager.rb +80 -1
  65. data/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb +15 -34
  66. data/solara/lib/core/scripts/solara_logger.rb +10 -0
  67. data/solara/lib/core/scripts/solara_settings_manager.rb +26 -1
  68. data/solara/lib/core/scripts/strings_xml_manager.rb +17 -2
  69. data/solara/lib/core/scripts/theme_generator.rb +133 -130
  70. data/solara/lib/core/scripts/yaml_manager.rb +23 -0
  71. data/solara/lib/core/solara_configurator.rb +1 -1
  72. data/solara/lib/core/template/brands/android/android_config.json +0 -1
  73. data/solara/lib/core/template/brands/android/res/values/strings.xml +4 -0
  74. data/solara/lib/core/template/brands/ios/InfoPlist.xcstrings +30 -0
  75. data/solara/lib/core/template/brands/ios/ios_config.json +1 -2
  76. data/solara/lib/core/template/brands/shared/brand_config.json +1 -0
  77. data/solara/lib/core/template/brands/shared/theme.json +3 -3
  78. data/solara/lib/core/template/config/android_template_config.json +11 -1
  79. data/solara/lib/core/template/config/flutter_template_config.json +12 -2
  80. data/solara/lib/core/template/config/ios_template_config.json +11 -1
  81. data/solara/lib/core/template/project_template_generator.rb +8 -3
  82. data/solara/lib/solara/version.rb +1 -1
  83. data/solara/lib/solara.rb +8 -4
  84. data/solara/lib/solara_initializer.rb +5 -2
  85. data/solara/lib/solara_manager.rb +1 -1
  86. metadata +62 -43
  87. data/solara/lib/core/dashboard/handler/brand_section_handler.rb +0 -20
  88. data/solara/lib/core/doctor/validator/directory_structure_validator.rb +0 -38
  89. data/solara/lib/core/doctor/validator/file_structure_validator.rb +0 -37
  90. data/solara/lib/core/scripts/platform/ios/ios_file_path_manager.rb +0 -109
  91. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/.DS_Store +0 -0
  92. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/100.png +0 -0
  93. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/102.png +0 -0
  94. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/1024.png +0 -0
  95. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/114.png +0 -0
  96. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/120.png +0 -0
  97. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/128.png +0 -0
  98. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/144.png +0 -0
  99. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/152.png +0 -0
  100. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/16.png +0 -0
  101. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/167.png +0 -0
  102. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/172.png +0 -0
  103. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/180.png +0 -0
  104. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/196.png +0 -0
  105. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/20.png +0 -0
  106. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/216.png +0 -0
  107. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/256.png +0 -0
  108. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/29.png +0 -0
  109. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/32.png +0 -0
  110. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/40.png +0 -0
  111. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/48.png +0 -0
  112. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/50.png +0 -0
  113. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/512.png +0 -0
  114. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/55.png +0 -0
  115. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/57.png +0 -0
  116. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/58.png +0 -0
  117. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/60.png +0 -0
  118. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/64.png +0 -0
  119. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/66.png +0 -0
  120. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/72.png +0 -0
  121. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/76.png +0 -0
  122. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/80.png +0 -0
  123. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/87.png +0 -0
  124. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/88.png +0 -0
  125. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/92.png +0 -0
  126. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/Contents.json +0 -0
@@ -0,0 +1,59 @@
1
+ $LOAD_PATH.unshift(File.expand_path(__dir__))
2
+
3
+ class InfoPlistSwitcher
4
+ def initialize(project_path, brand_key)
5
+ @project_path = project_path
6
+ @brand_key = brand_key
7
+ @project = Xcodeproj::Project.open(@project_path)
8
+ end
9
+
10
+ def switch
11
+ copy_string_catalog
12
+ update_info_plist
13
+ @project.save
14
+ Solara.logger.debug("Switched #{FilePath.info_plist} successfully.")
15
+ end
16
+
17
+ private
18
+
19
+ def copy_string_catalog
20
+ # Remove from project before copying
21
+ project_infoplist_string_catalog = FilePath.project_infoplist_string_catalog
22
+ if File.exist?(project_infoplist_string_catalog)
23
+ FileManager.delete_if_exists(project_infoplist_string_catalog)
24
+ Solara.logger.debug("Deleted #{project_infoplist_string_catalog} successfully.")
25
+ end
26
+
27
+ source = FilePath.brand_infoplist_string_catalog(@brand_key)
28
+ destination = FilePath.project_info_plist_directory
29
+ FolderCopier.new(source, destination).copy
30
+
31
+ # Add reference to XcodeProject
32
+ XcodeProjectManager.add_file_near_info_plist(@project, project_infoplist_string_catalog)
33
+ end
34
+
35
+ def update_info_plist
36
+ info_plist_path = FilePath.info_plist
37
+ manager = IOSPlistManager.new(@project, info_plist_path)
38
+ manager.set_info_plist_in_build_settings
39
+
40
+ xcconfig_values = {
41
+ 'CFBUNDLE_DISPLAY_NAME' => "$(CFBUNDLE_DISPLAY_NAME)",
42
+ 'CFBUNDLE_NAME' => "$(CFBUNDLE_NAME)",
43
+ 'PRODUCT_NAME' => "$(PRODUCT_NAME)",
44
+ 'PRODUCT_BUNDLE_IDENTIFIER' => "$(PRODUCT_BUNDLE_IDENTIFIER)",
45
+ 'MARKETING_VERSION' => "$(MARKETING_VERSION)",
46
+ 'BUNDLE_VERSION' => "$(BUNDLE_VERSION)"
47
+ }
48
+
49
+ info_plist = Xcodeproj::Plist.read_from_path(info_plist_path)
50
+ info_plist[InfoPListKey::BUNDLE_DISPLAY_NAME] = xcconfig_values['CFBUNDLE_DISPLAY_NAME']
51
+ info_plist[InfoPListKey::BUNDLE_NAME] = xcconfig_values['CFBUNDLE_NAME']
52
+ info_plist['CFBundleIdentifier'] = xcconfig_values['PRODUCT_BUNDLE_IDENTIFIER']
53
+ info_plist['CFBundleShortVersionString'] = xcconfig_values['MARKETING_VERSION']
54
+ info_plist['CFBundleVersion'] = xcconfig_values['BUNDLE_VERSION']
55
+
56
+ Xcodeproj::Plist.write_to_path(info_plist, info_plist_path)
57
+ end
58
+
59
+ end
@@ -1,4 +1,5 @@
1
1
  require 'xcodeproj'
2
+ require 'plist'
2
3
 
3
4
  class IOSPlistManager
4
5
  def initialize(project, info_plist_path)
@@ -6,31 +7,20 @@ class IOSPlistManager
6
7
  @info_plist_path = info_plist_path
7
8
  end
8
9
 
9
- def create_and_add_info_plist
10
- # add_info_plist_to_project
11
- set_info_plist_in_build_settings
12
- save_project
13
- end
14
-
15
- private
16
-
17
- def add_info_plist_to_project
18
- file_ref = @project.files.select { |f| f.path == @info_plist_path }.first
19
- if file_ref
20
- Solara.logger.debug("Info.plist file reference already exists in the project. Skipping this step.")
21
- else
22
- file_ref = XcodeProjectManager.new.add_single_file_to_group(@project, @project.main_group, @info_plist_path)
23
- Solara.logger.debug("Info.plist file created. file_ref = #{file_ref}")
24
- end
25
- end
26
-
27
10
  def set_info_plist_in_build_settings
28
- path = FileManager.get_relative_path(IOSFilePathManager.instance.xcode_project_directory, @info_plist_path)
11
+ path = FileManager.get_relative_path(FilePath.xcode_project_directory, @info_plist_path)
29
12
  main_target.build_configurations.each do |config|
30
13
  config.build_settings['INFOPLIST_FILE'] = path
31
14
  end
32
15
  end
33
16
 
17
+ def add_fonts(font_names)
18
+ font_manager = PlistFontManager.new(FilePath.info_plist)
19
+ font_manager.add_fonts(font_names)
20
+ end
21
+
22
+ private
23
+
34
24
  def save_project
35
25
  @project.save
36
26
  end
@@ -39,4 +29,5 @@ class IOSPlistManager
39
29
  @project.targets.first
40
30
  end
41
31
 
42
- end
32
+ end
33
+
@@ -0,0 +1,33 @@
1
+ class PlistFontManager
2
+ def initialize(plist_path)
3
+ @plist_path = plist_path
4
+ load_plist
5
+ end
6
+
7
+ def load_plist
8
+ @plist = Plist.parse_xml(@plist_path)
9
+ @plist['UIAppFonts'] ||= []
10
+ end
11
+
12
+ def add_fonts(font_names)
13
+ font_names.each do |font_name|
14
+ add_font(font_name)
15
+ end
16
+ end
17
+
18
+ def add_font(font_name)
19
+ unless @plist['UIAppFonts'].include?(font_name)
20
+ @plist['UIAppFonts'] << font_name
21
+ save_plist
22
+ Solara.logger.debug("#{font_name} added to UIAppFonts.")
23
+ else
24
+ Solara.logger.debug("#{font_name} already exists in UIAppFonts.")
25
+ end
26
+ end
27
+
28
+ def save_plist
29
+ File.open(@plist_path, 'w') do |file|
30
+ file.write(Plist::Emit.dump(@plist))
31
+ end
32
+ end
33
+ end
@@ -6,10 +6,10 @@ class XcconfigGenerator
6
6
 
7
7
  def generate
8
8
  Solara.logger.start_step("Generate Brand.xcconfig for iOS")
9
- destination = IOSFilePathManager.instance.brand_xcconfig
9
+ destination = FilePath.brand_xcconfig
10
10
  content = generate_xcconfig_content
11
11
  File.write(destination, content)
12
- Solara.logger.debug("🎉 Generated #{IOSFilePathManager.instance.brand_xcconfig}. Content below ⬇️")
12
+ Solara.logger.debug("🎉 Generated #{FilePath.brand_xcconfig}. Content below ⬇️")
13
13
  Solara.logger.debug("--------------\n#{content}--------------")
14
14
  Solara.logger.end_step("Generate Brand.xcconfig for iOS")
15
15
  end
@@ -18,7 +18,10 @@ class XcconfigGenerator
18
18
 
19
19
  def generate_xcconfig_content
20
20
  content = <<~XCCONFIG
21
- ASSETCATALOG_COMPILER_APPICON_NAME = Artifacts/AppIcon
21
+ APPICON_NAME = AppIcon
22
+ PRODUCT_NAME = #{get_value_of(InfoPListKey::BUNDLE_DISPLAY_NAME)}
23
+ CFBUNDLE_DISPLAY_NAME = #{get_value_of(InfoPListKey::BUNDLE_DISPLAY_NAME)}
24
+ CFBUNDLE_NAME = #{get_value_of(InfoPListKey::BUNDLE_NAME)}
22
25
  #{load_config.map { |key, value| "#{key.upcase} = #{value}" }.join("\n")}
23
26
  XCCONFIG
24
27
 
@@ -37,6 +40,15 @@ class XcconfigGenerator
37
40
  end
38
41
  end
39
42
 
43
+ def get_value_of(key)
44
+ infoplist_value = InfoPListStringCatalogManager.new(FilePath.brand_infoplist_string_catalog(@brand_key)).get(key)
45
+ return infoplist_value if !infoplist_value && !infoplist_value.empty?
46
+
47
+ brand_config_path = FilePath.brand_config(@brand_key)
48
+ brand_config = JSON.parse(File.read(brand_config_path))
49
+ brand_config['brandName']
50
+ end
51
+
40
52
  def load_config
41
53
  config_path = FilePath.ios_config(@brand_key)
42
54
  JSON.parse(File.read(config_path))
@@ -6,11 +6,10 @@ class XcodeAssetManager
6
6
  @asset_catalog_path = asset_catalog_path
7
7
  end
8
8
 
9
-
10
9
  def add(source)
11
10
  # Fetches only files in the specified source directory
12
11
  Dir.glob(File.join(source, '*.{png,jpg,jpeg,svg,heic,pdf}')).each do |file_path|
13
- if File.file?(file_path) # Ensure it's a file and not a directory
12
+ if File.file?(file_path) # Ensure it's a file and not a directory
14
13
  filename_without_extension = File.basename(file_path, File.extname(file_path))
15
14
  add_image(filename_without_extension, file_path, '1x')
16
15
  end
@@ -51,6 +50,6 @@ class XcodeAssetManager
51
50
  # Write the updated Contents.json
52
51
  File.write(contents_json_path, JSON.pretty_generate(contents))
53
52
 
54
- puts "Image '#{image_name}' added successfully at scale #{scale}."
53
+ Solara.logger.debug("XcodeAssetManager: Image '#{image_name}' added successfully at scale #{scale}.")
55
54
  end
56
55
  end
@@ -64,7 +64,6 @@ class XcodeProjectManager
64
64
 
65
65
  Solara.logger.debug("Base XCConfig files have been set for all build configurations.")
66
66
  end
67
-
68
67
  def self.set_xcconfig(project, config, xcconfig)
69
68
  # Find the existing file reference or create a new one if it doesn't exist
70
69
  file_reference = project.reference_for_path(xcconfig[:path])
@@ -79,4 +78,84 @@ class XcodeProjectManager
79
78
  end
80
79
  end
81
80
 
81
+ def add_file_to_root(project, file_path)
82
+ Solara.logger.debug("Adding file to root: #{file_path}")
83
+
84
+ root_group = project.main_group
85
+ file_name = File.basename(file_path, File.extname(file_path))
86
+
87
+ existing_file = root_group.files.find { |f| File.basename(f.path, File.extname(f.path))&.downcase == file_name.downcase }
88
+
89
+ if existing_file
90
+ Solara.logger.debug("Ignoring file: #{file_path} (Existing file reference: #{existing_file.path})")
91
+ return nil
92
+ else
93
+ file_reference = root_group.new_file(file_path)
94
+ Solara.logger.debug("Added new file to root: #{file_path} (File reference: #{file_reference.uuid})")
95
+
96
+ # Add the file to the project's main target if it's a source file
97
+ if %w[.swift .m .mm .c .cpp].include?(File.extname(file_path).downcase)
98
+ target = project.targets.first
99
+ target.add_file_references([file_reference])
100
+ Solara.logger.debug(" Added to target: #{target.name}")
101
+ end
102
+
103
+ file_reference
104
+ end
105
+ end
106
+
107
+ def self.add_file_near_info_plist(project, file_path)
108
+ Solara.logger.debug("Adding file near Info.plist: #{file_path}")
109
+
110
+ # Find the Info.plist file path
111
+ info_plist_path = project.targets.first.build_configurations.first.build_settings['INFOPLIST_FILE']
112
+ return Solara.logger.warn("No Info.plist file found for the target") unless info_plist_path
113
+
114
+ # Get the directory of the Info.plist file
115
+ info_plist_dir = File.dirname(info_plist_path)
116
+
117
+ target_file_path = File.basename(file_path)
118
+ infoplist_group = info_plist_dir === '.' ? project.main_group : find_group_by_path(project, [info_plist_dir])
119
+
120
+ # Check if a file with the same name already exists in the target directory
121
+ existing_file = infoplist_group.files.find { |f| f.path == target_file_path }
122
+
123
+ if existing_file
124
+ Solara.logger.debug("Ignoring file: #{file_path} (Existing file reference: #{existing_file.path})")
125
+ return nil
126
+ else
127
+ # Add the file to the main group, which corresponds to the directory of Info.plist
128
+ file_reference = infoplist_group.new_file(target_file_path)
129
+ Solara.logger.debug("Added new file near Info.plist: #{file_path} (File reference: #{file_reference.uuid})")
130
+
131
+ # Add the file to the project's main target as a resource
132
+ target = project.targets.first
133
+
134
+ # Create a new build file
135
+ build_file = project.new(Xcodeproj::Project::Object::PBXBuildFile)
136
+ build_file.file_ref = file_reference
137
+
138
+ # Add the build file to the target's resources build phase
139
+ resources_build_phase = target.resources_build_phase
140
+ resources_build_phase.add_file_reference(file_reference)
141
+
142
+ Solara.logger.debug(" Added to target: #{target.name}")
143
+ Solara.logger.debug(" Added to PBXBuildFile section as a resource")
144
+
145
+ file_reference
146
+ end
147
+ end
148
+ def self.find_group_by_path(project, paths)
149
+ current_group = project.main_group
150
+
151
+ paths.each do |path|
152
+ current_group = current_group.children.find { |child|
153
+ child.is_a?(Xcodeproj::Project::Object::PBXGroup) && child.path == path
154
+ }
155
+ return nil unless current_group
156
+ end
157
+ current_group
158
+ end
159
+
160
+
82
161
  end
@@ -11,11 +11,10 @@ class XcodeProjectSwitcher
11
11
 
12
12
  def switch
13
13
  update_xcode_target_settings
14
- update_info_plist
15
14
  add_artifacts_group
16
15
  update_debug_and_release_xcconfig
17
16
  @project.save
18
- Solara.logger.debug("Updated #{@project_path} to use the values of #{IOSFilePathManager.instance.brand_xcconfig}")
17
+ Solara.logger.debug("Switched #{@project_path} Successfully.")
19
18
  end
20
19
 
21
20
  private
@@ -23,8 +22,9 @@ class XcodeProjectSwitcher
23
22
  def update_xcode_target_settings
24
23
  @target.build_configurations.each do |config|
25
24
  config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = '$(PRODUCT_BUNDLE_IDENTIFIER)'
26
- config.build_settings['PRODUCT_NAME'] = '$(PRODUCT_NAME)'
27
25
  config.build_settings['MARKETING_VERSION'] = '$(MARKETING_VERSION)'
26
+ config.build_settings['ASSETCATALOG_COMPILER_APPICON_NAME'] = '$(APPICON_NAME)'
27
+ config.build_settings['PRODUCT_NAME'] = '$(PRODUCT_NAME)'
28
28
 
29
29
  # We need to apply code signing only if the user has provided its config
30
30
  path = FilePath.brand_signing(@brand_key, Platform::IOS)
@@ -47,30 +47,9 @@ class XcodeProjectSwitcher
47
47
  end
48
48
  end
49
49
 
50
- def update_info_plist
51
- info_plist_path = IOSFilePathManager.instance.info_plist
52
- manager = IOSPlistManager.new(@project, info_plist_path)
53
- manager.create_and_add_info_plist
54
-
55
- xcconfig_values = {
56
- 'PRODUCT_NAME' => "$(PRODUCT_NAME)",
57
- 'PRODUCT_BUNDLE_IDENTIFIER' => "$(PRODUCT_BUNDLE_IDENTIFIER)",
58
- 'MARKETING_VERSION' => "$(MARKETING_VERSION)",
59
- 'BUNDLE_VERSION' => "$(BUNDLE_VERSION)"
60
- }
61
-
62
- info_plist = Xcodeproj::Plist.read_from_path(info_plist_path)
63
- info_plist['CFBundleDisplayName'] = xcconfig_values['PRODUCT_NAME']
64
- info_plist['CFBundleIdentifier'] = xcconfig_values['PRODUCT_BUNDLE_IDENTIFIER']
65
- info_plist['CFBundleShortVersionString'] = xcconfig_values['MARKETING_VERSION']
66
- info_plist['CFBundleVersion'] = xcconfig_values['BUNDLE_VERSION']
67
-
68
- Xcodeproj::Plist.write_to_path(info_plist, info_plist_path)
69
- end
70
-
71
50
  def update_debug_and_release_xcconfig
72
- debug_xcconfig_path = IOSFilePathManager.instance.app_xcconfig('Debug.xcconfig')
73
- release_xcconfig_path = IOSFilePathManager.instance.app_xcconfig('Release.xcconfig')
51
+ debug_xcconfig_path = FilePath.app_xcconfig('Debug.xcconfig')
52
+ release_xcconfig_path = FilePath.app_xcconfig('Release.xcconfig')
74
53
 
75
54
  create_xcconfigs_and_add_to_project(debug_xcconfig_path, release_xcconfig_path)
76
55
  set_base_xcconfigs(debug_xcconfig_path, release_xcconfig_path)
@@ -78,7 +57,7 @@ class XcodeProjectSwitcher
78
57
 
79
58
  def create_xcconfigs_and_add_to_project(debug_xcconfig_path, release_xcconfig_path)
80
59
  FileManager.create_files_if_not_exist([debug_xcconfig_path, release_xcconfig_path])
81
- base_xcconfig_name = 'Artifacts/Brand.xcconfig'
60
+ base_xcconfig_name = "#{FilePath.artifacts_dir_name_ios}/Brand.xcconfig"
82
61
 
83
62
  case @platform
84
63
  when Platform::Flutter
@@ -87,7 +66,7 @@ class XcodeProjectSwitcher
87
66
  group_name = 'XCConfig'
88
67
  config_group = @project.groups.find { |group| group.name == group_name }
89
68
  config_group = @project.new_group(group_name) if config_group.nil?
90
- add_files_to_group(config_group, IOSFilePathManager.instance.app_xcconfig_directory)
69
+ add_files_to_group(config_group, FilePath.app_xcconfig_directory)
91
70
  else
92
71
  raise ArgumentError, "Invalid platform: #{@platform}"
93
72
  end
@@ -108,16 +87,18 @@ class XcodeProjectSwitcher
108
87
  end
109
88
 
110
89
  def add_artifacts_group
90
+ artifacts_dir_name = FilePath.artifacts_dir_name_ios
91
+
111
92
  case @platform
112
93
  when Platform::Flutter
113
94
  flutter_group = @project.groups.find { |group| group.name == 'Flutter' }
114
- artifacts_group = flutter_group.groups.find { |group| group.name == 'Artifacts' }
115
- artifacts_group = flutter_group.new_group("Artifacts") if artifacts_group.nil?
116
- add_files_to_group(artifacts_group, IOSFilePathManager.instance.artifacts)
95
+ artifacts_group = flutter_group.groups.find { |group| group.name == artifacts_dir_name }
96
+ artifacts_group = flutter_group.new_group(artifacts_dir_name) if artifacts_group.nil?
97
+ add_files_to_group(artifacts_group, FilePath.ios_project_root_artifacts)
117
98
  when Platform::IOS
118
- artifacts_group = @project.groups.find { |group| group.name == 'Artifacts' }
119
- artifacts_group = @project.new_group("Artifacts") if artifacts_group.nil?
120
- add_files_to_group(artifacts_group, IOSFilePathManager.instance.artifacts)
99
+ artifacts_group = @project.groups.find { |group| group.name == artifacts_dir_name }
100
+ artifacts_group = @project.new_group(artifacts_dir_name) if artifacts_group.nil?
101
+ add_files_to_group(artifacts_group, FilePath.ios_project_root_artifacts)
121
102
  else
122
103
  raise ArgumentError, "Invalid platform: #{@platform}"
123
104
  end
@@ -24,6 +24,10 @@ class SolaraLogger
24
24
  set_default_format
25
25
  end
26
26
 
27
+ def reset_steps
28
+ @step_count = 0
29
+ end
30
+
27
31
  def verbose=(value)
28
32
  @verbose = value
29
33
  @logger.level = @verbose ? Logger::DEBUG : Logger::INFO
@@ -43,6 +47,12 @@ class SolaraLogger
43
47
  line
44
48
  end
45
49
 
50
+ def log_step(step_name)
51
+ start_step(step_name)
52
+ yield
53
+ end_step(step_name)
54
+ end
55
+
46
56
  def title(message)
47
57
  @logger.info(message.green)
48
58
  line
@@ -6,7 +6,11 @@ require 'json'
6
6
  class SolaraSettingsManager
7
7
  include Singleton
8
8
 
9
- attr_accessor :root, :project_root
9
+ attr_accessor :root, :project_root, :environment
10
+
11
+ def initialize
12
+ @environment = SolaraEnvironment::Production
13
+ end
10
14
 
11
15
  def platform
12
16
  settings['platform']
@@ -28,6 +32,10 @@ class SolaraSettingsManager
28
32
  save(json)
29
33
  end
30
34
 
35
+ def is_test_environment
36
+ @environment === 'test'
37
+ end
38
+
31
39
  private
32
40
 
33
41
  def settings
@@ -70,4 +78,21 @@ def init(platform)
70
78
  unless Platform.all.include?(platform)
71
79
  raise ArgumentError, "Invalid platform. Please use one of: #{Platform.all.join(', ')}"
72
80
  end
81
+ end
82
+
83
+ module SolaraEnvironment
84
+ Production = 'production'
85
+ Test = 'test'
86
+
87
+ def self.all
88
+ [Production, Test]
89
+ end
90
+
91
+ def self.is_production
92
+ SolaraSettingsManager.instance.environment.downcase == Production.downcase
93
+ end
94
+
95
+ def self.is_test
96
+ SolaraSettingsManager.instance.environment.downcase == Test.downcase
97
+ end
73
98
  end
@@ -3,7 +3,7 @@ require 'rexml/document'
3
3
  class StringsXmlManager
4
4
  def initialize(file_path)
5
5
  @file_path = file_path
6
- @xml_content = File.read(@file_path)
6
+ @xml_content = File.read(@file_path, encoding: 'UTF-8')
7
7
  @doc = REXML::Document.new(@xml_content)
8
8
  end
9
9
 
@@ -11,7 +11,22 @@ class StringsXmlManager
11
11
  app_name_element = @doc.elements['resources/string[@name="app_name"]']
12
12
  app_name_element.remove if app_name_element
13
13
  save_changes
14
- Solara.logger.debug("Removed app_name from #{@file_path} to avoid duplication with artifacts/strings.xml.")
14
+ Solara.logger.debug("Removed app_name from #{@file_path} to avoid duplication with #{FilePath.artifacts_dir_name}/strings.xml.")
15
+ end
16
+
17
+ def update_string_value(string_name, new_value)
18
+ string_element = @doc.elements["resources/string[@name=\"#{string_name}\"]"]
19
+ if string_element
20
+ string_element.text = new_value
21
+ save_changes
22
+ Solara.logger.debug("Updated string '#{string_name}' to '#{new_value}' in #{@file_path}.")
23
+ else
24
+ Solara.logger.warn("String '#{string_name}' not found in #{@file_path}. Update failed.")
25
+ end
26
+ end
27
+
28
+ def get_value(string_name)
29
+ @doc.elements["resources/string[@name=\"#{string_name}\"]"].text
15
30
  end
16
31
 
17
32
  private