peterluo3131 commited on
Commit
bcaee17
·
1 Parent(s): 4c99672

feature(#56): complete the functionality to schedule an alarm

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Android/app/src/main/AndroidManifest.xml +8 -0
  2. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/RisingApplication.kt +1 -0
  3. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ContactDao.kt +4 -4
  4. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ImageDao.kt +4 -4
  5. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ContactModel.kt +0 -8
  6. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/HelpPromptModel.kt +0 -8
  7. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/{AlarmModel.kt → chat/AlarmModel.kt} +1 -1
  8. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/{ChatMessageModel.kt → chat/ChatMessageModel.kt} +1 -1
  9. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ContactModel.kt +8 -0
  10. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/{HelpCommandModel.kt → chat/HelpCommandModel.kt} +1 -1
  11. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/HelpPromptModel.kt +22 -0
  12. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/{ImageModel.kt → chat/ImageModel.kt} +1 -1
  13. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chatwidgetprops/ScheduleAlarmProps.kt +46 -0
  14. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/common/Time.kt +7 -0
  15. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiClient.kt +8 -4
  16. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiService.kt +11 -0
  17. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/ImageRelatednessApiRequest.kt +9 -0
  18. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/TrainContactsApiRequest.kt +9 -0
  19. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/TrainImageApiRequest.kt +9 -0
  20. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/ApiResponse.kt +0 -5
  21. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/EmptyResultApiResponse.kt +7 -0
  22. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/Result.kt +9 -0
  23. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/TrainImageApiResponse.kt +12 -0
  24. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/FirebaseRepository.kt +41 -2
  25. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RemoteRepository.kt +85 -9
  26. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RoomRepository.kt +8 -8
  27. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/adapters/ChatMainAdapter.kt +106 -37
  28. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/fragments/ChatMainFragment.kt +183 -42
  29. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/ChatMessageInterface.kt +2 -0
  30. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/OnHideListener.kt +5 -0
  31. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/SendSmsWidget.kt +4 -8
  32. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/alarm/DayOfWeekItem.kt +54 -0
  33. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/alarm/ScheduleAlarmWidget.kt +110 -0
  34. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/ContactDetailWidget.kt +15 -13
  35. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/SearchContactWidget.kt +7 -5
  36. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptWidget.kt +4 -2
  37. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/toolbar/ChatToolsWidget.kt +1 -1
  38. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/viewmodel/ChatViewModel.kt +173 -26
  39. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/Constants.kt +12 -1
  40. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/CallbackTypes.kt +6 -0
  41. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/Converter.kt +13 -3
  42. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmHelper.kt +65 -25
  43. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmReceiver.kt +13 -0
  44. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/CommandHelper.kt +2 -6
  45. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ContactHelper.kt +92 -4
  46. Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ImageHelper.kt +15 -2
  47. Android/app/src/main/res/drawable/bg_circle_button_schedule_alarm_day.xml +6 -0
  48. Android/app/src/main/res/drawable/bg_circle_button_schedule_alarm_day_selected.xml +6 -0
  49. Android/app/src/main/res/drawable/bg_item_error_message.xml +7 -0
  50. Android/app/src/main/res/layout/item_container_chat_widget.xml +12 -0
Android/app/src/main/AndroidManifest.xml CHANGED
@@ -9,6 +9,9 @@
9
  <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
10
  <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
11
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 
 
 
12
  <uses-permission
13
  android:name="android.permission.WRITE_EXTERNAL_STORAGE"
14
  android:maxSdkVersion="32" />
@@ -48,6 +51,11 @@
48
  <category android:name="android.intent.category.LAUNCHER" />
49
  </intent-filter>
50
  </activity>
 
 
 
 
 
51
  </application>
52
 
53
  </manifest>
 
9
  <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
10
  <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
11
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
12
+ <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
13
+ <uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
14
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
15
  <uses-permission
16
  android:name="android.permission.WRITE_EXTERNAL_STORAGE"
17
  android:maxSdkVersion="32" />
 
51
  <category android:name="android.intent.category.LAUNCHER" />
52
  </intent-filter>
53
  </activity>
54
+
55
+ <receiver
56
+ android:name=".utils.helpers.chat.AlarmReceiver"
57
+ android:enabled="true"
58
+ android:exported="true" />
59
  </application>
60
 
61
  </manifest>
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/RisingApplication.kt CHANGED
@@ -3,6 +3,7 @@ package com.matthaigh27.chatgptwrapper
3
  import android.annotation.SuppressLint
4
  import android.app.Application
5
  import android.provider.Settings
 
6
  import com.google.android.gms.tasks.OnCompleteListener
7
  import com.google.firebase.messaging.FirebaseMessaging
8
 
 
3
  import android.annotation.SuppressLint
4
  import android.app.Application
5
  import android.provider.Settings
6
+ import android.util.Log
7
  import com.google.android.gms.tasks.OnCompleteListener
8
  import com.google.firebase.messaging.FirebaseMessaging
9
 
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ContactDao.kt CHANGED
@@ -7,14 +7,14 @@ import com.matthaigh27.chatgptwrapper.data.local.entity.ContactEntity
7
  @Dao
8
  interface ContactDao {
9
  @Insert
10
- fun insert(contact: ContactEntity)
11
 
12
  @Update
13
- fun update(contact: ContactEntity)
14
 
15
  @Delete
16
- fun delete(contact: ContactEntity)
17
 
18
  @Query("SELECT * FROM contacts")
19
- fun getAllData(): List<ContactEntity>
20
  }
 
7
  @Dao
8
  interface ContactDao {
9
  @Insert
10
+ suspend fun insert(contact: ContactEntity)
11
 
12
  @Update
13
+ suspend fun update(contact: ContactEntity)
14
 
15
  @Delete
16
+ suspend fun delete(contact: ContactEntity)
17
 
18
  @Query("SELECT * FROM contacts")
19
+ suspend fun getAllData(): List<ContactEntity>
20
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ImageDao.kt CHANGED
@@ -7,14 +7,14 @@ import com.matthaigh27.chatgptwrapper.data.local.entity.ImageEntity
7
  @Dao
8
  interface ImageDao {
9
  @Insert
10
- fun insert(image: ImageEntity)
11
 
12
  @Update
13
- fun update(image: ImageEntity)
14
 
15
  @Delete
16
- fun delete(image: ImageEntity)
17
 
18
  @Query("SELECT * FROM images")
19
- fun getAllData(): List<ImageEntity>
20
  }
 
7
  @Dao
8
  interface ImageDao {
9
  @Insert
10
+ suspend fun insert(image: ImageEntity)
11
 
12
  @Update
13
+ suspend fun update(image: ImageEntity)
14
 
15
  @Delete
16
+ suspend fun delete(image: ImageEntity)
17
 
18
  @Query("SELECT * FROM images")
19
+ suspend fun getAllData(): List<ImageEntity>
20
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ContactModel.kt DELETED
@@ -1,8 +0,0 @@
1
- package com.matthaigh27.chatgptwrapper.data.models
2
-
3
- data class ContactModel(
4
- var id: String = "",
5
- var name: String = "",
6
- var phoneList: ArrayList<String> = ArrayList(),
7
- var status: String = ""
8
- )
 
 
 
 
 
 
 
 
 
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/HelpPromptModel.kt DELETED
@@ -1,8 +0,0 @@
1
- package com.matthaigh27.chatgptwrapper.data.models
2
-
3
- data class HelpPromptModel(
4
- var name: String = "",
5
- var description: String = "",
6
- var prompt: String = "",
7
- var tags: ArrayList<String> = ArrayList()
8
- )
 
 
 
 
 
 
 
 
 
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/{AlarmModel.kt → chat/AlarmModel.kt} RENAMED
@@ -1,3 +1,3 @@
1
- package com.matthaigh27.chatgptwrapper.data.models
2
 
3
  data class AlarmModel(val id: Int, val time: Long, val enabled: Boolean, val label: String)
 
1
+ package com.matthaigh27.chatgptwrapper.data.models.chat
2
 
3
  data class AlarmModel(val id: Int, val time: Long, val enabled: Boolean, val label: String)
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/{ChatMessageModel.kt → chat/ChatMessageModel.kt} RENAMED
@@ -1,4 +1,4 @@
1
- package com.matthaigh27.chatgptwrapper.data.models
2
 
3
  import com.google.gson.JsonElement
4
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.models.chat
2
 
3
  import com.google.gson.JsonElement
4
 
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ContactModel.kt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.models.chat
2
+
3
+ data class ContactModel(
4
+ var contactId: String = String(),
5
+ var displayName: String = String(),
6
+ var phoneNumbers: ArrayList<String> = ArrayList(),
7
+ var status: String = String()
8
+ )
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/{HelpCommandModel.kt → chat/HelpCommandModel.kt} RENAMED
@@ -1,4 +1,4 @@
1
- package com.matthaigh27.chatgptwrapper.data.models
2
 
3
  data class HelpCommandModel (
4
  var main: String? = null,
 
1
+ package com.matthaigh27.chatgptwrapper.data.models.chat
2
 
3
  data class HelpCommandModel (
4
  var main: String? = null,
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/HelpPromptModel.kt ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.models.chat
2
+
3
+ import com.google.gson.Gson
4
+
5
+ data class HelpPromptModel(
6
+ var name: String = "",
7
+ var description: String = "",
8
+ var prompt: String = "",
9
+ var tags: ArrayList<String> = ArrayList()
10
+ ) {
11
+ override fun toString(): String {
12
+ val gson = Gson()
13
+ return gson.toJson(this)
14
+ }
15
+
16
+ companion object {
17
+ fun init(string: String): HelpPromptModel {
18
+ val gson = Gson()
19
+ return gson.fromJson(string, HelpPromptModel::class.java)
20
+ }
21
+ }
22
+ }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/{ImageModel.kt → chat/ImageModel.kt} RENAMED
@@ -1,4 +1,4 @@
1
- package com.matthaigh27.chatgptwrapper.data.models
2
 
3
  import android.net.Uri
4
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.models.chat
2
 
3
  import android.net.Uri
4
 
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chatwidgetprops/ScheduleAlarmProps.kt ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.models.chatwidgetprops
2
+
3
+ import com.google.gson.Gson
4
+ import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel
5
+ import com.matthaigh27.chatgptwrapper.data.models.common.Time
6
+
7
+ data class ScheduleAlarmProps(
8
+ val time: Time? = null,
9
+ val label: String? = null,
10
+ val repeat: BooleanArray? = null
11
+ ) {
12
+ override fun equals(other: Any?): Boolean {
13
+ if (this === other) return true
14
+ if (javaClass != other?.javaClass) return false
15
+
16
+ other as ScheduleAlarmProps
17
+
18
+ if (time != other.time) return false
19
+ if (repeat != null) {
20
+ if (other.repeat == null) return false
21
+ if (!repeat.contentEquals(other.repeat)) return false
22
+ } else if (other.repeat != null) return false
23
+ if (label != other.label) return false
24
+
25
+ return true
26
+ }
27
+
28
+ override fun hashCode(): Int {
29
+ var result = time?.hashCode() ?: 0
30
+ result = 31 * result + (repeat?.contentHashCode() ?: 0)
31
+ result = 31 * result + (label?.hashCode() ?: 0)
32
+ return result
33
+ }
34
+
35
+ override fun toString(): String {
36
+ val gson = Gson()
37
+ return gson.toJson(this)
38
+ }
39
+
40
+ companion object {
41
+ fun init(string: String): ScheduleAlarmProps {
42
+ val gson = Gson()
43
+ return gson.fromJson(string, ScheduleAlarmProps::class.java)
44
+ }
45
+ }
46
+ }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/common/Time.kt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.models.common
2
+
3
+ data class Time (
4
+ val hour:Int,
5
+ val minute:Int,
6
+ val second:Int,
7
+ )
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiClient.kt CHANGED
@@ -1,6 +1,10 @@
1
  package com.matthaigh27.chatgptwrapper.data.remote
2
 
3
  import com.matthaigh27.chatgptwrapper.utils.Constants.API_BASE_URL
 
 
 
 
4
  import okhttp3.OkHttpClient
5
  import okhttp3.logging.HttpLoggingInterceptor
6
  import retrofit2.Retrofit
@@ -9,10 +13,10 @@ import java.util.concurrent.TimeUnit
9
 
10
  object ApiClient {
11
  private val client = OkHttpClient.Builder()
12
- .callTimeout(240, TimeUnit.SECONDS)
13
- .connectTimeout(240, TimeUnit.SECONDS)
14
- .readTimeout(240, TimeUnit.SECONDS)
15
- .writeTimeout(240, TimeUnit.SECONDS)
16
  .build()
17
 
18
  private val retrofit = Retrofit.Builder()
 
1
  package com.matthaigh27.chatgptwrapper.data.remote
2
 
3
  import com.matthaigh27.chatgptwrapper.utils.Constants.API_BASE_URL
4
+ import com.matthaigh27.chatgptwrapper.utils.Constants.TIME_OUT_CALL
5
+ import com.matthaigh27.chatgptwrapper.utils.Constants.TIME_OUT_CONNECT
6
+ import com.matthaigh27.chatgptwrapper.utils.Constants.TIME_OUT_READ
7
+ import com.matthaigh27.chatgptwrapper.utils.Constants.TIME_OUT_WRITE
8
  import okhttp3.OkHttpClient
9
  import okhttp3.logging.HttpLoggingInterceptor
10
  import retrofit2.Retrofit
 
13
 
14
  object ApiClient {
15
  private val client = OkHttpClient.Builder()
16
+ .callTimeout(TIME_OUT_CALL, TimeUnit.SECONDS)
17
+ .connectTimeout(TIME_OUT_CONNECT, TimeUnit.SECONDS)
18
+ .readTimeout(TIME_OUT_READ, TimeUnit.SECONDS)
19
+ .writeTimeout(TIME_OUT_WRITE, TimeUnit.SECONDS)
20
  .build()
21
 
22
  private val retrofit = Retrofit.Builder()
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiService.kt CHANGED
@@ -1,8 +1,13 @@
1
  package com.matthaigh27.chatgptwrapper.data.remote
2
 
3
  import com.matthaigh27.chatgptwrapper.data.remote.requests.BaseApiRequest
 
4
  import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
 
 
5
  import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
 
 
6
  import retrofit2.Call
7
  import retrofit2.http.Body
8
  import retrofit2.http.POST
@@ -12,4 +17,10 @@ interface ApiService {
12
  fun getAllHelpCommands(@Body request: BaseApiRequest) : Call<ApiResponse>
13
  @POST("sendNotification")
14
  fun sendNotification(@Body request: NotificationApiRequest) : Call<ApiResponse>
 
 
 
 
 
 
15
  }
 
1
  package com.matthaigh27.chatgptwrapper.data.remote
2
 
3
  import com.matthaigh27.chatgptwrapper.data.remote.requests.BaseApiRequest
4
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.ImageRelatednessApiRequest
5
  import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
6
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainContactsApiRequest
7
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainImageApiRequest
8
  import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
9
+ import com.matthaigh27.chatgptwrapper.data.remote.responses.EmptyResultApiResponse
10
+ import com.matthaigh27.chatgptwrapper.data.remote.responses.TrainImageApiResponse
11
  import retrofit2.Call
12
  import retrofit2.http.Body
13
  import retrofit2.http.POST
 
17
  fun getAllHelpCommands(@Body request: BaseApiRequest) : Call<ApiResponse>
18
  @POST("sendNotification")
19
  fun sendNotification(@Body request: NotificationApiRequest) : Call<ApiResponse>
20
+ @POST("train/contacts")
21
+ fun trainContacts(@Body request: TrainContactsApiRequest) : Call<EmptyResultApiResponse>
22
+ @POST("image_relatedness")
23
+ fun getImageRelatedness(@Body request: ImageRelatednessApiRequest) : Call<ApiResponse>
24
+ @POST("uploadImage")
25
+ fun trainImage(@Body request: TrainImageApiRequest) : Call<TrainImageApiResponse>
26
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/ImageRelatednessApiRequest.kt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.remote.requests
2
+
3
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys
4
+
5
+ data class ImageRelatednessApiRequest(
6
+ val image_name: String,
7
+ val message: String,
8
+ val confs: Keys
9
+ )
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/TrainContactsApiRequest.kt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.remote.requests
2
+
3
+ import com.matthaigh27.chatgptwrapper.data.models.chat.ContactModel
4
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys
5
+
6
+ data class TrainContactsApiRequest(
7
+ val contacts: ArrayList<ContactModel>,
8
+ val confs: Keys
9
+ )
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/TrainImageApiRequest.kt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.remote.requests
2
+
3
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys
4
+
5
+ data class TrainImageApiRequest(
6
+ val image_name: String,
7
+ val status: String,
8
+ val confs: Keys
9
+ )
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/ApiResponse.kt CHANGED
@@ -8,8 +8,3 @@ data class ApiResponse (
8
  val result: Result
9
  )
10
 
11
- data class Result (
12
- val program: String,
13
- val content: JsonElement,
14
- val url: String
15
- )
 
8
  val result: Result
9
  )
10
 
 
 
 
 
 
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/EmptyResultApiResponse.kt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.remote.responses
2
+
3
+ data class EmptyResultApiResponse(
4
+ val status_code: Int,
5
+ val message: List<String>,
6
+ val result: String
7
+ )
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/Result.kt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.remote.responses
2
+
3
+ import com.google.gson.JsonElement
4
+
5
+ data class Result (
6
+ val program: String,
7
+ val content: JsonElement,
8
+ val url: String
9
+ )
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/TrainImageApiResponse.kt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.data.remote.responses
2
+
3
+ data class TrainImageApiResponse(
4
+ val status_code: Int,
5
+ val message: List<String>,
6
+ val result: ImageInfo
7
+ )
8
+
9
+ data class ImageInfo(
10
+ val image_name: String,
11
+ val image_text: String
12
+ )
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/FirebaseRepository.kt CHANGED
@@ -1,8 +1,14 @@
1
  package com.matthaigh27.chatgptwrapper.data.repository
2
 
3
  import com.google.firebase.storage.FirebaseStorage
4
- import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnFailure
5
- import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnSuccess
 
 
 
 
 
 
6
 
7
  object FirebaseRepository {
8
  fun downloadImageWithName(
@@ -20,4 +26,37 @@ object FirebaseRepository {
20
  }
21
  return
22
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
 
1
  package com.matthaigh27.chatgptwrapper.data.repository
2
 
3
  import com.google.firebase.storage.FirebaseStorage
4
+ import com.google.protobuf.Empty
5
+ import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
6
+ import com.matthaigh27.chatgptwrapper.utils.helpers.OnFailure
7
+ import com.matthaigh27.chatgptwrapper.utils.helpers.OnSuccess
8
+ import kotlinx.coroutines.suspendCancellableCoroutine
9
+ import java.util.UUID
10
+ import kotlin.coroutines.resume
11
+ import kotlin.coroutines.suspendCoroutine
12
 
13
  object FirebaseRepository {
14
  fun downloadImageWithName(
 
26
  }
27
  return
28
  }
29
+
30
+ fun uploadImageAsync(
31
+ imageByteArray: ByteArray,
32
+ onSuccess: OnSuccess<String>,
33
+ onFailure: OnFailure<String>
34
+ ) {
35
+ val storageRef = FirebaseStorage.getInstance().reference
36
+ val uuid = UUID.randomUUID()
37
+ val imageName = "images/${uuid}"
38
+ val imageRef = storageRef.child(imageName)
39
+
40
+ val uploadTask = imageRef.putBytes(imageByteArray)
41
+ uploadTask.addOnFailureListener {
42
+ onFailure("Fail to upload image to firebase.")
43
+ }.addOnSuccessListener {
44
+ onSuccess("$uuid")
45
+ }
46
+ }
47
+
48
+ suspend fun uploadImage(imageByteArray: ByteArray): String = suspendCoroutine { continuation ->
49
+ val storageRef = FirebaseStorage.getInstance().reference
50
+ val uuid = UUID.randomUUID()
51
+ val imageName = "images/${uuid}"
52
+ val imageRef = storageRef.child(imageName)
53
+
54
+ val uploadTask = imageRef.putBytes(imageByteArray)
55
+
56
+ uploadTask.addOnFailureListener {
57
+ continuation.resume("Error")
58
+ }.addOnSuccessListener {
59
+ continuation.resume("$uuid")
60
+ }
61
+ }
62
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RemoteRepository.kt CHANGED
@@ -1,30 +1,37 @@
1
  package com.matthaigh27.chatgptwrapper.data.repository
2
 
3
  import com.matthaigh27.chatgptwrapper.data.remote.ApiClient
 
 
4
  import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
 
 
5
  import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
6
- import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnFailure
7
- import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnSuccess
 
 
8
  import com.matthaigh27.chatgptwrapper.utils.helpers.network.RequestFactory.buildBaseApiRequest
9
  import retrofit2.Call
10
  import retrofit2.Callback
11
  import retrofit2.Response
 
 
12
 
13
 
14
  object RemoteRepository {
15
  private val apiService = ApiClient.apiService
16
 
17
  fun getAllHelpCommands(
18
- onSuccess: OnSuccess<ApiResponse>,
19
- onFailure: OnFailure<String>
20
  ) {
21
  val call = apiService.getAllHelpCommands(buildBaseApiRequest())
22
 
23
  call.enqueue(object : Callback<ApiResponse> {
24
  override fun onResponse(call: Call<ApiResponse>, response: Response<ApiResponse>) {
25
- response.body()?.let {
26
- onSuccess(ApiResponse(it.status_code, it.message, it.result))
27
- }?: run {
28
  onFailure(response.message())
29
  }
30
  }
@@ -45,8 +52,77 @@ object RemoteRepository {
45
  call.enqueue(object : Callback<ApiResponse> {
46
  override fun onResponse(call: Call<ApiResponse>, response: Response<ApiResponse>) {
47
  response.body()?.let { data ->
48
- onSuccess(ApiResponse(data.status_code, data.message, data.result))
49
- }?: run {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  onFailure(response.message())
51
  }
52
  }
 
1
  package com.matthaigh27.chatgptwrapper.data.repository
2
 
3
  import com.matthaigh27.chatgptwrapper.data.remote.ApiClient
4
+ import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
5
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.ImageRelatednessApiRequest
6
  import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
7
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainContactsApiRequest
8
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainImageApiRequest
9
  import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
10
+ import com.matthaigh27.chatgptwrapper.data.remote.responses.EmptyResultApiResponse
11
+ import com.matthaigh27.chatgptwrapper.data.remote.responses.TrainImageApiResponse
12
+ import com.matthaigh27.chatgptwrapper.utils.helpers.OnFailure
13
+ import com.matthaigh27.chatgptwrapper.utils.helpers.OnSuccess
14
  import com.matthaigh27.chatgptwrapper.utils.helpers.network.RequestFactory.buildBaseApiRequest
15
  import retrofit2.Call
16
  import retrofit2.Callback
17
  import retrofit2.Response
18
+ import kotlin.coroutines.resume
19
+ import kotlin.coroutines.suspendCoroutine
20
 
21
 
22
  object RemoteRepository {
23
  private val apiService = ApiClient.apiService
24
 
25
  fun getAllHelpCommands(
26
+ onSuccess: OnSuccess<ApiResponse>, onFailure: OnFailure<String>
 
27
  ) {
28
  val call = apiService.getAllHelpCommands(buildBaseApiRequest())
29
 
30
  call.enqueue(object : Callback<ApiResponse> {
31
  override fun onResponse(call: Call<ApiResponse>, response: Response<ApiResponse>) {
32
+ response.body()?.let { data ->
33
+ onSuccess(data)
34
+ } ?: run {
35
  onFailure(response.message())
36
  }
37
  }
 
52
  call.enqueue(object : Callback<ApiResponse> {
53
  override fun onResponse(call: Call<ApiResponse>, response: Response<ApiResponse>) {
54
  response.body()?.let { data ->
55
+ onSuccess(data)
56
+ } ?: run {
57
+ onFailure(response.message())
58
+ }
59
+ }
60
+
61
+ override fun onFailure(call: Call<ApiResponse>, t: Throwable) {
62
+ onFailure(t.message.toString())
63
+ }
64
+ })
65
+ }
66
+
67
+ fun trainContacts(
68
+ request: TrainContactsApiRequest,
69
+ onSuccess: OnSuccess<EmptyResultApiResponse>,
70
+ onFailure: OnFailure<String>
71
+ ) {
72
+ val call = apiService.trainContacts(request)
73
+
74
+ call.enqueue(object : Callback<EmptyResultApiResponse> {
75
+ override fun onResponse(
76
+ call: Call<EmptyResultApiResponse>, response: Response<EmptyResultApiResponse>
77
+ ) {
78
+ response.body()?.let { data ->
79
+ onSuccess(data)
80
+ } ?: run {
81
+ onFailure(response.message())
82
+ }
83
+ }
84
+
85
+ override fun onFailure(call: Call<EmptyResultApiResponse>, t: Throwable) {
86
+ onFailure(t.message.toString())
87
+ }
88
+ })
89
+ }
90
+
91
+ suspend fun trainImage(request: TrainImageApiRequest) : ApiResource<TrainImageApiResponse> = suspendCoroutine { continuation ->
92
+
93
+ val call = apiService.trainImage(request)
94
+
95
+ call.enqueue(object : Callback<TrainImageApiResponse> {
96
+ override fun onResponse(
97
+ call: Call<TrainImageApiResponse>, response: Response<TrainImageApiResponse>
98
+ ) {
99
+ response.body()?.let { data ->
100
+ continuation.resume(ApiResource.Success(data))
101
+ } ?: run {
102
+ continuation.resume(ApiResource.Error("Error"))
103
+ }
104
+ }
105
+
106
+ override fun onFailure(call: Call<TrainImageApiResponse>, t: Throwable) {
107
+ continuation.resume(ApiResource.Error(t.message.toString()))
108
+ }
109
+ })
110
+ }
111
+
112
+ fun getImageRelatedness(
113
+ request: ImageRelatednessApiRequest,
114
+ onSuccess: OnSuccess<ApiResponse>,
115
+ onFailure: OnFailure<String>
116
+ ) {
117
+ val call = apiService.getImageRelatedness(request)
118
+
119
+ call.enqueue(object : Callback<ApiResponse> {
120
+ override fun onResponse(
121
+ call: Call<ApiResponse>, response: Response<ApiResponse>
122
+ ) {
123
+ response.body()?.let { data ->
124
+ onSuccess(data)
125
+ } ?: run {
126
  onFailure(response.message())
127
  }
128
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RoomRepository.kt CHANGED
@@ -13,35 +13,35 @@ object RoomRepository {
13
  private var imageDao = databaseHandler.imageDao()
14
  private var contactDao = databaseHandler.contactDao()
15
 
16
- fun getAllImages(): MutableLiveData<List<ImageEntity>> {
17
  return MutableLiveData(imageDao.getAllData())
18
  }
19
 
20
- fun insertImage(entity: ImageEntity) {
21
  imageDao.insert(entity)
22
  }
23
 
24
- fun updateImage(entity: ImageEntity) {
25
  imageDao.update(entity)
26
  }
27
 
28
- fun deleteImage(entity: ImageEntity) {
29
  imageDao.delete(entity)
30
  }
31
 
32
- fun getAllContacts(): MutableLiveData<List<ContactEntity>> {
33
  return MutableLiveData(contactDao.getAllData())
34
  }
35
 
36
- fun insertImage(entity: ContactEntity) {
37
  contactDao.insert(entity)
38
  }
39
 
40
- fun updateImage(entity: ContactEntity) {
41
  contactDao.update(entity)
42
  }
43
 
44
- fun deleteImage(entity: ContactEntity) {
45
  contactDao.delete(entity)
46
  }
47
  }
 
13
  private var imageDao = databaseHandler.imageDao()
14
  private var contactDao = databaseHandler.contactDao()
15
 
16
+ suspend fun getAllImages(): MutableLiveData<List<ImageEntity>> {
17
  return MutableLiveData(imageDao.getAllData())
18
  }
19
 
20
+ suspend fun insertImage(entity: ImageEntity) {
21
  imageDao.insert(entity)
22
  }
23
 
24
+ suspend fun updateImage(entity: ImageEntity) {
25
  imageDao.update(entity)
26
  }
27
 
28
+ suspend fun deleteImage(entity: ImageEntity) {
29
  imageDao.delete(entity)
30
  }
31
 
32
+ suspend fun getAllContacts(): MutableLiveData<List<ContactEntity>> {
33
  return MutableLiveData(contactDao.getAllData())
34
  }
35
 
36
+ suspend fun insertContact(entity: ContactEntity) {
37
  contactDao.insert(entity)
38
  }
39
 
40
+ suspend fun updateContact(entity: ContactEntity) {
41
  contactDao.update(entity)
42
  }
43
 
44
+ suspend fun deleteContact(entity: ContactEntity) {
45
  contactDao.delete(entity)
46
  }
47
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/adapters/ChatMainAdapter.kt CHANGED
@@ -7,16 +7,29 @@ import android.view.View
7
  import android.view.ViewGroup
8
  import android.widget.FrameLayout
9
  import android.widget.ImageView
 
10
  import android.widget.TextView
11
  import androidx.constraintlayout.widget.ConstraintLayout
12
  import androidx.recyclerview.widget.RecyclerView
13
  import com.matthaigh27.chatgptwrapper.R
14
- import com.matthaigh27.chatgptwrapper.data.models.ChatMessageModel
 
 
15
  import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
 
16
  import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.SendSmsWidget
 
 
17
  import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.helpprompt.HelpPromptWidget
18
- import com.matthaigh27.chatgptwrapper.utils.Constants
 
 
 
 
 
 
19
  import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper
 
20
 
21
  class ChatMainAdapter(
22
  context: Context, list: ArrayList<ChatMessageModel>, callbacks: ChatMessageInterface
@@ -25,6 +38,7 @@ class ChatMainAdapter(
25
  private val VIEW_TYPE_MSG_SENT = 0
26
  private val VIEW_TYPE_MSG_RECEIVED = 1
27
  private val VIEW_TYPE_CHAT_WIDGET = 2
 
28
 
29
  private var context: Context
30
  private var callbacks: ChatMessageInterface
@@ -41,7 +55,7 @@ class ChatMainAdapter(
41
 
42
  return when (viewType) {
43
  VIEW_TYPE_MSG_SENT -> {
44
- SentMessageViewHolder(
45
  inflater.inflate(
46
  R.layout.item_container_sent_message, parent, false
47
  )
@@ -49,13 +63,21 @@ class ChatMainAdapter(
49
  }
50
 
51
  VIEW_TYPE_MSG_RECEIVED -> {
52
- ReceivedMessageViewHolder(
53
  inflater.inflate(
54
  R.layout.item_container_received_message, parent, false
55
  )
56
  )
57
  }
58
 
 
 
 
 
 
 
 
 
59
  else -> {
60
  ChatWidgetViewHolder(
61
  inflater.inflate(
@@ -78,25 +100,17 @@ class ChatMainAdapter(
78
  val index = holder.adapterPosition
79
  val chatMessageModel: ChatMessageModel = chatMessageList[index]
80
  when (chatMessageModel.type) {
81
- VIEW_TYPE_MSG_SENT -> {
82
- setMessageData(holder as SentMessageViewHolder, chatMessageModel)
83
- }
84
-
85
- VIEW_TYPE_MSG_RECEIVED -> {
86
- setMessageData(holder as ReceivedMessageViewHolder, chatMessageModel)
87
  }
88
 
89
  else -> {
90
- setMessageData(holder as ChatWidgetViewHolder, chatMessageModel)
91
  }
92
  }
93
  }
94
 
95
- private fun setMessageData(holder: SentMessageViewHolder, data: ChatMessageModel) {
96
- holder.txtMessage.text = data.content
97
- }
98
-
99
- private fun setMessageData(holder: ReceivedMessageViewHolder, data: ChatMessageModel) {
100
  if (data.hasImage) {
101
  data.image?.let { image ->
102
  val originBitmap = BitmapFactory.decodeByteArray(image, 0, image.size)
@@ -114,48 +128,101 @@ class ChatMainAdapter(
114
  } else {
115
  holder.txtMessage.text = data.content
116
  holder.imgMessage.visibility = View.GONE
117
- holder.txtMessage.visibility = View.VISIBLE
 
 
 
 
118
  }
119
  }
120
 
121
  private fun setMessageData(holder: ChatWidgetViewHolder, data: ChatMessageModel) {
 
 
 
122
  when (data.content) {
123
- Constants.TYPE_WIDGET_SMS -> {
124
  val sendSmsWidget = SendSmsWidget(context).apply {
125
  this.callback = callbacks
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
 
127
  holder.itemLayout.addView(sendSmsWidget)
128
- holder.itemLayout.visibility = View.VISIBLE
129
  }
130
 
131
- Constants.TYPE_WIDGET_HELP_PROMPT -> {
132
- // val helpPromptWidget = HelpPromptWidget(context)
 
 
 
 
 
 
 
 
 
 
 
 
133
  }
134
 
135
- Constants.TYPE_WIDGET_SEARCH_CONTACT -> {
 
136
 
137
- }
138
 
139
- Constants.TYPE_WIDGET_FEEDBACK -> {
 
 
 
140
 
 
 
 
 
 
141
  }
142
- }
143
- }
144
 
145
- inner class ReceivedMessageViewHolder internal constructor(itemView: View) :
146
- RecyclerView.ViewHolder(itemView) {
147
- var txtMessage: TextView
148
- var imgMessage: ImageView
149
- var itemLayout: ConstraintLayout
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
- init {
152
- txtMessage = itemView.findViewById<View>(R.id.txt_message) as TextView
153
- imgMessage = itemView.findViewById<View>(R.id.img_message) as ImageView
154
- itemLayout = itemView.findViewById<View>(R.id.cl_received_message) as ConstraintLayout
155
  }
156
  }
157
 
158
- inner class SentMessageViewHolder internal constructor(itemView: View) :
159
  RecyclerView.ViewHolder(itemView) {
160
  var txtMessage: TextView
161
  var imgMessage: ImageView
@@ -164,16 +231,18 @@ class ChatMainAdapter(
164
  init {
165
  txtMessage = itemView.findViewById<View>(R.id.txt_message) as TextView
166
  imgMessage = itemView.findViewById<View>(R.id.img_message) as ImageView
167
- itemLayout = itemView.findViewById<View>(R.id.cl_sent_message) as ConstraintLayout
168
  }
169
  }
170
 
171
  inner class ChatWidgetViewHolder internal constructor(itemView: View) :
172
  RecyclerView.ViewHolder(itemView) {
173
  var itemLayout: FrameLayout
 
174
 
175
  init {
176
  itemLayout = itemView.findViewById<View>(R.id.fl_widget_message) as FrameLayout
 
177
  }
178
  }
179
  }
 
7
  import android.view.ViewGroup
8
  import android.widget.FrameLayout
9
  import android.widget.ImageView
10
+ import android.widget.LinearLayout
11
  import android.widget.TextView
12
  import androidx.constraintlayout.widget.ConstraintLayout
13
  import androidx.recyclerview.widget.RecyclerView
14
  import com.matthaigh27.chatgptwrapper.R
15
+ import com.matthaigh27.chatgptwrapper.data.models.chat.ChatMessageModel
16
+ import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel
17
+ import com.matthaigh27.chatgptwrapper.data.models.chatwidgetprops.ScheduleAlarmProps
18
  import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
19
+ import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.OnHideListener
20
  import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.SendSmsWidget
21
+ import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.alarm.ScheduleAlarmWidget
22
+ import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.contact.SearchContactWidget
23
  import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.helpprompt.HelpPromptWidget
24
+ import com.matthaigh27.chatgptwrapper.utils.Constants.PROPS_WIDGET_DESC
25
+ import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_HELP_PROMPT
26
+ import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SCHEDULE_ALARM
27
+ import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SEARCH_CONTACT
28
+ import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SMS
29
+ import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ContactHelper.getContactModelById
30
+ import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ContactHelper.getContacts
31
  import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper
32
+ import org.json.JSONArray
33
 
34
  class ChatMainAdapter(
35
  context: Context, list: ArrayList<ChatMessageModel>, callbacks: ChatMessageInterface
 
38
  private val VIEW_TYPE_MSG_SENT = 0
39
  private val VIEW_TYPE_MSG_RECEIVED = 1
40
  private val VIEW_TYPE_CHAT_WIDGET = 2
41
+ private val VIEW_TYPE_CHAT_ERROR = 3
42
 
43
  private var context: Context
44
  private var callbacks: ChatMessageInterface
 
55
 
56
  return when (viewType) {
57
  VIEW_TYPE_MSG_SENT -> {
58
+ MessageViewHolder(
59
  inflater.inflate(
60
  R.layout.item_container_sent_message, parent, false
61
  )
 
63
  }
64
 
65
  VIEW_TYPE_MSG_RECEIVED -> {
66
+ MessageViewHolder(
67
  inflater.inflate(
68
  R.layout.item_container_received_message, parent, false
69
  )
70
  )
71
  }
72
 
73
+ VIEW_TYPE_CHAT_ERROR -> {
74
+ MessageViewHolder(
75
+ inflater.inflate(
76
+ R.layout.item_container_error_message, parent, false
77
+ )
78
+ )
79
+ }
80
+
81
  else -> {
82
  ChatWidgetViewHolder(
83
  inflater.inflate(
 
100
  val index = holder.adapterPosition
101
  val chatMessageModel: ChatMessageModel = chatMessageList[index]
102
  when (chatMessageModel.type) {
103
+ VIEW_TYPE_CHAT_WIDGET -> {
104
+ setMessageData(holder as ChatWidgetViewHolder, chatMessageModel)
 
 
 
 
105
  }
106
 
107
  else -> {
108
+ setMessageData(holder as MessageViewHolder, chatMessageModel)
109
  }
110
  }
111
  }
112
 
113
+ private fun setMessageData(holder: MessageViewHolder, data: ChatMessageModel) {
 
 
 
 
114
  if (data.hasImage) {
115
  data.image?.let { image ->
116
  val originBitmap = BitmapFactory.decodeByteArray(image, 0, image.size)
 
128
  } else {
129
  holder.txtMessage.text = data.content
130
  holder.imgMessage.visibility = View.GONE
131
+ data.content?.let {
132
+ holder.txtMessage.visibility = View.VISIBLE
133
+ } ?: run {
134
+ holder.txtMessage.visibility = View.GONE
135
+ }
136
  }
137
  }
138
 
139
  private fun setMessageData(holder: ChatWidgetViewHolder, data: ChatMessageModel) {
140
+ holder.itemLayout.visibility = View.VISIBLE
141
+ val index = holder.adapterPosition
142
+
143
  when (data.content) {
144
+ TYPE_WIDGET_SMS -> {
145
  val sendSmsWidget = SendSmsWidget(context).apply {
146
  this.callback = callbacks
147
+ this.hideListener = object : OnHideListener {
148
+ override fun hide() {
149
+ holder.itemLayout.visibility = View.GONE
150
+ chatMessageList.removeAt(index)
151
+ notifyItemRemoved(index)
152
+ }
153
+ }
154
+ }
155
+
156
+ if (data.data != null) {
157
+ val widgetDesc = data.data.asJsonObject[PROPS_WIDGET_DESC].asString
158
+ if (widgetDesc.isNotEmpty()) {
159
+ sendSmsWidget.setPhoneNumber(widgetDesc)
160
+ }
161
  }
162
+
163
  holder.itemLayout.addView(sendSmsWidget)
 
164
  }
165
 
166
+ TYPE_WIDGET_HELP_PROMPT -> {
167
+ val widgetDesc = data.data!!.asJsonObject[PROPS_WIDGET_DESC].asString
168
+ val helpPromptWidget =
169
+ HelpPromptWidget(context, HelpPromptModel.init(widgetDesc)).apply {
170
+ this.callback = callbacks
171
+ this.hideListener = object : OnHideListener {
172
+ override fun hide() {
173
+ holder.itemLayout.visibility = View.GONE
174
+ chatMessageList.removeAt(index)
175
+ notifyItemRemoved(index)
176
+ }
177
+ }
178
+ }
179
+ holder.itemLayout.addView(helpPromptWidget)
180
  }
181
 
182
+ TYPE_WIDGET_SEARCH_CONTACT -> {
183
+ holder.llSearchContact.visibility = View.VISIBLE
184
 
185
+ val contacts = getContacts(context)
186
 
187
+ val contactIds = JSONArray(data.data!!.asString.replace("'", "\""))
188
+ for (i in 0 until contactIds.length()) {
189
+ val contactId = contactIds[i].toString()
190
+ val contact = getContactModelById(contactId, contacts)
191
 
192
+ val searchContactWidget = SearchContactWidget(context, contact).apply {
193
+ this.callback = callbacks
194
+ }
195
+ holder.llSearchContact.addView(searchContactWidget)
196
+ }
197
  }
 
 
198
 
199
+ TYPE_WIDGET_SCHEDULE_ALARM -> {
200
+ var props = ScheduleAlarmProps()
201
+ data.data?.run {
202
+ val widgetDesc = data.data.asJsonObject[PROPS_WIDGET_DESC].asString
203
+ props = ScheduleAlarmProps.init(widgetDesc)
204
+ }
205
+ val scheduleAlarmWidget =
206
+ ScheduleAlarmWidget(context, props.time, props.label, props.repeat).apply {
207
+ this.callback = callbacks
208
+ this.hideListener = object : OnHideListener {
209
+ override fun hide() {
210
+ holder.itemLayout.visibility = View.GONE
211
+ chatMessageList.removeAt(index)
212
+ notifyItemRemoved(index)
213
+ }
214
+ }
215
+ }
216
+ holder.itemLayout.addView(scheduleAlarmWidget)
217
+ }
218
 
219
+ else -> {
220
+ holder.itemLayout.visibility = View.GONE
221
+ }
 
222
  }
223
  }
224
 
225
+ inner class MessageViewHolder internal constructor(itemView: View) :
226
  RecyclerView.ViewHolder(itemView) {
227
  var txtMessage: TextView
228
  var imgMessage: ImageView
 
231
  init {
232
  txtMessage = itemView.findViewById<View>(R.id.txt_message) as TextView
233
  imgMessage = itemView.findViewById<View>(R.id.img_message) as ImageView
234
+ itemLayout = itemView.findViewById<View>(R.id.cl_message) as ConstraintLayout
235
  }
236
  }
237
 
238
  inner class ChatWidgetViewHolder internal constructor(itemView: View) :
239
  RecyclerView.ViewHolder(itemView) {
240
  var itemLayout: FrameLayout
241
+ var llSearchContact: LinearLayout
242
 
243
  init {
244
  itemLayout = itemView.findViewById<View>(R.id.fl_widget_message) as FrameLayout
245
+ llSearchContact = itemView.findViewById<View>(R.id.ll_contacts_widget) as LinearLayout
246
  }
247
  }
248
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/fragments/ChatMainFragment.kt CHANGED
@@ -13,17 +13,19 @@ import android.view.animation.RotateAnimation
13
  import android.widget.EditText
14
  import android.widget.ImageView
15
  import android.widget.LinearLayout
16
- import android.widget.Toast
17
  import androidx.fragment.app.Fragment
18
  import androidx.lifecycle.Observer
19
  import androidx.lifecycle.ViewModelProvider
20
  import androidx.recyclerview.widget.LinearLayoutManager
21
  import androidx.recyclerview.widget.RecyclerView
22
  import com.google.gson.JsonElement
 
23
  import com.matthaigh27.chatgptwrapper.R
24
- import com.matthaigh27.chatgptwrapper.data.models.ChatMessageModel
25
- import com.matthaigh27.chatgptwrapper.data.models.HelpCommandModel
26
- import com.matthaigh27.chatgptwrapper.data.models.HelpPromptModel
 
 
27
  import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
28
  import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
29
  import com.matthaigh27.chatgptwrapper.ui.chat.view.adapters.ChatMainAdapter
@@ -32,26 +34,33 @@ import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.toolbar.ChatToolsWidg
32
  import com.matthaigh27.chatgptwrapper.ui.chat.viewmodel.ChatViewModel
33
  import com.matthaigh27.chatgptwrapper.utils.Constants.ERROR_MSG_NOEXIST_COMMAND
34
  import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ALL
 
 
35
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_ALERT
36
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_BROWSER
37
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_CONTACT
38
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_IMAGE
39
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_MESSAGE
40
- import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_SMS
41
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_HELP_PROMPT
 
 
42
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SMS
 
43
  import com.matthaigh27.chatgptwrapper.utils.helpers.Converter.stringToHelpPromptList
44
  import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.getHelpCommandFromStr
45
  import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.isMainHelpCommand
46
  import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.makePromptItemUsage
47
  import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.makePromptUsage
48
  import com.matthaigh27.chatgptwrapper.utils.helpers.ui.NoNewLineInputFilter
 
 
49
 
50
  class ChatMainFragment : Fragment(), OnClickListener {
51
 
52
  private val TYPE_CHAT_SENT = 0
53
  private val TYPE_CHAT_RECEIVE = 1
54
  private val TYPE_CHAT_WIDGET = 2
 
55
 
56
  private lateinit var rootView: View
57
  lateinit var viewModel: ChatViewModel
@@ -68,6 +77,11 @@ class ChatMainFragment : Fragment(), OnClickListener {
68
  private var chatToolsWidget: ChatToolsWidget? = null
69
  private var helpPromptList: ArrayList<HelpPromptModel>? = null
70
 
 
 
 
 
 
71
  override fun onCreateView(
72
  inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
73
  ): View {
@@ -87,13 +101,15 @@ class ChatMainFragment : Fragment(), OnClickListener {
87
  fetchAllCommands()
88
  }
89
 
 
 
90
  private fun initViewModel() {
91
  viewModel = ViewModelProvider(this)[ChatViewModel::class.java]
92
  }
93
 
94
  private fun initLoadingRotate() {
95
  loadingRotate = RotateAnimation(/* fromDegrees = */ 0f, /* toDegrees = */
96
- 360f, /* pivotXType = */
97
  Animation.RELATIVE_TO_SELF, /* pivotXValue = */
98
  0.5f, /* pivotYType = */
99
  Animation.RELATIVE_TO_SELF, /* pivotYValue = */
@@ -135,24 +151,28 @@ class ChatMainFragment : Fragment(), OnClickListener {
135
  }
136
 
137
  private fun initChatToolsWidget() {
138
- chatToolsWidget = ChatToolsWidget(requireContext(), requireActivity())
 
 
139
  val llToolBar = rootView.findViewById<LinearLayout>(R.id.ll_toolbar)
140
  llToolBar.addView(chatToolsWidget)
141
  }
142
 
143
- private fun showToast(message: String) {
144
- Toast.makeText(requireContext(), message, Toast.LENGTH_LONG).show()
145
- }
146
-
147
  private fun showLoading(isLoading: Boolean) {
148
  val imgLoading = rootView.findViewById<ImageView>(R.id.sp_loading)
149
 
150
  if (isLoading) {
151
  imgLoading.startAnimation(loadingRotate)
152
  imgLoading.visibility = View.VISIBLE
 
 
153
  } else {
154
- imgLoading.clearAnimation()
155
- imgLoading.visibility = View.GONE
 
 
 
 
156
  }
157
  }
158
 
@@ -163,18 +183,44 @@ class ChatMainFragment : Fragment(), OnClickListener {
163
  hasImage: Boolean = false,
164
  image: ByteArray? = null
165
  ) {
166
- addChatItemToList(ChatMessageModel(type, content, data, hasImage, image))
167
  when (type) {
168
  TYPE_CHAT_SENT -> {
169
  if (content!!.isNotEmpty() && content.first() == '/') {
170
  openHelpPromptWidget(content)
171
  return
172
  }
173
- sendNotification(content)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  }
175
  }
176
  }
177
 
 
 
 
 
 
 
 
 
 
178
  @SuppressLint("NotifyDataSetChanged")
179
  private fun addChatItemToList(chatModel: ChatMessageModel) {
180
  edtMessageInput?.setText("")
@@ -184,6 +230,18 @@ class ChatMainFragment : Fragment(), OnClickListener {
184
  rvChatList?.scrollToPosition(chatMessageList.size - 1)
185
  }
186
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  private fun openHelpPromptWidget(message: String) {
188
  try {
189
  val command: HelpCommandModel = getHelpCommandFromStr(message)
@@ -201,17 +259,22 @@ class ChatMainFragment : Fragment(), OnClickListener {
201
  model.name == command.main
202
  }
203
 
204
- if(data.isEmpty()) {
205
  addMessage(
206
  type = TYPE_CHAT_RECEIVE, content = ERROR_MSG_NOEXIST_COMMAND
207
  )
208
  } else {
 
 
 
209
  addMessage(
210
  type = TYPE_CHAT_WIDGET,
211
  content = TYPE_WIDGET_HELP_PROMPT,
212
- data = data[0].toString() as JsonElement
213
  )
214
  }
 
 
215
  }
216
  }
217
  }
@@ -229,7 +292,7 @@ class ChatMainFragment : Fragment(), OnClickListener {
229
  }
230
  } catch (e: Exception) {
231
  e.printStackTrace()
232
- showToast(e.message.toString())
233
  }
234
  }
235
 
@@ -251,7 +314,7 @@ class ChatMainFragment : Fragment(), OnClickListener {
251
 
252
  is ApiResource.Error -> {
253
  showLoading(false)
254
- showToast(resource.message!!)
255
  }
256
  }
257
  })
@@ -263,35 +326,22 @@ class ChatMainFragment : Fragment(), OnClickListener {
263
  is ApiResource.Loading -> {
264
  showLoading(true)
265
  }
 
266
  is ApiResource.Success -> {
267
  showLoading(false)
268
  val apiResponse = resource.data
269
  when (apiResponse?.result?.program) {
270
- TYPE_RESPONSE_MESSAGE -> {
271
- addMessage(TYPE_CHAT_RECEIVE, apiResponse.result.content.toString())
272
- }
273
- TYPE_RESPONSE_BROWSER -> {
274
- fetchResponseBrowser(apiResponse)
275
- }
276
- TYPE_RESPONSE_ALERT -> {
277
-
278
- }
279
- TYPE_RESPONSE_CONTACT -> {
280
-
281
- }
282
- TYPE_RESPONSE_IMAGE -> {
283
- fetchResponseImage(apiResponse)
284
- }
285
- TYPE_RESPONSE_SMS -> {
286
-
287
- }
288
- else -> {
289
-
290
- }
291
  }
292
  }
 
293
  is ApiResource.Error -> {
294
- showToast(resource.message!!)
295
  showLoading(false)
296
  }
297
  }
@@ -325,13 +375,38 @@ class ChatMainFragment : Fragment(), OnClickListener {
325
  }
326
 
327
  is ApiResource.Error -> {
328
- showToast(resource.message!!)
329
  showLoading(false)
330
  }
331
  }
332
  })
333
  }
334
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
 
336
  private fun initChatInterface() {
337
  chatMessageInterface = object : ChatMessageInterface {
@@ -350,21 +425,81 @@ class ChatMainFragment : Fragment(), OnClickListener {
350
  }
351
 
352
  override fun sentHelpPrompt(prompt: String) {
 
 
 
 
353
  }
354
 
355
  override fun canceledHelpPrompt() {
 
 
 
 
356
  }
357
 
358
  override fun doVoiceCall(phoneNumber: String) {
 
 
 
 
359
  }
360
 
361
  override fun doVideoCall(phoneNumber: String) {
 
 
 
 
362
  }
363
 
364
  override fun sendSmsWithPhoneNumber(phoneNumber: String) {
 
 
 
 
 
 
 
 
365
  }
366
 
367
  override fun pickImage(isSuccess: Boolean, data: ByteArray?) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
  }
369
  }
370
  }
@@ -380,4 +515,10 @@ class ChatMainFragment : Fragment(), OnClickListener {
380
  }
381
  }
382
  }
 
 
 
 
 
 
383
  }
 
13
  import android.widget.EditText
14
  import android.widget.ImageView
15
  import android.widget.LinearLayout
 
16
  import androidx.fragment.app.Fragment
17
  import androidx.lifecycle.Observer
18
  import androidx.lifecycle.ViewModelProvider
19
  import androidx.recyclerview.widget.LinearLayoutManager
20
  import androidx.recyclerview.widget.RecyclerView
21
  import com.google.gson.JsonElement
22
+ import com.google.gson.JsonObject
23
  import com.matthaigh27.chatgptwrapper.R
24
+ import com.matthaigh27.chatgptwrapper.data.models.chat.ChatMessageModel
25
+ import com.matthaigh27.chatgptwrapper.data.models.chat.HelpCommandModel
26
+ import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel
27
+ import com.matthaigh27.chatgptwrapper.data.models.chatwidgetprops.ScheduleAlarmProps
28
+ import com.matthaigh27.chatgptwrapper.data.models.common.Time
29
  import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
30
  import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
31
  import com.matthaigh27.chatgptwrapper.ui.chat.view.adapters.ChatMainAdapter
 
34
  import com.matthaigh27.chatgptwrapper.ui.chat.viewmodel.ChatViewModel
35
  import com.matthaigh27.chatgptwrapper.utils.Constants.ERROR_MSG_NOEXIST_COMMAND
36
  import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ALL
37
+ import com.matthaigh27.chatgptwrapper.utils.Constants.PROPS_WIDGET_DESC
38
+ import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_ALARM
39
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_ALERT
40
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_BROWSER
41
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_CONTACT
42
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_IMAGE
43
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_MESSAGE
 
44
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_HELP_PROMPT
45
+ import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SCHEDULE_ALARM
46
+ import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SEARCH_CONTACT
47
  import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SMS
48
+ import com.matthaigh27.chatgptwrapper.utils.helpers.Converter
49
  import com.matthaigh27.chatgptwrapper.utils.helpers.Converter.stringToHelpPromptList
50
  import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.getHelpCommandFromStr
51
  import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.isMainHelpCommand
52
  import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.makePromptItemUsage
53
  import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.makePromptUsage
54
  import com.matthaigh27.chatgptwrapper.utils.helpers.ui.NoNewLineInputFilter
55
+ import org.json.JSONArray
56
+ import java.util.Calendar
57
 
58
  class ChatMainFragment : Fragment(), OnClickListener {
59
 
60
  private val TYPE_CHAT_SENT = 0
61
  private val TYPE_CHAT_RECEIVE = 1
62
  private val TYPE_CHAT_WIDGET = 2
63
+ private val TYPE_CHAT_ERROR = 3
64
 
65
  private lateinit var rootView: View
66
  lateinit var viewModel: ChatViewModel
 
77
  private var chatToolsWidget: ChatToolsWidget? = null
78
  private var helpPromptList: ArrayList<HelpPromptModel>? = null
79
 
80
+ private var currentSelectedImage: ByteArray? = null
81
+ private var currentUploadedImageName: String? = null
82
+ private var isImagePicked: Boolean = false
83
+ private var showloadingCount = 0
84
+
85
  override fun onCreateView(
86
  inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
87
  ): View {
 
101
  fetchAllCommands()
102
  }
103
 
104
+
105
+
106
  private fun initViewModel() {
107
  viewModel = ViewModelProvider(this)[ChatViewModel::class.java]
108
  }
109
 
110
  private fun initLoadingRotate() {
111
  loadingRotate = RotateAnimation(/* fromDegrees = */ 0f, /* toDegrees = */
112
+ 720f, /* pivotXType = */
113
  Animation.RELATIVE_TO_SELF, /* pivotXValue = */
114
  0.5f, /* pivotYType = */
115
  Animation.RELATIVE_TO_SELF, /* pivotYValue = */
 
151
  }
152
 
153
  private fun initChatToolsWidget() {
154
+ chatToolsWidget = ChatToolsWidget(requireContext(), requireActivity()).apply {
155
+ this.callback = chatMessageInterface
156
+ }
157
  val llToolBar = rootView.findViewById<LinearLayout>(R.id.ll_toolbar)
158
  llToolBar.addView(chatToolsWidget)
159
  }
160
 
 
 
 
 
161
  private fun showLoading(isLoading: Boolean) {
162
  val imgLoading = rootView.findViewById<ImageView>(R.id.sp_loading)
163
 
164
  if (isLoading) {
165
  imgLoading.startAnimation(loadingRotate)
166
  imgLoading.visibility = View.VISIBLE
167
+ edtMessageInput?.isEnabled = false
168
+ showloadingCount++
169
  } else {
170
+ showloadingCount--
171
+ if(showloadingCount == 0) {
172
+ imgLoading.clearAnimation()
173
+ imgLoading.visibility = View.GONE
174
+ edtMessageInput?.isEnabled = true
175
+ }
176
  }
177
  }
178
 
 
183
  hasImage: Boolean = false,
184
  image: ByteArray? = null
185
  ) {
 
186
  when (type) {
187
  TYPE_CHAT_SENT -> {
188
  if (content!!.isNotEmpty() && content.first() == '/') {
189
  openHelpPromptWidget(content)
190
  return
191
  }
192
+ if (isImagePicked) {
193
+ addChatItemToList(
194
+ ChatMessageModel(
195
+ type = type,
196
+ content = content,
197
+ data = data,
198
+ hasImage = true,
199
+ image = currentSelectedImage
200
+ )
201
+ )
202
+ isImagePicked = false
203
+ } else {
204
+ addChatItemToList(ChatMessageModel(type, content, data, hasImage, image))
205
+ sendNotification(content)
206
+ }
207
+ }
208
+
209
+ else -> {
210
+ addChatItemToList(ChatMessageModel(type, content, data, hasImage, image))
211
  }
212
  }
213
  }
214
 
215
+ private fun addErrorMessage(
216
+ message: String
217
+ ) {
218
+ addMessage(
219
+ type = TYPE_CHAT_RECEIVE,
220
+ content = message
221
+ )
222
+ }
223
+
224
  @SuppressLint("NotifyDataSetChanged")
225
  private fun addChatItemToList(chatModel: ChatMessageModel) {
226
  edtMessageInput?.setText("")
 
230
  rvChatList?.scrollToPosition(chatMessageList.size - 1)
231
  }
232
 
233
+ private fun trainContacts() {
234
+ viewModel.trainContacts().observe(viewLifecycleOwner, Observer { state ->
235
+ showLoading(state)
236
+ })
237
+ }
238
+
239
+ private fun trainImages() {
240
+ viewModel.trainImages().observe(viewLifecycleOwner, Observer { state ->
241
+ showLoading(state)
242
+ })
243
+ }
244
+
245
  private fun openHelpPromptWidget(message: String) {
246
  try {
247
  val command: HelpCommandModel = getHelpCommandFromStr(message)
 
259
  model.name == command.main
260
  }
261
 
262
+ if (data.isEmpty()) {
263
  addMessage(
264
  type = TYPE_CHAT_RECEIVE, content = ERROR_MSG_NOEXIST_COMMAND
265
  )
266
  } else {
267
+ val widgetDesc = JsonObject().apply {
268
+ this.addProperty(PROPS_WIDGET_DESC, data[0].toString())
269
+ }
270
  addMessage(
271
  type = TYPE_CHAT_WIDGET,
272
  content = TYPE_WIDGET_HELP_PROMPT,
273
+ data = widgetDesc
274
  )
275
  }
276
+ } ?: run {
277
+ addErrorMessage("Help commands don't exist.")
278
  }
279
  }
280
  }
 
292
  }
293
  } catch (e: Exception) {
294
  e.printStackTrace()
295
+ addErrorMessage(e.message.toString())
296
  }
297
  }
298
 
 
314
 
315
  is ApiResource.Error -> {
316
  showLoading(false)
317
+ addErrorMessage(resource.message!!)
318
  }
319
  }
320
  })
 
326
  is ApiResource.Loading -> {
327
  showLoading(true)
328
  }
329
+
330
  is ApiResource.Success -> {
331
  showLoading(false)
332
  val apiResponse = resource.data
333
  when (apiResponse?.result?.program) {
334
+ TYPE_RESPONSE_MESSAGE -> addMessage(TYPE_CHAT_RECEIVE, apiResponse.result.content.toString())
335
+ TYPE_RESPONSE_BROWSER -> fetchResponseBrowser(apiResponse)
336
+ TYPE_RESPONSE_CONTACT -> fetchResponseContact(apiResponse)
337
+ TYPE_RESPONSE_IMAGE -> fetchResponseImage(apiResponse)
338
+ TYPE_RESPONSE_ALARM -> fetchResponseAlarm(apiResponse)
339
+ else -> addMessage(TYPE_CHAT_RECEIVE, apiResponse!!.result.toString())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  }
341
  }
342
+
343
  is ApiResource.Error -> {
344
+ addErrorMessage(resource.message!!)
345
  showLoading(false)
346
  }
347
  }
 
375
  }
376
 
377
  is ApiResource.Error -> {
378
+ addErrorMessage(resource.message!!)
379
  showLoading(false)
380
  }
381
  }
382
  })
383
  }
384
 
385
+ private fun fetchResponseContact(apiResponse: ApiResponse) {
386
+ val contactIds = JSONArray(apiResponse.result.content.asString.replace("'", "\""))
387
+ if (contactIds.length() > 0) {
388
+ addMessage(
389
+ type = TYPE_CHAT_WIDGET,
390
+ content = TYPE_WIDGET_SEARCH_CONTACT,
391
+ data = apiResponse.result.content
392
+ )
393
+ } else {
394
+ addMessage(
395
+ type = TYPE_CHAT_RECEIVE,
396
+ content = "Contacts that you are looking for don't exist.",
397
+ )
398
+ }
399
+ }
400
+
401
+ private fun fetchResponseAlarm(apiResponse: ApiResponse) {
402
+ val time: Time = Converter.stringToTime(apiResponse.result.content.asJsonObject.get("time").asString)
403
+ val label = apiResponse.result.content.asJsonObject.get("label").asString
404
+ val props = ScheduleAlarmProps(time, label)
405
+ val widgetDesc = JsonObject().apply {
406
+ this.addProperty(PROPS_WIDGET_DESC, props.toString())
407
+ }
408
+ addMessage(TYPE_CHAT_WIDGET, TYPE_WIDGET_SCHEDULE_ALARM, widgetDesc)
409
+ }
410
 
411
  private fun initChatInterface() {
412
  chatMessageInterface = object : ChatMessageInterface {
 
425
  }
426
 
427
  override fun sentHelpPrompt(prompt: String) {
428
+ addMessage(
429
+ type = TYPE_CHAT_SENT,
430
+ content = prompt
431
+ )
432
  }
433
 
434
  override fun canceledHelpPrompt() {
435
+ addMessage(
436
+ type = TYPE_CHAT_RECEIVE,
437
+ content = "You canceled Help prompt."
438
+ )
439
  }
440
 
441
  override fun doVoiceCall(phoneNumber: String) {
442
+ addMessage(
443
+ type = TYPE_CHAT_RECEIVE,
444
+ content = "You made a voice call to $phoneNumber"
445
+ )
446
  }
447
 
448
  override fun doVideoCall(phoneNumber: String) {
449
+ addMessage(
450
+ type = TYPE_CHAT_RECEIVE,
451
+ content = "You made a video call to $phoneNumber"
452
+ )
453
  }
454
 
455
  override fun sendSmsWithPhoneNumber(phoneNumber: String) {
456
+ val widgetDesc = JsonObject().apply {
457
+ this.addProperty(PROPS_WIDGET_DESC, phoneNumber)
458
+ }
459
+ addMessage(
460
+ type = TYPE_CHAT_WIDGET,
461
+ content = TYPE_WIDGET_SMS,
462
+ data = widgetDesc
463
+ )
464
  }
465
 
466
  override fun pickImage(isSuccess: Boolean, data: ByteArray?) {
467
+ if (!isSuccess)
468
+ addErrorMessage("Fail to pick image")
469
+ viewModel.uploadImageToFirebase(data!!)
470
+ .observe(viewLifecycleOwner, Observer { resource ->
471
+ when (resource) {
472
+ is ApiResource.Loading -> {
473
+ showLoading(true)
474
+ }
475
+
476
+ is ApiResource.Success -> {
477
+ showLoading(false)
478
+ currentSelectedImage = data
479
+ currentUploadedImageName = resource.data
480
+ isImagePicked = true
481
+ }
482
+
483
+ is ApiResource.Error -> {
484
+ addErrorMessage(resource.message!!)
485
+ showLoading(false)
486
+ }
487
+ }
488
+ })
489
+ }
490
+
491
+ override fun setAlarm(hours: Int, minutes: Int, label: String) {
492
+ addMessage(
493
+ type = TYPE_CHAT_RECEIVE,
494
+ content = "You set an alarm for $hours:$minutes with the label($label)"
495
+ )
496
+ }
497
+
498
+ override fun cancelAlarm() {
499
+ addMessage(
500
+ type = TYPE_CHAT_RECEIVE,
501
+ content = "You canceled setting an alarm."
502
+ )
503
  }
504
  }
505
  }
 
515
  }
516
  }
517
  }
518
+
519
+ override fun onResume() {
520
+ super.onResume()
521
+ trainImages()
522
+ trainContacts()
523
+ }
524
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/ChatMessageInterface.kt CHANGED
@@ -9,4 +9,6 @@ interface ChatMessageInterface {
9
  fun doVideoCall(phoneNumber: String)
10
  fun sendSmsWithPhoneNumber(phoneNumber: String)
11
  fun pickImage(isSuccess: Boolean, data: ByteArray? = null)
 
 
12
  }
 
9
  fun doVideoCall(phoneNumber: String)
10
  fun sendSmsWithPhoneNumber(phoneNumber: String)
11
  fun pickImage(isSuccess: Boolean, data: ByteArray? = null)
12
+ fun setAlarm(hours: Int, minutes:Int, label: String)
13
+ fun cancelAlarm()
14
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/OnHideListener.kt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces
2
+
3
+ interface OnHideListener {
4
+ fun hide()
5
+ }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/SendSmsWidget.kt CHANGED
@@ -10,6 +10,7 @@ import android.widget.Toast
10
  import androidx.constraintlayout.widget.ConstraintLayout
11
  import com.matthaigh27.chatgptwrapper.R
12
  import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
 
13
 
14
  class SendSmsWidget(
15
  context: Context, attrs: AttributeSet? = null
@@ -24,6 +25,7 @@ class SendSmsWidget(
24
  private val btnCancel: Button
25
 
26
  var callback: ChatMessageInterface? = null
 
27
 
28
  init {
29
  inflate(context, R.layout.widget_send_sms, this)
@@ -47,12 +49,12 @@ class SendSmsWidget(
47
  ).show()
48
  return@setOnClickListener
49
  }
50
- hide()
51
  callback?.sentSms(edtPhoneNumber.text.toString(), edtMessage.text.toString())
52
  }
53
 
54
  btnCancel.setOnClickListener {
55
- hide()
56
  callback?.canceledSms()
57
  }
58
  }
@@ -60,10 +62,4 @@ class SendSmsWidget(
60
  fun setPhoneNumber(phonenumber: String) {
61
  edtPhoneNumber.setText(phonenumber)
62
  }
63
-
64
- fun hide() {
65
- this.visibility = View.GONE
66
- edtMessage.setText("")
67
- edtPhoneNumber.setText("")
68
- }
69
  }
 
10
  import androidx.constraintlayout.widget.ConstraintLayout
11
  import com.matthaigh27.chatgptwrapper.R
12
  import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
13
+ import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.OnHideListener
14
 
15
  class SendSmsWidget(
16
  context: Context, attrs: AttributeSet? = null
 
25
  private val btnCancel: Button
26
 
27
  var callback: ChatMessageInterface? = null
28
+ var hideListener: OnHideListener? = null
29
 
30
  init {
31
  inflate(context, R.layout.widget_send_sms, this)
 
49
  ).show()
50
  return@setOnClickListener
51
  }
52
+ hideListener?.hide()
53
  callback?.sentSms(edtPhoneNumber.text.toString(), edtMessage.text.toString())
54
  }
55
 
56
  btnCancel.setOnClickListener {
57
+ hideListener?.hide()
58
  callback?.canceledSms()
59
  }
60
  }
 
62
  fun setPhoneNumber(phonenumber: String) {
63
  edtPhoneNumber.setText(phonenumber)
64
  }
 
 
 
 
 
 
65
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/alarm/DayOfWeekItem.kt ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.alarm
2
+
3
+ import android.content.Context
4
+ import android.util.AttributeSet
5
+ import android.view.View
6
+ import android.view.ViewGroup
7
+ import android.widget.LinearLayout
8
+ import android.widget.TextView
9
+ import androidx.core.view.setPadding
10
+ import com.matthaigh27.chatgptwrapper.R
11
+
12
+ class DayOfWeekItem(
13
+ context: Context, day: String, attrs: AttributeSet? = null
14
+ ) : LinearLayout(context, attrs), View.OnClickListener {
15
+
16
+ private val context: Context
17
+ private var txtDay: TextView
18
+ var isChecked = false
19
+
20
+ init {
21
+ inflate(context, R.layout.item_day_of_week, this)
22
+ this.context = context
23
+
24
+ layoutParams = LayoutParams(
25
+ 0,
26
+ ViewGroup.LayoutParams.WRAP_CONTENT,
27
+ 1f
28
+ )
29
+
30
+ val padding = context.resources.getDimensionPixelSize(R.dimen.spacing_tiny)
31
+
32
+ txtDay = findViewById(R.id.txt_day)
33
+ txtDay.text = day
34
+
35
+ txtDay.setOnClickListener(this)
36
+ }
37
+
38
+ override fun onClick(view: View?) {
39
+ when (view?.id) {
40
+ R.id.txt_day -> {
41
+ isChecked = !isChecked
42
+ updateBackground()
43
+ }
44
+ }
45
+ }
46
+
47
+ fun updateBackground() {
48
+ if (isChecked) {
49
+ txtDay.background = resources.getDrawable(R.drawable.bg_circle_button_schedule_alarm_day_selected)
50
+ } else {
51
+ txtDay.background = resources.getDrawable(R.drawable.bg_circle_button_schedule_alarm_day)
52
+ }
53
+ }
54
+ }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/alarm/ScheduleAlarmWidget.kt ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.alarm
2
+
3
+ import android.content.Context
4
+ import android.util.AttributeSet
5
+ import android.view.View
6
+ import android.view.ViewGroup
7
+ import android.widget.LinearLayout
8
+ import android.widget.TimePicker
9
+ import androidx.constraintlayout.widget.ConstraintLayout
10
+ import com.google.android.material.textfield.TextInputLayout
11
+ import com.matthaigh27.chatgptwrapper.R
12
+ import com.matthaigh27.chatgptwrapper.data.models.common.Time
13
+ import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
14
+ import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.OnHideListener
15
+ import com.matthaigh27.chatgptwrapper.utils.helpers.chat.AlarmHelper
16
+
17
+ class ScheduleAlarmWidget(
18
+ context: Context,
19
+ time: Time? = null,
20
+ label: String? = null,
21
+ repeat: BooleanArray? = null,
22
+ attrs: AttributeSet? = null
23
+ ) : ConstraintLayout(context, attrs), View.OnClickListener {
24
+
25
+ private val WEEK_DAY_COUNT = 7
26
+ private val dayOfWeek = arrayOf(
27
+ "S", "M", "T", "W", "T", "F", "S"
28
+ )
29
+ private val selectedDayList: BooleanArray = BooleanArray(WEEK_DAY_COUNT) { false }
30
+ private val dayItemList: ArrayList<DayOfWeekItem> = ArrayList()
31
+
32
+ private val context: Context
33
+ private var repeat: BooleanArray? = null
34
+ private var llRpeat: LinearLayout
35
+ private var txtLabel: TextInputLayout
36
+ private var timePicker: TimePicker
37
+
38
+ var callback: ChatMessageInterface? = null
39
+ var hideListener: OnHideListener? = null
40
+
41
+ init {
42
+ inflate(context, R.layout.widget_schedule_alarm, this)
43
+ this.context = context
44
+ this.repeat = repeat
45
+
46
+ layoutParams = LayoutParams(
47
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
48
+ )
49
+
50
+ findViewById<View>(R.id.btn_ok).setOnClickListener(this)
51
+ findViewById<View>(R.id.btn_cancel).setOnClickListener(this)
52
+
53
+ llRpeat = findViewById(R.id.ll_repeat)
54
+ txtLabel = findViewById(R.id.txt_label)
55
+ if (label != null) {
56
+ txtLabel.editText!!.setText(label)
57
+ }
58
+ timePicker = findViewById(R.id.time_picker)
59
+ if (time != null) {
60
+ timePicker.hour = time.hour
61
+ timePicker.minute = time.minute
62
+ }
63
+
64
+ initRepeatSetting()
65
+ }
66
+
67
+ private fun initRepeatSetting() {
68
+ dayOfWeek.forEachIndexed { index, day ->
69
+ val item = DayOfWeekItem(context, day)
70
+ item.setOnClickListener {
71
+ selectedDayList[index] = !selectedDayList[index]
72
+ }
73
+ dayItemList.add(item)
74
+ llRpeat.addView(item)
75
+ }
76
+ if (repeat != null) {
77
+ setSelectedDay(repeat!!)
78
+ }
79
+ }
80
+
81
+ private fun setSelectedDay(list: BooleanArray) {
82
+ list.forEachIndexed { index, status ->
83
+ dayItemList[index].isChecked = status
84
+ dayItemList[index].updateBackground()
85
+ }
86
+ }
87
+
88
+ override fun onClick(view: View?) {
89
+ when (view?.id) {
90
+ R.id.btn_ok -> {
91
+ AlarmHelper.createAlarm(
92
+ context,
93
+ timePicker.hour,
94
+ timePicker.minute,
95
+ txtLabel.editText?.text.toString()
96
+ )
97
+ callback?.setAlarm(
98
+ timePicker.hour,
99
+ timePicker.minute,
100
+ txtLabel.editText?.text.toString()
101
+ )
102
+ }
103
+
104
+ R.id.btn_cancel -> {
105
+ callback?.cancelAlarm()
106
+ }
107
+ }
108
+ hideListener?.hide()
109
+ }
110
+ }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/ContactDetailWidget.kt CHANGED
@@ -11,7 +11,7 @@ import android.widget.TextView
11
  import com.bumptech.glide.Glide
12
  import com.google.android.material.bottomsheet.BottomSheetDialog
13
  import com.matthaigh27.chatgptwrapper.R
14
- import com.matthaigh27.chatgptwrapper.data.models.ContactModel
15
  import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
16
 
17
  class ContactDetailWidget(
@@ -39,22 +39,24 @@ class ContactDetailWidget(
39
  llPhones = findViewById(R.id.ll_contacts)
40
 
41
  llPhones?.removeAllViews()
42
- txtDisplayName?.text = contactModel.name
43
- contactModel.phoneList.forEach { phoneNumber ->
44
- val contactDetailItem = ContactDetailItem(context)
45
- contactDetailItem.setContactDetailItemInfo(phoneNumber, contactModel.name)
46
- contactDetailItem.setVisibilityListener(object :
47
- ContactDetailItem.OnContactDetailVisibilityListener {
48
- override fun invisible() {
49
- this@ContactDetailWidget.dismiss()
50
- }
51
- })
 
 
52
  llPhones?.addView(contactDetailItem)
53
  }
54
 
55
  btnEditContact?.setOnClickListener(this)
56
  imgAvatar = findViewById(R.id.img_avatar)
57
- imgAvatar?.setContactAvatar(contactModel.id.toLong())
58
  }
59
 
60
  private fun ImageView.setContactAvatar(contactId: Long) {
@@ -73,7 +75,7 @@ class ContactDetailWidget(
73
  override fun onClick(view: View?) {
74
  when (view!!.id) {
75
  R.id.btn_edit_contact -> {
76
- goToContactEditor(contactModel.id)
77
  }
78
 
79
  R.id.btn_send_message -> {
 
11
  import com.bumptech.glide.Glide
12
  import com.google.android.material.bottomsheet.BottomSheetDialog
13
  import com.matthaigh27.chatgptwrapper.R
14
+ import com.matthaigh27.chatgptwrapper.data.models.chat.ContactModel
15
  import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
16
 
17
  class ContactDetailWidget(
 
39
  llPhones = findViewById(R.id.ll_contacts)
40
 
41
  llPhones?.removeAllViews()
42
+ txtDisplayName?.text = contactModel.displayName
43
+ contactModel.phoneNumbers.forEach { phoneNumber ->
44
+ val contactDetailItem = ContactDetailItem(context).apply {
45
+ this.callback = callback
46
+ this.setContactDetailItemInfo(phoneNumber, contactModel.displayName)
47
+ this.setVisibilityListener(object :
48
+ ContactDetailItem.OnContactDetailVisibilityListener {
49
+ override fun invisible() {
50
+ this@ContactDetailWidget.dismiss()
51
+ }
52
+ })
53
+ }
54
  llPhones?.addView(contactDetailItem)
55
  }
56
 
57
  btnEditContact?.setOnClickListener(this)
58
  imgAvatar = findViewById(R.id.img_avatar)
59
+ imgAvatar?.setContactAvatar(contactModel.contactId.toLong())
60
  }
61
 
62
  private fun ImageView.setContactAvatar(contactId: Long) {
 
75
  override fun onClick(view: View?) {
76
  when (view!!.id) {
77
  R.id.btn_edit_contact -> {
78
+ goToContactEditor(contactModel.contactId)
79
  }
80
 
81
  R.id.btn_send_message -> {
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/SearchContactWidget.kt CHANGED
@@ -10,12 +10,12 @@ import android.widget.TextView
10
  import androidx.constraintlayout.widget.ConstraintLayout
11
  import com.bumptech.glide.Glide
12
  import com.matthaigh27.chatgptwrapper.R
13
- import com.matthaigh27.chatgptwrapper.data.models.ContactModel
14
  import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
15
  import de.hdodenhof.circleimageview.CircleImageView
16
 
17
  class SearchContactWidget(
18
- context: Context, cotactModel: ContactModel, attrs: AttributeSet?
19
  ) : ConstraintLayout(context, attrs), View.OnClickListener {
20
 
21
  private var context: Context
@@ -38,8 +38,8 @@ class SearchContactWidget(
38
  civInfoAvatar = findViewById(R.id.civ_avatar)
39
  txtInfoName = findViewById(R.id.txt_info_name)
40
 
41
- txtInfoName.text = contactModel.name
42
- civInfoAvatar.setContactAvatar(context, contactModel.id.toLong())
43
 
44
  this.setOnClickListener(this)
45
  }
@@ -59,7 +59,9 @@ class SearchContactWidget(
59
 
60
 
61
  private fun showContactDetailView() {
62
- val bottomSheetDialog = ContactDetailWidget(context, contactModel)
 
 
63
  bottomSheetDialog.show()
64
  }
65
 
 
10
  import androidx.constraintlayout.widget.ConstraintLayout
11
  import com.bumptech.glide.Glide
12
  import com.matthaigh27.chatgptwrapper.R
13
+ import com.matthaigh27.chatgptwrapper.data.models.chat.ContactModel
14
  import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
15
  import de.hdodenhof.circleimageview.CircleImageView
16
 
17
  class SearchContactWidget(
18
+ context: Context, cotactModel: ContactModel, attrs: AttributeSet? = null
19
  ) : ConstraintLayout(context, attrs), View.OnClickListener {
20
 
21
  private var context: Context
 
38
  civInfoAvatar = findViewById(R.id.civ_avatar)
39
  txtInfoName = findViewById(R.id.txt_info_name)
40
 
41
+ txtInfoName.text = contactModel.displayName
42
+ civInfoAvatar.setContactAvatar(context, contactModel.contactId.toLong())
43
 
44
  this.setOnClickListener(this)
45
  }
 
59
 
60
 
61
  private fun showContactDetailView() {
62
+ val bottomSheetDialog = ContactDetailWidget(context, contactModel).apply {
63
+ this.callback = callback
64
+ }
65
  bottomSheetDialog.show()
66
  }
67
 
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptWidget.kt CHANGED
@@ -10,8 +10,9 @@ import android.widget.LinearLayout
10
  import android.widget.TextView
11
  import androidx.constraintlayout.widget.ConstraintLayout
12
  import com.matthaigh27.chatgptwrapper.R
13
- import com.matthaigh27.chatgptwrapper.data.models.HelpPromptModel
14
  import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
 
15
 
16
  class HelpPromptWidget(context: Context, model: HelpPromptModel) : ConstraintLayout(context),
17
  View.OnClickListener {
@@ -21,7 +22,7 @@ class HelpPromptWidget(context: Context, model: HelpPromptModel) : ConstraintLay
21
  private var promptEditTextList: ArrayList<EditText>? = null
22
  private val promptModel: HelpPromptModel
23
  var callback: ChatMessageInterface? = null
24
-
25
 
26
  init {
27
  promptModel = model
@@ -70,6 +71,7 @@ class HelpPromptWidget(context: Context, model: HelpPromptModel) : ConstraintLay
70
  callback?.canceledHelpPrompt()
71
  }
72
  }
 
73
  }
74
 
75
  private fun outputCompletePrompt() {
 
10
  import android.widget.TextView
11
  import androidx.constraintlayout.widget.ConstraintLayout
12
  import com.matthaigh27.chatgptwrapper.R
13
+ import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel
14
  import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
15
+ import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.OnHideListener
16
 
17
  class HelpPromptWidget(context: Context, model: HelpPromptModel) : ConstraintLayout(context),
18
  View.OnClickListener {
 
22
  private var promptEditTextList: ArrayList<EditText>? = null
23
  private val promptModel: HelpPromptModel
24
  var callback: ChatMessageInterface? = null
25
+ var hideListener: OnHideListener? = null
26
 
27
  init {
28
  promptModel = model
 
71
  callback?.canceledHelpPrompt()
72
  }
73
  }
74
+ hideListener?.hide()
75
  }
76
 
77
  private fun outputCompletePrompt() {
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/toolbar/ChatToolsWidget.kt CHANGED
@@ -95,7 +95,7 @@ class ChatToolsWidget(context: Context, parentActivity: Activity, attrs: Attribu
95
  }
96
 
97
  override fun onFailed(exception: Exception) {
98
-
99
  }
100
  })
101
  }
 
95
  }
96
 
97
  override fun onFailed(exception: Exception) {
98
+ callback?.pickImage(false)
99
  }
100
  })
101
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/viewmodel/ChatViewModel.kt CHANGED
@@ -1,15 +1,34 @@
1
  package com.matthaigh27.chatgptwrapper.ui.chat.viewmodel
2
 
 
3
  import androidx.lifecycle.MutableLiveData
4
  import androidx.lifecycle.ViewModel
5
- import com.matthaigh27.chatgptwrapper.RisingApplication
 
6
  import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
 
7
  import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
 
 
8
  import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
 
9
  import com.matthaigh27.chatgptwrapper.data.repository.FirebaseRepository
10
  import com.matthaigh27.chatgptwrapper.data.repository.RemoteRepository
11
- import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper
 
 
 
 
 
12
  import com.matthaigh27.chatgptwrapper.utils.helpers.network.RequestFactory
 
 
 
 
 
 
 
 
13
 
14
  class ChatViewModel : ViewModel() {
15
 
@@ -28,22 +47,17 @@ class ChatViewModel : ViewModel() {
28
 
29
  fun sendNotification(message: String): MutableLiveData<ApiResource<ApiResponse>> {
30
  val request = NotificationApiRequest(
31
- message = message,
32
- confs = RequestFactory.buildApiKeys()
33
  )
34
 
35
  val resource: MutableLiveData<ApiResource<ApiResponse>> = MutableLiveData()
36
  resource.value = ApiResource.Loading()
37
 
38
- RemoteRepository.sendNotification(
39
- request,
40
- onSuccess = { apiResponse ->
41
- resource.value = ApiResource.Success(apiResponse)
42
- },
43
- onFailure = { throwable ->
44
- resource.value = ApiResource.Error(throwable)
45
- }
46
- )
47
 
48
  return resource
49
  }
@@ -52,25 +66,158 @@ class ChatViewModel : ViewModel() {
52
  val resource: MutableLiveData<ApiResource<ByteArray>> = MutableLiveData()
53
  resource.value = ApiResource.Loading()
54
 
55
- FirebaseRepository.downloadImageWithName(
56
- name,
57
- onSuccess = { apiResponse ->
58
- resource.value = ApiResource.Success(apiResponse)
59
- },
60
- onFailure = { throwable ->
61
- resource.value = ApiResource.Error(throwable)
62
- }
63
- )
64
 
65
  return resource
66
  }
67
 
68
- fun trainImages() {
69
- val originalLocalImages =
70
- ImageHelper.getImagesFromExternalStorage(RisingApplication.appContext.contentResolver)
 
 
 
 
 
 
 
 
71
  }
72
 
73
- fun trainContacts() {
 
 
 
 
 
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  }
76
  }
 
1
  package com.matthaigh27.chatgptwrapper.ui.chat.viewmodel
2
 
3
+ import android.util.Log
4
  import androidx.lifecycle.MutableLiveData
5
  import androidx.lifecycle.ViewModel
6
+ import com.matthaigh27.chatgptwrapper.RisingApplication.Companion.appContext
7
+ import com.matthaigh27.chatgptwrapper.data.local.entity.ImageEntity
8
  import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
9
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.ImageRelatednessApiRequest
10
  import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
11
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainContactsApiRequest
12
+ import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainImageApiRequest
13
  import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
14
+ import com.matthaigh27.chatgptwrapper.data.remote.responses.EmptyResultApiResponse
15
  import com.matthaigh27.chatgptwrapper.data.repository.FirebaseRepository
16
  import com.matthaigh27.chatgptwrapper.data.repository.RemoteRepository
17
+ import com.matthaigh27.chatgptwrapper.data.repository.RoomRepository
18
+ import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ContactHelper.getChangedContacts
19
+ import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ContactHelper.getContacts
20
+ import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper.getBytesFromPath
21
+ import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper.getImagesFromExternalStorage
22
+ import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper.getLocalPathFromUri
23
  import com.matthaigh27.chatgptwrapper.utils.helpers.network.RequestFactory
24
+ import com.matthaigh27.chatgptwrapper.utils.helpers.network.RequestFactory.buildApiKeys
25
+ import kotlinx.coroutines.CoroutineScope
26
+ import kotlinx.coroutines.Deferred
27
+ import kotlinx.coroutines.Dispatchers
28
+ import kotlinx.coroutines.async
29
+ import kotlinx.coroutines.awaitAll
30
+ import kotlinx.coroutines.launch
31
+ import kotlinx.coroutines.withContext
32
 
33
  class ChatViewModel : ViewModel() {
34
 
 
47
 
48
  fun sendNotification(message: String): MutableLiveData<ApiResource<ApiResponse>> {
49
  val request = NotificationApiRequest(
50
+ message = message, confs = RequestFactory.buildApiKeys()
 
51
  )
52
 
53
  val resource: MutableLiveData<ApiResource<ApiResponse>> = MutableLiveData()
54
  resource.value = ApiResource.Loading()
55
 
56
+ RemoteRepository.sendNotification(request, onSuccess = { apiResponse ->
57
+ resource.value = ApiResource.Success(apiResponse)
58
+ }, onFailure = { throwable ->
59
+ resource.value = ApiResource.Error(throwable)
60
+ })
 
 
 
 
61
 
62
  return resource
63
  }
 
66
  val resource: MutableLiveData<ApiResource<ByteArray>> = MutableLiveData()
67
  resource.value = ApiResource.Loading()
68
 
69
+ FirebaseRepository.downloadImageWithName(name, onSuccess = { apiResponse ->
70
+ resource.value = ApiResource.Success(apiResponse)
71
+ }, onFailure = { throwable ->
72
+ resource.value = ApiResource.Error(throwable)
73
+ })
 
 
 
 
74
 
75
  return resource
76
  }
77
 
78
+ fun uploadImageToFirebase(imageByteArray: ByteArray): MutableLiveData<ApiResource<String>> {
79
+ val resource: MutableLiveData<ApiResource<String>> = MutableLiveData()
80
+ resource.value = ApiResource.Loading()
81
+
82
+ FirebaseRepository.uploadImageAsync(imageByteArray, onSuccess = { apiResponse ->
83
+ resource.value = ApiResource.Success(apiResponse)
84
+ }, onFailure = { throwable ->
85
+ resource.value = ApiResource.Error(throwable)
86
+ })
87
+
88
+ return resource
89
  }
90
 
91
+ fun trainImages(): MutableLiveData<Boolean> {
92
+ val state: MutableLiveData<Boolean> = MutableLiveData()
93
+ state.value = true
94
+ CoroutineScope(Dispatchers.IO).launch {
95
+ val images = getImagesFromExternalStorage(appContext.contentResolver)
96
+ val originalImages = RoomRepository.getAllImages().value
97
 
98
+ val existImageStatus = BooleanArray(originalImages!!.size) { false }
99
+ val tasks = mutableListOf<Deferred<Unit>>()
100
+
101
+ Log.d("Brain", "Start")
102
+ images.forEach { image ->
103
+ var isExist = false
104
+ val path = getLocalPathFromUri(appContext, image.uri)
105
+ for (i in originalImages.indices) {
106
+ val entity: ImageEntity = originalImages[i]
107
+ if (entity.path == path) {
108
+ if (entity.dataModified != image.modifiedDate) {
109
+ val byteArray = getBytesFromPath(path)
110
+ val task = async {
111
+ val uuid = FirebaseRepository.uploadImage(byteArray)
112
+ if (uuid != "Error") {
113
+ RoomRepository.updateImage(
114
+ ImageEntity(
115
+ id = 0,
116
+ path = path,
117
+ name = uuid,
118
+ dataModified = image.modifiedDate
119
+ )
120
+ )
121
+ RemoteRepository.trainImage(
122
+ TrainImageApiRequest(
123
+ uuid, "updated", buildApiKeys()
124
+ )
125
+ )
126
+ }
127
+ }
128
+ tasks.add(task)
129
+ }
130
+ isExist = true
131
+ existImageStatus[i] = true
132
+ break
133
+ }
134
+ }
135
+ if (!isExist) {
136
+ path?.let {
137
+ val byteArray = getBytesFromPath(it)
138
+ val task = async {
139
+ val uuid = FirebaseRepository.uploadImage(byteArray)
140
+ if (uuid != "Error") {
141
+ RoomRepository.insertImage(
142
+ ImageEntity(
143
+ id = 0,
144
+ path = path,
145
+ name = uuid,
146
+ dataModified = image.modifiedDate
147
+ )
148
+ )
149
+ RemoteRepository.trainImage(
150
+ TrainImageApiRequest(
151
+ uuid, "created", buildApiKeys()
152
+ )
153
+ )
154
+ }
155
+ }
156
+ tasks.add(task)
157
+ }
158
+ }
159
+ }
160
+
161
+ for (i in existImageStatus.indices) {
162
+ if (!existImageStatus[i]) {
163
+ val task = async {
164
+ RoomRepository.deleteImage(
165
+ ImageEntity(
166
+ originalImages[i].id, "", "", 0L
167
+ )
168
+ )
169
+ val result = RemoteRepository.trainImage(
170
+ TrainImageApiRequest(
171
+ originalImages[i].name, "deleted", buildApiKeys()
172
+ )
173
+ )
174
+ }
175
+ tasks.add(task)
176
+ }
177
+ }
178
+
179
+ tasks.awaitAll()
180
+ Log.d("Brain", "Finish")
181
+ withContext(Dispatchers.Main) {
182
+ state.value = false
183
+ }
184
+ }
185
+ return state
186
+ }
187
+
188
+ fun trainContacts(): MutableLiveData<Boolean> {
189
+ val state: MutableLiveData<Boolean> = MutableLiveData()
190
+ state.value = true
191
+ val contacts = getContacts(appContext)
192
+ CoroutineScope(Dispatchers.Main).launch {
193
+ val resource: MutableLiveData<ApiResource<EmptyResultApiResponse>> = MutableLiveData()
194
+ val changedContacts = getChangedContacts(contacts)
195
+ val request = TrainContactsApiRequest(changedContacts, RequestFactory.buildApiKeys())
196
+ RemoteRepository.trainContacts(request, onSuccess = { apiResponse ->
197
+ resource.value = ApiResource.Success(apiResponse)
198
+ }, onFailure = { throwable ->
199
+ resource.value = ApiResource.Error(throwable)
200
+ })
201
+ withContext(Dispatchers.Main) {
202
+ state.value = false
203
+ }
204
+ }
205
+ return state
206
+ }
207
+
208
+ fun getImageRelatedness(imageName: String, message: String): MutableLiveData<ApiResource<ApiResponse>> {
209
+ val resource: MutableLiveData<ApiResource<ApiResponse>> = MutableLiveData()
210
+ val request = ImageRelatednessApiRequest(
211
+ image_name = imageName, message = message, confs = buildApiKeys()
212
+ )
213
+ resource.value = ApiResource.Loading()
214
+
215
+ RemoteRepository.getImageRelatedness(request, onSuccess = { apiResponse ->
216
+ resource.value = ApiResource.Success(apiResponse)
217
+ }, onFailure = { throwable ->
218
+ resource.value = ApiResource.Error(throwable)
219
+ })
220
+
221
+ return resource
222
  }
223
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/Constants.kt CHANGED
@@ -1,7 +1,9 @@
1
  package com.matthaigh27.chatgptwrapper.utils
2
 
 
 
3
  object Constants {
4
- val API_BASE_URL = "https://ttt246-brain.hf.space/"
5
 
6
  val TYPE_RESPONSE_MESSAGE = "message"
7
  val TYPE_RESPONSE_BROWSER = "browser"
@@ -10,12 +12,14 @@ object Constants {
10
  val TYPE_RESPONSE_IMAGE = "image"
11
  val TYPE_RESPONSE_HELP_COMMAND = "help_command"
12
  val TYPE_RESPONSE_SMS = "sms"
 
13
  val TYPE_RESPONSE_CONTACT = "contact"
14
 
15
  val TYPE_WIDGET_SMS = "sms"
16
  val TYPE_WIDGET_HELP_PROMPT = "help_prompt"
17
  val TYPE_WIDGET_FEEDBACK = "feedback"
18
  val TYPE_WIDGET_SEARCH_CONTACT = "search_contact"
 
19
 
20
  val HELP_COMMAND_ERROR_NO_MAIN = "no main command"
21
  val HELP_COMMAND_ERROR_NO_INVALID_FORMAT = "Invalid Command Format"
@@ -31,4 +35,11 @@ object Constants {
31
  val FIELD_HELP_PROMPT_PROMPT = "prompt"
32
  val FIELD_HELP_PROMPT_DESCRIPTION = "description"
33
  val FIELD_HELP_PROMPT_TAGS = "tags"
 
 
 
 
 
 
 
34
  }
 
1
  package com.matthaigh27.chatgptwrapper.utils
2
 
3
+ import com.matthaigh27.chatgptwrapper.BuildConfig
4
+
5
  object Constants {
6
+ val API_BASE_URL = BuildConfig.BASE_URL
7
 
8
  val TYPE_RESPONSE_MESSAGE = "message"
9
  val TYPE_RESPONSE_BROWSER = "browser"
 
12
  val TYPE_RESPONSE_IMAGE = "image"
13
  val TYPE_RESPONSE_HELP_COMMAND = "help_command"
14
  val TYPE_RESPONSE_SMS = "sms"
15
+ val TYPE_RESPONSE_ALARM = "alarm"
16
  val TYPE_RESPONSE_CONTACT = "contact"
17
 
18
  val TYPE_WIDGET_SMS = "sms"
19
  val TYPE_WIDGET_HELP_PROMPT = "help_prompt"
20
  val TYPE_WIDGET_FEEDBACK = "feedback"
21
  val TYPE_WIDGET_SEARCH_CONTACT = "search_contact"
22
+ val TYPE_WIDGET_SCHEDULE_ALARM = "schedule_alarm"
23
 
24
  val HELP_COMMAND_ERROR_NO_MAIN = "no main command"
25
  val HELP_COMMAND_ERROR_NO_INVALID_FORMAT = "Invalid Command Format"
 
35
  val FIELD_HELP_PROMPT_PROMPT = "prompt"
36
  val FIELD_HELP_PROMPT_DESCRIPTION = "description"
37
  val FIELD_HELP_PROMPT_TAGS = "tags"
38
+
39
+ val PROPS_WIDGET_DESC = "widget description"
40
+
41
+ val TIME_OUT_CALL = 60L
42
+ val TIME_OUT_CONNECT = 60L
43
+ val TIME_OUT_READ = 60L
44
+ val TIME_OUT_WRITE = 60L
45
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/CallbackTypes.kt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.utils.helpers
2
+
3
+ typealias OnSuccess<T> = (T) -> Unit
4
+ typealias OnFailure<T> = (T) -> Unit
5
+
6
+ typealias OnHide = () -> Unit
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/Converter.kt CHANGED
@@ -1,8 +1,9 @@
1
  package com.matthaigh27.chatgptwrapper.utils.helpers
2
 
3
- import com.matthaigh27.chatgptwrapper.data.models.HelpPromptModel
 
 
4
  import com.matthaigh27.chatgptwrapper.utils.Constants
5
- import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper
6
  import org.json.JSONArray
7
  import org.json.JSONException
8
  import org.json.JSONObject
@@ -18,7 +19,8 @@ object Converter {
18
 
19
  val helpPromptModel = HelpPromptModel()
20
  helpPromptModel.name = helpCommand.getString(Constants.FIELD_HELP_PROMPT_NAME)
21
- helpPromptModel.description = helpCommand.getString(Constants.FIELD_HELP_PROMPT_DESCRIPTION)
 
22
  helpPromptModel.prompt = helpCommand.getString(Constants.FIELD_HELP_PROMPT_PROMPT)
23
 
24
  helpPromptModel.tags = ArrayList()
@@ -34,4 +36,12 @@ object Converter {
34
  }
35
  return promptList
36
  }
 
 
 
 
 
 
 
 
37
  }
 
1
  package com.matthaigh27.chatgptwrapper.utils.helpers
2
 
3
+ import com.google.gson.Gson
4
+ import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel
5
+ import com.matthaigh27.chatgptwrapper.data.models.common.Time
6
  import com.matthaigh27.chatgptwrapper.utils.Constants
 
7
  import org.json.JSONArray
8
  import org.json.JSONException
9
  import org.json.JSONObject
 
19
 
20
  val helpPromptModel = HelpPromptModel()
21
  helpPromptModel.name = helpCommand.getString(Constants.FIELD_HELP_PROMPT_NAME)
22
+ helpPromptModel.description =
23
+ helpCommand.getString(Constants.FIELD_HELP_PROMPT_DESCRIPTION)
24
  helpPromptModel.prompt = helpCommand.getString(Constants.FIELD_HELP_PROMPT_PROMPT)
25
 
26
  helpPromptModel.tags = ArrayList()
 
36
  }
37
  return promptList
38
  }
39
+
40
+ fun stringToTime(strTime: String): Time {
41
+ val list = strTime.split(':')
42
+ val hour = list[0].toInt()
43
+ val minute = list[1].toInt()
44
+ val time = Time(hour, minute, 0)
45
+ return time
46
+ }
47
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmHelper.kt CHANGED
@@ -1,34 +1,74 @@
1
  package com.matthaigh27.chatgptwrapper.utils.helpers.chat
2
 
 
 
3
  import android.content.Context
4
- import android.database.Cursor
5
- import android.net.Uri
6
- import com.matthaigh27.chatgptwrapper.data.models.AlarmModel
 
 
 
7
 
8
  object AlarmHelper {
9
- fun getAlarmList(context: Context): List<AlarmModel> {
10
- val alarmsList = mutableListOf<AlarmModel>()
11
- val contentUri: Uri = Uri.parse("content://com.android.alarmclock/alarm")
12
- val cursor: Cursor? = context.contentResolver.query(contentUri, null, null, null, null)
13
-
14
- cursor?.let {
15
- val idIndex = it.getColumnIndex("_id")
16
- val timeIndex = it.getColumnIndex("alarmtime")
17
- val enabledIndex = it.getColumnIndex("enabled")
18
- val labelIndex = it.getColumnIndex("message")
19
-
20
- while (it.moveToNext()) {
21
- val id = it.getInt(idIndex)
22
- val time = it.getLong(timeIndex)
23
- val enabled = it.getInt(enabledIndex) == 1
24
- val label = it.getString(labelIndex)
25
-
26
- val alarm = AlarmModel(id, time, enabled, label)
27
- alarmsList.add(alarm)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  }
29
  }
30
 
31
- cursor?.close()
32
- return alarmsList
 
 
 
 
33
  }
34
- }
 
1
  package com.matthaigh27.chatgptwrapper.utils.helpers.chat
2
 
3
+ import android.app.AlarmManager
4
+ import android.app.PendingIntent
5
  import android.content.Context
6
+ import android.content.Context.ALARM_SERVICE
7
+ import android.content.Intent
8
+ import android.provider.AlarmClock
9
+ import android.util.Log
10
+ import java.util.Calendar
11
+
12
 
13
  object AlarmHelper {
14
+ fun createAlarm(context: Context, hour: Int, minute: Int, label: String) {
15
+ val calendar = Calendar.getInstance()
16
+
17
+ calendar.set(Calendar.HOUR_OF_DAY, hour)
18
+ calendar.set(Calendar.MINUTE, minute)
19
+ calendar.set(Calendar.SECOND, 0)
20
+
21
+
22
+ val intent = Intent("android.intent.action.SET_ALARM")
23
+ intent.putExtra("android.intent.extra.alarm.HOUR", hour)
24
+ intent.putExtra("android.intent.extra.alarm.MINUTES", minute)
25
+ intent.putExtra("android.intent.extra.alarm.SKIP_UI", true)
26
+ intent.putExtra("android.intent.extra.alarm.MESSAGE", label)
27
+
28
+ context.startActivity(intent)
29
+ }
30
+
31
+ fun scheduleRepeatingAlarm(context: Context, selectedDays: ArrayList<Int>, hour: Int, minute: Int) {
32
+ val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
33
+
34
+ val alarmIntent = Intent(context, AlarmReceiver::class.java)
35
+ alarmIntent.action = "com.matthaigh27.chatgptwrapper"
36
+
37
+ val pendingIntent = PendingIntent.getBroadcast(
38
+ context,
39
+ 0,
40
+ alarmIntent,
41
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
42
+ )
43
+
44
+ // Calculate the time difference between the next alarm time and now.
45
+ val calendar = Calendar.getInstance()
46
+ val timeNow = calendar.timeInMillis
47
+ var minTimeDiff = Long.MAX_VALUE
48
+
49
+ for (dayOfWeek in selectedDays) {
50
+ calendar.set(Calendar.HOUR_OF_DAY, hour)
51
+ calendar.set(Calendar.MINUTE, minute)
52
+ calendar.set(Calendar.SECOND, 0)
53
+ calendar.set(Calendar.MILLISECOND, 0)
54
+ calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek)
55
+
56
+ var alarmTime = calendar.timeInMillis
57
+ if (alarmTime < timeNow) { // If the alarm time is in the past, set it for the next week.
58
+ alarmTime += AlarmManager.INTERVAL_DAY * 7
59
+ }
60
+
61
+ val timeDiff = alarmTime - timeNow
62
+ if (timeDiff < minTimeDiff) {
63
+ minTimeDiff = timeDiff
64
  }
65
  }
66
 
67
+ alarmManager.setInexactRepeating(
68
+ AlarmManager.RTC_WAKEUP,
69
+ timeNow + minTimeDiff,
70
+ AlarmManager.INTERVAL_DAY * 7, // Set to repeat every week.
71
+ pendingIntent
72
+ )
73
  }
74
+ }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmReceiver.kt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package com.matthaigh27.chatgptwrapper.utils.helpers.chat
2
+
3
+ import android.content.BroadcastReceiver
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import android.util.Log
7
+
8
+ class AlarmReceiver : BroadcastReceiver() {
9
+ override fun onReceive(context: Context, intent: Intent) {
10
+ val label = intent.getStringExtra("label")
11
+ Log.d("AlarmReceiver", "Alarm triggered. Label: $label")
12
+ }
13
+ }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/CommandHelper.kt CHANGED
@@ -1,15 +1,11 @@
1
  package com.matthaigh27.chatgptwrapper.utils.helpers.chat
2
 
3
- import com.matthaigh27.chatgptwrapper.data.models.HelpCommandModel
4
- import com.matthaigh27.chatgptwrapper.data.models.HelpPromptModel
5
- import com.matthaigh27.chatgptwrapper.utils.Constants.ERROR_MSG_JSON
6
  import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND
7
  import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ALL
8
  import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ERROR_NO_INVALID_FORMAT
9
  import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ERROR_NO_MAIN
10
- import org.json.JSONArray
11
- import org.json.JSONException
12
- import org.json.JSONObject
13
 
14
  object CommandHelper {
15
  fun isMainHelpCommand(model: HelpCommandModel): Boolean {
 
1
  package com.matthaigh27.chatgptwrapper.utils.helpers.chat
2
 
3
+ import com.matthaigh27.chatgptwrapper.data.models.chat.HelpCommandModel
4
+ import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel
 
5
  import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND
6
  import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ALL
7
  import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ERROR_NO_INVALID_FORMAT
8
  import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ERROR_NO_MAIN
 
 
 
9
 
10
  object CommandHelper {
11
  fun isMainHelpCommand(model: HelpCommandModel): Boolean {
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ContactHelper.kt CHANGED
@@ -4,7 +4,12 @@ import android.annotation.SuppressLint
4
  import android.content.ContentResolver
5
  import android.content.Context
6
  import android.provider.ContactsContract
7
- import com.matthaigh27.chatgptwrapper.data.models.ContactModel
 
 
 
 
 
8
 
9
  object ContactHelper {
10
  @SuppressLint("Range")
@@ -26,8 +31,8 @@ object ContactHelper {
26
  )).toInt()
27
 
28
  val contact = ContactModel()
29
- contact.id = id
30
- contact.name = name
31
 
32
  if (phoneNumber > 0) {
33
  val cursorPhone = context.contentResolver.query(
@@ -43,7 +48,7 @@ object ContactHelper {
43
  val phoneNumValue = cursorPhone.getString(
44
  cursorPhone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
45
  )
46
- contact.phoneList.add(phoneNumValue)
47
  }
48
  }
49
  cursorPhone.close()
@@ -55,4 +60,87 @@ object ContactHelper {
55
  cursor.close()
56
  return contacts
57
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  }
 
4
  import android.content.ContentResolver
5
  import android.content.Context
6
  import android.provider.ContactsContract
7
+ import com.matthaigh27.chatgptwrapper.data.local.entity.ContactEntity
8
+ import com.matthaigh27.chatgptwrapper.data.models.chat.ContactModel
9
+ import com.matthaigh27.chatgptwrapper.data.repository.RoomRepository
10
+ import kotlinx.coroutines.CoroutineScope
11
+ import kotlinx.coroutines.Dispatchers
12
+ import kotlinx.coroutines.async
13
 
14
  object ContactHelper {
15
  @SuppressLint("Range")
 
31
  )).toInt()
32
 
33
  val contact = ContactModel()
34
+ contact.contactId = id
35
+ contact.displayName = name
36
 
37
  if (phoneNumber > 0) {
38
  val cursorPhone = context.contentResolver.query(
 
48
  val phoneNumValue = cursorPhone.getString(
49
  cursorPhone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
50
  )
51
+ contact.phoneNumbers.add(phoneNumValue)
52
  }
53
  }
54
  cursorPhone.close()
 
60
  cursor.close()
61
  return contacts
62
  }
63
+
64
+ suspend fun getChangedContacts(
65
+ contacts: ArrayList<ContactModel>
66
+ ): ArrayList<ContactModel> {
67
+ return CoroutineScope(Dispatchers.IO).async {
68
+ val originalContacts = RoomRepository.getAllContacts().value
69
+ val changedContactList = ArrayList<ContactModel>()
70
+ for (i in originalContacts!!.indices) {
71
+ var isExist = false
72
+ contacts.forEach { contact ->
73
+ if (originalContacts[i].id == contact.contactId) {
74
+ if (originalContacts[i].name != contact.displayName || originalContacts[i].phoneNumber != contact.phoneNumbers.toString()) {
75
+ contact.status = "updated"
76
+ changedContactList.add(contact)
77
+
78
+ try {
79
+ RoomRepository.updateContact(
80
+ ContactEntity(
81
+ contact.contactId,
82
+ contact.displayName,
83
+ contact.phoneNumbers.toString()
84
+ )
85
+ )
86
+ } catch (e: Exception) {
87
+ e.printStackTrace()
88
+ }
89
+ } else {
90
+ contact.status = "nothing"
91
+ }
92
+ isExist = true
93
+ return@forEach
94
+ }
95
+ }
96
+ if (!isExist) {
97
+ val deletedContacts = ContactModel()
98
+ deletedContacts.contactId = originalContacts[i].id
99
+ deletedContacts.status = "deleted"
100
+ changedContactList.add(deletedContacts)
101
+
102
+ try {
103
+ RoomRepository.deleteContact(
104
+ ContactEntity(
105
+ deletedContacts.contactId,
106
+ deletedContacts.displayName,
107
+ deletedContacts.phoneNumbers.toString()
108
+ )
109
+ )
110
+ } catch (e: Exception) {
111
+ e.printStackTrace()
112
+ }
113
+ }
114
+ }
115
+ contacts.forEach { contact ->
116
+ if (contact.status.isEmpty()) {
117
+ contact.status = "created"
118
+ changedContactList.add(contact)
119
+ try {
120
+ RoomRepository.insertContact(
121
+ ContactEntity(
122
+ contact.contactId,
123
+ contact.displayName,
124
+ contact.phoneNumbers.toString()
125
+ )
126
+ )
127
+ } catch (e: Exception) {
128
+ e.printStackTrace()
129
+ }
130
+ }
131
+ }
132
+ changedContactList
133
+ }.await()
134
+ }
135
+
136
+ fun getContactModelById(contactId: String, contacts: ArrayList<ContactModel>): ContactModel {
137
+ var contactModel = ContactModel()
138
+ val searchResults = contacts.filter { contact ->
139
+ contactId == contact.contactId
140
+ }
141
+ if (searchResults.isNotEmpty()) {
142
+ contactModel = searchResults[0]
143
+ }
144
+ return contactModel
145
+ }
146
  }
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ImageHelper.kt CHANGED
@@ -1,6 +1,8 @@
1
  package com.matthaigh27.chatgptwrapper.utils.helpers.chat
2
 
3
  import android.content.ContentResolver
 
 
4
  import android.graphics.Bitmap
5
  import android.graphics.BitmapFactory
6
  import android.graphics.Canvas
@@ -13,7 +15,7 @@ import android.net.Uri
13
  import android.os.Environment
14
  import android.provider.MediaStore
15
  import com.matthaigh27.chatgptwrapper.RisingApplication
16
- import com.matthaigh27.chatgptwrapper.data.models.ImageModel
17
  import java.io.ByteArrayOutputStream
18
  import java.io.File
19
  import java.io.FileInputStream
@@ -110,5 +112,16 @@ object ImageHelper {
110
  return listOfImages
111
  }
112
 
113
-
 
 
 
 
 
 
 
 
 
 
 
114
  }
 
1
  package com.matthaigh27.chatgptwrapper.utils.helpers.chat
2
 
3
  import android.content.ContentResolver
4
+ import android.content.Context
5
+ import android.database.Cursor
6
  import android.graphics.Bitmap
7
  import android.graphics.BitmapFactory
8
  import android.graphics.Canvas
 
15
  import android.os.Environment
16
  import android.provider.MediaStore
17
  import com.matthaigh27.chatgptwrapper.RisingApplication
18
+ import com.matthaigh27.chatgptwrapper.data.models.chat.ImageModel
19
  import java.io.ByteArrayOutputStream
20
  import java.io.File
21
  import java.io.FileInputStream
 
112
  return listOfImages
113
  }
114
 
115
+ fun getLocalPathFromUri(context: Context, contentUri: Uri?): String? {
116
+ var cursor: Cursor? = null
117
+ return try {
118
+ val proj = arrayOf(MediaStore.Images.Media.DATA)
119
+ cursor = context.contentResolver.query(contentUri!!, proj, null, null, null)
120
+ val column_index: Int = cursor!!.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
121
+ cursor.moveToFirst()
122
+ cursor.getString(column_index)
123
+ } finally {
124
+ cursor?.close()
125
+ }
126
+ }
127
  }
Android/app/src/main/res/drawable/bg_circle_button_schedule_alarm_day.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <shape xmlns:android="http://schemas.android.com/apk/res/android"
3
+ android:shape="rectangle">
4
+ <corners android:radius="@dimen/radius_huge" />
5
+ <solid android:color="@color/color_primary_dark" />
6
+ </shape>
Android/app/src/main/res/drawable/bg_circle_button_schedule_alarm_day_selected.xml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <shape xmlns:android="http://schemas.android.com/apk/res/android"
3
+ android:shape="rectangle">
4
+ <corners android:radius="@dimen/radius_huge" />
5
+ <solid android:color="@color/color_accent" />
6
+ </shape>
Android/app/src/main/res/drawable/bg_item_error_message.xml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <shape xmlns:android="http://schemas.android.com/apk/res/android"
3
+ android:shape="rectangle">
4
+ <solid android:color="@color/bg_color_message_error" />
5
+ <corners
6
+ android:radius="@dimen/radius_normal" />
7
+ </shape>
Android/app/src/main/res/layout/item_container_chat_widget.xml CHANGED
@@ -7,4 +7,16 @@
7
  android:layout_marginTop="@dimen/spacing_tiny"
8
  android:padding="@dimen/spacing_tiny">
9
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  </FrameLayout>
 
7
  android:layout_marginTop="@dimen/spacing_tiny"
8
  android:padding="@dimen/spacing_tiny">
9
 
10
+ <HorizontalScrollView
11
+ android:layout_width="match_parent"
12
+ android:layout_height="wrap_content"
13
+ android:orientation="horizontal">
14
+ <LinearLayout
15
+ android:id="@+id/ll_contacts_widget"
16
+ android:layout_width="match_parent"
17
+ android:layout_height="wrap_content"
18
+ android:orientation="horizontal"
19
+ android:visibility="gone" />
20
+ </HorizontalScrollView>
21
+
22
  </FrameLayout>