diff --git a/Android/app/src/main/AndroidManifest.xml b/Android/app/src/main/AndroidManifest.xml index ba0f495f6065fcca8608f5ce7ff5d4a94241389a..51be55a1a2968d64f0b101d360576b37cc77cdbf 100644 --- a/Android/app/src/main/AndroidManifest.xml +++ b/Android/app/src/main/AndroidManifest.xml @@ -9,6 +9,9 @@ + + + @@ -48,6 +51,11 @@ + + \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/RisingApplication.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/RisingApplication.kt index b5910f63aa2d54c3141a59bb90f9626ed8c3d5d0..3eb5b16292de4c68326ed2028816bfe4063de946 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/RisingApplication.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/RisingApplication.kt @@ -3,6 +3,7 @@ package com.matthaigh27.chatgptwrapper import android.annotation.SuppressLint import android.app.Application import android.provider.Settings +import android.util.Log import com.google.android.gms.tasks.OnCompleteListener import com.google.firebase.messaging.FirebaseMessaging diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ContactDao.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ContactDao.kt index 9eb2010056fe52c67f60cb174ea3f2431a0d26a6..ecb1de64c94b6c0e6cca209dcc15649a30b42563 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ContactDao.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ContactDao.kt @@ -7,14 +7,14 @@ import com.matthaigh27.chatgptwrapper.data.local.entity.ContactEntity @Dao interface ContactDao { @Insert - fun insert(contact: ContactEntity) + suspend fun insert(contact: ContactEntity) @Update - fun update(contact: ContactEntity) + suspend fun update(contact: ContactEntity) @Delete - fun delete(contact: ContactEntity) + suspend fun delete(contact: ContactEntity) @Query("SELECT * FROM contacts") - fun getAllData(): List + suspend fun getAllData(): List } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ImageDao.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ImageDao.kt index a68090332134d04543ac8dcbd3e8eae5481c3264..83d6a562ab88f20110e4ecba8d692bc241b34770 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ImageDao.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ImageDao.kt @@ -7,14 +7,14 @@ import com.matthaigh27.chatgptwrapper.data.local.entity.ImageEntity @Dao interface ImageDao { @Insert - fun insert(image: ImageEntity) + suspend fun insert(image: ImageEntity) @Update - fun update(image: ImageEntity) + suspend fun update(image: ImageEntity) @Delete - fun delete(image: ImageEntity) + suspend fun delete(image: ImageEntity) @Query("SELECT * FROM images") - fun getAllData(): List + suspend fun getAllData(): List } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ContactModel.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ContactModel.kt deleted file mode 100644 index 37acc802af87eec9934b70770c16e8a8da2fff27..0000000000000000000000000000000000000000 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ContactModel.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.matthaigh27.chatgptwrapper.data.models - -data class ContactModel( - var id: String = "", - var name: String = "", - var phoneList: ArrayList = ArrayList(), - var status: String = "" -) diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/HelpPromptModel.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/HelpPromptModel.kt deleted file mode 100644 index dfbf1fefd0526d3bda705a37e36fda5ab3b0dfa6..0000000000000000000000000000000000000000 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/HelpPromptModel.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.matthaigh27.chatgptwrapper.data.models - -data class HelpPromptModel( - var name: String = "", - var description: String = "", - var prompt: String = "", - var tags: ArrayList = ArrayList() -) diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/AlarmModel.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/AlarmModel.kt similarity index 62% rename from Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/AlarmModel.kt rename to Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/AlarmModel.kt index 8ffd6e9b0d9492f5431e0df363e42e550dfe8833..af305e5e5f883cf3262ff5d8552cf25b014e2ba1 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/AlarmModel.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/AlarmModel.kt @@ -1,3 +1,3 @@ -package com.matthaigh27.chatgptwrapper.data.models +package com.matthaigh27.chatgptwrapper.data.models.chat data class AlarmModel(val id: Int, val time: Long, val enabled: Boolean, val label: String) \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ChatMessageModel.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ChatMessageModel.kt similarity index 94% rename from Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ChatMessageModel.kt rename to Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ChatMessageModel.kt index ce6fb97eb53df247050cf85163eddd3211b95e94..3894530a75ff62e21fb1cb95e017b0fc7c495c09 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ChatMessageModel.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ChatMessageModel.kt @@ -1,4 +1,4 @@ -package com.matthaigh27.chatgptwrapper.data.models +package com.matthaigh27.chatgptwrapper.data.models.chat import com.google.gson.JsonElement diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ContactModel.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ContactModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..5e359ab9080991ad26b7df267a663e13f6383c7f --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ContactModel.kt @@ -0,0 +1,8 @@ +package com.matthaigh27.chatgptwrapper.data.models.chat + +data class ContactModel( + var contactId: String = String(), + var displayName: String = String(), + var phoneNumbers: ArrayList = ArrayList(), + var status: String = String() +) diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/HelpCommandModel.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/HelpCommandModel.kt similarity index 62% rename from Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/HelpCommandModel.kt rename to Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/HelpCommandModel.kt index b6bd5d3dd5be36cd7044c7c65ba08dafe6a8be74..0ac371761b96706e50e96f1fd2a9c0c44bc512f5 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/HelpCommandModel.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/HelpCommandModel.kt @@ -1,4 +1,4 @@ -package com.matthaigh27.chatgptwrapper.data.models +package com.matthaigh27.chatgptwrapper.data.models.chat data class HelpCommandModel ( var main: String? = null, diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/HelpPromptModel.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/HelpPromptModel.kt new file mode 100644 index 0000000000000000000000000000000000000000..635a80e1f19a636ac71280c96059b7430ab571fb --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/HelpPromptModel.kt @@ -0,0 +1,22 @@ +package com.matthaigh27.chatgptwrapper.data.models.chat + +import com.google.gson.Gson + +data class HelpPromptModel( + var name: String = "", + var description: String = "", + var prompt: String = "", + var tags: ArrayList = ArrayList() +) { + override fun toString(): String { + val gson = Gson() + return gson.toJson(this) + } + + companion object { + fun init(string: String): HelpPromptModel { + val gson = Gson() + return gson.fromJson(string, HelpPromptModel::class.java) + } + } +} diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ImageModel.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ImageModel.kt similarity index 62% rename from Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ImageModel.kt rename to Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ImageModel.kt index c346042454201baea4d740ef0e6d638c743b724f..b3fbd5d53b469deb26853c73770e6749aba68697 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ImageModel.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ImageModel.kt @@ -1,4 +1,4 @@ -package com.matthaigh27.chatgptwrapper.data.models +package com.matthaigh27.chatgptwrapper.data.models.chat import android.net.Uri diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chatwidgetprops/ScheduleAlarmProps.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chatwidgetprops/ScheduleAlarmProps.kt new file mode 100644 index 0000000000000000000000000000000000000000..5e91e71c3058d603a2b93215296285ab5aba6f3e --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chatwidgetprops/ScheduleAlarmProps.kt @@ -0,0 +1,46 @@ +package com.matthaigh27.chatgptwrapper.data.models.chatwidgetprops + +import com.google.gson.Gson +import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel +import com.matthaigh27.chatgptwrapper.data.models.common.Time + +data class ScheduleAlarmProps( + val time: Time? = null, + val label: String? = null, + val repeat: BooleanArray? = null +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ScheduleAlarmProps + + if (time != other.time) return false + if (repeat != null) { + if (other.repeat == null) return false + if (!repeat.contentEquals(other.repeat)) return false + } else if (other.repeat != null) return false + if (label != other.label) return false + + return true + } + + override fun hashCode(): Int { + var result = time?.hashCode() ?: 0 + result = 31 * result + (repeat?.contentHashCode() ?: 0) + result = 31 * result + (label?.hashCode() ?: 0) + return result + } + + override fun toString(): String { + val gson = Gson() + return gson.toJson(this) + } + + companion object { + fun init(string: String): ScheduleAlarmProps { + val gson = Gson() + return gson.fromJson(string, ScheduleAlarmProps::class.java) + } + } +} diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/common/Time.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/common/Time.kt new file mode 100644 index 0000000000000000000000000000000000000000..6ce132adcbbeec0efc541855789d3bba3a111bc9 --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/common/Time.kt @@ -0,0 +1,7 @@ +package com.matthaigh27.chatgptwrapper.data.models.common + +data class Time ( + val hour:Int, + val minute:Int, + val second:Int, +) \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiClient.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiClient.kt index f996199814238b7209885d74fde7021d9798ce4c..3923677834f7a909e11cafcff5fa1f379f301b1b 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiClient.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiClient.kt @@ -1,6 +1,10 @@ package com.matthaigh27.chatgptwrapper.data.remote import com.matthaigh27.chatgptwrapper.utils.Constants.API_BASE_URL +import com.matthaigh27.chatgptwrapper.utils.Constants.TIME_OUT_CALL +import com.matthaigh27.chatgptwrapper.utils.Constants.TIME_OUT_CONNECT +import com.matthaigh27.chatgptwrapper.utils.Constants.TIME_OUT_READ +import com.matthaigh27.chatgptwrapper.utils.Constants.TIME_OUT_WRITE import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit @@ -9,10 +13,10 @@ import java.util.concurrent.TimeUnit object ApiClient { private val client = OkHttpClient.Builder() - .callTimeout(240, TimeUnit.SECONDS) - .connectTimeout(240, TimeUnit.SECONDS) - .readTimeout(240, TimeUnit.SECONDS) - .writeTimeout(240, TimeUnit.SECONDS) + .callTimeout(TIME_OUT_CALL, TimeUnit.SECONDS) + .connectTimeout(TIME_OUT_CONNECT, TimeUnit.SECONDS) + .readTimeout(TIME_OUT_READ, TimeUnit.SECONDS) + .writeTimeout(TIME_OUT_WRITE, TimeUnit.SECONDS) .build() private val retrofit = Retrofit.Builder() diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiService.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiService.kt index aba49215779f85e86c0614ae017d70fd11952e12..dec32d613a41fc5634e9b5864fd97bf2e3e5b47e 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiService.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiService.kt @@ -1,8 +1,13 @@ package com.matthaigh27.chatgptwrapper.data.remote import com.matthaigh27.chatgptwrapper.data.remote.requests.BaseApiRequest +import com.matthaigh27.chatgptwrapper.data.remote.requests.ImageRelatednessApiRequest import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest +import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainContactsApiRequest +import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainImageApiRequest import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse +import com.matthaigh27.chatgptwrapper.data.remote.responses.EmptyResultApiResponse +import com.matthaigh27.chatgptwrapper.data.remote.responses.TrainImageApiResponse import retrofit2.Call import retrofit2.http.Body import retrofit2.http.POST @@ -12,4 +17,10 @@ interface ApiService { fun getAllHelpCommands(@Body request: BaseApiRequest) : Call @POST("sendNotification") fun sendNotification(@Body request: NotificationApiRequest) : Call + @POST("train/contacts") + fun trainContacts(@Body request: TrainContactsApiRequest) : Call + @POST("image_relatedness") + fun getImageRelatedness(@Body request: ImageRelatednessApiRequest) : Call + @POST("uploadImage") + fun trainImage(@Body request: TrainImageApiRequest) : Call } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/ImageRelatednessApiRequest.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/ImageRelatednessApiRequest.kt new file mode 100644 index 0000000000000000000000000000000000000000..c637c99e45072f96160c912da0927914b558cd82 --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/ImageRelatednessApiRequest.kt @@ -0,0 +1,9 @@ +package com.matthaigh27.chatgptwrapper.data.remote.requests + +import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys + +data class ImageRelatednessApiRequest( + val image_name: String, + val message: String, + val confs: Keys +) diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/TrainContactsApiRequest.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/TrainContactsApiRequest.kt new file mode 100644 index 0000000000000000000000000000000000000000..6aaf90aaa18b92ac0a269782962f87705bb828df --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/TrainContactsApiRequest.kt @@ -0,0 +1,9 @@ +package com.matthaigh27.chatgptwrapper.data.remote.requests + +import com.matthaigh27.chatgptwrapper.data.models.chat.ContactModel +import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys + +data class TrainContactsApiRequest( + val contacts: ArrayList, + val confs: Keys +) \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/TrainImageApiRequest.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/TrainImageApiRequest.kt new file mode 100644 index 0000000000000000000000000000000000000000..781b17c1c3170d1ccfaa66fbc9491cc0d6bfd2f9 --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/TrainImageApiRequest.kt @@ -0,0 +1,9 @@ +package com.matthaigh27.chatgptwrapper.data.remote.requests + +import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys + +data class TrainImageApiRequest( + val image_name: String, + val status: String, + val confs: Keys +) diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/ApiResponse.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/ApiResponse.kt index 035c9a2a8bffde48d83ab4c67e39b4b5ab315df5..502ebe4e3ac935df2ecd2c7ceb264067e4f2e4b1 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/ApiResponse.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/ApiResponse.kt @@ -8,8 +8,3 @@ data class ApiResponse ( val result: Result ) -data class Result ( - val program: String, - val content: JsonElement, - val url: String -) \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/EmptyResultApiResponse.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/EmptyResultApiResponse.kt new file mode 100644 index 0000000000000000000000000000000000000000..250961cab023963f7dea7691f500ad7708cdd650 --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/EmptyResultApiResponse.kt @@ -0,0 +1,7 @@ +package com.matthaigh27.chatgptwrapper.data.remote.responses + +data class EmptyResultApiResponse( + val status_code: Int, + val message: List, + val result: String +) \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/Result.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/Result.kt new file mode 100644 index 0000000000000000000000000000000000000000..652d70188920db95f4d29acc4a93425e30664e2d --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/Result.kt @@ -0,0 +1,9 @@ +package com.matthaigh27.chatgptwrapper.data.remote.responses + +import com.google.gson.JsonElement + +data class Result ( + val program: String, + val content: JsonElement, + val url: String +) \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/TrainImageApiResponse.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/TrainImageApiResponse.kt new file mode 100644 index 0000000000000000000000000000000000000000..336ba4c3db289d3b3af515f345bfe5622aed3a90 --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/TrainImageApiResponse.kt @@ -0,0 +1,12 @@ +package com.matthaigh27.chatgptwrapper.data.remote.responses + +data class TrainImageApiResponse( + val status_code: Int, + val message: List, + val result: ImageInfo +) + +data class ImageInfo( + val image_name: String, + val image_text: String +) \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/FirebaseRepository.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/FirebaseRepository.kt index 2b74b7ce97a00d32146d9a716e7b3f959df55a1d..dfa3d6c7f754a856ded7bba6367b2e414e41f3bd 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/FirebaseRepository.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/FirebaseRepository.kt @@ -1,8 +1,14 @@ package com.matthaigh27.chatgptwrapper.data.repository import com.google.firebase.storage.FirebaseStorage -import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnFailure -import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnSuccess +import com.google.protobuf.Empty +import com.matthaigh27.chatgptwrapper.data.remote.ApiResource +import com.matthaigh27.chatgptwrapper.utils.helpers.OnFailure +import com.matthaigh27.chatgptwrapper.utils.helpers.OnSuccess +import kotlinx.coroutines.suspendCancellableCoroutine +import java.util.UUID +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine object FirebaseRepository { fun downloadImageWithName( @@ -20,4 +26,37 @@ object FirebaseRepository { } return } + + fun uploadImageAsync( + imageByteArray: ByteArray, + onSuccess: OnSuccess, + onFailure: OnFailure + ) { + val storageRef = FirebaseStorage.getInstance().reference + val uuid = UUID.randomUUID() + val imageName = "images/${uuid}" + val imageRef = storageRef.child(imageName) + + val uploadTask = imageRef.putBytes(imageByteArray) + uploadTask.addOnFailureListener { + onFailure("Fail to upload image to firebase.") + }.addOnSuccessListener { + onSuccess("$uuid") + } + } + + suspend fun uploadImage(imageByteArray: ByteArray): String = suspendCoroutine { continuation -> + val storageRef = FirebaseStorage.getInstance().reference + val uuid = UUID.randomUUID() + val imageName = "images/${uuid}" + val imageRef = storageRef.child(imageName) + + val uploadTask = imageRef.putBytes(imageByteArray) + + uploadTask.addOnFailureListener { + continuation.resume("Error") + }.addOnSuccessListener { + continuation.resume("$uuid") + } + } } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RemoteRepository.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RemoteRepository.kt index 7797ca5f08088eeb2d63b29d5853cf36b57cc1c9..cd6b8a7054a17baf3f95314a16b48c32447a952f 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RemoteRepository.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RemoteRepository.kt @@ -1,30 +1,37 @@ package com.matthaigh27.chatgptwrapper.data.repository import com.matthaigh27.chatgptwrapper.data.remote.ApiClient +import com.matthaigh27.chatgptwrapper.data.remote.ApiResource +import com.matthaigh27.chatgptwrapper.data.remote.requests.ImageRelatednessApiRequest import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest +import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainContactsApiRequest +import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainImageApiRequest import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse -import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnFailure -import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnSuccess +import com.matthaigh27.chatgptwrapper.data.remote.responses.EmptyResultApiResponse +import com.matthaigh27.chatgptwrapper.data.remote.responses.TrainImageApiResponse +import com.matthaigh27.chatgptwrapper.utils.helpers.OnFailure +import com.matthaigh27.chatgptwrapper.utils.helpers.OnSuccess import com.matthaigh27.chatgptwrapper.utils.helpers.network.RequestFactory.buildBaseApiRequest import retrofit2.Call import retrofit2.Callback import retrofit2.Response +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine object RemoteRepository { private val apiService = ApiClient.apiService fun getAllHelpCommands( - onSuccess: OnSuccess, - onFailure: OnFailure + onSuccess: OnSuccess, onFailure: OnFailure ) { val call = apiService.getAllHelpCommands(buildBaseApiRequest()) call.enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { - response.body()?.let { - onSuccess(ApiResponse(it.status_code, it.message, it.result)) - }?: run { + response.body()?.let { data -> + onSuccess(data) + } ?: run { onFailure(response.message()) } } @@ -45,8 +52,77 @@ object RemoteRepository { call.enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { response.body()?.let { data -> - onSuccess(ApiResponse(data.status_code, data.message, data.result)) - }?: run { + onSuccess(data) + } ?: run { + onFailure(response.message()) + } + } + + override fun onFailure(call: Call, t: Throwable) { + onFailure(t.message.toString()) + } + }) + } + + fun trainContacts( + request: TrainContactsApiRequest, + onSuccess: OnSuccess, + onFailure: OnFailure + ) { + val call = apiService.trainContacts(request) + + call.enqueue(object : Callback { + override fun onResponse( + call: Call, response: Response + ) { + response.body()?.let { data -> + onSuccess(data) + } ?: run { + onFailure(response.message()) + } + } + + override fun onFailure(call: Call, t: Throwable) { + onFailure(t.message.toString()) + } + }) + } + + suspend fun trainImage(request: TrainImageApiRequest) : ApiResource = suspendCoroutine { continuation -> + + val call = apiService.trainImage(request) + + call.enqueue(object : Callback { + override fun onResponse( + call: Call, response: Response + ) { + response.body()?.let { data -> + continuation.resume(ApiResource.Success(data)) + } ?: run { + continuation.resume(ApiResource.Error("Error")) + } + } + + override fun onFailure(call: Call, t: Throwable) { + continuation.resume(ApiResource.Error(t.message.toString())) + } + }) + } + + fun getImageRelatedness( + request: ImageRelatednessApiRequest, + onSuccess: OnSuccess, + onFailure: OnFailure + ) { + val call = apiService.getImageRelatedness(request) + + call.enqueue(object : Callback { + override fun onResponse( + call: Call, response: Response + ) { + response.body()?.let { data -> + onSuccess(data) + } ?: run { onFailure(response.message()) } } diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RoomRepository.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RoomRepository.kt index 81cb0a36f9e86df7b8176fa3c5e4dc7fd6e6df01..86d825f20f6bb16b79dd947b4abb6eb3dff1edbc 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RoomRepository.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RoomRepository.kt @@ -13,35 +13,35 @@ object RoomRepository { private var imageDao = databaseHandler.imageDao() private var contactDao = databaseHandler.contactDao() - fun getAllImages(): MutableLiveData> { + suspend fun getAllImages(): MutableLiveData> { return MutableLiveData(imageDao.getAllData()) } - fun insertImage(entity: ImageEntity) { + suspend fun insertImage(entity: ImageEntity) { imageDao.insert(entity) } - fun updateImage(entity: ImageEntity) { + suspend fun updateImage(entity: ImageEntity) { imageDao.update(entity) } - fun deleteImage(entity: ImageEntity) { + suspend fun deleteImage(entity: ImageEntity) { imageDao.delete(entity) } - fun getAllContacts(): MutableLiveData> { + suspend fun getAllContacts(): MutableLiveData> { return MutableLiveData(contactDao.getAllData()) } - fun insertImage(entity: ContactEntity) { + suspend fun insertContact(entity: ContactEntity) { contactDao.insert(entity) } - fun updateImage(entity: ContactEntity) { + suspend fun updateContact(entity: ContactEntity) { contactDao.update(entity) } - fun deleteImage(entity: ContactEntity) { + suspend fun deleteContact(entity: ContactEntity) { contactDao.delete(entity) } } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/adapters/ChatMainAdapter.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/adapters/ChatMainAdapter.kt index 03deb5e800281637c07a1a8641ca31bb176f3f03..604c689af46a7199eb695e1adaa028563254b812 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/adapters/ChatMainAdapter.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/adapters/ChatMainAdapter.kt @@ -7,16 +7,29 @@ import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import android.widget.ImageView +import android.widget.LinearLayout import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.recyclerview.widget.RecyclerView import com.matthaigh27.chatgptwrapper.R -import com.matthaigh27.chatgptwrapper.data.models.ChatMessageModel +import com.matthaigh27.chatgptwrapper.data.models.chat.ChatMessageModel +import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel +import com.matthaigh27.chatgptwrapper.data.models.chatwidgetprops.ScheduleAlarmProps import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface +import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.OnHideListener import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.SendSmsWidget +import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.alarm.ScheduleAlarmWidget +import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.contact.SearchContactWidget import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.helpprompt.HelpPromptWidget -import com.matthaigh27.chatgptwrapper.utils.Constants +import com.matthaigh27.chatgptwrapper.utils.Constants.PROPS_WIDGET_DESC +import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_HELP_PROMPT +import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SCHEDULE_ALARM +import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SEARCH_CONTACT +import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SMS +import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ContactHelper.getContactModelById +import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ContactHelper.getContacts import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper +import org.json.JSONArray class ChatMainAdapter( context: Context, list: ArrayList, callbacks: ChatMessageInterface @@ -25,6 +38,7 @@ class ChatMainAdapter( private val VIEW_TYPE_MSG_SENT = 0 private val VIEW_TYPE_MSG_RECEIVED = 1 private val VIEW_TYPE_CHAT_WIDGET = 2 + private val VIEW_TYPE_CHAT_ERROR = 3 private var context: Context private var callbacks: ChatMessageInterface @@ -41,7 +55,7 @@ class ChatMainAdapter( return when (viewType) { VIEW_TYPE_MSG_SENT -> { - SentMessageViewHolder( + MessageViewHolder( inflater.inflate( R.layout.item_container_sent_message, parent, false ) @@ -49,13 +63,21 @@ class ChatMainAdapter( } VIEW_TYPE_MSG_RECEIVED -> { - ReceivedMessageViewHolder( + MessageViewHolder( inflater.inflate( R.layout.item_container_received_message, parent, false ) ) } + VIEW_TYPE_CHAT_ERROR -> { + MessageViewHolder( + inflater.inflate( + R.layout.item_container_error_message, parent, false + ) + ) + } + else -> { ChatWidgetViewHolder( inflater.inflate( @@ -78,25 +100,17 @@ class ChatMainAdapter( val index = holder.adapterPosition val chatMessageModel: ChatMessageModel = chatMessageList[index] when (chatMessageModel.type) { - VIEW_TYPE_MSG_SENT -> { - setMessageData(holder as SentMessageViewHolder, chatMessageModel) - } - - VIEW_TYPE_MSG_RECEIVED -> { - setMessageData(holder as ReceivedMessageViewHolder, chatMessageModel) + VIEW_TYPE_CHAT_WIDGET -> { + setMessageData(holder as ChatWidgetViewHolder, chatMessageModel) } else -> { - setMessageData(holder as ChatWidgetViewHolder, chatMessageModel) + setMessageData(holder as MessageViewHolder, chatMessageModel) } } } - private fun setMessageData(holder: SentMessageViewHolder, data: ChatMessageModel) { - holder.txtMessage.text = data.content - } - - private fun setMessageData(holder: ReceivedMessageViewHolder, data: ChatMessageModel) { + private fun setMessageData(holder: MessageViewHolder, data: ChatMessageModel) { if (data.hasImage) { data.image?.let { image -> val originBitmap = BitmapFactory.decodeByteArray(image, 0, image.size) @@ -114,48 +128,101 @@ class ChatMainAdapter( } else { holder.txtMessage.text = data.content holder.imgMessage.visibility = View.GONE - holder.txtMessage.visibility = View.VISIBLE + data.content?.let { + holder.txtMessage.visibility = View.VISIBLE + } ?: run { + holder.txtMessage.visibility = View.GONE + } } } private fun setMessageData(holder: ChatWidgetViewHolder, data: ChatMessageModel) { + holder.itemLayout.visibility = View.VISIBLE + val index = holder.adapterPosition + when (data.content) { - Constants.TYPE_WIDGET_SMS -> { + TYPE_WIDGET_SMS -> { val sendSmsWidget = SendSmsWidget(context).apply { this.callback = callbacks + this.hideListener = object : OnHideListener { + override fun hide() { + holder.itemLayout.visibility = View.GONE + chatMessageList.removeAt(index) + notifyItemRemoved(index) + } + } + } + + if (data.data != null) { + val widgetDesc = data.data.asJsonObject[PROPS_WIDGET_DESC].asString + if (widgetDesc.isNotEmpty()) { + sendSmsWidget.setPhoneNumber(widgetDesc) + } } + holder.itemLayout.addView(sendSmsWidget) - holder.itemLayout.visibility = View.VISIBLE } - Constants.TYPE_WIDGET_HELP_PROMPT -> { -// val helpPromptWidget = HelpPromptWidget(context) + TYPE_WIDGET_HELP_PROMPT -> { + val widgetDesc = data.data!!.asJsonObject[PROPS_WIDGET_DESC].asString + val helpPromptWidget = + HelpPromptWidget(context, HelpPromptModel.init(widgetDesc)).apply { + this.callback = callbacks + this.hideListener = object : OnHideListener { + override fun hide() { + holder.itemLayout.visibility = View.GONE + chatMessageList.removeAt(index) + notifyItemRemoved(index) + } + } + } + holder.itemLayout.addView(helpPromptWidget) } - Constants.TYPE_WIDGET_SEARCH_CONTACT -> { + TYPE_WIDGET_SEARCH_CONTACT -> { + holder.llSearchContact.visibility = View.VISIBLE - } + val contacts = getContacts(context) - Constants.TYPE_WIDGET_FEEDBACK -> { + val contactIds = JSONArray(data.data!!.asString.replace("'", "\"")) + for (i in 0 until contactIds.length()) { + val contactId = contactIds[i].toString() + val contact = getContactModelById(contactId, contacts) + val searchContactWidget = SearchContactWidget(context, contact).apply { + this.callback = callbacks + } + holder.llSearchContact.addView(searchContactWidget) + } } - } - } - inner class ReceivedMessageViewHolder internal constructor(itemView: View) : - RecyclerView.ViewHolder(itemView) { - var txtMessage: TextView - var imgMessage: ImageView - var itemLayout: ConstraintLayout + TYPE_WIDGET_SCHEDULE_ALARM -> { + var props = ScheduleAlarmProps() + data.data?.run { + val widgetDesc = data.data.asJsonObject[PROPS_WIDGET_DESC].asString + props = ScheduleAlarmProps.init(widgetDesc) + } + val scheduleAlarmWidget = + ScheduleAlarmWidget(context, props.time, props.label, props.repeat).apply { + this.callback = callbacks + this.hideListener = object : OnHideListener { + override fun hide() { + holder.itemLayout.visibility = View.GONE + chatMessageList.removeAt(index) + notifyItemRemoved(index) + } + } + } + holder.itemLayout.addView(scheduleAlarmWidget) + } - init { - txtMessage = itemView.findViewById(R.id.txt_message) as TextView - imgMessage = itemView.findViewById(R.id.img_message) as ImageView - itemLayout = itemView.findViewById(R.id.cl_received_message) as ConstraintLayout + else -> { + holder.itemLayout.visibility = View.GONE + } } } - inner class SentMessageViewHolder internal constructor(itemView: View) : + inner class MessageViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) { var txtMessage: TextView var imgMessage: ImageView @@ -164,16 +231,18 @@ class ChatMainAdapter( init { txtMessage = itemView.findViewById(R.id.txt_message) as TextView imgMessage = itemView.findViewById(R.id.img_message) as ImageView - itemLayout = itemView.findViewById(R.id.cl_sent_message) as ConstraintLayout + itemLayout = itemView.findViewById(R.id.cl_message) as ConstraintLayout } } inner class ChatWidgetViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) { var itemLayout: FrameLayout + var llSearchContact: LinearLayout init { itemLayout = itemView.findViewById(R.id.fl_widget_message) as FrameLayout + llSearchContact = itemView.findViewById(R.id.ll_contacts_widget) as LinearLayout } } } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/fragments/ChatMainFragment.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/fragments/ChatMainFragment.kt index b24d07cea244ac302757188e6789318f2f8feb56..2367d21fc82ff7e3ec7f250b7624167f6d317330 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/fragments/ChatMainFragment.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/fragments/ChatMainFragment.kt @@ -13,17 +13,19 @@ import android.view.animation.RotateAnimation import android.widget.EditText import android.widget.ImageView import android.widget.LinearLayout -import android.widget.Toast import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.gson.JsonElement +import com.google.gson.JsonObject import com.matthaigh27.chatgptwrapper.R -import com.matthaigh27.chatgptwrapper.data.models.ChatMessageModel -import com.matthaigh27.chatgptwrapper.data.models.HelpCommandModel -import com.matthaigh27.chatgptwrapper.data.models.HelpPromptModel +import com.matthaigh27.chatgptwrapper.data.models.chat.ChatMessageModel +import com.matthaigh27.chatgptwrapper.data.models.chat.HelpCommandModel +import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel +import com.matthaigh27.chatgptwrapper.data.models.chatwidgetprops.ScheduleAlarmProps +import com.matthaigh27.chatgptwrapper.data.models.common.Time import com.matthaigh27.chatgptwrapper.data.remote.ApiResource import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse import com.matthaigh27.chatgptwrapper.ui.chat.view.adapters.ChatMainAdapter @@ -32,26 +34,33 @@ import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.toolbar.ChatToolsWidg import com.matthaigh27.chatgptwrapper.ui.chat.viewmodel.ChatViewModel import com.matthaigh27.chatgptwrapper.utils.Constants.ERROR_MSG_NOEXIST_COMMAND import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ALL +import com.matthaigh27.chatgptwrapper.utils.Constants.PROPS_WIDGET_DESC +import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_ALARM import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_ALERT import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_BROWSER import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_CONTACT import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_IMAGE import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_MESSAGE -import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_SMS import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_HELP_PROMPT +import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SCHEDULE_ALARM +import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SEARCH_CONTACT import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SMS +import com.matthaigh27.chatgptwrapper.utils.helpers.Converter import com.matthaigh27.chatgptwrapper.utils.helpers.Converter.stringToHelpPromptList import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.getHelpCommandFromStr import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.isMainHelpCommand import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.makePromptItemUsage import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.makePromptUsage import com.matthaigh27.chatgptwrapper.utils.helpers.ui.NoNewLineInputFilter +import org.json.JSONArray +import java.util.Calendar class ChatMainFragment : Fragment(), OnClickListener { private val TYPE_CHAT_SENT = 0 private val TYPE_CHAT_RECEIVE = 1 private val TYPE_CHAT_WIDGET = 2 + private val TYPE_CHAT_ERROR = 3 private lateinit var rootView: View lateinit var viewModel: ChatViewModel @@ -68,6 +77,11 @@ class ChatMainFragment : Fragment(), OnClickListener { private var chatToolsWidget: ChatToolsWidget? = null private var helpPromptList: ArrayList? = null + private var currentSelectedImage: ByteArray? = null + private var currentUploadedImageName: String? = null + private var isImagePicked: Boolean = false + private var showloadingCount = 0 + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { @@ -87,13 +101,15 @@ class ChatMainFragment : Fragment(), OnClickListener { fetchAllCommands() } + + private fun initViewModel() { viewModel = ViewModelProvider(this)[ChatViewModel::class.java] } private fun initLoadingRotate() { loadingRotate = RotateAnimation(/* fromDegrees = */ 0f, /* toDegrees = */ - 360f, /* pivotXType = */ + 720f, /* pivotXType = */ Animation.RELATIVE_TO_SELF, /* pivotXValue = */ 0.5f, /* pivotYType = */ Animation.RELATIVE_TO_SELF, /* pivotYValue = */ @@ -135,24 +151,28 @@ class ChatMainFragment : Fragment(), OnClickListener { } private fun initChatToolsWidget() { - chatToolsWidget = ChatToolsWidget(requireContext(), requireActivity()) + chatToolsWidget = ChatToolsWidget(requireContext(), requireActivity()).apply { + this.callback = chatMessageInterface + } val llToolBar = rootView.findViewById(R.id.ll_toolbar) llToolBar.addView(chatToolsWidget) } - private fun showToast(message: String) { - Toast.makeText(requireContext(), message, Toast.LENGTH_LONG).show() - } - private fun showLoading(isLoading: Boolean) { val imgLoading = rootView.findViewById(R.id.sp_loading) if (isLoading) { imgLoading.startAnimation(loadingRotate) imgLoading.visibility = View.VISIBLE + edtMessageInput?.isEnabled = false + showloadingCount++ } else { - imgLoading.clearAnimation() - imgLoading.visibility = View.GONE + showloadingCount-- + if(showloadingCount == 0) { + imgLoading.clearAnimation() + imgLoading.visibility = View.GONE + edtMessageInput?.isEnabled = true + } } } @@ -163,18 +183,44 @@ class ChatMainFragment : Fragment(), OnClickListener { hasImage: Boolean = false, image: ByteArray? = null ) { - addChatItemToList(ChatMessageModel(type, content, data, hasImage, image)) when (type) { TYPE_CHAT_SENT -> { if (content!!.isNotEmpty() && content.first() == '/') { openHelpPromptWidget(content) return } - sendNotification(content) + if (isImagePicked) { + addChatItemToList( + ChatMessageModel( + type = type, + content = content, + data = data, + hasImage = true, + image = currentSelectedImage + ) + ) + isImagePicked = false + } else { + addChatItemToList(ChatMessageModel(type, content, data, hasImage, image)) + sendNotification(content) + } + } + + else -> { + addChatItemToList(ChatMessageModel(type, content, data, hasImage, image)) } } } + private fun addErrorMessage( + message: String + ) { + addMessage( + type = TYPE_CHAT_RECEIVE, + content = message + ) + } + @SuppressLint("NotifyDataSetChanged") private fun addChatItemToList(chatModel: ChatMessageModel) { edtMessageInput?.setText("") @@ -184,6 +230,18 @@ class ChatMainFragment : Fragment(), OnClickListener { rvChatList?.scrollToPosition(chatMessageList.size - 1) } + private fun trainContacts() { + viewModel.trainContacts().observe(viewLifecycleOwner, Observer { state -> + showLoading(state) + }) + } + + private fun trainImages() { + viewModel.trainImages().observe(viewLifecycleOwner, Observer { state -> + showLoading(state) + }) + } + private fun openHelpPromptWidget(message: String) { try { val command: HelpCommandModel = getHelpCommandFromStr(message) @@ -201,17 +259,22 @@ class ChatMainFragment : Fragment(), OnClickListener { model.name == command.main } - if(data.isEmpty()) { + if (data.isEmpty()) { addMessage( type = TYPE_CHAT_RECEIVE, content = ERROR_MSG_NOEXIST_COMMAND ) } else { + val widgetDesc = JsonObject().apply { + this.addProperty(PROPS_WIDGET_DESC, data[0].toString()) + } addMessage( type = TYPE_CHAT_WIDGET, content = TYPE_WIDGET_HELP_PROMPT, - data = data[0].toString() as JsonElement + data = widgetDesc ) } + } ?: run { + addErrorMessage("Help commands don't exist.") } } } @@ -229,7 +292,7 @@ class ChatMainFragment : Fragment(), OnClickListener { } } catch (e: Exception) { e.printStackTrace() - showToast(e.message.toString()) + addErrorMessage(e.message.toString()) } } @@ -251,7 +314,7 @@ class ChatMainFragment : Fragment(), OnClickListener { is ApiResource.Error -> { showLoading(false) - showToast(resource.message!!) + addErrorMessage(resource.message!!) } } }) @@ -263,35 +326,22 @@ class ChatMainFragment : Fragment(), OnClickListener { is ApiResource.Loading -> { showLoading(true) } + is ApiResource.Success -> { showLoading(false) val apiResponse = resource.data when (apiResponse?.result?.program) { - TYPE_RESPONSE_MESSAGE -> { - addMessage(TYPE_CHAT_RECEIVE, apiResponse.result.content.toString()) - } - TYPE_RESPONSE_BROWSER -> { - fetchResponseBrowser(apiResponse) - } - TYPE_RESPONSE_ALERT -> { - - } - TYPE_RESPONSE_CONTACT -> { - - } - TYPE_RESPONSE_IMAGE -> { - fetchResponseImage(apiResponse) - } - TYPE_RESPONSE_SMS -> { - - } - else -> { - - } + TYPE_RESPONSE_MESSAGE -> addMessage(TYPE_CHAT_RECEIVE, apiResponse.result.content.toString()) + TYPE_RESPONSE_BROWSER -> fetchResponseBrowser(apiResponse) + TYPE_RESPONSE_CONTACT -> fetchResponseContact(apiResponse) + TYPE_RESPONSE_IMAGE -> fetchResponseImage(apiResponse) + TYPE_RESPONSE_ALARM -> fetchResponseAlarm(apiResponse) + else -> addMessage(TYPE_CHAT_RECEIVE, apiResponse!!.result.toString()) } } + is ApiResource.Error -> { - showToast(resource.message!!) + addErrorMessage(resource.message!!) showLoading(false) } } @@ -325,13 +375,38 @@ class ChatMainFragment : Fragment(), OnClickListener { } is ApiResource.Error -> { - showToast(resource.message!!) + addErrorMessage(resource.message!!) showLoading(false) } } }) } + private fun fetchResponseContact(apiResponse: ApiResponse) { + val contactIds = JSONArray(apiResponse.result.content.asString.replace("'", "\"")) + if (contactIds.length() > 0) { + addMessage( + type = TYPE_CHAT_WIDGET, + content = TYPE_WIDGET_SEARCH_CONTACT, + data = apiResponse.result.content + ) + } else { + addMessage( + type = TYPE_CHAT_RECEIVE, + content = "Contacts that you are looking for don't exist.", + ) + } + } + + private fun fetchResponseAlarm(apiResponse: ApiResponse) { + val time: Time = Converter.stringToTime(apiResponse.result.content.asJsonObject.get("time").asString) + val label = apiResponse.result.content.asJsonObject.get("label").asString + val props = ScheduleAlarmProps(time, label) + val widgetDesc = JsonObject().apply { + this.addProperty(PROPS_WIDGET_DESC, props.toString()) + } + addMessage(TYPE_CHAT_WIDGET, TYPE_WIDGET_SCHEDULE_ALARM, widgetDesc) + } private fun initChatInterface() { chatMessageInterface = object : ChatMessageInterface { @@ -350,21 +425,81 @@ class ChatMainFragment : Fragment(), OnClickListener { } override fun sentHelpPrompt(prompt: String) { + addMessage( + type = TYPE_CHAT_SENT, + content = prompt + ) } override fun canceledHelpPrompt() { + addMessage( + type = TYPE_CHAT_RECEIVE, + content = "You canceled Help prompt." + ) } override fun doVoiceCall(phoneNumber: String) { + addMessage( + type = TYPE_CHAT_RECEIVE, + content = "You made a voice call to $phoneNumber" + ) } override fun doVideoCall(phoneNumber: String) { + addMessage( + type = TYPE_CHAT_RECEIVE, + content = "You made a video call to $phoneNumber" + ) } override fun sendSmsWithPhoneNumber(phoneNumber: String) { + val widgetDesc = JsonObject().apply { + this.addProperty(PROPS_WIDGET_DESC, phoneNumber) + } + addMessage( + type = TYPE_CHAT_WIDGET, + content = TYPE_WIDGET_SMS, + data = widgetDesc + ) } override fun pickImage(isSuccess: Boolean, data: ByteArray?) { + if (!isSuccess) + addErrorMessage("Fail to pick image") + viewModel.uploadImageToFirebase(data!!) + .observe(viewLifecycleOwner, Observer { resource -> + when (resource) { + is ApiResource.Loading -> { + showLoading(true) + } + + is ApiResource.Success -> { + showLoading(false) + currentSelectedImage = data + currentUploadedImageName = resource.data + isImagePicked = true + } + + is ApiResource.Error -> { + addErrorMessage(resource.message!!) + showLoading(false) + } + } + }) + } + + override fun setAlarm(hours: Int, minutes: Int, label: String) { + addMessage( + type = TYPE_CHAT_RECEIVE, + content = "You set an alarm for $hours:$minutes with the label($label)" + ) + } + + override fun cancelAlarm() { + addMessage( + type = TYPE_CHAT_RECEIVE, + content = "You canceled setting an alarm." + ) } } } @@ -380,4 +515,10 @@ class ChatMainFragment : Fragment(), OnClickListener { } } } + + override fun onResume() { + super.onResume() + trainImages() + trainContacts() + } } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/ChatMessageInterface.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/ChatMessageInterface.kt index db3e2b98cd001eaae36d00fe65ad5a815e14ed6f..fe99148c23f44c8d0a4aea8f411c4be3becc8556 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/ChatMessageInterface.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/ChatMessageInterface.kt @@ -9,4 +9,6 @@ interface ChatMessageInterface { fun doVideoCall(phoneNumber: String) fun sendSmsWithPhoneNumber(phoneNumber: String) fun pickImage(isSuccess: Boolean, data: ByteArray? = null) + fun setAlarm(hours: Int, minutes:Int, label: String) + fun cancelAlarm() } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/OnHideListener.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/OnHideListener.kt new file mode 100644 index 0000000000000000000000000000000000000000..a1fe0595ccf8714498dc5a868973adf3965972ed --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/OnHideListener.kt @@ -0,0 +1,5 @@ +package com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces + +interface OnHideListener { + fun hide() +} \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/SendSmsWidget.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/SendSmsWidget.kt index bbcbe8ca9a427c1497f4438a9e3a35aa1a9db986..4e522a29d1186d0bd8de895e953759c977aa136d 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/SendSmsWidget.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/SendSmsWidget.kt @@ -10,6 +10,7 @@ import android.widget.Toast import androidx.constraintlayout.widget.ConstraintLayout import com.matthaigh27.chatgptwrapper.R import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface +import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.OnHideListener class SendSmsWidget( context: Context, attrs: AttributeSet? = null @@ -24,6 +25,7 @@ class SendSmsWidget( private val btnCancel: Button var callback: ChatMessageInterface? = null + var hideListener: OnHideListener? = null init { inflate(context, R.layout.widget_send_sms, this) @@ -47,12 +49,12 @@ class SendSmsWidget( ).show() return@setOnClickListener } - hide() + hideListener?.hide() callback?.sentSms(edtPhoneNumber.text.toString(), edtMessage.text.toString()) } btnCancel.setOnClickListener { - hide() + hideListener?.hide() callback?.canceledSms() } } @@ -60,10 +62,4 @@ class SendSmsWidget( fun setPhoneNumber(phonenumber: String) { edtPhoneNumber.setText(phonenumber) } - - fun hide() { - this.visibility = View.GONE - edtMessage.setText("") - edtPhoneNumber.setText("") - } } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/alarm/DayOfWeekItem.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/alarm/DayOfWeekItem.kt new file mode 100644 index 0000000000000000000000000000000000000000..fe13fdab012abd43d306fa994a1563b3f6e6821a --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/alarm/DayOfWeekItem.kt @@ -0,0 +1,54 @@ +package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.alarm + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.view.setPadding +import com.matthaigh27.chatgptwrapper.R + +class DayOfWeekItem( + context: Context, day: String, attrs: AttributeSet? = null +) : LinearLayout(context, attrs), View.OnClickListener { + + private val context: Context + private var txtDay: TextView + var isChecked = false + + init { + inflate(context, R.layout.item_day_of_week, this) + this.context = context + + layoutParams = LayoutParams( + 0, + ViewGroup.LayoutParams.WRAP_CONTENT, + 1f + ) + + val padding = context.resources.getDimensionPixelSize(R.dimen.spacing_tiny) + + txtDay = findViewById(R.id.txt_day) + txtDay.text = day + + txtDay.setOnClickListener(this) + } + + override fun onClick(view: View?) { + when (view?.id) { + R.id.txt_day -> { + isChecked = !isChecked + updateBackground() + } + } + } + + fun updateBackground() { + if (isChecked) { + txtDay.background = resources.getDrawable(R.drawable.bg_circle_button_schedule_alarm_day_selected) + } else { + txtDay.background = resources.getDrawable(R.drawable.bg_circle_button_schedule_alarm_day) + } + } +} \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/alarm/ScheduleAlarmWidget.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/alarm/ScheduleAlarmWidget.kt new file mode 100644 index 0000000000000000000000000000000000000000..8b644ab2fca5f828a8dc5b50ab51f6f794a7a5c2 --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/alarm/ScheduleAlarmWidget.kt @@ -0,0 +1,110 @@ +package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.alarm + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.TimePicker +import androidx.constraintlayout.widget.ConstraintLayout +import com.google.android.material.textfield.TextInputLayout +import com.matthaigh27.chatgptwrapper.R +import com.matthaigh27.chatgptwrapper.data.models.common.Time +import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface +import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.OnHideListener +import com.matthaigh27.chatgptwrapper.utils.helpers.chat.AlarmHelper + +class ScheduleAlarmWidget( + context: Context, + time: Time? = null, + label: String? = null, + repeat: BooleanArray? = null, + attrs: AttributeSet? = null +) : ConstraintLayout(context, attrs), View.OnClickListener { + + private val WEEK_DAY_COUNT = 7 + private val dayOfWeek = arrayOf( + "S", "M", "T", "W", "T", "F", "S" + ) + private val selectedDayList: BooleanArray = BooleanArray(WEEK_DAY_COUNT) { false } + private val dayItemList: ArrayList = ArrayList() + + private val context: Context + private var repeat: BooleanArray? = null + private var llRpeat: LinearLayout + private var txtLabel: TextInputLayout + private var timePicker: TimePicker + + var callback: ChatMessageInterface? = null + var hideListener: OnHideListener? = null + + init { + inflate(context, R.layout.widget_schedule_alarm, this) + this.context = context + this.repeat = repeat + + layoutParams = LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT + ) + + findViewById(R.id.btn_ok).setOnClickListener(this) + findViewById(R.id.btn_cancel).setOnClickListener(this) + + llRpeat = findViewById(R.id.ll_repeat) + txtLabel = findViewById(R.id.txt_label) + if (label != null) { + txtLabel.editText!!.setText(label) + } + timePicker = findViewById(R.id.time_picker) + if (time != null) { + timePicker.hour = time.hour + timePicker.minute = time.minute + } + + initRepeatSetting() + } + + private fun initRepeatSetting() { + dayOfWeek.forEachIndexed { index, day -> + val item = DayOfWeekItem(context, day) + item.setOnClickListener { + selectedDayList[index] = !selectedDayList[index] + } + dayItemList.add(item) + llRpeat.addView(item) + } + if (repeat != null) { + setSelectedDay(repeat!!) + } + } + + private fun setSelectedDay(list: BooleanArray) { + list.forEachIndexed { index, status -> + dayItemList[index].isChecked = status + dayItemList[index].updateBackground() + } + } + + override fun onClick(view: View?) { + when (view?.id) { + R.id.btn_ok -> { + AlarmHelper.createAlarm( + context, + timePicker.hour, + timePicker.minute, + txtLabel.editText?.text.toString() + ) + callback?.setAlarm( + timePicker.hour, + timePicker.minute, + txtLabel.editText?.text.toString() + ) + } + + R.id.btn_cancel -> { + callback?.cancelAlarm() + } + } + hideListener?.hide() + } +} \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/ContactDetailWidget.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/ContactDetailWidget.kt index d984993ecf1a97d05cae146e0d94ac86585c2133..56f4f98a1400af2b1339e85df813e684a7838f8d 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/ContactDetailWidget.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/ContactDetailWidget.kt @@ -11,7 +11,7 @@ import android.widget.TextView import com.bumptech.glide.Glide import com.google.android.material.bottomsheet.BottomSheetDialog import com.matthaigh27.chatgptwrapper.R -import com.matthaigh27.chatgptwrapper.data.models.ContactModel +import com.matthaigh27.chatgptwrapper.data.models.chat.ContactModel import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface class ContactDetailWidget( @@ -39,22 +39,24 @@ class ContactDetailWidget( llPhones = findViewById(R.id.ll_contacts) llPhones?.removeAllViews() - txtDisplayName?.text = contactModel.name - contactModel.phoneList.forEach { phoneNumber -> - val contactDetailItem = ContactDetailItem(context) - contactDetailItem.setContactDetailItemInfo(phoneNumber, contactModel.name) - contactDetailItem.setVisibilityListener(object : - ContactDetailItem.OnContactDetailVisibilityListener { - override fun invisible() { - this@ContactDetailWidget.dismiss() - } - }) + txtDisplayName?.text = contactModel.displayName + contactModel.phoneNumbers.forEach { phoneNumber -> + val contactDetailItem = ContactDetailItem(context).apply { + this.callback = callback + this.setContactDetailItemInfo(phoneNumber, contactModel.displayName) + this.setVisibilityListener(object : + ContactDetailItem.OnContactDetailVisibilityListener { + override fun invisible() { + this@ContactDetailWidget.dismiss() + } + }) + } llPhones?.addView(contactDetailItem) } btnEditContact?.setOnClickListener(this) imgAvatar = findViewById(R.id.img_avatar) - imgAvatar?.setContactAvatar(contactModel.id.toLong()) + imgAvatar?.setContactAvatar(contactModel.contactId.toLong()) } private fun ImageView.setContactAvatar(contactId: Long) { @@ -73,7 +75,7 @@ class ContactDetailWidget( override fun onClick(view: View?) { when (view!!.id) { R.id.btn_edit_contact -> { - goToContactEditor(contactModel.id) + goToContactEditor(contactModel.contactId) } R.id.btn_send_message -> { diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/SearchContactWidget.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/SearchContactWidget.kt index 5dbedba37044b9e0f4b7099dc94782587e692763..10579fb5f2531ba7102e847ceeb0e4834fc7419d 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/SearchContactWidget.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/contact/SearchContactWidget.kt @@ -10,12 +10,12 @@ import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import com.bumptech.glide.Glide import com.matthaigh27.chatgptwrapper.R -import com.matthaigh27.chatgptwrapper.data.models.ContactModel +import com.matthaigh27.chatgptwrapper.data.models.chat.ContactModel import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface import de.hdodenhof.circleimageview.CircleImageView class SearchContactWidget( - context: Context, cotactModel: ContactModel, attrs: AttributeSet? + context: Context, cotactModel: ContactModel, attrs: AttributeSet? = null ) : ConstraintLayout(context, attrs), View.OnClickListener { private var context: Context @@ -38,8 +38,8 @@ class SearchContactWidget( civInfoAvatar = findViewById(R.id.civ_avatar) txtInfoName = findViewById(R.id.txt_info_name) - txtInfoName.text = contactModel.name - civInfoAvatar.setContactAvatar(context, contactModel.id.toLong()) + txtInfoName.text = contactModel.displayName + civInfoAvatar.setContactAvatar(context, contactModel.contactId.toLong()) this.setOnClickListener(this) } @@ -59,7 +59,9 @@ class SearchContactWidget( private fun showContactDetailView() { - val bottomSheetDialog = ContactDetailWidget(context, contactModel) + val bottomSheetDialog = ContactDetailWidget(context, contactModel).apply { + this.callback = callback + } bottomSheetDialog.show() } diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptWidget.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptWidget.kt index a6f8d750351d1a0370ff72a46f0e508edad08308..48c59992c939a5df05b6c95e802d8b81ca09d942 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptWidget.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptWidget.kt @@ -10,8 +10,9 @@ import android.widget.LinearLayout import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout import com.matthaigh27.chatgptwrapper.R -import com.matthaigh27.chatgptwrapper.data.models.HelpPromptModel +import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface +import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.OnHideListener class HelpPromptWidget(context: Context, model: HelpPromptModel) : ConstraintLayout(context), View.OnClickListener { @@ -21,7 +22,7 @@ class HelpPromptWidget(context: Context, model: HelpPromptModel) : ConstraintLay private var promptEditTextList: ArrayList? = null private val promptModel: HelpPromptModel var callback: ChatMessageInterface? = null - + var hideListener: OnHideListener? = null init { promptModel = model @@ -70,6 +71,7 @@ class HelpPromptWidget(context: Context, model: HelpPromptModel) : ConstraintLay callback?.canceledHelpPrompt() } } + hideListener?.hide() } private fun outputCompletePrompt() { diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/toolbar/ChatToolsWidget.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/toolbar/ChatToolsWidget.kt index e5c775a29860cea6ed30df80b1ea2ed1b12fa6f7..7e5affc8c80af6a6c0e03fdc87fb0df697c3c53f 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/toolbar/ChatToolsWidget.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/toolbar/ChatToolsWidget.kt @@ -95,7 +95,7 @@ class ChatToolsWidget(context: Context, parentActivity: Activity, attrs: Attribu } override fun onFailed(exception: Exception) { - + callback?.pickImage(false) } }) } diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/viewmodel/ChatViewModel.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/viewmodel/ChatViewModel.kt index fb6cc737b7999297b746b32b2e68b073d6c4a939..fd109a389bd693a884ed906795ae3abc49589202 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/viewmodel/ChatViewModel.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/viewmodel/ChatViewModel.kt @@ -1,15 +1,34 @@ package com.matthaigh27.chatgptwrapper.ui.chat.viewmodel +import android.util.Log import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.matthaigh27.chatgptwrapper.RisingApplication +import com.matthaigh27.chatgptwrapper.RisingApplication.Companion.appContext +import com.matthaigh27.chatgptwrapper.data.local.entity.ImageEntity import com.matthaigh27.chatgptwrapper.data.remote.ApiResource +import com.matthaigh27.chatgptwrapper.data.remote.requests.ImageRelatednessApiRequest import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest +import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainContactsApiRequest +import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainImageApiRequest import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse +import com.matthaigh27.chatgptwrapper.data.remote.responses.EmptyResultApiResponse import com.matthaigh27.chatgptwrapper.data.repository.FirebaseRepository import com.matthaigh27.chatgptwrapper.data.repository.RemoteRepository -import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper +import com.matthaigh27.chatgptwrapper.data.repository.RoomRepository +import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ContactHelper.getChangedContacts +import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ContactHelper.getContacts +import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper.getBytesFromPath +import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper.getImagesFromExternalStorage +import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper.getLocalPathFromUri import com.matthaigh27.chatgptwrapper.utils.helpers.network.RequestFactory +import com.matthaigh27.chatgptwrapper.utils.helpers.network.RequestFactory.buildApiKeys +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class ChatViewModel : ViewModel() { @@ -28,22 +47,17 @@ class ChatViewModel : ViewModel() { fun sendNotification(message: String): MutableLiveData> { val request = NotificationApiRequest( - message = message, - confs = RequestFactory.buildApiKeys() + message = message, confs = RequestFactory.buildApiKeys() ) val resource: MutableLiveData> = MutableLiveData() resource.value = ApiResource.Loading() - RemoteRepository.sendNotification( - request, - onSuccess = { apiResponse -> - resource.value = ApiResource.Success(apiResponse) - }, - onFailure = { throwable -> - resource.value = ApiResource.Error(throwable) - } - ) + RemoteRepository.sendNotification(request, onSuccess = { apiResponse -> + resource.value = ApiResource.Success(apiResponse) + }, onFailure = { throwable -> + resource.value = ApiResource.Error(throwable) + }) return resource } @@ -52,25 +66,158 @@ class ChatViewModel : ViewModel() { val resource: MutableLiveData> = MutableLiveData() resource.value = ApiResource.Loading() - FirebaseRepository.downloadImageWithName( - name, - onSuccess = { apiResponse -> - resource.value = ApiResource.Success(apiResponse) - }, - onFailure = { throwable -> - resource.value = ApiResource.Error(throwable) - } - ) + FirebaseRepository.downloadImageWithName(name, onSuccess = { apiResponse -> + resource.value = ApiResource.Success(apiResponse) + }, onFailure = { throwable -> + resource.value = ApiResource.Error(throwable) + }) return resource } - fun trainImages() { - val originalLocalImages = - ImageHelper.getImagesFromExternalStorage(RisingApplication.appContext.contentResolver) + fun uploadImageToFirebase(imageByteArray: ByteArray): MutableLiveData> { + val resource: MutableLiveData> = MutableLiveData() + resource.value = ApiResource.Loading() + + FirebaseRepository.uploadImageAsync(imageByteArray, onSuccess = { apiResponse -> + resource.value = ApiResource.Success(apiResponse) + }, onFailure = { throwable -> + resource.value = ApiResource.Error(throwable) + }) + + return resource } - fun trainContacts() { + fun trainImages(): MutableLiveData { + val state: MutableLiveData = MutableLiveData() + state.value = true + CoroutineScope(Dispatchers.IO).launch { + val images = getImagesFromExternalStorage(appContext.contentResolver) + val originalImages = RoomRepository.getAllImages().value + val existImageStatus = BooleanArray(originalImages!!.size) { false } + val tasks = mutableListOf>() + + Log.d("Brain", "Start") + images.forEach { image -> + var isExist = false + val path = getLocalPathFromUri(appContext, image.uri) + for (i in originalImages.indices) { + val entity: ImageEntity = originalImages[i] + if (entity.path == path) { + if (entity.dataModified != image.modifiedDate) { + val byteArray = getBytesFromPath(path) + val task = async { + val uuid = FirebaseRepository.uploadImage(byteArray) + if (uuid != "Error") { + RoomRepository.updateImage( + ImageEntity( + id = 0, + path = path, + name = uuid, + dataModified = image.modifiedDate + ) + ) + RemoteRepository.trainImage( + TrainImageApiRequest( + uuid, "updated", buildApiKeys() + ) + ) + } + } + tasks.add(task) + } + isExist = true + existImageStatus[i] = true + break + } + } + if (!isExist) { + path?.let { + val byteArray = getBytesFromPath(it) + val task = async { + val uuid = FirebaseRepository.uploadImage(byteArray) + if (uuid != "Error") { + RoomRepository.insertImage( + ImageEntity( + id = 0, + path = path, + name = uuid, + dataModified = image.modifiedDate + ) + ) + RemoteRepository.trainImage( + TrainImageApiRequest( + uuid, "created", buildApiKeys() + ) + ) + } + } + tasks.add(task) + } + } + } + + for (i in existImageStatus.indices) { + if (!existImageStatus[i]) { + val task = async { + RoomRepository.deleteImage( + ImageEntity( + originalImages[i].id, "", "", 0L + ) + ) + val result = RemoteRepository.trainImage( + TrainImageApiRequest( + originalImages[i].name, "deleted", buildApiKeys() + ) + ) + } + tasks.add(task) + } + } + + tasks.awaitAll() + Log.d("Brain", "Finish") + withContext(Dispatchers.Main) { + state.value = false + } + } + return state + } + + fun trainContacts(): MutableLiveData { + val state: MutableLiveData = MutableLiveData() + state.value = true + val contacts = getContacts(appContext) + CoroutineScope(Dispatchers.Main).launch { + val resource: MutableLiveData> = MutableLiveData() + val changedContacts = getChangedContacts(contacts) + val request = TrainContactsApiRequest(changedContacts, RequestFactory.buildApiKeys()) + RemoteRepository.trainContacts(request, onSuccess = { apiResponse -> + resource.value = ApiResource.Success(apiResponse) + }, onFailure = { throwable -> + resource.value = ApiResource.Error(throwable) + }) + withContext(Dispatchers.Main) { + state.value = false + } + } + return state + } + + fun getImageRelatedness(imageName: String, message: String): MutableLiveData> { + val resource: MutableLiveData> = MutableLiveData() + val request = ImageRelatednessApiRequest( + image_name = imageName, message = message, confs = buildApiKeys() + ) + resource.value = ApiResource.Loading() + + RemoteRepository.getImageRelatedness(request, onSuccess = { apiResponse -> + resource.value = ApiResource.Success(apiResponse) + }, onFailure = { throwable -> + resource.value = ApiResource.Error(throwable) + }) + + return resource } } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/Constants.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/Constants.kt index a62c2fdc2a57041ed6f61b7357957cd58fe45e6d..b8efcc7cd14dd4a23b68c58678d2efcc1aa77e21 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/Constants.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/Constants.kt @@ -1,7 +1,9 @@ package com.matthaigh27.chatgptwrapper.utils +import com.matthaigh27.chatgptwrapper.BuildConfig + object Constants { - val API_BASE_URL = "https://ttt246-brain.hf.space/" + val API_BASE_URL = BuildConfig.BASE_URL val TYPE_RESPONSE_MESSAGE = "message" val TYPE_RESPONSE_BROWSER = "browser" @@ -10,12 +12,14 @@ object Constants { val TYPE_RESPONSE_IMAGE = "image" val TYPE_RESPONSE_HELP_COMMAND = "help_command" val TYPE_RESPONSE_SMS = "sms" + val TYPE_RESPONSE_ALARM = "alarm" val TYPE_RESPONSE_CONTACT = "contact" val TYPE_WIDGET_SMS = "sms" val TYPE_WIDGET_HELP_PROMPT = "help_prompt" val TYPE_WIDGET_FEEDBACK = "feedback" val TYPE_WIDGET_SEARCH_CONTACT = "search_contact" + val TYPE_WIDGET_SCHEDULE_ALARM = "schedule_alarm" val HELP_COMMAND_ERROR_NO_MAIN = "no main command" val HELP_COMMAND_ERROR_NO_INVALID_FORMAT = "Invalid Command Format" @@ -31,4 +35,11 @@ object Constants { val FIELD_HELP_PROMPT_PROMPT = "prompt" val FIELD_HELP_PROMPT_DESCRIPTION = "description" val FIELD_HELP_PROMPT_TAGS = "tags" + + val PROPS_WIDGET_DESC = "widget description" + + val TIME_OUT_CALL = 60L + val TIME_OUT_CONNECT = 60L + val TIME_OUT_READ = 60L + val TIME_OUT_WRITE = 60L } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/CallbackTypes.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/CallbackTypes.kt new file mode 100644 index 0000000000000000000000000000000000000000..53d68b28a3ce4d629e440f29e80e94d5f67d8754 --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/CallbackTypes.kt @@ -0,0 +1,6 @@ +package com.matthaigh27.chatgptwrapper.utils.helpers + +typealias OnSuccess = (T) -> Unit +typealias OnFailure = (T) -> Unit + +typealias OnHide = () -> Unit \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/Converter.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/Converter.kt index bbd2334f35f6ea02cb024cd8b181f6b1ae74b7a5..2fa733490f4424fcb93b2bb0a3476ce0b38cc43e 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/Converter.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/Converter.kt @@ -1,8 +1,9 @@ package com.matthaigh27.chatgptwrapper.utils.helpers -import com.matthaigh27.chatgptwrapper.data.models.HelpPromptModel +import com.google.gson.Gson +import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel +import com.matthaigh27.chatgptwrapper.data.models.common.Time import com.matthaigh27.chatgptwrapper.utils.Constants -import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper import org.json.JSONArray import org.json.JSONException import org.json.JSONObject @@ -18,7 +19,8 @@ object Converter { val helpPromptModel = HelpPromptModel() helpPromptModel.name = helpCommand.getString(Constants.FIELD_HELP_PROMPT_NAME) - helpPromptModel.description = helpCommand.getString(Constants.FIELD_HELP_PROMPT_DESCRIPTION) + helpPromptModel.description = + helpCommand.getString(Constants.FIELD_HELP_PROMPT_DESCRIPTION) helpPromptModel.prompt = helpCommand.getString(Constants.FIELD_HELP_PROMPT_PROMPT) helpPromptModel.tags = ArrayList() @@ -34,4 +36,12 @@ object Converter { } return promptList } + + fun stringToTime(strTime: String): Time { + val list = strTime.split(':') + val hour = list[0].toInt() + val minute = list[1].toInt() + val time = Time(hour, minute, 0) + return time + } } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmHelper.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmHelper.kt index ba8b4382c0869e8f7044eb5a17d67571e9415a24..b8624729487f9d05a799d2f3c19793c4c42ea452 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmHelper.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmHelper.kt @@ -1,34 +1,74 @@ package com.matthaigh27.chatgptwrapper.utils.helpers.chat +import android.app.AlarmManager +import android.app.PendingIntent import android.content.Context -import android.database.Cursor -import android.net.Uri -import com.matthaigh27.chatgptwrapper.data.models.AlarmModel +import android.content.Context.ALARM_SERVICE +import android.content.Intent +import android.provider.AlarmClock +import android.util.Log +import java.util.Calendar + object AlarmHelper { - fun getAlarmList(context: Context): List { - val alarmsList = mutableListOf() - val contentUri: Uri = Uri.parse("content://com.android.alarmclock/alarm") - val cursor: Cursor? = context.contentResolver.query(contentUri, null, null, null, null) - - cursor?.let { - val idIndex = it.getColumnIndex("_id") - val timeIndex = it.getColumnIndex("alarmtime") - val enabledIndex = it.getColumnIndex("enabled") - val labelIndex = it.getColumnIndex("message") - - while (it.moveToNext()) { - val id = it.getInt(idIndex) - val time = it.getLong(timeIndex) - val enabled = it.getInt(enabledIndex) == 1 - val label = it.getString(labelIndex) - - val alarm = AlarmModel(id, time, enabled, label) - alarmsList.add(alarm) + fun createAlarm(context: Context, hour: Int, minute: Int, label: String) { + val calendar = Calendar.getInstance() + + calendar.set(Calendar.HOUR_OF_DAY, hour) + calendar.set(Calendar.MINUTE, minute) + calendar.set(Calendar.SECOND, 0) + + + val intent = Intent("android.intent.action.SET_ALARM") + intent.putExtra("android.intent.extra.alarm.HOUR", hour) + intent.putExtra("android.intent.extra.alarm.MINUTES", minute) + intent.putExtra("android.intent.extra.alarm.SKIP_UI", true) + intent.putExtra("android.intent.extra.alarm.MESSAGE", label) + + context.startActivity(intent) + } + + fun scheduleRepeatingAlarm(context: Context, selectedDays: ArrayList, hour: Int, minute: Int) { + val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager + + val alarmIntent = Intent(context, AlarmReceiver::class.java) + alarmIntent.action = "com.matthaigh27.chatgptwrapper" + + val pendingIntent = PendingIntent.getBroadcast( + context, + 0, + alarmIntent, + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + ) + + // Calculate the time difference between the next alarm time and now. + val calendar = Calendar.getInstance() + val timeNow = calendar.timeInMillis + var minTimeDiff = Long.MAX_VALUE + + for (dayOfWeek in selectedDays) { + calendar.set(Calendar.HOUR_OF_DAY, hour) + calendar.set(Calendar.MINUTE, minute) + calendar.set(Calendar.SECOND, 0) + calendar.set(Calendar.MILLISECOND, 0) + calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek) + + var alarmTime = calendar.timeInMillis + if (alarmTime < timeNow) { // If the alarm time is in the past, set it for the next week. + alarmTime += AlarmManager.INTERVAL_DAY * 7 + } + + val timeDiff = alarmTime - timeNow + if (timeDiff < minTimeDiff) { + minTimeDiff = timeDiff } } - cursor?.close() - return alarmsList + alarmManager.setInexactRepeating( + AlarmManager.RTC_WAKEUP, + timeNow + minTimeDiff, + AlarmManager.INTERVAL_DAY * 7, // Set to repeat every week. + pendingIntent + ) } -} \ No newline at end of file +} diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmReceiver.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmReceiver.kt new file mode 100644 index 0000000000000000000000000000000000000000..2d1336cf9e3abcec6df2efaa244d40882329a719 --- /dev/null +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmReceiver.kt @@ -0,0 +1,13 @@ +package com.matthaigh27.chatgptwrapper.utils.helpers.chat + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.util.Log + +class AlarmReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val label = intent.getStringExtra("label") + Log.d("AlarmReceiver", "Alarm triggered. Label: $label") + } +} \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/CommandHelper.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/CommandHelper.kt index e67d2c5822e2549a9f1a9664f14f985c299844f9..4de05e0b86b88f37b6d060ddbdcc85be228e7901 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/CommandHelper.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/CommandHelper.kt @@ -1,15 +1,11 @@ package com.matthaigh27.chatgptwrapper.utils.helpers.chat -import com.matthaigh27.chatgptwrapper.data.models.HelpCommandModel -import com.matthaigh27.chatgptwrapper.data.models.HelpPromptModel -import com.matthaigh27.chatgptwrapper.utils.Constants.ERROR_MSG_JSON +import com.matthaigh27.chatgptwrapper.data.models.chat.HelpCommandModel +import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ALL import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ERROR_NO_INVALID_FORMAT import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ERROR_NO_MAIN -import org.json.JSONArray -import org.json.JSONException -import org.json.JSONObject object CommandHelper { fun isMainHelpCommand(model: HelpCommandModel): Boolean { diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ContactHelper.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ContactHelper.kt index a87e3f6a1b1708a84295289bc6a30ca259fe2739..5e468f3bb3a05e8167c85d0713500dbba0f69f1e 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ContactHelper.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ContactHelper.kt @@ -4,7 +4,12 @@ import android.annotation.SuppressLint import android.content.ContentResolver import android.content.Context import android.provider.ContactsContract -import com.matthaigh27.chatgptwrapper.data.models.ContactModel +import com.matthaigh27.chatgptwrapper.data.local.entity.ContactEntity +import com.matthaigh27.chatgptwrapper.data.models.chat.ContactModel +import com.matthaigh27.chatgptwrapper.data.repository.RoomRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async object ContactHelper { @SuppressLint("Range") @@ -26,8 +31,8 @@ object ContactHelper { )).toInt() val contact = ContactModel() - contact.id = id - contact.name = name + contact.contactId = id + contact.displayName = name if (phoneNumber > 0) { val cursorPhone = context.contentResolver.query( @@ -43,7 +48,7 @@ object ContactHelper { val phoneNumValue = cursorPhone.getString( cursorPhone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER) ) - contact.phoneList.add(phoneNumValue) + contact.phoneNumbers.add(phoneNumValue) } } cursorPhone.close() @@ -55,4 +60,87 @@ object ContactHelper { cursor.close() return contacts } + + suspend fun getChangedContacts( + contacts: ArrayList + ): ArrayList { + return CoroutineScope(Dispatchers.IO).async { + val originalContacts = RoomRepository.getAllContacts().value + val changedContactList = ArrayList() + for (i in originalContacts!!.indices) { + var isExist = false + contacts.forEach { contact -> + if (originalContacts[i].id == contact.contactId) { + if (originalContacts[i].name != contact.displayName || originalContacts[i].phoneNumber != contact.phoneNumbers.toString()) { + contact.status = "updated" + changedContactList.add(contact) + + try { + RoomRepository.updateContact( + ContactEntity( + contact.contactId, + contact.displayName, + contact.phoneNumbers.toString() + ) + ) + } catch (e: Exception) { + e.printStackTrace() + } + } else { + contact.status = "nothing" + } + isExist = true + return@forEach + } + } + if (!isExist) { + val deletedContacts = ContactModel() + deletedContacts.contactId = originalContacts[i].id + deletedContacts.status = "deleted" + changedContactList.add(deletedContacts) + + try { + RoomRepository.deleteContact( + ContactEntity( + deletedContacts.contactId, + deletedContacts.displayName, + deletedContacts.phoneNumbers.toString() + ) + ) + } catch (e: Exception) { + e.printStackTrace() + } + } + } + contacts.forEach { contact -> + if (contact.status.isEmpty()) { + contact.status = "created" + changedContactList.add(contact) + try { + RoomRepository.insertContact( + ContactEntity( + contact.contactId, + contact.displayName, + contact.phoneNumbers.toString() + ) + ) + } catch (e: Exception) { + e.printStackTrace() + } + } + } + changedContactList + }.await() + } + + fun getContactModelById(contactId: String, contacts: ArrayList): ContactModel { + var contactModel = ContactModel() + val searchResults = contacts.filter { contact -> + contactId == contact.contactId + } + if (searchResults.isNotEmpty()) { + contactModel = searchResults[0] + } + return contactModel + } } \ No newline at end of file diff --git a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ImageHelper.kt b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ImageHelper.kt index cee191888d8be71dbcfa5adee4a718dc82036b5c..9e94e95628d8a75e958dcf11f6a1bd699e3cc907 100644 --- a/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ImageHelper.kt +++ b/Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ImageHelper.kt @@ -1,6 +1,8 @@ package com.matthaigh27.chatgptwrapper.utils.helpers.chat import android.content.ContentResolver +import android.content.Context +import android.database.Cursor import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.Canvas @@ -13,7 +15,7 @@ import android.net.Uri import android.os.Environment import android.provider.MediaStore import com.matthaigh27.chatgptwrapper.RisingApplication -import com.matthaigh27.chatgptwrapper.data.models.ImageModel +import com.matthaigh27.chatgptwrapper.data.models.chat.ImageModel import java.io.ByteArrayOutputStream import java.io.File import java.io.FileInputStream @@ -110,5 +112,16 @@ object ImageHelper { return listOfImages } - + fun getLocalPathFromUri(context: Context, contentUri: Uri?): String? { + var cursor: Cursor? = null + return try { + val proj = arrayOf(MediaStore.Images.Media.DATA) + cursor = context.contentResolver.query(contentUri!!, proj, null, null, null) + val column_index: Int = cursor!!.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) + cursor.moveToFirst() + cursor.getString(column_index) + } finally { + cursor?.close() + } + } } \ No newline at end of file diff --git a/Android/app/src/main/res/drawable/bg_circle_button_schedule_alarm_day.xml b/Android/app/src/main/res/drawable/bg_circle_button_schedule_alarm_day.xml new file mode 100644 index 0000000000000000000000000000000000000000..e721748920f4a117cdcadd4cf0b943b53e575dd5 --- /dev/null +++ b/Android/app/src/main/res/drawable/bg_circle_button_schedule_alarm_day.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Android/app/src/main/res/drawable/bg_circle_button_schedule_alarm_day_selected.xml b/Android/app/src/main/res/drawable/bg_circle_button_schedule_alarm_day_selected.xml new file mode 100644 index 0000000000000000000000000000000000000000..3c43a978c1791f6c6f9b4081d768afff6d603eab --- /dev/null +++ b/Android/app/src/main/res/drawable/bg_circle_button_schedule_alarm_day_selected.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Android/app/src/main/res/drawable/bg_item_error_message.xml b/Android/app/src/main/res/drawable/bg_item_error_message.xml new file mode 100644 index 0000000000000000000000000000000000000000..0a10e84a8d5f2b33ab773b41fb8c1a3ddb7ea1e2 --- /dev/null +++ b/Android/app/src/main/res/drawable/bg_item_error_message.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/Android/app/src/main/res/layout/item_container_chat_widget.xml b/Android/app/src/main/res/layout/item_container_chat_widget.xml index 134bcfde83d12401c0125f98ae9b698644b67a3d..adea31a10545db076eb93b52f8dc7f069fc133f3 100644 --- a/Android/app/src/main/res/layout/item_container_chat_widget.xml +++ b/Android/app/src/main/res/layout/item_container_chat_widget.xml @@ -7,4 +7,16 @@ android:layout_marginTop="@dimen/spacing_tiny" android:padding="@dimen/spacing_tiny"> + + + + \ No newline at end of file diff --git a/Android/app/src/main/res/layout/item_container_error_message.xml b/Android/app/src/main/res/layout/item_container_error_message.xml new file mode 100644 index 0000000000000000000000000000000000000000..4d3de7dd2ea259ba950f537cde57efe360395751 --- /dev/null +++ b/Android/app/src/main/res/layout/item_container_error_message.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Android/app/src/main/res/layout/item_container_received_message.xml b/Android/app/src/main/res/layout/item_container_received_message.xml index 9401f96f2e46380f5ef62dcb857dcbe40256d744..f418e6f7bdb4bb2d56365ebbd840e8fc206c6506 100644 --- a/Android/app/src/main/res/layout/item_container_received_message.xml +++ b/Android/app/src/main/res/layout/item_container_received_message.xml @@ -1,7 +1,7 @@ + + + + + \ No newline at end of file diff --git a/Android/app/src/main/res/layout/widget_help_prompt.xml b/Android/app/src/main/res/layout/widget_help_prompt.xml index 090589af91a5784a0a7fb5ee605e8107350c94da..bc309f898fb76400e2e901ca5437a8c686e256af 100644 --- a/Android/app/src/main/res/layout/widget_help_prompt.xml +++ b/Android/app/src/main/res/layout/widget_help_prompt.xml @@ -52,12 +52,12 @@ app:layout_constraintTop_toBottomOf="@+id/ll_prompt_keys">