Thomas Richardson commited on
Commit
1f154fd
·
unverified ·
2 Parent(s): c6797b2bcaee17

Merge pull request #110 from ttt246/feature/alarm_android_new_56

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>