@rentlydev/rently-tuya 0.1.0

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 (288) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +281 -0
  3. package/android/build.gradle +182 -0
  4. package/android/gradle.properties +7 -0
  5. package/android/libs/airbrake-android-1.4.0.jar +0 -0
  6. package/android/src/main/AndroidManifest.xml +1 -0
  7. package/android/src/main/AndroidManifestNew.xml +25 -0
  8. package/android/src/main/java/com/rentlytuya/RentlyTuyaModule.kt +503 -0
  9. package/android/src/main/java/com/rentlytuya/RentlyTuyaPackage.kt +18 -0
  10. package/android/src/main/java/com/rentlytuya/TuyaActivity.kt +45 -0
  11. package/android/src/main/java/com/rentlytuya/alerts/FormatSDCardAlert.kt +83 -0
  12. package/android/src/main/java/com/rentlytuya/alerts/PermissionAlert.kt +91 -0
  13. package/android/src/main/java/com/rentlytuya/alerts/RemoveDoorbellAlert.kt +83 -0
  14. package/android/src/main/java/com/rentlytuya/alerts/RemoveDoorbellFailureAlert.kt +71 -0
  15. package/android/src/main/java/com/rentlytuya/alerts/ResetWifiAlert.kt +83 -0
  16. package/android/src/main/java/com/rentlytuya/alerts/SuccessAlert.kt +74 -0
  17. package/android/src/main/java/com/rentlytuya/components/Alert.kt +47 -0
  18. package/android/src/main/java/com/rentlytuya/components/AnchorButton.kt +125 -0
  19. package/android/src/main/java/com/rentlytuya/components/Button.kt +147 -0
  20. package/android/src/main/java/com/rentlytuya/components/CustomDatePicker.kt +275 -0
  21. package/android/src/main/java/com/rentlytuya/components/Divider.kt +53 -0
  22. package/android/src/main/java/com/rentlytuya/components/EncryptedImageView.kt +59 -0
  23. package/android/src/main/java/com/rentlytuya/components/Label.kt +155 -0
  24. package/android/src/main/java/com/rentlytuya/components/LoadingIndicator.kt +75 -0
  25. package/android/src/main/java/com/rentlytuya/components/Slider.kt +66 -0
  26. package/android/src/main/java/com/rentlytuya/components/Switch.kt +51 -0
  27. package/android/src/main/java/com/rentlytuya/components/VideoView.kt +45 -0
  28. package/android/src/main/java/com/rentlytuya/dashboard/AdvancedSettings.kt +259 -0
  29. package/android/src/main/java/com/rentlytuya/dashboard/Dashboard.kt +551 -0
  30. package/android/src/main/java/com/rentlytuya/dashboard/DoorbellSettings.kt +874 -0
  31. package/android/src/main/java/com/rentlytuya/dashboard/Messages.kt +463 -0
  32. package/android/src/main/java/com/rentlytuya/dashboard/NavController.kt +358 -0
  33. package/android/src/main/java/com/rentlytuya/dashboard/OfflineScreen.kt +160 -0
  34. package/android/src/main/java/com/rentlytuya/dashboard/Playback.kt +685 -0
  35. package/android/src/main/java/com/rentlytuya/tuya/Messages.kt +234 -0
  36. package/android/src/main/java/com/rentlytuya/tuya/Playback.kt +385 -0
  37. package/android/src/main/java/com/rentlytuya/tuya/ScreenCapture.kt +244 -0
  38. package/android/src/main/java/com/rentlytuya/tuya/Settings.kt +809 -0
  39. package/android/src/main/java/com/rentlytuya/tuya/Tuya.kt +497 -0
  40. package/android/src/main/java/com/rentlytuya/ui/theme/LocalColor.kt +80 -0
  41. package/android/src/main/java/com/rentlytuya/ui/theme/LocalFont.kt +35 -0
  42. package/android/src/main/java/com/rentlytuya/ui/theme/Theme.kt +34 -0
  43. package/android/src/main/java/com/rentlytuya/ui/theme/Type.kt +34 -0
  44. package/android/src/main/java/com/rentlytuya/util/Airbrake.kt +40 -0
  45. package/android/src/main/java/com/rentlytuya/util/DpConstants.kt +53 -0
  46. package/android/src/main/java/com/rentlytuya/util/FrescoManager.kt +86 -0
  47. package/android/src/main/java/com/rentlytuya/util/HeapAnalytics.kt +16 -0
  48. package/android/src/main/java/com/rentlytuya/util/KeylessModule.kt +81 -0
  49. package/android/src/main/java/com/rentlytuya/util/PermissionHandler.kt +75 -0
  50. package/android/src/main/java/com/rentlytuya/util/ReactParamsCheck.kt +152 -0
  51. package/android/src/main/java/com/rentlytuya/util/Util.kt +128 -0
  52. package/android/src/main/res/drawable/ic_close.xml +12 -0
  53. package/android/src/main/res/drawable/ic_launcher_background.xml +170 -0
  54. package/android/src/main/res/drawable/ic_launcher_foreground.xml +30 -0
  55. package/android/src/main/res/drawable/img_place_holder.png +0 -0
  56. package/android/src/main/res/drawable-hdpi/ic_action_arrow_backward.png +0 -0
  57. package/android/src/main/res/drawable-hdpi/ic_arrow_backward_white.png +0 -0
  58. package/android/src/main/res/drawable-hdpi/ic_arrow_blue_right.png +0 -0
  59. package/android/src/main/res/drawable-hdpi/ic_calendar.png +0 -0
  60. package/android/src/main/res/drawable-hdpi/ic_camera.png +0 -0
  61. package/android/src/main/res/drawable-hdpi/ic_message.png +0 -0
  62. package/android/src/main/res/drawable-hdpi/ic_pause.png +0 -0
  63. package/android/src/main/res/drawable-hdpi/ic_play.png +0 -0
  64. package/android/src/main/res/drawable-hdpi/ic_play_back.png +0 -0
  65. package/android/src/main/res/drawable-hdpi/ic_record.png +0 -0
  66. package/android/src/main/res/drawable-hdpi/ic_retry.png +0 -0
  67. package/android/src/main/res/drawable-hdpi/ic_setting.png +0 -0
  68. package/android/src/main/res/drawable-hdpi/ic_sound_off.png +0 -0
  69. package/android/src/main/res/drawable-hdpi/ic_sound_on.png +0 -0
  70. package/android/src/main/res/drawable-mdpi/ic_action_arrow_backward.png +0 -0
  71. package/android/src/main/res/drawable-mdpi/ic_arrow_backward_white.png +0 -0
  72. package/android/src/main/res/drawable-mdpi/ic_arrow_blue_right.png +0 -0
  73. package/android/src/main/res/drawable-mdpi/ic_battery_average.png +0 -0
  74. package/android/src/main/res/drawable-mdpi/ic_battery_charging.png +0 -0
  75. package/android/src/main/res/drawable-mdpi/ic_battery_full.png +0 -0
  76. package/android/src/main/res/drawable-mdpi/ic_battery_good.png +0 -0
  77. package/android/src/main/res/drawable-mdpi/ic_battery_low.png +0 -0
  78. package/android/src/main/res/drawable-mdpi/ic_calendar.png +0 -0
  79. package/android/src/main/res/drawable-mdpi/ic_camera.png +0 -0
  80. package/android/src/main/res/drawable-mdpi/ic_message.png +0 -0
  81. package/android/src/main/res/drawable-mdpi/ic_pause.png +0 -0
  82. package/android/src/main/res/drawable-mdpi/ic_play.png +0 -0
  83. package/android/src/main/res/drawable-mdpi/ic_play_back.png +0 -0
  84. package/android/src/main/res/drawable-mdpi/ic_record.png +0 -0
  85. package/android/src/main/res/drawable-mdpi/ic_retry.png +0 -0
  86. package/android/src/main/res/drawable-mdpi/ic_setting.png +0 -0
  87. package/android/src/main/res/drawable-mdpi/ic_sound_off.png +0 -0
  88. package/android/src/main/res/drawable-mdpi/ic_sound_on.png +0 -0
  89. package/android/src/main/res/drawable-xhdpi/ic_action_arrow_backward.png +0 -0
  90. package/android/src/main/res/drawable-xhdpi/ic_arrow_backward_white.png +0 -0
  91. package/android/src/main/res/drawable-xhdpi/ic_arrow_blue_right.png +0 -0
  92. package/android/src/main/res/drawable-xhdpi/ic_battery_average.png +0 -0
  93. package/android/src/main/res/drawable-xhdpi/ic_battery_charging.png +0 -0
  94. package/android/src/main/res/drawable-xhdpi/ic_battery_full.png +0 -0
  95. package/android/src/main/res/drawable-xhdpi/ic_battery_good.png +0 -0
  96. package/android/src/main/res/drawable-xhdpi/ic_battery_low.png +0 -0
  97. package/android/src/main/res/drawable-xhdpi/ic_calendar.png +0 -0
  98. package/android/src/main/res/drawable-xhdpi/ic_camera.png +0 -0
  99. package/android/src/main/res/drawable-xhdpi/ic_message.png +0 -0
  100. package/android/src/main/res/drawable-xhdpi/ic_pause.png +0 -0
  101. package/android/src/main/res/drawable-xhdpi/ic_play.png +0 -0
  102. package/android/src/main/res/drawable-xhdpi/ic_play_back.png +0 -0
  103. package/android/src/main/res/drawable-xhdpi/ic_record.png +0 -0
  104. package/android/src/main/res/drawable-xhdpi/ic_retry.png +0 -0
  105. package/android/src/main/res/drawable-xhdpi/ic_setting.png +0 -0
  106. package/android/src/main/res/drawable-xhdpi/ic_sound_off.png +0 -0
  107. package/android/src/main/res/drawable-xhdpi/ic_sound_on.png +0 -0
  108. package/android/src/main/res/drawable-xxhdpi/ic_action_arrow_backward.png +0 -0
  109. package/android/src/main/res/drawable-xxhdpi/ic_arrow_backward_white.png +0 -0
  110. package/android/src/main/res/drawable-xxhdpi/ic_arrow_blue_right.png +0 -0
  111. package/android/src/main/res/drawable-xxhdpi/ic_battery_average.png +0 -0
  112. package/android/src/main/res/drawable-xxhdpi/ic_battery_charging.png +0 -0
  113. package/android/src/main/res/drawable-xxhdpi/ic_battery_full.png +0 -0
  114. package/android/src/main/res/drawable-xxhdpi/ic_battery_good.png +0 -0
  115. package/android/src/main/res/drawable-xxhdpi/ic_battery_low.png +0 -0
  116. package/android/src/main/res/drawable-xxhdpi/ic_calendar.png +0 -0
  117. package/android/src/main/res/drawable-xxhdpi/ic_camera.png +0 -0
  118. package/android/src/main/res/drawable-xxhdpi/ic_message.png +0 -0
  119. package/android/src/main/res/drawable-xxhdpi/ic_pause.png +0 -0
  120. package/android/src/main/res/drawable-xxhdpi/ic_play.png +0 -0
  121. package/android/src/main/res/drawable-xxhdpi/ic_play_back.png +0 -0
  122. package/android/src/main/res/drawable-xxhdpi/ic_record.png +0 -0
  123. package/android/src/main/res/drawable-xxhdpi/ic_retry.png +0 -0
  124. package/android/src/main/res/drawable-xxhdpi/ic_setting.png +0 -0
  125. package/android/src/main/res/drawable-xxhdpi/ic_sound_off.png +0 -0
  126. package/android/src/main/res/drawable-xxhdpi/ic_sound_on.png +0 -0
  127. package/android/src/main/res/drawable-xxxhdpi/ic_action_arrow_backward.png +0 -0
  128. package/android/src/main/res/drawable-xxxhdpi/ic_arrow_backward_white.png +0 -0
  129. package/android/src/main/res/drawable-xxxhdpi/ic_arrow_blue_right.png +0 -0
  130. package/android/src/main/res/drawable-xxxhdpi/ic_calendar.png +0 -0
  131. package/android/src/main/res/drawable-xxxhdpi/ic_camera.png +0 -0
  132. package/android/src/main/res/drawable-xxxhdpi/ic_message.png +0 -0
  133. package/android/src/main/res/drawable-xxxhdpi/ic_pause.png +0 -0
  134. package/android/src/main/res/drawable-xxxhdpi/ic_play.png +0 -0
  135. package/android/src/main/res/drawable-xxxhdpi/ic_play_back.png +0 -0
  136. package/android/src/main/res/drawable-xxxhdpi/ic_record.png +0 -0
  137. package/android/src/main/res/drawable-xxxhdpi/ic_retry.png +0 -0
  138. package/android/src/main/res/drawable-xxxhdpi/ic_setting.png +0 -0
  139. package/android/src/main/res/drawable-xxxhdpi/ic_sound_off.png +0 -0
  140. package/android/src/main/res/drawable-xxxhdpi/ic_sound_on.png +0 -0
  141. package/android/src/main/res/font/quicksand_bold.ttf +0 -0
  142. package/android/src/main/res/font/quicksand_light.ttf +0 -0
  143. package/android/src/main/res/font/quicksand_medium.ttf +0 -0
  144. package/android/src/main/res/font/quicksand_regular.ttf +0 -0
  145. package/android/src/main/res/font/quicksand_semi_bold.ttf +0 -0
  146. package/android/src/main/res/values/strings.xml +121 -0
  147. package/android/thingMapping.gradle +200 -0
  148. package/android/thingMapping.json +2014 -0
  149. package/ios/components/Alert.swift +54 -0
  150. package/ios/components/AnchorButton.swift +100 -0
  151. package/ios/components/Button.swift +118 -0
  152. package/ios/components/CustomDatePicker.swift +275 -0
  153. package/ios/components/Divider.swift +28 -0
  154. package/ios/components/Image.swift +72 -0
  155. package/ios/components/Label.swift +105 -0
  156. package/ios/components/Switch.swift +61 -0
  157. package/ios/dashboard/AdvanceSettings.swift +127 -0
  158. package/ios/dashboard/Dashboard.swift +354 -0
  159. package/ios/dashboard/Messages.swift +361 -0
  160. package/ios/dashboard/NavigationController.swift +173 -0
  161. package/ios/dashboard/OfflineScreen.swift +109 -0
  162. package/ios/dashboard/Playback.swift +543 -0
  163. package/ios/dashboard/PreviewManager.swift +117 -0
  164. package/ios/dashboard/Settings.swift +672 -0
  165. package/ios/icons/Charging.png +0 -0
  166. package/ios/icons/Charging@2x.png +0 -0
  167. package/ios/icons/Charging@3x.png +0 -0
  168. package/ios/icons/back_arraow.png +0 -0
  169. package/ios/icons/back_arraow@2x.png +0 -0
  170. package/ios/icons/back_arraow@3x.png +0 -0
  171. package/ios/icons/battery_average.png +0 -0
  172. package/ios/icons/battery_average@2x.png +0 -0
  173. package/ios/icons/battery_average@3x.png +0 -0
  174. package/ios/icons/battery_full.png +0 -0
  175. package/ios/icons/battery_full@2x.png +0 -0
  176. package/ios/icons/battery_full@3x.png +0 -0
  177. package/ios/icons/battery_good.png +0 -0
  178. package/ios/icons/battery_good@2x.png +0 -0
  179. package/ios/icons/battery_good@3x.png +0 -0
  180. package/ios/icons/battery_low.png +0 -0
  181. package/ios/icons/battery_low@2x.png +0 -0
  182. package/ios/icons/battery_low@3x.png +0 -0
  183. package/ios/icons/calendar.png +0 -0
  184. package/ios/icons/calendar@2x.png +0 -0
  185. package/ios/icons/calendar@3x.png +0 -0
  186. package/ios/icons/cloud.png +0 -0
  187. package/ios/icons/cloud@2x.png +0 -0
  188. package/ios/icons/cloud@3x.png +0 -0
  189. package/ios/icons/down_update.png +0 -0
  190. package/ios/icons/down_update@2x.png +0 -0
  191. package/ios/icons/down_update@3x.png +0 -0
  192. package/ios/icons/exit_fullscreen.png +0 -0
  193. package/ios/icons/exit_fullscreen@2x.png +0 -0
  194. package/ios/icons/exit_fullscreen@3x.png +0 -0
  195. package/ios/icons/expand.png +0 -0
  196. package/ios/icons/fullscreen.png +0 -0
  197. package/ios/icons/fullscreen@2x.png +0 -0
  198. package/ios/icons/fullscreen@3x.png +0 -0
  199. package/ios/icons/image_placeholder.png +0 -0
  200. package/ios/icons/information.png +0 -0
  201. package/ios/icons/information@2x.png +0 -0
  202. package/ios/icons/information@3x.png +0 -0
  203. package/ios/icons/keyless_Setting.png +0 -0
  204. package/ios/icons/keyless_Setting@2x.png +0 -0
  205. package/ios/icons/keyless_Setting@3x.png +0 -0
  206. package/ios/icons/keyless_back@1x.png +0 -0
  207. package/ios/icons/keyless_back@2x.png +0 -0
  208. package/ios/icons/keyless_back@3x.png +0 -0
  209. package/ios/icons/keyless_filter.png +0 -0
  210. package/ios/icons/keyless_filter@2x.png +0 -0
  211. package/ios/icons/keyless_filter@3x.png +0 -0
  212. package/ios/icons/keyless_message.png +0 -0
  213. package/ios/icons/keyless_message@2x.png +0 -0
  214. package/ios/icons/keyless_message@3x.png +0 -0
  215. package/ios/icons/keyless_pause.png +0 -0
  216. package/ios/icons/keyless_pause@2x.png +0 -0
  217. package/ios/icons/keyless_pause@3x.png +0 -0
  218. package/ios/icons/keyless_photo.png +0 -0
  219. package/ios/icons/keyless_photo@2x.png +0 -0
  220. package/ios/icons/keyless_photo@3x.png +0 -0
  221. package/ios/icons/keyless_play.png +0 -0
  222. package/ios/icons/keyless_play@2x.png +0 -0
  223. package/ios/icons/keyless_play@3x.png +0 -0
  224. package/ios/icons/keyless_play_list.png +0 -0
  225. package/ios/icons/keyless_play_list@2x.png +0 -0
  226. package/ios/icons/keyless_play_list@3x.png +0 -0
  227. package/ios/icons/keyless_play_playback.png +0 -0
  228. package/ios/icons/keyless_play_playback@2x.png +0 -0
  229. package/ios/icons/keyless_play_playback@3x.png +0 -0
  230. package/ios/icons/keyless_record.png +0 -0
  231. package/ios/icons/keyless_record@2x.png +0 -0
  232. package/ios/icons/keyless_record@3x.png +0 -0
  233. package/ios/icons/keyless_record_on.png +0 -0
  234. package/ios/icons/keyless_record_on@2x.png +0 -0
  235. package/ios/icons/keyless_record_on@3x.png +0 -0
  236. package/ios/icons/keyless_sound_off.png +0 -0
  237. package/ios/icons/keyless_sound_off@2x.png +0 -0
  238. package/ios/icons/keyless_sound_off@3x.png +0 -0
  239. package/ios/icons/keyless_sound_on.png +0 -0
  240. package/ios/icons/keyless_sound_on@2x.png +0 -0
  241. package/ios/icons/keyless_sound_on@3x.png +0 -0
  242. package/ios/icons/keyless_speak_off.png +0 -0
  243. package/ios/icons/keyless_speak_off@2x.png +0 -0
  244. package/ios/icons/keyless_speak_on.png +0 -0
  245. package/ios/icons/keyless_speak_on@2x.png +0 -0
  246. package/ios/icons/keyless_speak_on@3x.png +0 -0
  247. package/ios/icons/refresh.png +0 -0
  248. package/ios/icons/refresh@2x.png +0 -0
  249. package/ios/icons/refresh@3x.png +0 -0
  250. package/ios/icons/ty_camera_control_hd_normal@2x.png +0 -0
  251. package/ios/icons/ty_camera_control_hd_normal@3x.png +0 -0
  252. package/ios/icons/ty_camera_control_sd_normal@2x.png +0 -0
  253. package/ios/icons/ty_camera_control_sd_normal@3x.png +0 -0
  254. package/ios/icons/upgrade_success.png +0 -0
  255. package/ios/icons/upgrade_success@2x.png +0 -0
  256. package/ios/icons/upgrade_success@3x.png +0 -0
  257. package/ios/listener/KeylessListener.m +8 -0
  258. package/ios/listener/KeylessListener.swift +56 -0
  259. package/ios/listener/RentlyTuya-Bridging-Header.h +5 -0
  260. package/ios/listener/RentlyTuya.mm +56 -0
  261. package/ios/listener/RentlyTuya.swift +544 -0
  262. package/ios/theme/LocalColor.swift +33 -0
  263. package/ios/theme/LocalFont.swift +32 -0
  264. package/ios/theme/Theme.swift +71 -0
  265. package/ios/tuya/CameraManager.swift +296 -0
  266. package/ios/tuya/SettingsManager.swift +475 -0
  267. package/ios/tuya/Tuya.swift +570 -0
  268. package/ios/tuya/TuyaMessages.swift +98 -0
  269. package/ios/utils/Airbrake.swift +31 -0
  270. package/ios/utils/AppUtility.swift +76 -0
  271. package/ios/utils/HeapAnalytics.swift +8 -0
  272. package/ios/utils/OrientationManager.swift +60 -0
  273. package/ios/utils/PromiseHandler.swift +36 -0
  274. package/lib/commonjs/index.js +90 -0
  275. package/lib/commonjs/index.js.map +1 -0
  276. package/lib/commonjs/package.json +1 -0
  277. package/lib/module/index.js +83 -0
  278. package/lib/module/index.js.map +1 -0
  279. package/lib/module/package.json +1 -0
  280. package/lib/typescript/commonjs/package.json +1 -0
  281. package/lib/typescript/commonjs/src/index.d.ts +75 -0
  282. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  283. package/lib/typescript/module/package.json +1 -0
  284. package/lib/typescript/module/src/index.d.ts +75 -0
  285. package/lib/typescript/module/src/index.d.ts.map +1 -0
  286. package/package.json +188 -0
  287. package/rently-tuya.podspec +52 -0
  288. package/src/index.tsx +158 -0
@@ -0,0 +1,544 @@
1
+ import SwiftUI
2
+ import ThingSmartBaseKit
3
+ import ThingSmartCameraKit
4
+ import ThingSmartActivatorKit
5
+ import ThingSmartActivatorCoreKit
6
+
7
+ @objc(RentlyTuya)
8
+ class RentlyTuya: NSObject {
9
+
10
+ private var activatorResolve: RCTPromiseResolveBlock?
11
+ private var activatorReject: RCTPromiseRejectBlock?
12
+
13
+ @objc(initAirbrake:resolver:rejecter:)
14
+ func initAirbrake(
15
+ params: NSDictionary,
16
+ resolver: @escaping RCTPromiseResolveBlock,
17
+ rejecter: @escaping RCTPromiseRejectBlock
18
+ ) {
19
+ guard let projectId = params["id"] as? String,
20
+ let projectKey = params["key"] as? String else {
21
+ let message = "Missing required parameters."
22
+ rejecter("invalid_params", message, nil)
23
+ return
24
+ }
25
+
26
+ Airbrake.initialize(apiKey: projectKey, projectID: projectId)
27
+ resolver(true)
28
+ }
29
+
30
+ @objc(getCurrentWifi:rejecter:)
31
+ func getCurrentWifi(
32
+ resolver: @escaping RCTPromiseResolveBlock,
33
+ rejecter: @escaping RCTPromiseRejectBlock
34
+ ) {
35
+ let ssid = ThingSmartActivator.currentWifiSSID()
36
+ if (ssid.isEmpty) {
37
+ let message = "Unable to retrieve the current Wi-Fi SSID."
38
+ print("Tuya: \(message)")
39
+ rejecter("wifi_error", message, nil)
40
+ return
41
+ }
42
+ print("Tuya: Successfully retrieved current Wi-Fi SSID - \(ssid)")
43
+ resolver(ssid)
44
+ }
45
+
46
+ // Currently this is not being used in Smart Home app
47
+ @objc(getDeviceData:resolver:rejecter:)
48
+ func getDeviceData(
49
+ params: NSDictionary,
50
+ resolver: @escaping RCTPromiseResolveBlock,
51
+ rejecter: @escaping RCTPromiseRejectBlock
52
+ ) {
53
+ guard let deviceId = params["devId"] as? String else {
54
+ let message = "Device ID is missing in the params."
55
+ print("Tuya: \(message)")
56
+ rejecter("invalid_params", message, nil)
57
+ return
58
+ }
59
+
60
+ print("Tuya: Fetch device data for device ID - \(deviceId)")
61
+ }
62
+
63
+ // TODO:: Change the function name to make it consistent with Android
64
+ // Currently this is not being used in Smart Home app
65
+ @objc(getHomeDetail:resolver:rejecter:)
66
+ func getHomeDetail(
67
+ params: NSDictionary,
68
+ resolver: @escaping RCTPromiseResolveBlock,
69
+ rejecter: @escaping RCTPromiseRejectBlock
70
+ ) {
71
+ guard let homeIdString = params["homeId"] as? String,
72
+ let homeId = Int64(homeIdString) else {
73
+ let message = "Home ID is missing or invalid."
74
+ print("Tuya: \(message)")
75
+ rejecter("invalid_params", message, nil)
76
+ return
77
+ }
78
+
79
+ let currentHome = ThingSmartHome(homeId: homeId)
80
+
81
+ guard let home = currentHome else {
82
+ let message = "Failed to retrieve home details for home ID \(homeId)."
83
+ print("Tuya: \(message)")
84
+ rejecter("home_error", message, nil)
85
+ return
86
+ }
87
+
88
+ let homeDetails: [String: Any] = [
89
+ "deviceList": home.deviceList ?? [],
90
+ "groupList": home.groupList ?? [],
91
+ "sharedDeviceList": home.sharedDeviceList ?? [],
92
+ "sharedGroupList": home.sharedGroupList ?? []
93
+ ]
94
+
95
+ print("Tuya: Successfully retrieved home details - Home Details: \(homeDetails)")
96
+ resolver(homeDetails)
97
+ }
98
+
99
+ @objc(getTokenForQRCode:resolver:rejecter:)
100
+ func getTokenForQRCode(
101
+ params: NSDictionary,
102
+ resolver: @escaping RCTPromiseResolveBlock,
103
+ rejecter: @escaping RCTPromiseRejectBlock
104
+ ) {
105
+ guard let homeIdString = params["homeId"] as? String,
106
+ let homeId = Int64(homeIdString) else {
107
+ let message = "Home ID is missing or invalid."
108
+ print("Tuya: \(message)")
109
+ rejecter("invalid_params", message, nil)
110
+ return
111
+ }
112
+
113
+ ThingSmartActivator.sharedInstance()?.getTokenWithHomeId(
114
+ homeId,
115
+ success: { token in
116
+ print("Tuya: Successfully retrieved token for QR code - \(token ?? "nil").")
117
+ resolver(token)
118
+ },
119
+ failure: { error in
120
+ let errorMessage = error?.localizedDescription ?? "An unknown error occurred while retrieving the token."
121
+ print("Tuya: \(errorMessage)")
122
+ rejecter("get_token_error", errorMessage, error)
123
+ }
124
+ )
125
+ }
126
+
127
+ @objc(initActivatorForQRCode:resolver:rejecter:)
128
+ func initActivatorForQRCode(
129
+ params: NSDictionary,
130
+ resolver: @escaping RCTPromiseResolveBlock,
131
+ rejecter: @escaping RCTPromiseRejectBlock
132
+ ) {
133
+ guard let ssid = params["ssid"] as? String,
134
+ let password = params["password"] as? String,
135
+ let timeout = params["time"] as? Int,
136
+ let token = params["token"] as? String else {
137
+ let message = "SSID, password, time, or token is missing in the params."
138
+ print("Tuya: \(message)")
139
+ ThingSmartActivator.sharedInstance()?.stopConfigWiFi()
140
+ rejecter("invalid_params", message, nil)
141
+ return
142
+ }
143
+
144
+ activatorResolve = resolver
145
+ activatorReject = rejecter
146
+
147
+ ThingSmartActivator.sharedInstance()?.delegate = self
148
+ ThingSmartActivator.sharedInstance()?.startConfigWiFi(
149
+ .qrCode,
150
+ ssid: ssid,
151
+ password: password,
152
+ token: token,
153
+ timeout: TimeInterval(timeout)
154
+ )
155
+ print("Tuya: Successfully initiated Wi-Fi configuration using QR code.")
156
+ }
157
+
158
+ @objc(loginWithUid:resolver:rejecter:)
159
+ func loginWithUid(
160
+ params: NSDictionary,
161
+ resolver: @escaping RCTPromiseResolveBlock,
162
+ rejecter: @escaping RCTPromiseRejectBlock
163
+ ) {
164
+ guard let uid = params["uid"] as? String,
165
+ let password = params["password"] as? String,
166
+ let countryCode = params["countryCode"] as? String else {
167
+ let message = "UID, password, or country code is missing in the params."
168
+ print("Tuya: \(message)")
169
+ rejecter("invalid_params", message, nil)
170
+ return
171
+ }
172
+
173
+ ThingSmartUser.sharedInstance().loginOrRegister(
174
+ withCountryCode: countryCode,
175
+ uid: uid,
176
+ password: password,
177
+ createHome: false,
178
+ success: { result in
179
+ print("Tuya: Successfully logged in user.")
180
+ resolver(true)
181
+ },
182
+ failure: { error in
183
+ let errorMessage = error?.localizedDescription ?? "An unknown error occurred during login."
184
+ print("Tuya: \(errorMessage)")
185
+ rejecter("login_error", errorMessage, error)
186
+ }
187
+ )
188
+ }
189
+
190
+ @objc(logout:rejecter:)
191
+ func logout(
192
+ resolver: @escaping RCTPromiseResolveBlock,
193
+ rejecter: @escaping RCTPromiseRejectBlock
194
+ ) {
195
+ ThingSmartUser.sharedInstance().loginOut {
196
+ print("Tuya: Successfully logged out.")
197
+ resolver(true)
198
+ } failure: { error in
199
+ let errorMessage = error?.localizedDescription ?? "An unknown error occurred during logout."
200
+ print("Tuya: \(errorMessage)")
201
+ rejecter("logout_error", errorMessage, error)
202
+ }
203
+ }
204
+
205
+ @objc(openCameraLivePreview:resolver:rejecter:)
206
+ func openCameraLivePreview(
207
+ params: NSDictionary,
208
+ resolver: @escaping RCTPromiseResolveBlock,
209
+ rejecter: @escaping RCTPromiseRejectBlock
210
+ ) {
211
+ guard let countryCode = params["countryCode"] as? String,
212
+ let uid = params["uid"] as? String,
213
+ let password = params["passwd"] as? String,
214
+ let deviceId = params["devId"] as? String,
215
+ let homeId = params["homeId"] as? String,
216
+ let id = params["id"] as? String,
217
+ let flavour = params["flavour"] as? String else {
218
+ rejecter("invalid_params", "Missing required params: countryCode, uid, passwd, devId, homeId, id or flavour", nil)
219
+ return
220
+ }
221
+
222
+ let lastMoveoutAt = params["last_moveout_at"] as? String
223
+ let resetRequired = params["resetRequired"] as? Bool
224
+ let isResident = params["isResident"] as? Bool ?? true
225
+ let displayRemoveDoorbellButton = params["display_remove_doorbell_button"] as? Bool
226
+ let tuyaProductName = params["tuya_product_name"] as? String
227
+ let tuyaProductID = params["product_id"] as? String
228
+ let uuid = params["device_uuid"] as? String
229
+ let serialNumber = params["serial_no"] as? String
230
+ let isDefaultSettingsUpdated = params["doorbell_default_settings_updated"] as? Bool ?? false
231
+ let motionDetection = params["motion_detection"] as? Bool ?? false
232
+ let continuousRecording = params["continuous_recording"] as? Bool ?? false
233
+ let eventRecording = params["event_recording"] as? Bool ?? false
234
+ let setSensitivityLow = params["set_sensitivity_low"] as? Bool ?? false
235
+
236
+ // Property Credentials
237
+ let propertyCredentialUsername = params["propertyCredentialUsername"] as? String
238
+ let propertyCredentialPassword = params["propertyCredentialPassword"] as? String
239
+
240
+ Tuya.shared.lastMoveoutAt = lastMoveoutAt
241
+ Tuya.shared.resetRequired = resetRequired
242
+ Tuya.shared.isResident = isResident
243
+ Tuya.shared.displayRemoveDoorbellButton = displayRemoveDoorbellButton
244
+ Tuya.shared.tuyaProductName = tuyaProductName
245
+ Tuya.shared.tuyaProductID = tuyaProductID
246
+ Tuya.shared.uuid = uuid
247
+ Tuya.shared.serialNumber = serialNumber
248
+ Tuya.shared.id = id
249
+ Tuya.shared.isDefaultSettingsUpdated = isDefaultSettingsUpdated
250
+ Tuya.shared.motionDetection = motionDetection
251
+ Tuya.shared.continuousRecording = continuousRecording
252
+ Tuya.shared.eventRecording = eventRecording
253
+ Tuya.shared.setSensitivityLow = setSensitivityLow
254
+ Tuya.shared.flavour = flavour
255
+
256
+ if !Tuya.shared.continuousRecording && !Tuya.shared.eventRecording {
257
+ Tuya.shared.eventRecording = true
258
+ }
259
+
260
+ Tuya.shared.loginAndSetDevice(
261
+ deviceId: deviceId,
262
+ propertyUid: propertyCredentialUsername ?? uid,
263
+ propertyPassword: propertyCredentialPassword ?? password,
264
+ countryCode: countryCode,
265
+ homeId: homeId,
266
+ completion: { success, errorMessage, error in
267
+ if (success) {
268
+ openLivePreview(appFlavor: Tuya.shared.flavour)
269
+ resolver(true)
270
+ } else {
271
+ rejecter("sync_failed", errorMessage, error)
272
+ }
273
+ }
274
+ )
275
+ }
276
+
277
+ @objc(registerForPushNotification:resolver:rejecter:)
278
+ func registerForPushNotification(
279
+ params: NSDictionary,
280
+ resolver: @escaping RCTPromiseResolveBlock,
281
+ rejecter: @escaping RCTPromiseRejectBlock
282
+ ) {
283
+ guard let token = params["token"] as? String else {
284
+ let message = "Token is missing in the params."
285
+ print("Tuya: \(message)")
286
+ rejecter("invalid_params", message, nil)
287
+ return
288
+ }
289
+
290
+ DispatchQueue.main.async {
291
+ if let tokenData = token.hexToData() {
292
+ let error: NSError? = nil
293
+ ThingSmartSDK.sharedInstance().setDeviceToken(tokenData, withError: error)
294
+
295
+ if let error = error {
296
+ print("Failed to set device token: \(error.localizedDescription)")
297
+ rejecter("set_token_error", error.localizedDescription, error)
298
+ } else {
299
+ print("Tuya: Successfully registered for push notification")
300
+ resolver(true)
301
+ }
302
+ } else {
303
+ let message = "Unable to convert token to data"
304
+ print("Tuya: \(message)")
305
+ rejecter("invalid_token", message, nil)
306
+ }
307
+ }
308
+ }
309
+
310
+ @objc(renameDevice:resolver:rejecter:)
311
+ func renameDevice(
312
+ params: NSDictionary,
313
+ resolver: @escaping RCTPromiseResolveBlock,
314
+ rejecter: @escaping RCTPromiseRejectBlock
315
+ ) {
316
+ guard let deviceId = params["devId"] as? String,
317
+ let name = params["name"] as? String else {
318
+ let message = "Device ID or name is missing in the params."
319
+ print("Tuya: \(message)")
320
+ rejecter("invalid_params", message, nil)
321
+ return
322
+ }
323
+
324
+ ThingSmartDevice(deviceId: deviceId)?.updateName(
325
+ name,
326
+ success: {
327
+ print("Tuya: Device renamed successfully")
328
+ resolver(true)
329
+ },
330
+ failure: { error in
331
+ rejecter("rename_device_error", error?.localizedDescription ?? "Unknown error", error)
332
+ }
333
+ )
334
+ }
335
+
336
+ @objc(resetDevice:resolver:rejecter:)
337
+ func resetDevice(
338
+ params: NSDictionary,
339
+ resolver: @escaping RCTPromiseResolveBlock,
340
+ rejecter: @escaping RCTPromiseRejectBlock
341
+ ) {
342
+ print("Tuya: Received parameters -> \(params)")
343
+
344
+ guard let deviceId = params["devId"] as? String,
345
+ let homeId = params["homeId"] as? String,
346
+ let username = params["username"] as? String,
347
+ let password = params["password"] as? String,
348
+ let countryCode = params["countryCode"] as? String else {
349
+ print("Tuya: Error - Invalid parameters")
350
+ resolver(["success": false])
351
+ return
352
+ }
353
+
354
+ print("Tuya: Attempting login with deviceId: \(deviceId)")
355
+
356
+ Tuya.shared.loginAndSetDevice(
357
+ deviceId: deviceId,
358
+ propertyUid: username,
359
+ propertyPassword: password,
360
+ countryCode: countryCode,
361
+ homeId: homeId
362
+ ) { success, _, error in
363
+ if !success {
364
+ print("Tuya: Login failed")
365
+ resolver(["success": false])
366
+ return
367
+ }
368
+ print("Tuya: Device login successful for \(deviceId)")
369
+
370
+ guard let device = ThingSmartCameraDPManager(deviceId: deviceId) else {
371
+ print("Tuya: Error - Failed to get device instance")
372
+ resolver(["success": false])
373
+ return
374
+ }
375
+
376
+ let dispatchGroup = DispatchGroup()
377
+ let operationLock = DispatchQueue(label: "tuya.lock.queue")
378
+ var operationSuccess = true
379
+
380
+ print("Tuya: Starting reset operations...")
381
+
382
+ // Reset Chime Settings
383
+ if device.isSupportDP(ThingSmartCameraDPKey.init(rawValue: "165")) {
384
+ dispatchGroup.enter()
385
+ print("Tuya: Updating Chime Settings")
386
+ self.updateDeviceDP(device, key: ThingSmartCameraDPKey.init(rawValue: "165"), value: "1", message: "Chime Settings", group: dispatchGroup) { success in
387
+ operationLock.sync { operationSuccess = operationSuccess && success }
388
+ print("Tuya: Chime Settings update \(success ? "succeeded" : "failed")")
389
+ dispatchGroup.leave()
390
+ }
391
+ }
392
+
393
+ // Handle SD Card Formatting & Recording Mode
394
+ if device.isSupportDP(ThingSmartCameraDPKey.sdCardStatusDPName) {
395
+ print("Tuya: Device supports SD Card Status DP")
396
+
397
+ if device.isSupportDP(ThingSmartCameraDPKey.recordModeDPName) {
398
+ dispatchGroup.enter()
399
+ print("Tuya: Updating SD Card Record Mode")
400
+ self.updateDeviceDP(device, key: ThingSmartCameraDPKey.recordModeDPName, value: "1", message: "SD Card Record Mode", group: dispatchGroup) { success in
401
+ operationLock.sync { operationSuccess = operationSuccess && success }
402
+ print("Tuya: SD Card Record Mode update \(success ? "succeeded" : "failed")")
403
+ dispatchGroup.leave()
404
+ }
405
+ }
406
+
407
+ if let sdCardStatus = device.value(forDP: ThingSmartCameraDPKey.sdCardStatusDPName) as? Int {
408
+ print("Tuya: Retrieved SD Card Status -> \(sdCardStatus)")
409
+
410
+ if sdCardStatus != 5 {
411
+ dispatchGroup.enter()
412
+ print("Tuya: Formatting SD Card")
413
+ self.updateDeviceDP(device, key: ThingSmartCameraDPKey.sdCardFormatDPName, value: true, message: "SD Card Formatting", group: dispatchGroup) { success in
414
+ operationLock.sync { operationSuccess = operationSuccess && success }
415
+ print("Tuya: SD Card Formatting \(success ? "succeeded" : "failed")")
416
+ dispatchGroup.leave()
417
+ }
418
+ } else {
419
+ print("Tuya: SD Card already formatted or invalid status")
420
+ }
421
+ } else {
422
+ print("Tuya: Unable to retrieve SD Card status")
423
+ }
424
+ } else {
425
+ print("Tuya: SD Card status DP is not supported")
426
+ }
427
+
428
+ // Timeout to avoid infinite loader (Max 10s)
429
+ let timeoutResult = dispatchGroup.wait(timeout: .now() + 10)
430
+ if timeoutResult == .timedOut {
431
+ print("Tuya: Timeout - Some operations did not complete in time")
432
+ resolver(["success": false])
433
+ return
434
+ }
435
+
436
+ // Final Promise resolution
437
+ dispatchGroup.notify(queue: .main) {
438
+ print("Tuya: Reset operations completed. Final success state -> \(operationSuccess)")
439
+ resolver(["success": operationSuccess])
440
+ }
441
+ }
442
+ }
443
+
444
+
445
+ private func updateDeviceDP(
446
+ _ device: ThingSmartCameraDPManager,
447
+ key: ThingSmartCameraDPKey,
448
+ value: Any,
449
+ message: String,
450
+ group: DispatchGroup,
451
+ completion: @escaping (Bool) -> Void
452
+ ) {
453
+ group.enter()
454
+ device.setValue(value, forDP: key) { _ in
455
+ print("Tuya: \(message) updated successfully")
456
+ completion(true)
457
+ group.leave()
458
+ } failure: { error in
459
+ print("Tuya: Failed to update \(message): \(error?.localizedDescription ?? "Unknown error")")
460
+ completion(false)
461
+ group.leave()
462
+ }
463
+ }
464
+
465
+ }
466
+
467
+ extension RentlyTuya: ThingSmartActivatorDelegate {
468
+
469
+ func activator(_ activator: ThingSmartActivator, didReceiveDevice deviceModel: ThingSmartDeviceModel?, error: (any Error)?) {
470
+ defer {
471
+ activatorResolve = nil
472
+ activatorReject = nil
473
+ }
474
+
475
+ if let error = error as NSError? {
476
+ handleActivatorError(error, deviceModel: deviceModel)
477
+ return
478
+ }
479
+
480
+ if let deviceModel = deviceModel {
481
+ let jsonDict = deviceModel.toDictionary()
482
+ activatorResolve?(jsonDict)
483
+ } else {
484
+ let unknownError = NSError(domain: "RentlyTuya", code: -1, userInfo: [NSLocalizedDescriptionKey: "Device model is nil"])
485
+ activatorReject?("pair_failed", "Device pairing failed", unknownError)
486
+ }
487
+ }
488
+
489
+ func activator(_ activator: ThingSmartActivator, didPassWIFIToSecurityLevelDeviceWithUUID uuid: String) {
490
+ print("Tuya: Pairing Started")
491
+ // Continue configuration for security-level devices if necessary
492
+ // ThingSmartActivator.sharedInstance()?.continueConfigSecurityLevelDevice()
493
+ }
494
+
495
+ private func handleActivatorError(_ error: NSError, deviceModel: ThingSmartDeviceModel?) {
496
+ switch (error.code, error.localizedDescription) {
497
+ case (1512, "Timeout"):
498
+ let timeoutResponse: [String: Any] = ["is_timeout": "true"]
499
+ activatorResolve?(timeoutResponse)
500
+
501
+ case (1501, _):
502
+ let errorDetails: [String: Any] = [
503
+ "errorCode": error.localizedFailureReason ?? "",
504
+ "errorMsg": error.localizedDescription,
505
+ "id": deviceModel?.devId ?? "",
506
+ "uuid": deviceModel?.uuid ?? "",
507
+ "name": deviceModel?.name ?? ""
508
+ ]
509
+ let customError = NSError(domain: error.domain, code: error.code, userInfo: [NSLocalizedDescriptionKey: errorDetails])
510
+ activatorReject?("error_1501", error.localizedDescription, customError)
511
+
512
+ default:
513
+ activatorReject?("pair_failed", error.localizedDescription, error)
514
+ }
515
+ }
516
+ }
517
+
518
+ extension ThingSmartDeviceModel {
519
+ func toDictionary() -> [String: Any] {
520
+ return [
521
+ "devId": self.devId ?? "",
522
+ "uuid": self.uuid ?? ""
523
+ ]
524
+ }
525
+ }
526
+
527
+ extension String {
528
+ func hexToData() -> Data? {
529
+ var data = Data()
530
+ if self.count % 2 != 0 { return nil }
531
+
532
+ var hexStr = self
533
+ while hexStr.count > 0 {
534
+ let c = String(hexStr.prefix(2))
535
+ hexStr = String(hexStr.dropFirst(2))
536
+ if let byte = UInt8(c, radix: 16) {
537
+ data.append(byte)
538
+ } else {
539
+ return nil
540
+ }
541
+ }
542
+ return data
543
+ }
544
+ }
@@ -0,0 +1,33 @@
1
+ import SwiftUI
2
+
3
+ struct LocalColor {
4
+ struct Main {
5
+ static var light = Color(hex: "#f3faff")
6
+ static var dark = Color(hex: "#329ddc")
7
+ }
8
+
9
+ struct Primary {
10
+ static let light = Color(#colorLiteral(red: 0, green: 0.6419225335, blue: 0.9344936609, alpha: 1))
11
+ static let secondary = Color(#colorLiteral(red: 0.3606210351, green: 0.5981844068, blue: 0.7222386599, alpha: 1))
12
+ static let dark = Color(#colorLiteral(red: 0, green: 0.6262267828, blue: 0.8854203224, alpha: 1))
13
+ static let medium = Color(#colorLiteral(red: 0, green: 0.5515162945, blue: 0.8891028762, alpha: 1))
14
+ }
15
+
16
+ struct Secondary {
17
+ static let white = Color(#colorLiteral(red: 0.9466181397, green: 0.9815257192, blue: 1, alpha: 1))
18
+ static let light = Color(#colorLiteral(red: 0.8319713473, green: 0.9325252771, blue: 0.9908282161, alpha: 1))
19
+ }
20
+
21
+ struct Danger {
22
+ static let primary = Color(#colorLiteral(red: 0.8711757064, green: 0, blue: 0, alpha: 1))
23
+ }
24
+
25
+ struct Monochrome {
26
+ static let white = Color.white
27
+ static let regular = Color(#colorLiteral(red: 0.5263667703, green: 0.5214033127, blue: 0.5515511632, alpha: 1))
28
+ static let medium = Color(#colorLiteral(red: 0.2326147854, green: 0.3040209115, blue: 0.3540382385, alpha: 1))
29
+ static let grey = Color(#colorLiteral(red: 0.2156862617, green: 0.2156862617, blue: 0.2156862617, alpha: 1))
30
+ static let black = Color.black
31
+ static let transparent = Color.clear
32
+ }
33
+ }
@@ -0,0 +1,32 @@
1
+ import SwiftUI
2
+
3
+ import SwiftUI
4
+
5
+ struct LocalFont {
6
+ struct FontSize {
7
+ static let XS: CGFloat = 10
8
+ static let S: CGFloat = 12
9
+ static let M: CGFloat = 14
10
+ static let L: CGFloat = 16
11
+ static let XL18: CGFloat = 18
12
+ static let XL20: CGFloat = 20
13
+ static let XL22: CGFloat = 22
14
+ static let XL24: CGFloat = 24
15
+ static let XL26: CGFloat = 26
16
+ static let XL28: CGFloat = 28
17
+ static let XL30: CGFloat = 30
18
+ static let XL34: CGFloat = 34
19
+ static let XL40: CGFloat = 40
20
+ static let XL50: CGFloat = 50
21
+ static let XL80: CGFloat = 80
22
+ static let XL200: CGFloat = 200
23
+ }
24
+
25
+ struct FontFamily {
26
+ static let light = "Quicksand-Light"
27
+ static let regular = "Quicksand-Regular"
28
+ static let medium = "Quicksand-Medium"
29
+ static let semiBold = "Quicksand-SemiBold"
30
+ static let bold = "Quicksand-Bold"
31
+ }
32
+ }
@@ -0,0 +1,71 @@
1
+ import SwiftUI
2
+
3
+ struct Themes {
4
+ static func configureTheme(for flavor: String) {
5
+ switch flavor.lowercased() {
6
+ case "keyless":
7
+ configureSmartHomeTheme()
8
+ case "bellanet":
9
+ configureBellanetTheme()
10
+ case "coveyhomes":
11
+ configureCoveyHomesTheme()
12
+ case "progress":
13
+ configureProgressTheme()
14
+ default:
15
+ configureSmartHomeTheme()
16
+ }
17
+ }
18
+
19
+ private static func configureSmartHomeTheme() {
20
+ LocalColor.Main.light = Color(hex: "#f3faff")
21
+ LocalColor.Main.dark = Color(hex: "#329ddc")
22
+ }
23
+
24
+ private static func configureBellanetTheme() {
25
+ LocalColor.Main.light = Color(hex: "#E9F0FF")
26
+ LocalColor.Main.dark = Color(hex: "#0B1E44")
27
+ }
28
+
29
+ private static func configureCoveyHomesTheme() {
30
+ LocalColor.Main.light = Color(hex: "#FAF6F6")
31
+ LocalColor.Main.dark = Color(hex: "#99855E")
32
+ }
33
+
34
+ private static func configureProgressTheme() {
35
+ LocalColor.Main.light = Color(hex: "#EFF5F4")
36
+ LocalColor.Main.dark = Color(hex: "#279989")
37
+ }
38
+ }
39
+
40
+ extension Color {
41
+ init(hex: String) {
42
+ let cleanedHex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
43
+
44
+ var rgb: UInt64 = 0
45
+ Scanner(string: cleanedHex).scanHexInt64(&rgb)
46
+
47
+ let length = cleanedHex.count
48
+ let r, g, b, a: Double
49
+
50
+ switch length {
51
+ case 6:
52
+ r = Double((rgb >> 16) & 0xFF) / 255.0
53
+ g = Double((rgb >> 8) & 0xFF) / 255.0
54
+ b = Double(rgb & 0xFF) / 255.0
55
+ a = 1.0
56
+ case 8:
57
+ r = Double((rgb >> 24) & 0xFF) / 255.0
58
+ g = Double((rgb >> 16) & 0xFF) / 255.0
59
+ b = Double((rgb >> 8) & 0xFF) / 255.0
60
+ a = Double(rgb & 0xFF) / 255.0
61
+ default:
62
+ r = 0.0
63
+ g = 0.0
64
+ b = 0.0
65
+ a = 1.0
66
+ print("Invalid hex string, defaulting to black.")
67
+ }
68
+
69
+ self.init(red: r, green: g, blue: b, opacity: a)
70
+ }
71
+ }