@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,570 @@
1
+ import Foundation
2
+ import SwiftUI
3
+ import ThingSmartCameraBase
4
+ import ThingSmartDeviceKit
5
+ import ThingSmartCameraKit
6
+ // ThingSmartDeviceDelegate - For firmware upgrade
7
+
8
+ class Tuya: NSObject, ObservableObject {
9
+
10
+ static let shared = Tuya()
11
+
12
+ private override init() {}
13
+
14
+ var device: ThingSmartDevice!
15
+ var dpManager: ThingSmartCameraDPManager?
16
+ var cameraType: ThingSmartCameraType?
17
+ var messages: ThingSmartCameraMessage?
18
+
19
+ @Published var isConnected: Bool = false
20
+ @Published var isPreviewing: Bool = false
21
+ @Published var isMicOn: Bool = false
22
+ @Published var isMuted: Bool = true
23
+ @Published var isHD: Bool = true
24
+ @Published var isScreenshotSuccess = false
25
+ @Published var isRecording = false
26
+ @Published var isRecordingSuccess = false
27
+ @Published var isRecordingFailure = false
28
+
29
+ @Published var isAosu: Bool = false
30
+ @Published var is8s: Bool = false
31
+
32
+ // Settings
33
+ @Published var isWaterMarkEnabled: Bool = false
34
+ @Published var isFlipEnabled: Bool = false
35
+ @Published var isAntiDismantlingAlarmEnabled: Bool = false
36
+ @Published var nightVisionLevel: String = ThingSmartCameraNightvision.auto.rawValue
37
+ @Published var isMotionDetectionEnabled: Bool = false
38
+ @Published var motionSensitivityLevel: String = ThingSmartCameraMotion.medium.rawValue
39
+ @Published var isPIRDetectionEnabled: Bool = false
40
+ @Published var pirSensitivityLevel: Int = 3
41
+ @Published var basicPIRSensitivityLevel: String = ThingSmartCameraPIR.stateMedium.rawValue
42
+ @Published var sdCardStatus: Int = 1
43
+ @Published var isSDCardStorageEnabled: Bool = false
44
+ @Published var sdCardRecordingType: String = ThingSmartCameraRecordMode.event.rawValue
45
+ @Published var remainingBattery: Int? = nil
46
+ @Published var powerMode: String? = nil
47
+ @Published var chimeType: String = "0"
48
+ @Published var totalCapacity = 0.0
49
+ @Published var remainingCapacity = 0.0
50
+ @Published var used = 0.0
51
+ @Published var firwareVersion: String? = nil
52
+
53
+ // Playback
54
+ @Published var recordDays: [Int]? = nil
55
+ @Published var playbackVideoList: [[AnyHashable : Any]]? = nil
56
+ @Published var selectedItem: [AnyHashable: Any]? = nil
57
+ @Published var isPlaybacking: Bool = false
58
+ @Published var isPaused: Bool = false
59
+ @Published var isPlaybackMuted: Bool = true
60
+
61
+ // Loaders
62
+ @Published var previewLoader: Bool = true
63
+ @Published var dashboardLoader: Bool = false
64
+ @Published var playbackLoader: Bool = false
65
+ @Published var datePickerLoader: Bool = false
66
+ @Published var messagesLoader: Bool = false
67
+ @Published var settingsLoader: Bool = false
68
+
69
+ // Smart Home Values
70
+ var lastMoveoutAt: String? = nil
71
+ var resetRequired: Bool? = nil
72
+ var isResident: Bool = true
73
+ var displayRemoveDoorbellButton: Bool? = nil
74
+ var tuyaProductName: String? = nil
75
+ var tuyaProductID: String? = nil
76
+ var uuid: String? = nil
77
+ var serialNumber: String? = nil
78
+ var id: String? = nil
79
+ var flavour: String = "smarthome"
80
+
81
+ // Default Settings values
82
+ var isDefaultSettingsUpdated: Bool = false
83
+ var motionDetection: Bool = false
84
+ var continuousRecording: Bool = false
85
+ var eventRecording: Bool = false
86
+ var setSensitivityLow: Bool = false
87
+
88
+ // Login and Set Device
89
+ func loginAndSetDevice(
90
+ deviceId: String,
91
+ propertyUid: String,
92
+ propertyPassword: String,
93
+ countryCode: String,
94
+ homeId: String,
95
+ completion: @escaping (Bool, String?, Error?) -> Void
96
+ ) {
97
+ guard !deviceId.isEmpty, !propertyUid.isEmpty, !propertyPassword.isEmpty, !homeId.isEmpty else {
98
+ print("Tuya: Missing required parameters.")
99
+ completion(false, "invalid_params", nil)
100
+ return
101
+ }
102
+
103
+ ThingSmartUser.sharedInstance().loginOrRegister(
104
+ withCountryCode: countryCode,
105
+ uid: propertyUid,
106
+ password: propertyPassword,
107
+ createHome: false
108
+ ) { result in
109
+
110
+ print("Tuya: Successfully logged in user.")
111
+ guard let homeIdLong = Int64(homeId) else {
112
+ print("Tuya: Failed to convert homeId to Int64.")
113
+ completion(false, "invalid_homeId", nil)
114
+ return
115
+ }
116
+
117
+ self.syncDevice(
118
+ deviceId: deviceId,
119
+ homeId: homeIdLong,
120
+ completion: completion
121
+ )
122
+ } failure: { error in
123
+ print("Tuya: Login failed. Error: \(String(describing: error?.localizedDescription ?? "An Unknown error occured in login"))")
124
+ completion(false, error?.localizedDescription, error)
125
+ }
126
+ }
127
+
128
+ // Sync Device Info
129
+ private func syncDevice(
130
+ deviceId: String,
131
+ homeId: Int64,
132
+ completion: @escaping (Bool, String?, Error?) -> Void
133
+ ) {
134
+ ThingSmartDevice.syncDeviceInfo(withDevId: deviceId, homeId: homeId) {
135
+
136
+ print("Tuya: Device sync successful.")
137
+ self.device = ThingSmartDevice(deviceId: deviceId)
138
+ self.dpManager = ThingSmartCameraDPManager(deviceId: deviceId)
139
+ self.dpManager?.addObserver(SettingsManager.shared)
140
+ self.messages = ThingSmartCameraMessage(deviceId: deviceId, timeZone: TimeZone.current)
141
+
142
+ // Wake device - Battery powered devices will go to sleep state after some time, so connection may not happen.
143
+ if self.device != nil {
144
+ self.device.awake {
145
+ print("Tuya: Device wake success")
146
+ } failure: { error in
147
+ print("Tuya: Wake device failure \(String(describing: error?.localizedDescription))")
148
+ }
149
+ }
150
+
151
+ completion(true, nil, nil)
152
+ } failure: { error in
153
+ print("Tuya: Device sync failed. Error: \(String(describing: error?.localizedDescription ?? "Unknown error"))")
154
+ completion(false, error?.localizedDescription, error)
155
+ }
156
+ }
157
+
158
+ // Connect camera
159
+ func connect() {
160
+ guard let device = self.device else {
161
+ print("Tuya: Device not initialized")
162
+ self.updateStatus(isConnected: false, previewLoader: false)
163
+ return
164
+ }
165
+
166
+ guard let p2pType = device.deviceModel.skills["p2pType"] else {
167
+ print("Tuya: Missing p2pType")
168
+ self.updateStatus(isConnected: false, previewLoader: false)
169
+ return
170
+ }
171
+
172
+ previewLoader = true
173
+
174
+ device.awake {
175
+ print("Tuya: Device wake success")
176
+ } failure: { error in
177
+ print("Tuya: Wake device failure \(String(describing: error?.localizedDescription))")
178
+ }
179
+
180
+ let request = ThingSmartRequest()
181
+ request.request(withApiName: "tuya.m.ipc.config.get", postData: ["devId": device.devId], version: "2.0") { result in
182
+ guard let configData = result else {
183
+ print("Tuya: Config data missing")
184
+ self.updateStatus(isConnected: false, previewLoader: false)
185
+ return
186
+ }
187
+
188
+ self.configureCamera(
189
+ p2pType: p2pType,
190
+ configData: configData
191
+ )
192
+ } failure: { error in
193
+ print("Tuya: API error: \(String(describing: error?.localizedDescription))")
194
+ self.updateStatus(isConnected: false, previewLoader: false)
195
+ }
196
+ }
197
+
198
+ // Configure the camera
199
+ private func configureCamera(p2pType: Any, configData: Any) {
200
+ guard let config = ThingSmartCameraFactory.ipcConfig(
201
+ withUid: ThingSmartUser.sharedInstance().uid,
202
+ localKey: device.deviceModel.localKey,
203
+ configData: configData as? [AnyHashable: Any]
204
+ ) else {
205
+ print("Tuya: Camera config creation failed")
206
+ self.updateStatus(isConnected: false, previewLoader: false)
207
+ return
208
+ }
209
+
210
+ self.cameraType = ThingSmartCameraFactory.camera(
211
+ withP2PType: p2pType,
212
+ config: config,
213
+ delegate: CameraManager.shared
214
+ )
215
+
216
+ guard let cameraType = cameraType else {
217
+ print("Tuya: CameraType initialization failed")
218
+ self.updateStatus(isConnected: false, previewLoader: false)
219
+ return
220
+ }
221
+
222
+ print("Tuya: Connecting Doorbell...")
223
+ cameraType.connect?(with: .auto)
224
+ }
225
+
226
+ func configureSettings() {
227
+ let dpKeys: [(ThingSmartCameraDPKey, (AnyObject) -> Void)] = [
228
+ (ThingSmartCameraDPKey.basicFlipDPName, { value in
229
+ self.isFlipEnabled = value.thingsdk_toBool()
230
+ print("Tuya: Flip setting updated. Flip is now \(self.isFlipEnabled ? "enabled" : "disabled").")
231
+ }),
232
+ (ThingSmartCameraDPKey.basicOSDDPName, { value in
233
+ self.isWaterMarkEnabled = value.thingsdk_toBool()
234
+ print("Tuya: Watermark setting updated. Watermark (OSD) is now \(self.isWaterMarkEnabled ? "enabled" : "disabled").")
235
+ }),
236
+ (ThingSmartCameraDPKey.init(rawValue: "231"), { value in
237
+ self.isAntiDismantlingAlarmEnabled = value.thingsdk_toBool()
238
+ print("Tuya: Anti Dismantling Alarm setting updated. Anti Dismantling Alarm is now \(self.isAntiDismantlingAlarmEnabled ? "enabled" : "disabled").")
239
+ }),
240
+ (ThingSmartCameraDPKey.basicNightvisionDPName, { value in
241
+ self.nightVisionLevel = value.thingsdk_toString()
242
+ print("Tuya: Night vision mode updated to \(self.nightVisionLevel).")
243
+ }),
244
+ // 8s and Aosu Motion Detection
245
+ (ThingSmartCameraDPKey.motionDetectDPName, { value in
246
+ self.isMotionDetectionEnabled = value.thingsdk_toBool()
247
+ print("Tuya: Motion detection updated. Motion Detection is now \(self.isMotionDetectionEnabled ? "enabled" : "disabled").")
248
+ }),
249
+ // 8s Motion Sensitivity
250
+ (ThingSmartCameraDPKey.motionSensitivityDPName, { value in
251
+ self.motionSensitivityLevel = value.thingsdk_toString()
252
+ print("Tuya: Motion sensitivity level updated to \(self.motionSensitivityLevel).")
253
+ }),
254
+ // Aosu Motion Sensitivity
255
+ (ThingSmartCameraDPKey.basicPIRDPName, { value in
256
+ self.basicPIRSensitivityLevel = value.thingsdk_toString()
257
+ print("Tuya: Aosu Motion sensitivity level updated to \(self.basicPIRSensitivityLevel).")
258
+ }),
259
+ // 15s motion detection
260
+ (ThingSmartCameraDPKey.init(rawValue: "240"), { value in
261
+ self.isPIRDetectionEnabled = value.thingsdk_toBool()
262
+ print("Tuya: PIR detection updated. PIR Detection is now \(self.isPIRDetectionEnabled ? "enabled" : "disabled").")
263
+ }),
264
+ // 15s motion sensitivity
265
+ (ThingSmartCameraDPKey.init(rawValue: "241"), { value in
266
+ self.pirSensitivityLevel = value.thingsdk_toInt()
267
+ print("Tuya: PIR sensitivity level updated to \(self.pirSensitivityLevel).")
268
+ }),
269
+ (ThingSmartCameraDPKey.sdCardStatusDPName, { value in
270
+ self.sdCardStatus = value.thingsdk_toInt()
271
+ print("Tuya: SD card status updated to \(self.sdCardStatus).")
272
+ }),
273
+ (ThingSmartCameraDPKey.sdCardRecordDPName, { value in
274
+ self.isSDCardStorageEnabled = value.thingsdk_toBool()
275
+ print("Tuya: SD card storage updated. Storage is now \(self.isSDCardStorageEnabled ? "enabled" : "disabled").")
276
+ }),
277
+ (ThingSmartCameraDPKey.recordModeDPName, { value in
278
+ self.sdCardRecordingType = value.thingsdk_toString()
279
+ print("Tuya: SD card recording mode updated to \(self.sdCardRecordingType).")
280
+ }),
281
+ (ThingSmartCameraDPKey.wirelessPowerModeDPName, { value in
282
+ self.powerMode = value.thingsdk_toString()
283
+ print("Tuya: Power mode updated to \(String(describing: self.powerMode)).")
284
+ }),
285
+ (ThingSmartCameraDPKey.wirelessElectricityDPName, { value in
286
+ self.remainingBattery = value.thingsdk_toInt()
287
+ print("Tuya: Battery percentage updated to \(self.remainingBattery ?? 0)%.")
288
+ }),
289
+ (ThingSmartCameraDPKey.init(rawValue: "165"), { value in
290
+ self.chimeType = value.thingsdk_toString()
291
+ print("Tuya: Chime type updated to \(self.chimeType).")
292
+ })
293
+ // (ThingSmartCameraDPKey.basicIndicatorDPName, { value in
294
+ // let indicatorON = value.thingsdk_toBool()
295
+ //}),
296
+ // (ThingSmartCameraDPKey.basicPrivateDPName, { value in
297
+ // let privateOn = value.thingsdk_toBool()
298
+ //}),
299
+ // (ThingSmartCameraDPKey.decibelDetectDPName, { value in
300
+ // let decibelDetectOn = value.thingsdk_toBool()
301
+ //}),
302
+ //(ThingSmartCameraDPKey.decibelSensitivityDPName, { value in
303
+ // let decibelSensitivity = value.thingsdk_toString()
304
+ //}),
305
+ //(ThingSmartCameraDPKey.wirelessBatteryLockDPName, { value in
306
+ // let batteryLockOn = value.thingsdk_toBool()
307
+ //})
308
+ ]
309
+ let dispatchGroup = DispatchGroup()
310
+ for (dpKey, action) in dpKeys {
311
+ dispatchGroup.enter()
312
+ if let value = SettingsManager.shared.getDPValue(dpKey: dpKey) as AnyObject? {
313
+ action(value)
314
+ } else {
315
+ print("Tuya: Settings - Unsupported DP key or invalid value detected for '\(dpKey)'.")
316
+ }
317
+ dispatchGroup.leave()
318
+ }
319
+ dispatchGroup.notify(queue: .main) {
320
+ self.isAosu = SettingsManager.shared.isAosu()
321
+ self.is8s = SettingsManager.shared.is8s()
322
+ print("Tuya: Settings isAosu and is8s falg set successfully.")
323
+ }
324
+ }
325
+
326
+ private func withCameraType<T>(execute: (ThingSmartCameraType) -> T?) -> T? {
327
+ guard let cameraType = self.cameraType else {
328
+ print("Tuya: Camera type is not initialized. Updating status to disconnected.")
329
+ self.updateStatus(isConnected: false, isPreviewing: false, previewLoader: false)
330
+ return nil
331
+ }
332
+ return execute(cameraType)
333
+ }
334
+
335
+ // Disconnect camera
336
+ func disconnect() {
337
+
338
+ if !self.isConnected {
339
+ AppUtility.dismissRootViewController()
340
+ }
341
+
342
+ withCameraType { cameraType in
343
+ self.updateStatus(previewLoader: true, settingsLoader: true)
344
+ let result = cameraType.disConnect()
345
+ print("Tuya: Disconnect triggered. Result: \(result)")
346
+
347
+ if AppUtility.shouldClose {
348
+ print("Tuya: Closing the Tuya Module.")
349
+ AppUtility.dismissRootViewController()
350
+ }
351
+
352
+ // TODO:: Check why disconnect not triggering the callback instead of handling the states.
353
+ self.updateStatus(
354
+ isConnected: false,
355
+ isPreviewing: false,
356
+ isPlaybacking: false,
357
+ isMicOn: false,
358
+ previewLoader: false,
359
+ dashboardLoader: false,
360
+ playbackLoader: false,
361
+ settingsLoader: false
362
+ )
363
+ }
364
+ }
365
+
366
+ // Camera Voice control functions
367
+ func startTalk() {
368
+ withCameraType { cameraType in
369
+ self.updateStatus(dashboardLoader: true)
370
+ let result = cameraType.startAudioTalk()
371
+ print("Tuya: Start audio talk triggered. Result: \(result)")
372
+ }
373
+ }
374
+
375
+ func stopTalk() {
376
+ withCameraType { cameraType in
377
+ self.updateStatus(dashboardLoader: true)
378
+ let result = cameraType.stopAudioTalk()
379
+ print("Tuya: Stop audio talk triggered. Result: \(result)")
380
+ }
381
+ }
382
+
383
+ func enableMute(
384
+ enable: Bool,
385
+ type: ThingSmartCameraPlayMode
386
+ ) {
387
+ withCameraType { cameraType in
388
+ let result = cameraType.enableMute(enable, for: type)
389
+ print("Tuya: Mute action triggered to \(enable ? "enabled" : "disabled"). Result: \(result)")
390
+ if result == -20005 {
391
+ print("Tuya: Mute/unmute not allowed during recording.")
392
+ }
393
+ }
394
+ }
395
+
396
+ // Change resolution
397
+ func changeResolution(
398
+ resolution: ThingSmartCameraDefinition
399
+ ) {
400
+ withCameraType { cameraType in
401
+ let result = cameraType.setDefinition(resolution)
402
+ print("Tuya: Resolution change triggered to \(resolution). Result: \(result)")
403
+ }
404
+ }
405
+
406
+ // Start and stop preview
407
+ func startPreview() {
408
+ withCameraType { cameraType in
409
+ if isConnected {
410
+ self.updateStatus(previewLoader: true)
411
+ let result = cameraType.startPreview()
412
+ print("Tuya: Start Preview triggered. Result: \(result)")
413
+ } else {
414
+ self.updateStatus(isConnected: false, isPreviewing: false, previewLoader: false)
415
+ print("Tuya: Cannot start preview. Camera is not connected.")
416
+ }
417
+ }
418
+ }
419
+
420
+ func stopPreview() {
421
+ withCameraType { cameraType in
422
+ let result = cameraType.stopPreview()
423
+ print("Tuya: Stop Preview triggered. Result: \(result)")
424
+ }
425
+ }
426
+
427
+ // Screenshot and video recording
428
+ func screenshot() {
429
+ withCameraType { cameraType in
430
+ let result = cameraType.snapShoot()
431
+
432
+ if result == nil {
433
+ print("Tuya: Screenshot failed.")
434
+ } else {
435
+ self.isScreenshotSuccess = true
436
+ print("Tuya: Screenshot captured successfully.")
437
+ }
438
+ }
439
+ }
440
+
441
+ func startRecording() {
442
+ withCameraType { cameraType in
443
+ let result = cameraType.startRecord()
444
+ print("Tuya: Start video recording triggered. Result: \(result)")
445
+ }
446
+ }
447
+
448
+ func stopRecording() {
449
+ withCameraType { cameraType in
450
+ let result = cameraType.stopRecord()
451
+ print("Tuya: Stop video recording triggered. Result: \(result)")
452
+ if result == -30011 || result == -30012 {
453
+ self.isRecordingFailure = true
454
+ self.isRecording = false
455
+ print("Tuya: Recording forcefully stopped due to an error. Marking as failure.")
456
+ }
457
+ }
458
+ }
459
+
460
+ // Playback
461
+ func getVideoList(
462
+ year: UInt,
463
+ month: UInt,
464
+ day: UInt
465
+ ) {
466
+ withCameraType { cameraType in
467
+ self.updateStatus(playbackLoader: true)
468
+ print("Tuya: Querying video list. Parameters - Year: \(year), Month: \(month), Day: \(day)")
469
+ self.cameraType?.queryRecordTimeSlice(
470
+ withYear: year,
471
+ month: month,
472
+ day: day
473
+ )
474
+ }
475
+ }
476
+
477
+ func getAvailableDays(
478
+ year: UInt,
479
+ month: UInt
480
+ ) {
481
+ withCameraType { cameraType in
482
+ self.updateStatus(datePickerLoader: true)
483
+ print("Tuya: Querying available days. Parameters - Year: \(year), Month: \(month)")
484
+ cameraType.queryRecordDays(
485
+ withYear: year,
486
+ month: month
487
+ )
488
+ }
489
+ }
490
+
491
+ func startPlayback(
492
+ playTime: Int,
493
+ startTime: Int,
494
+ stopTime: Int
495
+ ) {
496
+ withCameraType { cameraType in
497
+ self.updateStatus(playbackLoader: true)
498
+ cameraType.enterPlayback()
499
+ let result = cameraType.startPlayback(
500
+ playTime,
501
+ startTime: startTime,
502
+ stopTime: stopTime
503
+ )
504
+ print("Tuya: Start playback triggered. Result: \(result)")
505
+ }
506
+ }
507
+
508
+ func stopPlayback() {
509
+ withCameraType { cameraType in
510
+ let result = cameraType.stopPlayback()
511
+ print("Tuya: Stop playback triggered. Result: \(result)")
512
+ }
513
+ }
514
+
515
+ func resumePlayback() {
516
+ withCameraType { cameraType in
517
+ self.updateStatus(playbackLoader: true)
518
+ let result = cameraType.resumePlayback()
519
+ print("Tuya: Resume playback triggered. Result: \(result)")
520
+ }
521
+ }
522
+
523
+ func pausePlayback() {
524
+ withCameraType { cameraType in
525
+ self.updateStatus(playbackLoader: true)
526
+ let result = cameraType.pausePlayback()
527
+ print("Tuya: Pause playback triggered. Result: \(result)")
528
+ }
529
+ }
530
+
531
+ private func updateStatus(
532
+ isConnected: Bool? = nil,
533
+ isPreviewing: Bool? = nil,
534
+ isPlaybacking: Bool? = nil,
535
+ isMicOn: Bool? = nil,
536
+ previewLoader: Bool? = nil,
537
+ dashboardLoader: Bool? = nil,
538
+ playbackLoader: Bool? = nil,
539
+ datePickerLoader: Bool? = nil,
540
+ settingsLoader: Bool? = nil
541
+ ) {
542
+ if let isConnected = isConnected {
543
+ Tuya.shared.isConnected = isConnected
544
+ }
545
+ if let isPreviewing = isPreviewing {
546
+ Tuya.shared.isPreviewing = isPreviewing
547
+ }
548
+ if let isPlaybacking = isPlaybacking {
549
+ Tuya.shared.isPlaybacking = isPlaybacking
550
+ }
551
+ if let isMicOn = isMicOn {
552
+ Tuya.shared.isMicOn = isMicOn
553
+ }
554
+ if let previewLoader = previewLoader {
555
+ Tuya.shared.previewLoader = previewLoader
556
+ }
557
+ if let dashboardLoader = dashboardLoader {
558
+ Tuya.shared.dashboardLoader = dashboardLoader
559
+ }
560
+ if let playbackLoader = playbackLoader {
561
+ Tuya.shared.playbackLoader = playbackLoader
562
+ }
563
+ if let datePickerLoader = datePickerLoader {
564
+ Tuya.shared.datePickerLoader = datePickerLoader
565
+ }
566
+ if let settingsLoader = settingsLoader {
567
+ Tuya.shared.settingsLoader = settingsLoader
568
+ }
569
+ }
570
+ }
@@ -0,0 +1,98 @@
1
+ import ThingSmartCameraBase
2
+ import ThingSmartDeviceKit
3
+ import ThingSmartCameraKit
4
+
5
+ class TuyaMessages: NSObject {
6
+
7
+ static let shared = TuyaMessages()
8
+
9
+ private override init() {}
10
+
11
+ func getAvailableMessageDates(
12
+ year: Int,
13
+ month: Int,
14
+ success: @escaping ([Int]) -> Void,
15
+ failure: @escaping (Error?) -> Void
16
+ ) {
17
+ guard let messages = Tuya.shared.messages else {
18
+ print("Tuya: Messages is not initialized")
19
+ failure(nil)
20
+ return
21
+ }
22
+
23
+ Tuya.shared.datePickerLoader = true
24
+
25
+ messages.messageDays(
26
+ forYear: year,
27
+ month: month,
28
+ success: { days in
29
+ Tuya.shared.datePickerLoader = false
30
+ print("Tuya: get message days \(String(describing: days))")
31
+
32
+ if let days = days {
33
+ let updatedDays = days.compactMap { Int($0) }
34
+ success(updatedDays)
35
+ print("Updated Available Message Days: \(updatedDays)")
36
+ } else {
37
+ print("Tuya: No available days returned")
38
+ success([])
39
+ }
40
+ },
41
+ failure: { error in
42
+ Tuya.shared.datePickerLoader = false
43
+ Airbrake.logMessage(title: "Error in get messageDays", message: error?.localizedDescription ?? "")
44
+ failure(error)
45
+ }
46
+ )
47
+ }
48
+
49
+ func getMessages(
50
+ startDate: Date,
51
+ offset: Int,
52
+ completion: @escaping ([ThingSmartCameraMessageModel]?) -> Void
53
+ ) {
54
+ guard let messages = Tuya.shared.messages else {
55
+ print("Tuya: Messages is not initialized")
56
+ completion(nil)
57
+ return
58
+ }
59
+
60
+ Tuya.shared.messagesLoader = true
61
+
62
+ let selectedDateInSeconds = max(
63
+ Int(startDate.timeIntervalSince1970),
64
+ Tuya.shared.lastMoveoutAt.map { DateUtil.shared.convertToEpoch(isoDateString: $0) } ?? 0
65
+ )
66
+
67
+ // Calculate the endTime by adding 24 hours (86340 seconds)
68
+ let endTime = selectedDateInSeconds + 86340
69
+
70
+ print("Tuya: Fetching messages for: \(selectedDateInSeconds) to \(endTime), offset: \(offset)")
71
+
72
+ messages.getSchemes { result in
73
+ if let firstScheme = result?.first {
74
+ messages.messages(
75
+ withMessageCodes: firstScheme.msgCodes,
76
+ offset: offset,
77
+ limit: 20,
78
+ startTime: selectedDateInSeconds,
79
+ endTime: endTime
80
+ ) { resultArray in
81
+ completion(resultArray)
82
+ } failure: { error in
83
+ Airbrake.logMessage(title: "Error in getMessages", message: error?.localizedDescription ?? "")
84
+ Tuya.shared.messagesLoader = false
85
+ completion(nil)
86
+ }
87
+ } else {
88
+ print("Tuya: No schemes available")
89
+ Tuya.shared.messagesLoader = false
90
+ completion(nil)
91
+ }
92
+ } failure: { error in
93
+ Airbrake.logMessage(title: "Error in getMessageScheme", message: error?.localizedDescription ?? "")
94
+ Tuya.shared.messagesLoader = false
95
+ completion(nil)
96
+ }
97
+ }
98
+ }
@@ -0,0 +1,31 @@
1
+ import Foundation
2
+ import Airbrake_iOS
3
+
4
+ final class Airbrake {
5
+
6
+ static func initialize(apiKey: String, projectID: String) {
7
+ ABNotifier.start(
8
+ withAPIKey: apiKey,
9
+ projectID: projectID,
10
+ environmentName: ABNotifierAutomaticEnvironment,
11
+ useSSL: true
12
+ )
13
+ print("Tuya: Airbrake initialized successfully.")
14
+ }
15
+
16
+ static func logMessage(title: String, message: String, additionalInfo: [AnyHashable: Any]? = nil) {
17
+ print("Tuya: \(title) \(message) \(String(describing: additionalInfo))")
18
+
19
+ let exception = NSException(
20
+ name: NSExceptionName(rawValue: title),
21
+ reason: message,
22
+ userInfo: nil
23
+ )
24
+
25
+ if let additionalInfo = additionalInfo {
26
+ ABNotifier.logException(exception, parameters: additionalInfo)
27
+ } else {
28
+ ABNotifier.logException(exception)
29
+ }
30
+ }
31
+ }