solara 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/bin/solara +3 -1
  3. data/solara/lib/core/.DS_Store +0 -0
  4. data/solara/lib/core/aliases/alias_generator.rb +1 -0
  5. data/solara/lib/core/aliases/alias_generator_manager.rb +2 -1
  6. data/solara/lib/core/aliases/solara_terminal_setup.rb +1 -1
  7. data/solara/lib/core/brands/brand_font_switcher.rb +154 -0
  8. data/solara/lib/core/brands/brand_onboarder.rb +8 -6
  9. data/solara/lib/core/brands/brand_switcher.rb +232 -166
  10. data/solara/lib/core/brands/brands_manager.rb +15 -39
  11. data/solara/lib/core/dashboard/brand/BrandDetail.js +19 -0
  12. data/solara/lib/core/dashboard/brand/BrandDetailController.js +50 -8
  13. data/solara/lib/core/dashboard/brand/BrandDetailModel.js +9 -30
  14. data/solara/lib/core/dashboard/brand/BrandDetailView.js +49 -3
  15. data/solara/lib/core/dashboard/brand/InfoPlistStringCatalogManager.js +19 -0
  16. data/solara/lib/core/dashboard/brand/brand.html +209 -62
  17. data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +1 -1
  18. data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +38 -53
  19. data/solara/lib/core/dashboard/brands/BrandsController.js +6 -5
  20. data/solara/lib/core/dashboard/brands/BrandsModel.js +2 -2
  21. data/solara/lib/core/dashboard/brands/BrandsView.js +2 -2
  22. data/solara/lib/core/dashboard/brands/brands.html +3 -1
  23. data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +7 -5
  24. data/solara/lib/core/dashboard/dashboard_manager.rb +2 -0
  25. data/solara/lib/core/dashboard/dashboard_server.rb +1 -3
  26. data/solara/lib/core/dashboard/handler/brand_alisases_handler.rb +4 -11
  27. data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +11 -11
  28. data/solara/lib/core/dashboard/handler/{brand_configurations_handler.rb → brand_details_handler.rb} +4 -4
  29. data/solara/lib/core/dashboard/handler/brands_handler.rb +1 -1
  30. data/solara/lib/core/dashboard/handler/edit_section_handler.rb +8 -8
  31. data/solara/lib/core/doctor/brand_doctor.rb +31 -31
  32. data/solara/lib/core/doctor/doctor_manager.rb +0 -1
  33. data/solara/lib/core/doctor/project_doctor.rb +0 -1
  34. data/solara/lib/core/doctor/schema/platform/android/android_config.json +0 -4
  35. data/solara/lib/core/doctor/schema/platform/ios/InfoPlist.xcstrings +15 -0
  36. data/solara/lib/core/doctor/schema/platform/ios/ios_config.json +0 -5
  37. data/solara/lib/core/doctor/schema/platform/shared/brand_config.json +9 -0
  38. data/solara/lib/core/doctor/schema/platform/shared/theme.json +94 -9
  39. data/solara/lib/core/doctor/validator/brand_settings_validator.rb +6 -0
  40. data/solara/lib/core/doctor/validator/brand_settings_validator_manager.rb +9 -21
  41. data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +22 -4
  42. data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +22 -6
  43. data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +22 -4
  44. data/solara/lib/core/scripts/brand_config_generator.rb +1 -0
  45. data/solara/lib/core/scripts/brand_config_manager.rb +2 -4
  46. data/solara/lib/core/scripts/brand_exporter.rb +1 -1
  47. data/solara/lib/core/scripts/brand_importer.rb +2 -3
  48. data/solara/lib/core/scripts/brand_offboarder.rb +5 -0
  49. data/solara/lib/core/scripts/brand_resources_manager.rb +127 -54
  50. data/solara/lib/core/scripts/directory_creator.rb +2 -2
  51. data/solara/lib/core/scripts/file_manager.rb +53 -19
  52. data/solara/lib/core/scripts/file_path.rb +175 -30
  53. data/solara/lib/core/scripts/folder_copier.rb +3 -7
  54. data/solara/lib/core/scripts/gitignore_manager.rb +21 -10
  55. data/solara/lib/core/scripts/interactive_file_system_validator.rb +8 -2
  56. data/solara/lib/core/scripts/platform/android/android_manifest_switcher.rb +3 -3
  57. data/solara/lib/core/scripts/platform/android/android_strings_switcher.rb +26 -24
  58. data/solara/lib/core/scripts/platform/android/gradle_switcher.rb +7 -6
  59. data/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb +123 -0
  60. data/solara/lib/core/scripts/platform/ios/infoplist_switcher.rb +59 -0
  61. data/solara/lib/core/scripts/platform/ios/ios_plist_manager.rb +11 -20
  62. data/solara/lib/core/scripts/platform/ios/plist_font_manager.rb +33 -0
  63. data/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb +15 -3
  64. data/solara/lib/core/scripts/platform/ios/xcode_asset_manager.rb +2 -3
  65. data/solara/lib/core/scripts/platform/ios/xcode_project_manager.rb +80 -1
  66. data/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb +15 -34
  67. data/solara/lib/core/scripts/solara_logger.rb +10 -0
  68. data/solara/lib/core/scripts/solara_settings_manager.rb +26 -1
  69. data/solara/lib/core/scripts/strings_xml_manager.rb +17 -2
  70. data/solara/lib/core/scripts/theme_generator.rb +133 -130
  71. data/solara/lib/core/scripts/yaml_manager.rb +23 -0
  72. data/solara/lib/core/solara_configurator.rb +1 -1
  73. data/solara/lib/core/template/brands/android/android_config.json +0 -1
  74. data/solara/lib/core/template/brands/android/res/values/strings.xml +4 -0
  75. data/solara/lib/core/template/brands/ios/InfoPlist.xcstrings +30 -0
  76. data/solara/lib/core/template/brands/ios/ios_config.json +1 -2
  77. data/solara/lib/core/template/brands/shared/brand_config.json +1 -0
  78. data/solara/lib/core/template/brands/shared/theme.json +3 -3
  79. data/solara/lib/core/template/config/android_template_config.json +11 -1
  80. data/solara/lib/core/template/config/flutter_template_config.json +12 -2
  81. data/solara/lib/core/template/config/ios_template_config.json +11 -1
  82. data/solara/lib/core/template/project_template_generator.rb +8 -3
  83. data/solara/lib/solara/version.rb +1 -1
  84. data/solara/lib/solara.rb +8 -4
  85. data/solara/lib/solara_initializer.rb +5 -2
  86. data/solara/lib/solara_manager.rb +1 -1
  87. metadata +63 -44
  88. data/solara/lib/core/dashboard/handler/brand_section_handler.rb +0 -20
  89. data/solara/lib/core/doctor/validator/directory_structure_validator.rb +0 -38
  90. data/solara/lib/core/doctor/validator/file_structure_validator.rb +0 -37
  91. data/solara/lib/core/scripts/platform/ios/ios_file_path_manager.rb +0 -109
  92. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/.DS_Store +0 -0
  93. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/100.png +0 -0
  94. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/102.png +0 -0
  95. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/1024.png +0 -0
  96. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/114.png +0 -0
  97. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/120.png +0 -0
  98. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/128.png +0 -0
  99. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/144.png +0 -0
  100. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/152.png +0 -0
  101. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/16.png +0 -0
  102. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/167.png +0 -0
  103. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/172.png +0 -0
  104. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/180.png +0 -0
  105. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/196.png +0 -0
  106. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/20.png +0 -0
  107. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/216.png +0 -0
  108. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/256.png +0 -0
  109. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/29.png +0 -0
  110. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/32.png +0 -0
  111. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/40.png +0 -0
  112. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/48.png +0 -0
  113. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/50.png +0 -0
  114. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/512.png +0 -0
  115. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/55.png +0 -0
  116. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/57.png +0 -0
  117. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/58.png +0 -0
  118. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/60.png +0 -0
  119. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/64.png +0 -0
  120. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/66.png +0 -0
  121. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/72.png +0 -0
  122. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/76.png +0 -0
  123. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/80.png +0 -0
  124. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/87.png +0 -0
  125. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/88.png +0 -0
  126. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/92.png +0 -0
  127. /data/solara/lib/core/template/brands/ios/{assets → xcassets}/AppIcon.appiconset/Contents.json +0 -0
@@ -1,77 +1,65 @@
1
1
  require 'json'
2
2
  require 'fileutils'
3
3
 
4
- class ThemeGenerator
5
- def initialize(input_path, output_path, language)
6
- @theme = JSON.parse(File.read(input_path))
7
- @output_path = output_path
8
- @language = language.downcase
4
+ class ThemeGeneratorManager
5
+ def initialize(input_path)
6
+ @input_path = input_path
7
+ end
9
8
 
10
- unless %w[kotlin swift dart].include?(@language)
11
- raise ArgumentError, "Unsupported language. Choose 'kotlin', 'swift', or 'dart'."
9
+ def generate(language, output_path)
10
+ case language.downcase
11
+ when 'kotlin'
12
+ generator = KotlinThemeGenerator.new(@input_path, output_path)
13
+ when 'swift'
14
+ generator = SwiftThemeGenerator.new(@input_path, output_path)
15
+ when 'dart'
16
+ generator = DartThemeGenerator.new(@input_path, output_path)
17
+ else
18
+ Solara.logger.fatal("Unsupported language: #{language}")
19
+ return
12
20
  end
13
- end
14
21
 
15
- def generate
16
- code = send("generate_#{@language}")
17
- write_to_file(code)
22
+ generator.generate
18
23
  end
24
+ end
19
25
 
20
- private
21
-
22
- def generate_kotlin
23
- kotlin_code = "import androidx.compose.ui.graphics.Color\n"
24
- kotlin_code += "import androidx.compose.ui.unit.dp\n"
25
- kotlin_code += "import androidx.compose.ui.unit.sp\n\n"
26
- kotlin_code += "object #{@theme['name']} {\n"
27
- kotlin_code += generate_kotlin_colors
28
- kotlin_code += generate_kotlin_typography
29
- kotlin_code += generate_kotlin_spacing
30
- kotlin_code += generate_kotlin_border_radius
31
- kotlin_code += generate_kotlin_elevation
32
- kotlin_code += "}"
33
- kotlin_code
34
- end
35
-
36
- def generate_swift
37
- swift_code = "import SwiftUI\n\n"
38
- swift_code += "struct #{@theme['name']} {\n"
39
- swift_code += generate_swift_colors
40
- swift_code += generate_swift_typography
41
- swift_code += generate_swift_spacing
42
- swift_code += generate_swift_border_radius
43
- swift_code += generate_swift_elevation
44
- swift_code += "}\n\n"
45
- swift_code += generate_swift_colors_hext_extension
46
- swift_code
47
- end
48
-
49
- def generate_dart
50
- dart_code = "import 'package:flutter/material.dart';\n\n"
51
- dart_code += generate_dart_colors
52
- dart_code += generate_dart_typography
53
- dart_code += generate_dart_spacing
54
- dart_code += generate_dart_border_radius
55
- dart_code += generate_dart_elevation
56
- dart_code
26
+ class ThemeGenerator
27
+ def initialize(input_path, output_path)
28
+ @theme = JSON.parse(File.read(input_path))
29
+ @output_path = output_path
57
30
  end
58
31
 
59
32
  def write_to_file(code)
60
33
  FileUtils.mkdir_p(File.dirname(@output_path))
61
34
  File.write(@output_path, code)
62
- Solara.logger.debug("Generated #{@language.capitalize} theme file: #{@output_path}")
35
+ Solara.logger.debug("Generated theme file: #{@output_path}")
36
+ end
37
+ end
38
+
39
+ class KotlinThemeGenerator < ThemeGenerator
40
+ def generate
41
+ code = "import android.graphics.Color\n\n"
42
+ code += "object BrandTheme {\n"
43
+ code += generate_colors
44
+ code += generate_typography
45
+ code += generate_spacing
46
+ code += generate_border_radius
47
+ code += generate_elevation
48
+ code += "}"
49
+ write_to_file(code)
63
50
  end
64
51
 
65
- def generate_kotlin_colors
52
+ private
53
+
54
+ def generate_colors
66
55
  code = " object Colors {\n"
67
56
  @theme['colors'].each do |name, value|
68
- code += " val #{name} = Color(0xFF#{value[1..-1]})\n"
57
+ code += " val #{name} = Color.parseColor(\"#{value}\")\n"
69
58
  end
70
- code += " }\n\n"
71
- code
59
+ code + " }\n\n"
72
60
  end
73
61
 
74
- def generate_kotlin_typography
62
+ def generate_typography
75
63
  code = " object Typography {\n"
76
64
  code += " object FontFamily {\n"
77
65
  @theme['typography']['fontFamily'].each do |name, value|
@@ -80,82 +68,92 @@ class ThemeGenerator
80
68
  code += " }\n\n"
81
69
  code += " object FontSize {\n"
82
70
  @theme['typography']['fontSize'].each do |name, value|
83
- code += " val #{name} = #{value}.sp\n"
71
+ code += " val #{name} = #{value}\n"
84
72
  end
85
73
  code += " }\n"
86
- code += " }\n\n"
87
- code
74
+ code + " }\n\n"
88
75
  end
89
76
 
90
- def generate_kotlin_spacing
77
+ def generate_spacing
91
78
  code = " object Spacing {\n"
92
79
  @theme['spacing'].each do |name, value|
93
- code += " val #{name} = #{value}.dp\n"
80
+ code += " val #{name} = #{value}\n"
94
81
  end
95
- code += " }\n\n"
96
- code
82
+ code + " }\n\n"
97
83
  end
98
84
 
99
- def generate_kotlin_border_radius
85
+ def generate_border_radius
100
86
  code = " object BorderRadius {\n"
101
87
  @theme['borderRadius'].each do |name, value|
102
- code += " val #{name} = #{value}.dp\n"
88
+ code += " val #{name} = #{value}\n"
103
89
  end
104
- code += " }\n\n"
105
- code
90
+ code + " }\n\n"
106
91
  end
107
92
 
108
- def generate_kotlin_elevation
93
+ def generate_elevation
109
94
  code = " object Elevation {\n"
110
95
  @theme['elevation'].each do |name, value|
111
- code += " val #{name} = #{value}.dp\n"
96
+ code += " val #{name} = #{value}\n"
112
97
  end
113
- code += " }\n"
114
- code
98
+ code + " }\n"
99
+ end
100
+ end
101
+
102
+ class SwiftThemeGenerator < ThemeGenerator
103
+ def generate
104
+ code = "import UIKit\n\n"
105
+ code += "struct BrandTheme {\n"
106
+ code += generate_colors
107
+ code += generate_typography
108
+ code += generate_spacing
109
+ code += generate_border_radius
110
+ code += generate_elevation
111
+ code += "}\n\n"
112
+ code += generate_colors_hex_extension
113
+ write_to_file(code)
115
114
  end
116
115
 
117
- def generate_swift_colors
116
+ private
117
+
118
+ def generate_colors
118
119
  code = " struct Colors {\n"
119
120
  @theme['colors'].each do |name, value|
120
- code += " static let #{name} = Color(hex: \"#{value}\")\n"
121
- end
122
- code += " }\n\n"
123
- code
124
- end
125
-
126
- def generate_swift_colors_hext_extension
127
- code = <<-SWIFT
128
- extension Color {
129
- init(hex: String) {
130
- let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
131
- var int: UInt64 = 0
132
- Scanner(string: hex).scanHexInt64(&int)
133
- let a, r, g, b: UInt64
134
- switch hex.count {
135
- case 3: // RGB (12-bit)
136
- (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
137
- case 6: // RGB (24-bit)
138
- (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
139
- case 8: // ARGB (32-bit)
140
- (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
141
- default:
142
- (a, r, g, b) = (1, 1, 1, 0)
143
- }
144
-
145
- self.init(
146
- .sRGB,
147
- red: Double(r) / 255,
148
- green: Double(g) / 255,
149
- blue: Double(b) / 255,
150
- opacity: Double(a) / 255
151
- )
152
- }
121
+ code += " static let #{name} = UIColor(hex: \"#{value}\")\n"
122
+ end
123
+ code + " }\n\n"
124
+ end
125
+
126
+ def generate_colors_hex_extension
127
+ <<-SWIFT
128
+ extension UIColor {
129
+ convenience init(hex: String) {
130
+ let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
131
+ var int: UInt64 = 0
132
+ Scanner(string: hex).scanHexInt64(&int)
133
+ let a, r, g, b: UInt64
134
+ switch hex.count {
135
+ case 3: // RGB (12-bit)
136
+ (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
137
+ case 6: // RGB (24-bit)
138
+ (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
139
+ case 8: // ARGB (32-bit)
140
+ (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
141
+ default:
142
+ (a, r, g, b) = (255, 255, 255, 0)
143
+ }
144
+
145
+ self.init(
146
+ red: CGFloat(r) / 255,
147
+ green: CGFloat(g) / 255,
148
+ blue: CGFloat(b) / 255,
149
+ alpha: CGFloat(a) / 255
150
+ )
151
+ }
153
152
  }
154
153
  SWIFT
155
- code
156
154
  end
157
155
 
158
- def generate_swift_typography
156
+ def generate_typography
159
157
  code = " struct Typography {\n"
160
158
  code += " struct FontFamily {\n"
161
159
  @theme['typography']['fontFamily'].each do |name, value|
@@ -167,47 +165,56 @@ extension Color {
167
165
  code += " static let #{name}: CGFloat = #{value}\n"
168
166
  end
169
167
  code += " }\n"
170
- code += " }\n\n"
171
- code
168
+ code + " }\n\n"
172
169
  end
173
170
 
174
- def generate_swift_spacing
171
+ def generate_spacing
175
172
  code = " struct Spacing {\n"
176
173
  @theme['spacing'].each do |name, value|
177
174
  code += " static let #{name}: CGFloat = #{value}\n"
178
175
  end
179
- code += " }\n\n"
180
- code
176
+ code + " }\n\n"
181
177
  end
182
178
 
183
- def generate_swift_border_radius
179
+ def generate_border_radius
184
180
  code = " struct BorderRadius {\n"
185
181
  @theme['borderRadius'].each do |name, value|
186
182
  code += " static let #{name}: CGFloat = #{value}\n"
187
183
  end
188
- code += " }\n\n"
189
- code
184
+ code + " }\n\n"
190
185
  end
191
186
 
192
- def generate_swift_elevation
187
+ def generate_elevation
193
188
  code = " struct Elevation {\n"
194
189
  @theme['elevation'].each do |name, value|
195
190
  code += " static let #{name}: CGFloat = #{value}\n"
196
191
  end
197
- code += " }\n"
198
- code
192
+ code + " }\n"
193
+ end
194
+ end
195
+
196
+ class DartThemeGenerator < ThemeGenerator
197
+ def generate
198
+ code = "import 'package:flutter/material.dart';\n\n"
199
+ code += generate_colors
200
+ code += generate_typography
201
+ code += generate_spacing
202
+ code += generate_border_radius
203
+ code += generate_elevation
204
+ write_to_file(code)
199
205
  end
200
206
 
201
- def generate_dart_colors
207
+ private
208
+
209
+ def generate_colors
202
210
  code = " class BrandColors {\n"
203
211
  @theme['colors'].each do |name, value|
204
212
  code += " static const Color #{name} = Color(0xFF#{value[1..-1]});\n"
205
213
  end
206
- code += " }\n\n"
207
- code
214
+ code + " }\n\n"
208
215
  end
209
216
 
210
- def generate_dart_typography
217
+ def generate_typography
211
218
  code = " class FontFamily {\n"
212
219
  @theme['typography']['fontFamily'].each do |name, value|
213
220
  code += " static const String #{name} = '#{value}';\n"
@@ -217,34 +224,30 @@ extension Color {
217
224
  @theme['typography']['fontSize'].each do |name, value|
218
225
  code += " static const double #{name} = #{value};\n"
219
226
  end
220
- code += " }\n\n"
221
- code
227
+ code + " }\n\n"
222
228
  end
223
229
 
224
- def generate_dart_spacing
230
+ def generate_spacing
225
231
  code = " class Spacing {\n"
226
232
  @theme['spacing'].each do |name, value|
227
233
  code += " static const double #{name} = #{value};\n"
228
234
  end
229
- code += " }\n\n"
230
- code
235
+ code + " }\n\n"
231
236
  end
232
237
 
233
- def generate_dart_border_radius
238
+ def generate_border_radius
234
239
  code = " class BorderRadius {\n"
235
240
  @theme['borderRadius'].each do |name, value|
236
241
  code += " static const double #{name} = #{value};\n"
237
242
  end
238
243
  code += " }\n\n"
239
- code
240
244
  end
241
245
 
242
- def generate_dart_elevation
246
+ def generate_elevation
243
247
  code = " class Elevation {\n"
244
248
  @theme['elevation'].each do |name, value|
245
249
  code += " static const double #{name} = #{value};\n"
246
250
  end
247
- code += " }\n"
248
- code
251
+ code + " }\n"
249
252
  end
250
253
  end
@@ -6,6 +6,29 @@ class YamlManager
6
6
  @file_path = file_path
7
7
  end
8
8
 
9
+ def add_font(family, assets)
10
+ yaml_data = load_yaml
11
+
12
+ # Ensure the 'flutter' key exists
13
+ yaml_data['flutter'] ||= {}
14
+ yaml_data['flutter']['fonts'] ||= []
15
+
16
+ # Check if the font family already exists
17
+ existing_font = yaml_data['flutter']['fonts'].find { |f| f['family'] == family }
18
+
19
+ if existing_font
20
+ Solara.logger.debug("YamlManager: Font family '#{family}' already exists.")
21
+ # Update existing font assets
22
+ existing_font['fonts'] = assets
23
+ else
24
+ # Add new font family
25
+ yaml_data['flutter']['fonts'] << { 'family' => family, 'fonts' => assets }
26
+ Solara.logger.debug("YamlManager: Font family '#{family}' has been added.")
27
+ end
28
+
29
+ save_yaml(yaml_data)
30
+ end
31
+
9
32
  def add_property(property_name, property_value)
10
33
  yaml_data = load_yaml
11
34
 
@@ -7,7 +7,7 @@ class SolaraConfigurator
7
7
  end
8
8
 
9
9
  def start
10
- GitignoreManager.ignore_redundant_files
10
+ GitignoreManager.ignore
11
11
  AliasGeneratorManager.new.start
12
12
  end
13
13
 
@@ -1,5 +1,4 @@
1
1
  {
2
- "brandName": "",
3
2
  "applicationId": "",
4
3
  "versionName": "1.0.0",
5
4
  "versionCode": 1,
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <string name="app_name"></string>
4
+ </resources>
@@ -0,0 +1,30 @@
1
+ {
2
+ "sourceLanguage": "en",
3
+ "strings": {
4
+ "CFBundleDisplayName": {
5
+ "comment": "Bundle display name",
6
+ "extractionState": "extracted_with_value",
7
+ "localizations": {
8
+ "en": {
9
+ "stringUnit": {
10
+ "state": "new",
11
+ "value": ""
12
+ }
13
+ }
14
+ }
15
+ },
16
+ "CFBundleName": {
17
+ "comment": "Bundle name",
18
+ "extractionState": "extracted_with_value",
19
+ "localizations": {
20
+ "en": {
21
+ "stringUnit": {
22
+ "state": "new",
23
+ "value": ""
24
+ }
25
+ }
26
+ }
27
+ }
28
+ },
29
+ "version": "1.0"
30
+ }
@@ -1,7 +1,6 @@
1
1
  {
2
- "PRODUCT_NAME": "",
3
2
  "PRODUCT_BUNDLE_IDENTIFIER": "",
4
3
  "MARKETING_VERSION": "1.0.0",
5
- "BUNDLE_VERSION": "1",
4
+ "BUNDLE_VERSION": 1,
6
5
  "APL_MRCH_ID": ""
7
6
  }
@@ -1,2 +1,3 @@
1
1
  {
2
+ "brandName": ""
2
3
  }
@@ -15,9 +15,9 @@
15
15
  },
16
16
  "typography": {
17
17
  "fontFamily": {
18
- "regular": "Roboto",
19
- "medium": "Roboto-Medium",
20
- "bold": "Roboto-Bold"
18
+ "regular": "",
19
+ "medium": "",
20
+ "bold": ""
21
21
  },
22
22
  "fontSize": {
23
23
  "small": 12,
@@ -25,10 +25,20 @@
25
25
  "target": "android/android_signing.json",
26
26
  "condition": "true"
27
27
  },
28
+ {
29
+ "source": "ios/xcassets/",
30
+ "target": "ios/xcassets/",
31
+ "condition": "true"
32
+ },
28
33
  {
29
34
  "source": "ios/assets/",
30
35
  "target": "ios/assets/",
31
- "condition": "true"
36
+ "condition": "true"
37
+ },
38
+ {
39
+ "source": "ios/InfoPlist.xcstrings",
40
+ "target": "ios/InfoPlist.xcstrings",
41
+ "condition": "true"
32
42
  },
33
43
  {
34
44
  "source": "ios/ios_config.json",
@@ -25,11 +25,21 @@
25
25
  "target": "android/android_signing.json",
26
26
  "condition": "true"
27
27
  },
28
+ {
29
+ "source": "ios/xcassets/",
30
+ "target": "ios/xcassets/",
31
+ "condition": "true"
32
+ },
28
33
  {
29
34
  "source": "ios/assets/",
30
35
  "target": "ios/assets/",
31
36
  "condition": "true"
32
37
  },
38
+ {
39
+ "source": "ios/InfoPlist.xcstrings",
40
+ "target": "ios/InfoPlist.xcstrings",
41
+ "condition": "true"
42
+ },
33
43
  {
34
44
  "source": "ios/ios_config.json",
35
45
  "target": "ios/ios_config.json",
@@ -41,8 +51,8 @@
41
51
  "condition": "true"
42
52
  },
43
53
  {
44
- "source": "shared/assets/",
45
- "target": "shared/assets/",
54
+ "source": "flutter/assets/",
55
+ "target": "flutter/assets/",
46
56
  "condition": "true"
47
57
  },
48
58
  {
@@ -25,15 +25,25 @@
25
25
  "target": "android/android_signing.json",
26
26
  "condition": "true"
27
27
  },
28
+ {
29
+ "source": "ios/xcassets/",
30
+ "target": "ios/xcassets/",
31
+ "condition": "true"
32
+ },
28
33
  {
29
34
  "source": "ios/assets/",
30
35
  "target": "ios/assets/",
31
36
  "condition": "true"
32
37
  },
38
+ {
39
+ "source": "ios/InfoPlist.xcstrings",
40
+ "target": "ios/InfoPlist.xcstrings",
41
+ "condition": "true"
42
+ },
33
43
  {
34
44
  "source": "ios/ios_config.json",
35
45
  "target": "ios/ios_config.json",
36
- "condition": "true"
46
+ "condition": "true"
37
47
  },
38
48
  {
39
49
  "source": "ios/ios_signing.json",
@@ -15,9 +15,14 @@ class ProjectTemplateGenerator
15
15
  source_path = File.join(@template_dir, file["source"])
16
16
  target_path = File.join(@target_dir, file["target"])
17
17
 
18
- copy_content = file.fetch("copy_content", true)
19
- copy_item(source_path, target_path, copy_content)
20
- replace_variables(target_path, @config["variables"]) if copy_content
18
+ if file["source"].nil? || file["source"].empty? || !File.exist?(source_path)
19
+ # Create the target directory if no source path is provided
20
+ FileUtils.mkdir_p(target_path)
21
+ else
22
+ copy_content = file.fetch("copy_content", true)
23
+ copy_item(source_path, target_path, copy_content)
24
+ replace_variables(target_path, @config["variables"]) if copy_content
25
+ end
21
26
  end
22
27
  end
23
28
  end
@@ -1,3 +1,3 @@
1
1
  module Solara
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.1"
3
3
  end
data/solara/lib/solara.rb CHANGED
@@ -54,6 +54,10 @@ module Solara
54
54
  brand_name = options['brand_name']
55
55
  input_platform = options['platform']
56
56
 
57
+ if !brand_key || !brand_name
58
+ Solara.logger.warn('To set up Solara, we need to onboard an initial brand. Please provide the following details for your first brand:')
59
+ end
60
+
57
61
  brand_key = validate_brand_key(brand_key, ignore_brand_check: true)
58
62
  brand_name = validate_brand_name(brand_name)
59
63
 
@@ -66,7 +70,7 @@ module Solara
66
70
  platform = platform.to_s.downcase
67
71
 
68
72
  SolaraSettingsManager.instance.platform = platform
69
- SolaraManager.new.init(platform, brand_key, brand_name)
73
+ SolaraManager.new.init(brand_key, brand_name)
70
74
  end
71
75
 
72
76
  desc "status", "Check the current status of Solara. The results may include information about the brand's current standing, the list of brands, and additional details."
@@ -142,7 +146,7 @@ module Solara
142
146
  brand_key = validate_brand_key(brand_key)
143
147
  begin
144
148
  SolaraManager.new.switch(brand_key)
145
- rescue StandardError => e
149
+ rescue Issue => e
146
150
  Solara.logger.fatal("Switching to #{brand_key} failed.")
147
151
  exit 1
148
152
  end
@@ -192,7 +196,7 @@ module Solara
192
196
  return brand_key
193
197
  end
194
198
 
195
- if brand_key.nil? || brand_key.empty? || (!ignore_brand_check && BrandsManager.instance.find(brand_key).nil?)
199
+ if brand_key.nil? || brand_key.empty? || (!ignore_brand_check && !BrandsManager.instance.exists(brand_key))
196
200
  message = message || (brand_key.nil? || brand_key.empty? ? "Please enter brand key: " : "Please enter existing brand key: ")
197
201
  brand_key = TerminalInputManager.new.get_validated(message) do |input|
198
202
  # Validate that it starts with a letter and contains no spaces
@@ -202,7 +206,7 @@ module Solara
202
206
  end
203
207
 
204
208
  # Check if the brand exists in the list
205
- if !ignore_brand_check && BrandsManager.instance.find(input).nil?
209
+ if !ignore_brand_check && !BrandsManager.instance.exists(input)
206
210
  Solara.logger.failure("Brand key does not exist.")
207
211
  next false # Use `next` to continue the loop
208
212
  end
@@ -20,12 +20,15 @@ class SolaraInitializer
20
20
  def init
21
21
  Solara.logger.header("Initializing Solara")
22
22
  confirm_init_if_necessary
23
+
24
+ ProjectDoctor.new.visit
25
+
23
26
  message = "Initialized #{SolaraSettingsManager.instance.platform} successfully."
24
27
  SolaraManager.new.onboard(@brand_key, @brand_name, init: true, success_message: message)
25
28
  end
26
29
 
27
30
  def confirm_init_if_necessary
28
- brand_path = File.join(FilePath.solara, 'brands')
31
+ brand_path = FilePath.brands
29
32
  # Check if Solara path exists
30
33
  if Dir.exist?(brand_path)
31
34
  Solara.logger.warn("Solara already initialized! Be aware that reinitializing will delete all current brands!")
@@ -37,7 +40,7 @@ class SolaraInitializer
37
40
  Solara.logger.info("Solara initialization cancelled.")
38
41
  exit 1
39
42
  end
40
- FileUtils.rm_rf(brand_path)
43
+ FileManager.delete_if_exists(brand_path)
41
44
  end
42
45
  end
43
46