Merge pull request #213 from ttt246/feature/ui_part2_191
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitignore +1 -1
- Android/app/src/main/AndroidManifest.xml +8 -6
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ContactDao.kt +0 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ImageDao.kt +0 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/entity/ContactEntity.kt +1 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/entity/ImageEntity.kt +1 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/AlarmModel.kt +6 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ChatMessageModel.kt +1 -26
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/HelpCommandModel.kt +1 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/MailModel.kt +10 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chatwidgetprops/MailsProps.kt +20 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chatwidgetprops/ScheduleAlarmProps.kt +0 -23
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiClient.kt +9 -7
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiResource.kt +1 -2
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiService.kt +18 -5
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/ComposeMailApiRequest.kt +19 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/ReadMailApiRequest.kt +14 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/ApiResponse.kt +1 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/results/CommonResult.kt +1 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/results/ImageRelatenessResult.kt +1 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/FirebaseRepository.kt +2 -10
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RemoteRepository.kt +53 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/SharedPreferencesRepository.kt +1 -2
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/ChatActivity.kt +1 -85
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/adapters/ChatMainAdapter.kt +64 -6
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/dialogs/ConfirmDialog.kt +3 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/fragments/ChatMainFragment.kt +293 -145
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/ChatMessageInterface.kt +19 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/OnHideListener.kt +3 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptKeyEditText.kt +0 -44
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptKeyItem.kt +30 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptWidget.kt +6 -5
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/mail/{compose/ComposeMailWidget.kt → ComposeMailWidget.kt} +74 -2
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/mail/MailWidget.kt +17 -6
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/mail/ReadMailWidget.kt +67 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/viewmodel/ChatViewModel.kt +144 -4
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/setting/viewmodel/SettingViewModel.kt +8 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/splash/SplashActivity.kt +133 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/constants/CommonConstants.kt +1 -5
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/constants/TypeChatWidgetConstants.kt +1 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/constants/TypeResponseConstants.kt +1 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmHelper.kt +4 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/CommandHelper.kt +12 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ContactHelper.kt +11 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ImageHelper.kt +23 -0
- Android/app/src/main/res/drawable/image_logo.png +0 -0
- Android/app/src/main/res/layout/activity_chat.xml +3 -9
- Android/app/src/main/res/layout/activity_splash.xml +20 -0
- Android/app/src/main/res/layout/item_help_prompt_key.xml +15 -0
- Android/app/src/main/res/layout/widget_help_prompt.xml +45 -30
.gitignore
CHANGED
|
@@ -2,4 +2,4 @@
|
|
| 2 |
/.idea
|
| 3 |
Brain/firebase_cred.json
|
| 4 |
Brain/logs/*
|
| 5 |
-
|
|
|
|
| 2 |
/.idea
|
| 3 |
Brain/firebase_cred.json
|
| 4 |
Brain/logs/*
|
| 5 |
+
**/.DS_Store
|
Android/app/src/main/AndroidManifest.xml
CHANGED
|
@@ -39,18 +39,20 @@
|
|
| 39 |
android:supportsRtl="true"
|
| 40 |
android:theme="@style/AppTheme">
|
| 41 |
<activity
|
| 42 |
-
android:name=".ui.
|
| 43 |
-
android:exported="
|
| 44 |
-
<activity
|
| 45 |
-
android:name=".ui.chat.view.ChatActivity"
|
| 46 |
-
android:exported="true"
|
| 47 |
-
android:windowSoftInputMode="adjustResize">
|
| 48 |
<intent-filter>
|
| 49 |
<action android:name="android.intent.action.MAIN" />
|
| 50 |
|
| 51 |
<category android:name="android.intent.category.LAUNCHER" />
|
| 52 |
</intent-filter>
|
| 53 |
</activity>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
<receiver
|
| 56 |
android:name=".utils.helpers.chat.AlarmReceiver"
|
|
|
|
| 39 |
android:supportsRtl="true"
|
| 40 |
android:theme="@style/AppTheme">
|
| 41 |
<activity
|
| 42 |
+
android:name=".ui.splash.SplashActivity"
|
| 43 |
+
android:exported="true">
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
<intent-filter>
|
| 45 |
<action android:name="android.intent.action.MAIN" />
|
| 46 |
|
| 47 |
<category android:name="android.intent.category.LAUNCHER" />
|
| 48 |
</intent-filter>
|
| 49 |
</activity>
|
| 50 |
+
<activity
|
| 51 |
+
android:name=".ui.setting.view.SettingActivity"
|
| 52 |
+
android:exported="false" />
|
| 53 |
+
<activity
|
| 54 |
+
android:name=".ui.chat.view.ChatActivity"
|
| 55 |
+
android:exported="false" />
|
| 56 |
|
| 57 |
<receiver
|
| 58 |
android:name=".utils.helpers.chat.AlarmReceiver"
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ContactDao.kt
CHANGED
|
@@ -1,6 +1,5 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.local.dao
|
| 2 |
|
| 3 |
-
import androidx.lifecycle.MutableLiveData
|
| 4 |
import androidx.room.*
|
| 5 |
import com.matthaigh27.chatgptwrapper.data.local.entity.ContactEntity
|
| 6 |
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.local.dao
|
| 2 |
|
|
|
|
| 3 |
import androidx.room.*
|
| 4 |
import com.matthaigh27.chatgptwrapper.data.local.entity.ContactEntity
|
| 5 |
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ImageDao.kt
CHANGED
|
@@ -1,6 +1,5 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.local.dao
|
| 2 |
|
| 3 |
-
import androidx.lifecycle.MutableLiveData
|
| 4 |
import androidx.room.*
|
| 5 |
import com.matthaigh27.chatgptwrapper.data.local.entity.ImageEntity
|
| 6 |
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.local.dao
|
| 2 |
|
|
|
|
| 3 |
import androidx.room.*
|
| 4 |
import com.matthaigh27.chatgptwrapper.data.local.entity.ImageEntity
|
| 5 |
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/entity/ContactEntity.kt
CHANGED
|
@@ -4,7 +4,7 @@ import androidx.room.Entity
|
|
| 4 |
import androidx.room.PrimaryKey
|
| 5 |
|
| 6 |
@Entity(tableName = "contacts")
|
| 7 |
-
data class ContactEntity
|
| 8 |
@PrimaryKey(autoGenerate = false) val id: String,
|
| 9 |
val name: String,
|
| 10 |
val phoneNumber: String,
|
|
|
|
| 4 |
import androidx.room.PrimaryKey
|
| 5 |
|
| 6 |
@Entity(tableName = "contacts")
|
| 7 |
+
data class ContactEntity(
|
| 8 |
@PrimaryKey(autoGenerate = false) val id: String,
|
| 9 |
val name: String,
|
| 10 |
val phoneNumber: String,
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/entity/ImageEntity.kt
CHANGED
|
@@ -4,7 +4,7 @@ import androidx.room.Entity
|
|
| 4 |
import androidx.room.PrimaryKey
|
| 5 |
|
| 6 |
@Entity(tableName = "images")
|
| 7 |
-
data class ImageEntity
|
| 8 |
@PrimaryKey(autoGenerate = true) val id: Int,
|
| 9 |
val path: String,
|
| 10 |
val name: String,
|
|
|
|
| 4 |
import androidx.room.PrimaryKey
|
| 5 |
|
| 6 |
@Entity(tableName = "images")
|
| 7 |
+
data class ImageEntity(
|
| 8 |
@PrimaryKey(autoGenerate = true) val id: Int,
|
| 9 |
val path: String,
|
| 10 |
val name: String,
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/AlarmModel.kt
CHANGED
|
@@ -1,3 +1,8 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.models.chat
|
| 2 |
|
| 3 |
-
data class AlarmModel(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.models.chat
|
| 2 |
|
| 3 |
+
data class AlarmModel(
|
| 4 |
+
val id: Int,
|
| 5 |
+
val time: Long,
|
| 6 |
+
val enabled: Boolean,
|
| 7 |
+
val label: String
|
| 8 |
+
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/ChatMessageModel.kt
CHANGED
|
@@ -8,29 +8,4 @@ data class ChatMessageModel(
|
|
| 8 |
val data: JsonElement? = null,
|
| 9 |
val hasImage: Boolean = false,
|
| 10 |
val image: ByteArray? = 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 ChatMessageModel
|
| 17 |
-
|
| 18 |
-
if (type != other.type) return false
|
| 19 |
-
if (content != other.content) return false
|
| 20 |
-
if (data != other.data) return false
|
| 21 |
-
if (image != null) {
|
| 22 |
-
if (other.image == null) return false
|
| 23 |
-
if (!image.contentEquals(other.image)) return false
|
| 24 |
-
} else if (other.image != null) return false
|
| 25 |
-
|
| 26 |
-
return true
|
| 27 |
-
}
|
| 28 |
-
|
| 29 |
-
override fun hashCode(): Int {
|
| 30 |
-
var result = type
|
| 31 |
-
result = 31 * result + content.hashCode()
|
| 32 |
-
result = 31 * result + (data?.hashCode() ?: 0)
|
| 33 |
-
result = 31 * result + (image?.contentHashCode() ?: 0)
|
| 34 |
-
return result
|
| 35 |
-
}
|
| 36 |
-
}
|
|
|
|
| 8 |
val data: JsonElement? = null,
|
| 9 |
val hasImage: Boolean = false,
|
| 10 |
val image: ByteArray? = null,
|
| 11 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/HelpCommandModel.kt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.models.chat
|
| 2 |
|
| 3 |
-
data class HelpCommandModel
|
| 4 |
var main: String? = null,
|
| 5 |
var assist: String? = null
|
| 6 |
)
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.models.chat
|
| 2 |
|
| 3 |
+
data class HelpCommandModel(
|
| 4 |
var main: String? = null,
|
| 5 |
var assist: String? = null
|
| 6 |
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chat/MailModel.kt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.models.chat
|
| 2 |
+
|
| 3 |
+
data class MailModel(
|
| 4 |
+
val from: String,
|
| 5 |
+
val to: String,
|
| 6 |
+
val date: String,
|
| 7 |
+
val cc: String,
|
| 8 |
+
val subject: String,
|
| 9 |
+
val body: String,
|
| 10 |
+
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chatwidgetprops/MailsProps.kt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.models.chatwidgetprops
|
| 2 |
+
|
| 3 |
+
import com.google.gson.Gson
|
| 4 |
+
import com.matthaigh27.chatgptwrapper.data.models.chat.MailModel
|
| 5 |
+
|
| 6 |
+
data class MailsProps(
|
| 7 |
+
val mails: ArrayList<MailModel>
|
| 8 |
+
) {
|
| 9 |
+
override fun toString(): String {
|
| 10 |
+
val gson = Gson()
|
| 11 |
+
return gson.toJson(this)
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
companion object {
|
| 15 |
+
fun init(string: String): MailsProps {
|
| 16 |
+
val gson = Gson()
|
| 17 |
+
return gson.fromJson(string, MailsProps::class.java)
|
| 18 |
+
}
|
| 19 |
+
}
|
| 20 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/chatwidgetprops/ScheduleAlarmProps.kt
CHANGED
|
@@ -9,29 +9,6 @@ data class ScheduleAlarmProps(
|
|
| 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)
|
|
|
|
| 9 |
val label: String? = null,
|
| 10 |
val repeat: BooleanArray? = null
|
| 11 |
) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
override fun toString(): String {
|
| 13 |
val gson = Gson()
|
| 14 |
return gson.toJson(this)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiClient.kt
CHANGED
|
@@ -1,25 +1,27 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.remote
|
| 2 |
|
| 3 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.API_BASE_URL
|
| 4 |
-
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.TIME_OUT_CALL
|
| 5 |
-
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.TIME_OUT_CONNECT
|
| 6 |
-
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.TIME_OUT_READ
|
| 7 |
-
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.TIME_OUT_WRITE
|
| 8 |
import okhttp3.OkHttpClient
|
| 9 |
-
import okhttp3.logging.HttpLoggingInterceptor
|
| 10 |
import retrofit2.Retrofit
|
| 11 |
import retrofit2.converter.gson.GsonConverterFactory
|
| 12 |
import java.util.concurrent.TimeUnit
|
| 13 |
|
| 14 |
object ApiClient {
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
|
|
|
| 23 |
.baseUrl(API_BASE_URL)
|
| 24 |
.addConverterFactory(GsonConverterFactory.create())
|
| 25 |
.client(client)
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.remote
|
| 2 |
|
| 3 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.API_BASE_URL
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
import okhttp3.OkHttpClient
|
|
|
|
| 5 |
import retrofit2.Retrofit
|
| 6 |
import retrofit2.converter.gson.GsonConverterFactory
|
| 7 |
import java.util.concurrent.TimeUnit
|
| 8 |
|
| 9 |
object ApiClient {
|
| 10 |
+
val TIME_OUT_CALL = 60L
|
| 11 |
+
val TIME_OUT_CONNECT = 60L
|
| 12 |
+
val TIME_OUT_READ = 60L
|
| 13 |
+
val TIME_OUT_WRITE = 60L
|
| 14 |
+
|
| 15 |
+
private val client = OkHttpClient
|
| 16 |
+
.Builder()
|
| 17 |
.callTimeout(TIME_OUT_CALL, TimeUnit.SECONDS)
|
| 18 |
.connectTimeout(TIME_OUT_CONNECT, TimeUnit.SECONDS)
|
| 19 |
.readTimeout(TIME_OUT_READ, TimeUnit.SECONDS)
|
| 20 |
.writeTimeout(TIME_OUT_WRITE, TimeUnit.SECONDS)
|
| 21 |
.build()
|
| 22 |
|
| 23 |
+
private val retrofit = Retrofit
|
| 24 |
+
.Builder()
|
| 25 |
.baseUrl(API_BASE_URL)
|
| 26 |
.addConverterFactory(GsonConverterFactory.create())
|
| 27 |
.client(client)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiResource.kt
CHANGED
|
@@ -1,8 +1,7 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.remote
|
| 2 |
|
| 3 |
sealed class ApiResource<T>(
|
| 4 |
-
val data: T? = null,
|
| 5 |
-
val message: String? = null
|
| 6 |
) {
|
| 7 |
class Success<T>(data: T) : ApiResource<T>(data)
|
| 8 |
class Error<T>(message: String, data: T? = null) : ApiResource<T>(data, message)
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.remote
|
| 2 |
|
| 3 |
sealed class ApiResource<T>(
|
| 4 |
+
val data: T? = null, val message: String? = null
|
|
|
|
| 5 |
) {
|
| 6 |
class Success<T>(data: T) : ApiResource<T>(data)
|
| 7 |
class Error<T>(message: String, data: T? = null) : ApiResource<T>(data, message)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiService.kt
CHANGED
|
@@ -1,8 +1,11 @@
|
|
| 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
|
|
@@ -16,13 +19,23 @@ import retrofit2.http.POST
|
|
| 16 |
|
| 17 |
interface ApiService {
|
| 18 |
@POST("commands")
|
| 19 |
-
fun getAllHelpCommands(@Body request: BaseApiRequest)
|
|
|
|
| 20 |
@POST("sendNotification")
|
| 21 |
-
fun sendNotification(@Body request: NotificationApiRequest)
|
|
|
|
| 22 |
@POST("train/contacts")
|
| 23 |
-
fun trainContacts(@Body request: TrainContactsApiRequest)
|
|
|
|
| 24 |
@POST("image_relatedness")
|
| 25 |
-
fun getImageRelatedness(@Body request: ImageRelatednessApiRequest)
|
|
|
|
| 26 |
@POST("uploadImage")
|
| 27 |
-
fun trainImage(@Body request: TrainImageApiRequest)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
}
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.remote
|
| 2 |
|
| 3 |
+
import com.matthaigh27.chatgptwrapper.data.models.chat.MailModel
|
| 4 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.BaseApiRequest
|
| 5 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.ComposeMailApiRequest
|
| 6 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.ImageRelatednessApiRequest
|
| 7 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
|
| 8 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.ReadMailApiRequest
|
| 9 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainContactsApiRequest
|
| 10 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainImageApiRequest
|
| 11 |
import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
|
|
|
|
| 19 |
|
| 20 |
interface ApiService {
|
| 21 |
@POST("commands")
|
| 22 |
+
fun getAllHelpCommands(@Body request: BaseApiRequest): Call<ApiResponse<HelpCommandResult>>
|
| 23 |
+
|
| 24 |
@POST("sendNotification")
|
| 25 |
+
fun sendNotification(@Body request: NotificationApiRequest): Call<ApiResponse<CommonResult>>
|
| 26 |
+
|
| 27 |
@POST("train/contacts")
|
| 28 |
+
fun trainContacts(@Body request: TrainContactsApiRequest): Call<ApiResponse<String>>
|
| 29 |
+
|
| 30 |
@POST("image_relatedness")
|
| 31 |
+
fun getImageRelatedness(@Body request: ImageRelatednessApiRequest): Call<ApiResponse<ImageRelatenessResult>>
|
| 32 |
+
|
| 33 |
@POST("uploadImage")
|
| 34 |
+
fun trainImage(@Body request: TrainImageApiRequest): Call<ApiResponse<TrainImageResult>>
|
| 35 |
+
|
| 36 |
+
@POST("email/read_emails")
|
| 37 |
+
fun readEmails(@Body request: ReadMailApiRequest): Call<ApiResponse<ArrayList<MailModel>>>
|
| 38 |
+
|
| 39 |
+
@POST("email/send_email")
|
| 40 |
+
fun sendEmail(@Body request: ComposeMailApiRequest): Call<ApiResponse<String>>
|
| 41 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/ComposeMailApiRequest.kt
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.remote.requests
|
| 2 |
+
|
| 3 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys
|
| 4 |
+
|
| 5 |
+
data class ComposeMailApiRequest(
|
| 6 |
+
val data: ComposeMailData,
|
| 7 |
+
val confs: Keys
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
data class ComposeMailData(
|
| 11 |
+
private val sender: String,
|
| 12 |
+
private val pwd: String,
|
| 13 |
+
private val to: String,
|
| 14 |
+
private val subject: String,
|
| 15 |
+
private val body: String,
|
| 16 |
+
private val to_send: Boolean,
|
| 17 |
+
private val filename: String,
|
| 18 |
+
private val file_content: String
|
| 19 |
+
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/ReadMailApiRequest.kt
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.remote.requests
|
| 2 |
+
|
| 3 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys
|
| 4 |
+
|
| 5 |
+
data class ReadMailApiRequest(
|
| 6 |
+
val data: ReadMailData,
|
| 7 |
+
val confs: Keys
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
data class ReadMailData(
|
| 11 |
+
val sender: String,
|
| 12 |
+
val pwd: String,
|
| 13 |
+
val imap_folder: String,
|
| 14 |
+
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/ApiResponse.kt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.remote.responses
|
| 2 |
|
| 3 |
-
data class ApiResponse
|
| 4 |
val status_code: Int,
|
| 5 |
val message: List<String>,
|
| 6 |
val result: T
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.remote.responses
|
| 2 |
|
| 3 |
+
data class ApiResponse<T>(
|
| 4 |
val status_code: Int,
|
| 5 |
val message: List<String>,
|
| 6 |
val result: T
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/results/CommonResult.kt
CHANGED
|
@@ -2,7 +2,7 @@ package com.matthaigh27.chatgptwrapper.data.remote.responses.results
|
|
| 2 |
|
| 3 |
import com.google.gson.JsonElement
|
| 4 |
|
| 5 |
-
data class CommonResult
|
| 6 |
val program: String,
|
| 7 |
val content: JsonElement
|
| 8 |
)
|
|
|
|
| 2 |
|
| 3 |
import com.google.gson.JsonElement
|
| 4 |
|
| 5 |
+
data class CommonResult(
|
| 6 |
val program: String,
|
| 7 |
val content: JsonElement
|
| 8 |
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/results/ImageRelatenessResult.kt
CHANGED
|
@@ -5,7 +5,7 @@ data class ImageRelatenessResult(
|
|
| 5 |
val content: ImageRelatenessContent
|
| 6 |
)
|
| 7 |
|
| 8 |
-
data class ImageRelatenessContent
|
| 9 |
val image_name: String,
|
| 10 |
val image_desc: String
|
| 11 |
)
|
|
|
|
| 5 |
val content: ImageRelatenessContent
|
| 6 |
)
|
| 7 |
|
| 8 |
+
data class ImageRelatenessContent(
|
| 9 |
val image_name: String,
|
| 10 |
val image_desc: String
|
| 11 |
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/FirebaseRepository.kt
CHANGED
|
@@ -1,21 +1,15 @@
|
|
| 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.models.chat.AutoTaskModel
|
| 6 |
-
import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
|
| 7 |
import com.matthaigh27.chatgptwrapper.utils.helpers.OnFailure
|
| 8 |
import com.matthaigh27.chatgptwrapper.utils.helpers.OnSuccess
|
| 9 |
-
import kotlinx.coroutines.suspendCancellableCoroutine
|
| 10 |
import java.util.UUID
|
| 11 |
import kotlin.coroutines.resume
|
| 12 |
import kotlin.coroutines.suspendCoroutine
|
| 13 |
|
| 14 |
object FirebaseRepository {
|
| 15 |
fun downloadImageWithName(
|
| 16 |
-
name: String,
|
| 17 |
-
onSuccess: OnSuccess<ByteArray>,
|
| 18 |
-
onFailure: OnFailure<String>
|
| 19 |
) {
|
| 20 |
val reference = "images/$name"
|
| 21 |
|
|
@@ -29,9 +23,7 @@ object FirebaseRepository {
|
|
| 29 |
}
|
| 30 |
|
| 31 |
fun uploadImageAsync(
|
| 32 |
-
imageByteArray: ByteArray,
|
| 33 |
-
onSuccess: OnSuccess<String>,
|
| 34 |
-
onFailure: OnFailure<String>
|
| 35 |
) {
|
| 36 |
val storageRef = FirebaseStorage.getInstance().reference
|
| 37 |
val uuid = UUID.randomUUID()
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.repository
|
| 2 |
|
| 3 |
import com.google.firebase.storage.FirebaseStorage
|
|
|
|
|
|
|
|
|
|
| 4 |
import com.matthaigh27.chatgptwrapper.utils.helpers.OnFailure
|
| 5 |
import com.matthaigh27.chatgptwrapper.utils.helpers.OnSuccess
|
|
|
|
| 6 |
import java.util.UUID
|
| 7 |
import kotlin.coroutines.resume
|
| 8 |
import kotlin.coroutines.suspendCoroutine
|
| 9 |
|
| 10 |
object FirebaseRepository {
|
| 11 |
fun downloadImageWithName(
|
| 12 |
+
name: String, onSuccess: OnSuccess<ByteArray>, onFailure: OnFailure<String>
|
|
|
|
|
|
|
| 13 |
) {
|
| 14 |
val reference = "images/$name"
|
| 15 |
|
|
|
|
| 23 |
}
|
| 24 |
|
| 25 |
fun uploadImageAsync(
|
| 26 |
+
imageByteArray: ByteArray, onSuccess: OnSuccess<String>, onFailure: OnFailure<String>
|
|
|
|
|
|
|
| 27 |
) {
|
| 28 |
val storageRef = FirebaseStorage.getInstance().reference
|
| 29 |
val uuid = UUID.randomUUID()
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RemoteRepository.kt
CHANGED
|
@@ -1,12 +1,15 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.repository
|
| 2 |
|
| 3 |
import com.matthaigh27.chatgptwrapper.RisingApplication.Companion.appContext
|
|
|
|
| 4 |
import com.matthaigh27.chatgptwrapper.data.models.setting.SettingModel
|
| 5 |
import com.matthaigh27.chatgptwrapper.data.remote.ApiClient
|
| 6 |
import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
|
| 7 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.BaseApiRequest
|
|
|
|
| 8 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.ImageRelatednessApiRequest
|
| 9 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
|
|
|
|
| 10 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainContactsApiRequest
|
| 11 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainImageApiRequest
|
| 12 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys
|
|
@@ -45,7 +48,8 @@ object RemoteRepository {
|
|
| 45 |
}
|
| 46 |
|
| 47 |
fun getAllHelpCommands(
|
| 48 |
-
onSuccess: OnSuccess<ApiResponse<HelpCommandResult>>,
|
|
|
|
| 49 |
) {
|
| 50 |
val call = apiService.getAllHelpCommands(BaseApiRequest(getKeys()))
|
| 51 |
|
|
@@ -154,4 +158,52 @@ object RemoteRepository {
|
|
| 154 |
}
|
| 155 |
})
|
| 156 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
}
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.repository
|
| 2 |
|
| 3 |
import com.matthaigh27.chatgptwrapper.RisingApplication.Companion.appContext
|
| 4 |
+
import com.matthaigh27.chatgptwrapper.data.models.chat.MailModel
|
| 5 |
import com.matthaigh27.chatgptwrapper.data.models.setting.SettingModel
|
| 6 |
import com.matthaigh27.chatgptwrapper.data.remote.ApiClient
|
| 7 |
import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
|
| 8 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.BaseApiRequest
|
| 9 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.ComposeMailApiRequest
|
| 10 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.ImageRelatednessApiRequest
|
| 11 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
|
| 12 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.ReadMailApiRequest
|
| 13 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainContactsApiRequest
|
| 14 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainImageApiRequest
|
| 15 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys
|
|
|
|
| 48 |
}
|
| 49 |
|
| 50 |
fun getAllHelpCommands(
|
| 51 |
+
onSuccess: OnSuccess<ApiResponse<HelpCommandResult>>,
|
| 52 |
+
onFailure: OnFailure<String>
|
| 53 |
) {
|
| 54 |
val call = apiService.getAllHelpCommands(BaseApiRequest(getKeys()))
|
| 55 |
|
|
|
|
| 158 |
}
|
| 159 |
})
|
| 160 |
}
|
| 161 |
+
|
| 162 |
+
fun readEmails(
|
| 163 |
+
request: ReadMailApiRequest,
|
| 164 |
+
onSuccess: OnSuccess<ApiResponse<ArrayList<MailModel>>>,
|
| 165 |
+
onFailure: OnFailure<String>
|
| 166 |
+
) {
|
| 167 |
+
val call = apiService.readEmails(request)
|
| 168 |
+
|
| 169 |
+
call.enqueue(object : Callback<ApiResponse<ArrayList<MailModel>>> {
|
| 170 |
+
override fun onResponse(
|
| 171 |
+
call: Call<ApiResponse<ArrayList<MailModel>>>, response: Response<ApiResponse<ArrayList<MailModel>>>
|
| 172 |
+
) {
|
| 173 |
+
response.body()?.let { data ->
|
| 174 |
+
onSuccess(data)
|
| 175 |
+
} ?: run {
|
| 176 |
+
onFailure(response.message())
|
| 177 |
+
}
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
override fun onFailure(call: Call<ApiResponse<ArrayList<MailModel>>>, t: Throwable) {
|
| 181 |
+
onFailure(t.message.toString())
|
| 182 |
+
}
|
| 183 |
+
})
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
fun sendEmail(
|
| 187 |
+
request: ComposeMailApiRequest,
|
| 188 |
+
onSuccess: OnSuccess<ApiResponse<String>>,
|
| 189 |
+
onFailure: OnFailure<String>
|
| 190 |
+
) {
|
| 191 |
+
val call = apiService.sendEmail(request)
|
| 192 |
+
|
| 193 |
+
call.enqueue(object : Callback<ApiResponse<String>> {
|
| 194 |
+
override fun onResponse(
|
| 195 |
+
call: Call<ApiResponse<String>>, response: Response<ApiResponse<String>>
|
| 196 |
+
) {
|
| 197 |
+
response.body()?.let { data ->
|
| 198 |
+
onSuccess(data)
|
| 199 |
+
} ?: run {
|
| 200 |
+
onFailure(response.message())
|
| 201 |
+
}
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
override fun onFailure(call: Call<ApiResponse<String>>, t: Throwable) {
|
| 205 |
+
onFailure(t.message.toString())
|
| 206 |
+
}
|
| 207 |
+
})
|
| 208 |
+
}
|
| 209 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/SharedPreferencesRepository.kt
CHANGED
|
@@ -1,7 +1,6 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.repository
|
| 2 |
|
| 3 |
import android.content.Context
|
| 4 |
-
import android.content.SharedPreferences
|
| 5 |
import com.matthaigh27.chatgptwrapper.RisingApplication.Companion.appContext
|
| 6 |
import com.matthaigh27.chatgptwrapper.data.models.setting.SettingModel
|
| 7 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.SettingHelper.emptySettingModel
|
|
@@ -18,7 +17,7 @@ object SharedPreferencesRepository {
|
|
| 18 |
fun getConfig(): SettingModel {
|
| 19 |
val sharedPreferences = appContext.getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
| 20 |
val jsonString = sharedPreferences.getString("config", "")
|
| 21 |
-
if(jsonString == "" || jsonString == null) {
|
| 22 |
return emptySettingModel()
|
| 23 |
} else {
|
| 24 |
return SettingModel.init(jsonString)
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.data.repository
|
| 2 |
|
| 3 |
import android.content.Context
|
|
|
|
| 4 |
import com.matthaigh27.chatgptwrapper.RisingApplication.Companion.appContext
|
| 5 |
import com.matthaigh27.chatgptwrapper.data.models.setting.SettingModel
|
| 6 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.SettingHelper.emptySettingModel
|
|
|
|
| 17 |
fun getConfig(): SettingModel {
|
| 18 |
val sharedPreferences = appContext.getSharedPreferences("prefs", Context.MODE_PRIVATE)
|
| 19 |
val jsonString = sharedPreferences.getString("config", "")
|
| 20 |
+
if (jsonString == "" || jsonString == null) {
|
| 21 |
return emptySettingModel()
|
| 22 |
} else {
|
| 23 |
return SettingModel.init(jsonString)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/ChatActivity.kt
CHANGED
|
@@ -1,100 +1,16 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.ui.chat.view
|
| 2 |
|
| 3 |
-
import android.Manifest
|
| 4 |
-
import android.annotation.SuppressLint
|
| 5 |
-
import android.content.pm.PackageManager
|
| 6 |
-
import android.os.Build
|
| 7 |
import android.os.Bundle
|
| 8 |
-
import androidx.appcompat.app.AppCompatActivity
|
| 9 |
import com.matthaigh27.chatgptwrapper.R
|
| 10 |
import com.matthaigh27.chatgptwrapper.ui.base.BaseActivity
|
| 11 |
-
import com.matthaigh27.chatgptwrapper.ui.chat.view.dialogs.ConfirmDialog
|
| 12 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.fragments.ChatMainFragment
|
| 13 |
|
| 14 |
|
| 15 |
class ChatActivity : BaseActivity() {
|
| 16 |
-
|
| 17 |
-
private val PERMISSIONS_REQUEST_CODE = 1
|
| 18 |
-
private lateinit var permissions: Array<String>
|
| 19 |
-
private val CONFIRM_MESSAGE =
|
| 20 |
-
"This app requires SMS, Contacts and Phone " +
|
| 21 |
-
"permissions to function properly. " +
|
| 22 |
-
"Please grant the necessary permissions."
|
| 23 |
-
|
| 24 |
override fun onCreate(savedInstanceState: Bundle?) {
|
| 25 |
super.onCreate(savedInstanceState)
|
| 26 |
setContentView(R.layout.activity_chat)
|
| 27 |
-
|
| 28 |
-
requestPermissions()
|
| 29 |
-
}
|
| 30 |
-
|
| 31 |
-
private fun requestPermissions() {
|
| 32 |
-
/**
|
| 33 |
-
* In mobile phones that use Google API 33 or higher, the permission for reading external storage
|
| 34 |
-
* is disabled because the phones don't support the feature.
|
| 35 |
-
*/
|
| 36 |
-
permissions = if(Build.VERSION.SDK_INT > Build.VERSION_CODES.S_V2) {
|
| 37 |
-
arrayOf(
|
| 38 |
-
Manifest.permission.SEND_SMS,
|
| 39 |
-
Manifest.permission.READ_CONTACTS,
|
| 40 |
-
Manifest.permission.CALL_PHONE
|
| 41 |
-
)
|
| 42 |
-
} else {
|
| 43 |
-
arrayOf(
|
| 44 |
-
Manifest.permission.SEND_SMS,
|
| 45 |
-
Manifest.permission.READ_CONTACTS,
|
| 46 |
-
Manifest.permission.CALL_PHONE,
|
| 47 |
-
Manifest.permission.READ_EXTERNAL_STORAGE
|
| 48 |
-
)
|
| 49 |
-
}
|
| 50 |
-
val notGrantedPermissions = permissions.filter {
|
| 51 |
-
checkSelfPermission(it) != PackageManager.PERMISSION_GRANTED
|
| 52 |
-
}
|
| 53 |
-
|
| 54 |
-
if (notGrantedPermissions.isNotEmpty()) {
|
| 55 |
-
if (shouldShowRequestPermissionRationale(notGrantedPermissions[0])) {
|
| 56 |
-
// show custom permission rationale
|
| 57 |
-
val confirmDialog = ConfirmDialog(this@ChatActivity)
|
| 58 |
-
confirmDialog.setOnClickListener(object :
|
| 59 |
-
ConfirmDialog.OnDialogButtonClickListener {
|
| 60 |
-
override fun onPositiveButtonClick() {
|
| 61 |
-
requestPermissions(
|
| 62 |
-
notGrantedPermissions.toTypedArray(), PERMISSIONS_REQUEST_CODE
|
| 63 |
-
)
|
| 64 |
-
}
|
| 65 |
-
|
| 66 |
-
override fun onNegativeButtonClick() {
|
| 67 |
-
finish()
|
| 68 |
-
}
|
| 69 |
-
})
|
| 70 |
-
|
| 71 |
-
confirmDialog.show()
|
| 72 |
-
confirmDialog.setMessage(CONFIRM_MESSAGE)
|
| 73 |
-
|
| 74 |
-
} else {
|
| 75 |
-
requestPermissions(notGrantedPermissions.toTypedArray(), PERMISSIONS_REQUEST_CODE)
|
| 76 |
-
}
|
| 77 |
-
} else {
|
| 78 |
-
// Permissions already granted, navigate to your desired fragment
|
| 79 |
-
navigateToChatMainFragment()
|
| 80 |
-
}
|
| 81 |
-
}
|
| 82 |
-
|
| 83 |
-
@SuppressLint("MissingSuperCall")
|
| 84 |
-
override fun onRequestPermissionsResult(
|
| 85 |
-
requestCode: Int, permissions: Array<out String>, grantResults: IntArray
|
| 86 |
-
) {
|
| 87 |
-
when (requestCode) {
|
| 88 |
-
PERMISSIONS_REQUEST_CODE -> {
|
| 89 |
-
if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
|
| 90 |
-
// Permissions granted, navigate to your desired fragment
|
| 91 |
-
navigateToChatMainFragment()
|
| 92 |
-
} else {
|
| 93 |
-
requestPermissions()
|
| 94 |
-
}
|
| 95 |
-
return
|
| 96 |
-
}
|
| 97 |
-
}
|
| 98 |
}
|
| 99 |
|
| 100 |
private fun navigateToChatMainFragment() {
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.ui.chat.view
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
import android.os.Bundle
|
|
|
|
| 4 |
import com.matthaigh27.chatgptwrapper.R
|
| 5 |
import com.matthaigh27.chatgptwrapper.ui.base.BaseActivity
|
|
|
|
| 6 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.fragments.ChatMainFragment
|
| 7 |
|
| 8 |
|
| 9 |
class ChatActivity : BaseActivity() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
override fun onCreate(savedInstanceState: Bundle?) {
|
| 11 |
super.onCreate(savedInstanceState)
|
| 12 |
setContentView(R.layout.activity_chat)
|
| 13 |
+
navigateToChatMainFragment()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
}
|
| 15 |
|
| 16 |
private fun navigateToChatMainFragment() {
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/adapters/ChatMainAdapter.kt
CHANGED
|
@@ -14,6 +14,7 @@ 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
|
|
@@ -21,10 +22,12 @@ import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.SendSmsWid
|
|
| 21 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.alarm.ScheduleAlarmWidget
|
| 22 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.contact.ContactWidget
|
| 23 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.helpprompt.HelpPromptWidget
|
|
|
|
| 24 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.mail.MailWidget
|
| 25 |
-
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.mail.
|
| 26 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.PROPS_WIDGET_DESC
|
| 27 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_HELP_PROMPT
|
|
|
|
| 28 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_MAIL_READ
|
| 29 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_MAIL_WRITE
|
| 30 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_SCHEDULE_ALARM
|
|
@@ -35,19 +38,29 @@ import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ContactHelper.getContac
|
|
| 35 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper
|
| 36 |
import org.json.JSONArray
|
| 37 |
|
|
|
|
|
|
|
|
|
|
| 38 |
class ChatMainAdapter(
|
| 39 |
context: Context, list: ArrayList<ChatMessageModel>, callbacks: ChatMessageInterface
|
| 40 |
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
| 41 |
|
|
|
|
|
|
|
|
|
|
| 42 |
private val VIEW_TYPE_MSG_SENT = 0
|
| 43 |
private val VIEW_TYPE_MSG_RECEIVED = 1
|
| 44 |
private val VIEW_TYPE_CHAT_WIDGET = 2
|
| 45 |
private val VIEW_TYPE_CHAT_ERROR = 3
|
| 46 |
|
| 47 |
private var context: Context
|
| 48 |
-
private var callbacks: ChatMessageInterface
|
| 49 |
private var chatMessageList: ArrayList<ChatMessageModel> = ArrayList()
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
init {
|
| 52 |
this.context = context
|
| 53 |
this.chatMessageList = list
|
|
@@ -114,7 +127,13 @@ class ChatMainAdapter(
|
|
| 114 |
}
|
| 115 |
}
|
| 116 |
|
|
|
|
|
|
|
|
|
|
| 117 |
private fun setMessageData(holder: MessageViewHolder, data: ChatMessageModel) {
|
|
|
|
|
|
|
|
|
|
| 118 |
if (data.hasImage) {
|
| 119 |
data.image?.let { image ->
|
| 120 |
val originBitmap = BitmapFactory.decodeByteArray(image, 0, image.size)
|
|
@@ -140,12 +159,18 @@ class ChatMainAdapter(
|
|
| 140 |
}
|
| 141 |
}
|
| 142 |
|
|
|
|
|
|
|
|
|
|
| 143 |
private fun setMessageData(holder: ChatWidgetViewHolder, data: ChatMessageModel) {
|
| 144 |
holder.itemLayout.visibility = View.VISIBLE
|
| 145 |
holder.llHorizontalScroll.removeAllViews()
|
| 146 |
holder.itemLayout.removeAllViews()
|
| 147 |
val index = holder.adapterPosition
|
| 148 |
|
|
|
|
|
|
|
|
|
|
| 149 |
when (data.content) {
|
| 150 |
TYPE_WIDGET_SMS -> {
|
| 151 |
val sendSmsWidget = SendSmsWidget(context).apply {
|
|
@@ -222,19 +247,46 @@ class ChatMainAdapter(
|
|
| 222 |
holder.itemLayout.addView(scheduleAlarmWidget)
|
| 223 |
}
|
| 224 |
|
| 225 |
-
|
| 226 |
holder.llHorizontalScroll.visibility = View.VISIBLE
|
|
|
|
|
|
|
|
|
|
|
|
|
| 227 |
|
| 228 |
-
|
| 229 |
-
val mailWidget = MailWidget(context).apply {
|
| 230 |
this.callback = callbacks
|
| 231 |
}
|
| 232 |
holder.llHorizontalScroll.addView(mailWidget)
|
| 233 |
}
|
| 234 |
}
|
| 235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
TYPE_WIDGET_MAIL_WRITE -> {
|
| 237 |
-
val composeMailWIdget = ComposeMailWidget(context)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
holder.itemLayout.addView(composeMailWIdget)
|
| 239 |
}
|
| 240 |
|
|
@@ -244,6 +296,9 @@ class ChatMainAdapter(
|
|
| 244 |
}
|
| 245 |
}
|
| 246 |
|
|
|
|
|
|
|
|
|
|
| 247 |
inner class MessageViewHolder internal constructor(itemView: View) :
|
| 248 |
RecyclerView.ViewHolder(itemView) {
|
| 249 |
var txtMessage: TextView
|
|
@@ -257,6 +312,9 @@ class ChatMainAdapter(
|
|
| 257 |
}
|
| 258 |
}
|
| 259 |
|
|
|
|
|
|
|
|
|
|
| 260 |
inner class ChatWidgetViewHolder internal constructor(itemView: View) :
|
| 261 |
RecyclerView.ViewHolder(itemView) {
|
| 262 |
var itemLayout: FrameLayout
|
|
|
|
| 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.MailsProps
|
| 18 |
import com.matthaigh27.chatgptwrapper.data.models.chatwidgetprops.ScheduleAlarmProps
|
| 19 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
|
| 20 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.OnHideListener
|
|
|
|
| 22 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.alarm.ScheduleAlarmWidget
|
| 23 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.contact.ContactWidget
|
| 24 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.helpprompt.HelpPromptWidget
|
| 25 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.mail.ComposeMailWidget
|
| 26 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.mail.MailWidget
|
| 27 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.mail.ReadMailWidget
|
| 28 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.PROPS_WIDGET_DESC
|
| 29 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_HELP_PROMPT
|
| 30 |
+
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_MAILS
|
| 31 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_MAIL_READ
|
| 32 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_MAIL_WRITE
|
| 33 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_SCHEDULE_ALARM
|
|
|
|
| 38 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper
|
| 39 |
import org.json.JSONArray
|
| 40 |
|
| 41 |
+
/**
|
| 42 |
+
* This adapter class is used to display a list of chat messages on a recycler view.
|
| 43 |
+
*/
|
| 44 |
class ChatMainAdapter(
|
| 45 |
context: Context, list: ArrayList<ChatMessageModel>, callbacks: ChatMessageInterface
|
| 46 |
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
| 47 |
|
| 48 |
+
/**
|
| 49 |
+
* These variables are used to presents the type of messages
|
| 50 |
+
*/
|
| 51 |
private val VIEW_TYPE_MSG_SENT = 0
|
| 52 |
private val VIEW_TYPE_MSG_RECEIVED = 1
|
| 53 |
private val VIEW_TYPE_CHAT_WIDGET = 2
|
| 54 |
private val VIEW_TYPE_CHAT_ERROR = 3
|
| 55 |
|
| 56 |
private var context: Context
|
|
|
|
| 57 |
private var chatMessageList: ArrayList<ChatMessageModel> = ArrayList()
|
| 58 |
|
| 59 |
+
/**
|
| 60 |
+
* This is a callback that retrieves result from chat widgets.
|
| 61 |
+
*/
|
| 62 |
+
private var callbacks: ChatMessageInterface
|
| 63 |
+
|
| 64 |
init {
|
| 65 |
this.context = context
|
| 66 |
this.chatMessageList = list
|
|
|
|
| 127 |
}
|
| 128 |
}
|
| 129 |
|
| 130 |
+
/**
|
| 131 |
+
* This function is used to set data for common messages.
|
| 132 |
+
*/
|
| 133 |
private fun setMessageData(holder: MessageViewHolder, data: ChatMessageModel) {
|
| 134 |
+
/**
|
| 135 |
+
* If an image is included into a message, the image is displayed by below code.
|
| 136 |
+
*/
|
| 137 |
if (data.hasImage) {
|
| 138 |
data.image?.let { image ->
|
| 139 |
val originBitmap = BitmapFactory.decodeByteArray(image, 0, image.size)
|
|
|
|
| 159 |
}
|
| 160 |
}
|
| 161 |
|
| 162 |
+
/**
|
| 163 |
+
* This function is used to display chat widgets on a recycler view.
|
| 164 |
+
*/
|
| 165 |
private fun setMessageData(holder: ChatWidgetViewHolder, data: ChatMessageModel) {
|
| 166 |
holder.itemLayout.visibility = View.VISIBLE
|
| 167 |
holder.llHorizontalScroll.removeAllViews()
|
| 168 |
holder.itemLayout.removeAllViews()
|
| 169 |
val index = holder.adapterPosition
|
| 170 |
|
| 171 |
+
/**
|
| 172 |
+
* Depending on type of widget, the proper widget is displayed.
|
| 173 |
+
*/
|
| 174 |
when (data.content) {
|
| 175 |
TYPE_WIDGET_SMS -> {
|
| 176 |
val sendSmsWidget = SendSmsWidget(context).apply {
|
|
|
|
| 247 |
holder.itemLayout.addView(scheduleAlarmWidget)
|
| 248 |
}
|
| 249 |
|
| 250 |
+
TYPE_WIDGET_MAILS -> {
|
| 251 |
holder.llHorizontalScroll.visibility = View.VISIBLE
|
| 252 |
+
val props = data.data?.run {
|
| 253 |
+
val widgetDesc = data.data.asJsonObject[PROPS_WIDGET_DESC].asString
|
| 254 |
+
MailsProps.init(widgetDesc)
|
| 255 |
+
}
|
| 256 |
|
| 257 |
+
props?.mails?.forEach { mail ->
|
| 258 |
+
val mailWidget = MailWidget(context, mail).apply {
|
| 259 |
this.callback = callbacks
|
| 260 |
}
|
| 261 |
holder.llHorizontalScroll.addView(mailWidget)
|
| 262 |
}
|
| 263 |
}
|
| 264 |
|
| 265 |
+
TYPE_WIDGET_MAIL_READ -> {
|
| 266 |
+
val readMailWidget = ReadMailWidget(context).apply {
|
| 267 |
+
this.callback = callbacks
|
| 268 |
+
this.hideListener = object : OnHideListener {
|
| 269 |
+
override fun hide() {
|
| 270 |
+
holder.itemLayout.visibility = View.GONE
|
| 271 |
+
chatMessageList.removeAt(index)
|
| 272 |
+
notifyItemRemoved(index)
|
| 273 |
+
}
|
| 274 |
+
}
|
| 275 |
+
}
|
| 276 |
+
holder.itemLayout.addView(readMailWidget)
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
TYPE_WIDGET_MAIL_WRITE -> {
|
| 280 |
+
val composeMailWIdget = ComposeMailWidget(context).apply {
|
| 281 |
+
this.callback = callbacks
|
| 282 |
+
this.hideListener = object : OnHideListener {
|
| 283 |
+
override fun hide() {
|
| 284 |
+
holder.itemLayout.visibility = View.GONE
|
| 285 |
+
chatMessageList.removeAt(index)
|
| 286 |
+
notifyItemRemoved(index)
|
| 287 |
+
}
|
| 288 |
+
}
|
| 289 |
+
}
|
| 290 |
holder.itemLayout.addView(composeMailWIdget)
|
| 291 |
}
|
| 292 |
|
|
|
|
| 296 |
}
|
| 297 |
}
|
| 298 |
|
| 299 |
+
/**
|
| 300 |
+
* ViewHolder for common messages with message and image
|
| 301 |
+
*/
|
| 302 |
inner class MessageViewHolder internal constructor(itemView: View) :
|
| 303 |
RecyclerView.ViewHolder(itemView) {
|
| 304 |
var txtMessage: TextView
|
|
|
|
| 312 |
}
|
| 313 |
}
|
| 314 |
|
| 315 |
+
/**
|
| 316 |
+
* ViewHolder for chat widgets
|
| 317 |
+
*/
|
| 318 |
inner class ChatWidgetViewHolder internal constructor(itemView: View) :
|
| 319 |
RecyclerView.ViewHolder(itemView) {
|
| 320 |
var itemLayout: FrameLayout
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/dialogs/ConfirmDialog.kt
CHANGED
|
@@ -12,6 +12,9 @@ import android.widget.Button
|
|
| 12 |
import android.widget.TextView
|
| 13 |
import com.matthaigh27.chatgptwrapper.R
|
| 14 |
|
|
|
|
|
|
|
|
|
|
| 15 |
class ConfirmDialog(context: Context) : Dialog(context), View.OnClickListener {
|
| 16 |
|
| 17 |
private var txtMessage: TextView? = null
|
|
|
|
| 12 |
import android.widget.TextView
|
| 13 |
import com.matthaigh27.chatgptwrapper.R
|
| 14 |
|
| 15 |
+
/**
|
| 16 |
+
* This dialog is used to show confirm message to users.
|
| 17 |
+
*/
|
| 18 |
class ConfirmDialog(context: Context) : Dialog(context), View.OnClickListener {
|
| 19 |
|
| 20 |
private var txtMessage: TextView? = null
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/fragments/ChatMainFragment.kt
CHANGED
|
@@ -23,6 +23,8 @@ import com.matthaigh27.chatgptwrapper.R
|
|
| 23 |
import com.matthaigh27.chatgptwrapper.data.models.chat.ChatMessageModel
|
| 24 |
import com.matthaigh27.chatgptwrapper.data.models.chat.HelpCommandModel
|
| 25 |
import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel
|
|
|
|
|
|
|
| 26 |
import com.matthaigh27.chatgptwrapper.data.models.chatwidgetprops.ScheduleAlarmProps
|
| 27 |
import com.matthaigh27.chatgptwrapper.data.models.common.Time
|
| 28 |
import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
|
|
@@ -33,9 +35,11 @@ import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterfa
|
|
| 33 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.toolbar.ChatToolsWidget
|
| 34 |
import com.matthaigh27.chatgptwrapper.ui.chat.viewmodel.ChatViewModel
|
| 35 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.ERROR_MSG_NOEXIST_COMMAND
|
|
|
|
| 36 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.HELP_COMMAND_ALL
|
| 37 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.PROPS_WIDGET_DESC
|
| 38 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_HELP_PROMPT
|
|
|
|
| 39 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_MAIL_READ
|
| 40 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_MAIL_WRITE
|
| 41 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_SCHEDULE_ALARM
|
|
@@ -50,8 +54,10 @@ import com.matthaigh27.chatgptwrapper.utils.constants.TypeResponseConstants.TYPE
|
|
| 50 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeResponseConstants.TYPE_RESPONSE_MAIL_SEND
|
| 51 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeResponseConstants.TYPE_RESPONSE_MAIL_WRITE
|
| 52 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeResponseConstants.TYPE_RESPONSE_MESSAGE
|
|
|
|
| 53 |
import com.matthaigh27.chatgptwrapper.utils.helpers.Converter
|
| 54 |
import com.matthaigh27.chatgptwrapper.utils.helpers.Converter.responseToHelpPromptList
|
|
|
|
| 55 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.getHelpCommandFromStr
|
| 56 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.isMainHelpCommand
|
| 57 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.makePromptItemUsage
|
|
@@ -59,8 +65,17 @@ import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.makePromp
|
|
| 59 |
import com.matthaigh27.chatgptwrapper.utils.helpers.ui.NoNewLineInputFilter
|
| 60 |
import org.json.JSONArray
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
class ChatMainFragment : Fragment(), OnClickListener {
|
| 63 |
|
|
|
|
|
|
|
|
|
|
| 64 |
private val TYPE_CHAT_SENT = 0
|
| 65 |
private val TYPE_CHAT_RECEIVE = 1
|
| 66 |
private val TYPE_CHAT_WIDGET = 2
|
|
@@ -69,10 +84,12 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 69 |
private lateinit var rootView: View
|
| 70 |
lateinit var viewModel: ChatViewModel
|
| 71 |
|
| 72 |
-
/** View Components */
|
| 73 |
private var loadingRotate: RotateAnimation? = null
|
| 74 |
private var edtMessageInput: EditText? = null
|
| 75 |
|
|
|
|
|
|
|
|
|
|
| 76 |
private var rvChatList: RecyclerView? = null
|
| 77 |
private var chatMainAdapter: ChatMainAdapter? = null
|
| 78 |
private var chatMessageList: ArrayList<ChatMessageModel> = ArrayList()
|
|
@@ -81,9 +98,16 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 81 |
private var chatToolsWidget: ChatToolsWidget? = null
|
| 82 |
private var helpPromptList: ArrayList<HelpPromptModel>? = null
|
| 83 |
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
private var showLoadingCount = 0
|
| 88 |
|
| 89 |
override fun onCreateView(
|
|
@@ -95,6 +119,9 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 95 |
}
|
| 96 |
|
| 97 |
private fun init() {
|
|
|
|
|
|
|
|
|
|
| 98 |
initViewModel()
|
| 99 |
initLoadingRotate()
|
| 100 |
initButtonsClickListener()
|
|
@@ -105,11 +132,16 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 105 |
fetchAllCommands()
|
| 106 |
}
|
| 107 |
|
| 108 |
-
|
|
|
|
|
|
|
| 109 |
private fun initViewModel() {
|
| 110 |
viewModel = ViewModelProvider(this)[ChatViewModel::class.java]
|
| 111 |
}
|
| 112 |
|
|
|
|
|
|
|
|
|
|
| 113 |
private fun initLoadingRotate() {
|
| 114 |
loadingRotate = RotateAnimation(/* fromDegrees = */ 0f, /* toDegrees = */
|
| 115 |
720f, /* pivotXType = */
|
|
@@ -124,11 +156,17 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 124 |
}
|
| 125 |
}
|
| 126 |
|
|
|
|
|
|
|
|
|
|
| 127 |
private fun initButtonsClickListener() {
|
| 128 |
rootView.findViewById<View>(R.id.btn_open_chat_tools).setOnClickListener(this)
|
| 129 |
rootView.findViewById<View>(R.id.btn_audio_recognition).setOnClickListener(this)
|
| 130 |
}
|
| 131 |
|
|
|
|
|
|
|
|
|
|
| 132 |
private fun initChatInputListener() {
|
| 133 |
edtMessageInput = rootView.findViewById(R.id.edt_message)
|
| 134 |
edtMessageInput?.filters = edtMessageInput?.filters?.plus(NoNewLineInputFilter())
|
|
@@ -141,7 +179,13 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 141 |
}
|
| 142 |
}
|
| 143 |
|
|
|
|
|
|
|
|
|
|
| 144 |
private fun initChatRecyclerView() {
|
|
|
|
|
|
|
|
|
|
| 145 |
initChatInterface()
|
| 146 |
|
| 147 |
rvChatList = rootView.findViewById(R.id.rv_chat_list)
|
|
@@ -153,6 +197,10 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 153 |
rvChatList?.layoutManager = LinearLayoutManager(context)
|
| 154 |
}
|
| 155 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
private fun initChatToolsWidget() {
|
| 157 |
chatToolsWidget = ChatToolsWidget(requireContext(), requireActivity()).apply {
|
| 158 |
this.callback = chatMessageInterface
|
|
@@ -161,6 +209,14 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 161 |
llToolBar.addView(chatToolsWidget)
|
| 162 |
}
|
| 163 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 164 |
private fun showLoading(isLoading: Boolean) {
|
| 165 |
val imgLoading = rootView.findViewById<ImageView>(R.id.sp_loading)
|
| 166 |
|
|
@@ -179,6 +235,19 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 179 |
}
|
| 180 |
}
|
| 181 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
private fun addMessage(
|
| 183 |
type: Int,
|
| 184 |
content: String? = null,
|
|
@@ -188,11 +257,17 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 188 |
) {
|
| 189 |
when (type) {
|
| 190 |
TYPE_CHAT_SENT -> {
|
|
|
|
|
|
|
|
|
|
| 191 |
if (content!!.isNotEmpty() && content.first() == '/') {
|
| 192 |
openHelpPromptWidget(content)
|
| 193 |
return
|
| 194 |
}
|
| 195 |
if (isImagePicked) {
|
|
|
|
|
|
|
|
|
|
| 196 |
addChatItemToList(
|
| 197 |
ChatMessageModel(
|
| 198 |
type = type,
|
|
@@ -205,6 +280,9 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 205 |
fetchImageRelatedness(currentUploadedImageName!!, content)
|
| 206 |
isImagePicked = false
|
| 207 |
} else {
|
|
|
|
|
|
|
|
|
|
| 208 |
addChatItemToList(ChatMessageModel(type, content, data, hasImage, image))
|
| 209 |
sendNotification(content)
|
| 210 |
}
|
|
@@ -216,6 +294,9 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 216 |
}
|
| 217 |
}
|
| 218 |
|
|
|
|
|
|
|
|
|
|
| 219 |
private fun addErrorMessage(
|
| 220 |
message: String
|
| 221 |
) {
|
|
@@ -233,42 +314,49 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 233 |
rvChatList?.scrollToPosition(chatMessageList.size - 1)
|
| 234 |
}
|
| 235 |
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
|
|
|
|
|
|
| 250 |
}
|
| 251 |
-
}
|
| 252 |
-
}
|
| 253 |
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
showLoading(true)
|
| 259 |
-
}
|
| 260 |
|
| 261 |
-
|
| 262 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 263 |
}
|
| 264 |
|
| 265 |
-
is ApiResource.Error -> {
|
| 266 |
-
showLoading(false)
|
| 267 |
-
}
|
| 268 |
}
|
| 269 |
}
|
| 270 |
}
|
| 271 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 272 |
private fun openHelpPromptWidget(message: String) {
|
| 273 |
try {
|
| 274 |
val command: HelpCommandModel = getHelpCommandFromStr(message)
|
|
@@ -318,112 +406,90 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 318 |
}
|
| 319 |
}
|
| 320 |
} catch (e: Exception) {
|
| 321 |
-
e.printStackTrace()
|
| 322 |
addErrorMessage(e.message.toString())
|
| 323 |
}
|
| 324 |
}
|
| 325 |
|
| 326 |
|
|
|
|
|
|
|
|
|
|
| 327 |
private fun fetchAllCommands() {
|
| 328 |
viewModel.getAllHelpCommands().observe(viewLifecycleOwner) { resource ->
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
}
|
| 333 |
-
|
| 334 |
-
is ApiResource.Success -> {
|
| 335 |
-
showLoading(false)
|
| 336 |
-
resource.data?.let { data ->
|
| 337 |
-
helpPromptList = responseToHelpPromptList(data.result.content)
|
| 338 |
-
}
|
| 339 |
-
}
|
| 340 |
-
|
| 341 |
-
is ApiResource.Error -> {
|
| 342 |
-
showLoading(false)
|
| 343 |
-
addErrorMessage(resource.message!!)
|
| 344 |
}
|
| 345 |
}
|
| 346 |
}
|
| 347 |
}
|
| 348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 349 |
private fun fetchImageRelatedness(imageName: String, message: String) {
|
| 350 |
viewModel.getImageRelatedness(imageName, message).observe(viewLifecycleOwner) { resource ->
|
| 351 |
-
|
| 352 |
-
|
| 353 |
-
|
| 354 |
-
|
| 355 |
-
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
type = TYPE_CHAT_RECEIVE,
|
| 360 |
-
content = resource.data?.description,
|
| 361 |
-
data = null,
|
| 362 |
-
hasImage = true,
|
| 363 |
-
image = resource.data?.image
|
| 364 |
-
)
|
| 365 |
-
}
|
| 366 |
-
|
| 367 |
-
is ApiResource.Error -> {
|
| 368 |
-
showLoading(false)
|
| 369 |
-
addErrorMessage(resource.message!!)
|
| 370 |
-
}
|
| 371 |
}
|
| 372 |
}
|
| 373 |
}
|
| 374 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 375 |
private fun sendNotification(message: String) {
|
| 376 |
viewModel.sendNotification(message).observe(viewLifecycleOwner) { resource ->
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
val apiResponse = resource.data
|
| 385 |
-
when (apiResponse?.result?.program) {
|
| 386 |
-
TYPE_RESPONSE_MESSAGE -> addMessage(
|
| 387 |
-
TYPE_CHAT_RECEIVE, apiResponse.result.content.asString
|
| 388 |
-
)
|
| 389 |
-
|
| 390 |
-
TYPE_RESPONSE_BROWSER -> fetchResponseBrowser(apiResponse)
|
| 391 |
-
TYPE_RESPONSE_CONTACT -> fetchResponseContact(apiResponse)
|
| 392 |
-
TYPE_RESPONSE_IMAGE -> fetchResponseImage(apiResponse)
|
| 393 |
-
TYPE_RESPONSE_ALARM -> fetchResponseAlarm(apiResponse)
|
| 394 |
-
TYPE_RESPONSE_MAIL_READ -> fetchResponseMail(TYPE_RESPONSE_MAIL_READ)
|
| 395 |
-
TYPE_RESPONSE_MAIL_WRITE -> fetchResponseMail(TYPE_RESPONSE_MAIL_WRITE)
|
| 396 |
-
TYPE_RESPONSE_MAIL_SEND -> fetchResponseMail(TYPE_RESPONSE_MAIL_SEND)
|
| 397 |
-
TYPE_RESPONSE_AUTO_TASK -> fetchResponseAutoTask(apiResponse)
|
| 398 |
-
else -> addMessage(TYPE_CHAT_RECEIVE, apiResponse!!.result.toString())
|
| 399 |
-
}
|
| 400 |
-
}
|
| 401 |
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 405 |
}
|
| 406 |
}
|
| 407 |
-
|
| 408 |
}
|
| 409 |
}
|
| 410 |
|
|
|
|
|
|
|
|
|
|
| 411 |
private fun fetchResponseBrowser(apiResponse: ApiResponse<CommonResult>) {
|
| 412 |
addMessage(TYPE_CHAT_RECEIVE, apiResponse.result.content.asString)
|
| 413 |
}
|
| 414 |
|
|
|
|
|
|
|
|
|
|
| 415 |
private fun fetchResponseImage(apiResponse: ApiResponse<CommonResult>) {
|
| 416 |
val content = apiResponse.result.content.asJsonObject
|
| 417 |
-
viewModel.downloadImageFromFirebase(
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
when (resource) {
|
| 421 |
-
is ApiResource.Loading -> {
|
| 422 |
-
showLoading(true)
|
| 423 |
-
}
|
| 424 |
-
|
| 425 |
-
is ApiResource.Success -> {
|
| 426 |
-
showLoading(false)
|
| 427 |
addMessage(
|
| 428 |
type = TYPE_CHAT_RECEIVE,
|
| 429 |
content = null,
|
|
@@ -432,15 +498,12 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 432 |
image = resource.data
|
| 433 |
)
|
| 434 |
}
|
| 435 |
-
|
| 436 |
-
is ApiResource.Error -> {
|
| 437 |
-
addErrorMessage(resource.message!!)
|
| 438 |
-
showLoading(false)
|
| 439 |
-
}
|
| 440 |
}
|
| 441 |
-
}
|
| 442 |
}
|
| 443 |
|
|
|
|
|
|
|
|
|
|
| 444 |
private fun fetchResponseContact(apiResponse: ApiResponse<CommonResult>) {
|
| 445 |
val contactIds = JSONArray(apiResponse.result.content.asString.replace("'", "\""))
|
| 446 |
if (contactIds.length() > 0) {
|
|
@@ -457,6 +520,9 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 457 |
}
|
| 458 |
}
|
| 459 |
|
|
|
|
|
|
|
|
|
|
| 460 |
private fun fetchResponseAlarm(apiResponse: ApiResponse<CommonResult>) {
|
| 461 |
val time: Time =
|
| 462 |
Converter.stringToTime(apiResponse.result.content.asJsonObject.get("time").asString)
|
|
@@ -468,18 +534,13 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 468 |
addMessage(TYPE_CHAT_WIDGET, TYPE_WIDGET_SCHEDULE_ALARM, widgetDesc)
|
| 469 |
}
|
| 470 |
|
|
|
|
|
|
|
|
|
|
| 471 |
private fun fetchResponseMail(type: String) {
|
| 472 |
when (type) {
|
| 473 |
-
TYPE_RESPONSE_MAIL_READ ->
|
| 474 |
-
|
| 475 |
-
}
|
| 476 |
-
|
| 477 |
-
TYPE_RESPONSE_MAIL_WRITE -> {
|
| 478 |
-
addMessage(TYPE_CHAT_WIDGET, TYPE_WIDGET_MAIL_WRITE)
|
| 479 |
-
}
|
| 480 |
-
|
| 481 |
-
TYPE_RESPONSE_MAIL_SEND -> {
|
| 482 |
-
}
|
| 483 |
}
|
| 484 |
}
|
| 485 |
|
|
@@ -495,35 +556,47 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 495 |
).observe(viewLifecycleOwner) { resource ->
|
| 496 |
when (resource) {
|
| 497 |
is ApiResource.Loading -> {
|
|
|
|
| 498 |
resource.data?.let { data ->
|
| 499 |
if (data.result == null) {
|
| 500 |
data.thoughts?.let { thoughts ->
|
| 501 |
addMessage(
|
| 502 |
-
type = TYPE_CHAT_RECEIVE,
|
| 503 |
-
content = thoughts.speak
|
| 504 |
)
|
| 505 |
}
|
| 506 |
} else {
|
| 507 |
addMessage(
|
| 508 |
-
type = TYPE_CHAT_RECEIVE,
|
| 509 |
-
content = data.result
|
| 510 |
)
|
| 511 |
}
|
| 512 |
}
|
| 513 |
}
|
| 514 |
|
| 515 |
is ApiResource.Success -> {
|
|
|
|
| 516 |
addMessage(TYPE_CHAT_RECEIVE, "Task is finished.")
|
| 517 |
}
|
| 518 |
|
| 519 |
is ApiResource.Error -> {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 520 |
}
|
| 521 |
}
|
| 522 |
}
|
| 523 |
}
|
| 524 |
|
|
|
|
|
|
|
|
|
|
| 525 |
private fun initChatInterface() {
|
| 526 |
chatMessageInterface = object : ChatMessageInterface {
|
|
|
|
|
|
|
|
|
|
| 527 |
override fun sentSms(phoneNumber: String, message: String) {
|
| 528 |
addMessage(
|
| 529 |
type = TYPE_CHAT_RECEIVE,
|
|
@@ -531,6 +604,9 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 531 |
)
|
| 532 |
}
|
| 533 |
|
|
|
|
|
|
|
|
|
|
| 534 |
override fun canceledSms() {
|
| 535 |
addMessage(
|
| 536 |
type = TYPE_CHAT_RECEIVE,
|
|
@@ -538,30 +614,46 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 538 |
)
|
| 539 |
}
|
| 540 |
|
|
|
|
|
|
|
|
|
|
| 541 |
override fun sentHelpPrompt(prompt: String) {
|
| 542 |
addMessage(
|
| 543 |
type = TYPE_CHAT_SENT, content = prompt
|
| 544 |
)
|
| 545 |
}
|
| 546 |
|
|
|
|
|
|
|
|
|
|
| 547 |
override fun canceledHelpPrompt() {
|
| 548 |
addMessage(
|
| 549 |
type = TYPE_CHAT_RECEIVE, content = "You canceled Help prompt."
|
| 550 |
)
|
| 551 |
}
|
| 552 |
|
|
|
|
|
|
|
|
|
|
| 553 |
override fun doVoiceCall(phoneNumber: String) {
|
| 554 |
addMessage(
|
| 555 |
type = TYPE_CHAT_RECEIVE, content = "You made a voice call to $phoneNumber"
|
| 556 |
)
|
| 557 |
}
|
| 558 |
|
|
|
|
|
|
|
|
|
|
| 559 |
override fun doVideoCall(phoneNumber: String) {
|
| 560 |
addMessage(
|
| 561 |
type = TYPE_CHAT_RECEIVE, content = "You made a video call to $phoneNumber"
|
| 562 |
)
|
| 563 |
}
|
| 564 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 565 |
override fun sendSmsWithPhoneNumber(phoneNumber: String) {
|
| 566 |
val widgetDesc = JsonObject().apply {
|
| 567 |
this.addProperty(PROPS_WIDGET_DESC, phoneNumber)
|
|
@@ -571,29 +663,25 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 571 |
)
|
| 572 |
}
|
| 573 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 574 |
override fun pickImage(isSuccess: Boolean, data: ByteArray?) {
|
| 575 |
if (!isSuccess) addErrorMessage("Fail to pick image")
|
| 576 |
-
viewModel.uploadImageToFirebase(data!!).observe(viewLifecycleOwner) { resource ->
|
| 577 |
-
when (resource) {
|
| 578 |
-
is ApiResource.Loading -> {
|
| 579 |
-
showLoading(true)
|
| 580 |
-
}
|
| 581 |
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
}
|
| 588 |
-
|
| 589 |
-
is ApiResource.Error -> {
|
| 590 |
-
addErrorMessage(resource.message!!)
|
| 591 |
-
showLoading(false)
|
| 592 |
-
}
|
| 593 |
}
|
| 594 |
}
|
| 595 |
}
|
| 596 |
|
|
|
|
|
|
|
|
|
|
| 597 |
override fun setAlarm(hours: Int, minutes: Int, label: String) {
|
| 598 |
addMessage(
|
| 599 |
type = TYPE_CHAT_RECEIVE,
|
|
@@ -601,11 +689,64 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 601 |
)
|
| 602 |
}
|
| 603 |
|
|
|
|
|
|
|
|
|
|
| 604 |
override fun cancelAlarm() {
|
| 605 |
addMessage(
|
| 606 |
type = TYPE_CHAT_RECEIVE, content = "You canceled setting an alarm."
|
| 607 |
)
|
| 608 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 609 |
}
|
| 610 |
}
|
| 611 |
|
|
@@ -616,14 +757,21 @@ class ChatMainFragment : Fragment(), OnClickListener {
|
|
| 616 |
}
|
| 617 |
|
| 618 |
R.id.btn_audio_recognition -> {
|
| 619 |
-
|
| 620 |
}
|
| 621 |
}
|
| 622 |
}
|
| 623 |
|
| 624 |
override fun onResume() {
|
| 625 |
super.onResume()
|
| 626 |
-
|
| 627 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 628 |
}
|
| 629 |
}
|
|
|
|
| 23 |
import com.matthaigh27.chatgptwrapper.data.models.chat.ChatMessageModel
|
| 24 |
import com.matthaigh27.chatgptwrapper.data.models.chat.HelpCommandModel
|
| 25 |
import com.matthaigh27.chatgptwrapper.data.models.chat.HelpPromptModel
|
| 26 |
+
import com.matthaigh27.chatgptwrapper.data.models.chat.MailModel
|
| 27 |
+
import com.matthaigh27.chatgptwrapper.data.models.chatwidgetprops.MailsProps
|
| 28 |
import com.matthaigh27.chatgptwrapper.data.models.chatwidgetprops.ScheduleAlarmProps
|
| 29 |
import com.matthaigh27.chatgptwrapper.data.models.common.Time
|
| 30 |
import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
|
|
|
|
| 35 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.toolbar.ChatToolsWidget
|
| 36 |
import com.matthaigh27.chatgptwrapper.ui.chat.viewmodel.ChatViewModel
|
| 37 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.ERROR_MSG_NOEXIST_COMMAND
|
| 38 |
+
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.ERROR_MSG_UNKNOWN_ERROR
|
| 39 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.HELP_COMMAND_ALL
|
| 40 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.PROPS_WIDGET_DESC
|
| 41 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_HELP_PROMPT
|
| 42 |
+
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_MAILS
|
| 43 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_MAIL_READ
|
| 44 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_MAIL_WRITE
|
| 45 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeChatWidgetConstants.TYPE_WIDGET_SCHEDULE_ALARM
|
|
|
|
| 54 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeResponseConstants.TYPE_RESPONSE_MAIL_SEND
|
| 55 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeResponseConstants.TYPE_RESPONSE_MAIL_WRITE
|
| 56 |
import com.matthaigh27.chatgptwrapper.utils.constants.TypeResponseConstants.TYPE_RESPONSE_MESSAGE
|
| 57 |
+
import com.matthaigh27.chatgptwrapper.utils.constants.TypeResponseConstants.TYPE_RESPONSE_SMS
|
| 58 |
import com.matthaigh27.chatgptwrapper.utils.helpers.Converter
|
| 59 |
import com.matthaigh27.chatgptwrapper.utils.helpers.Converter.responseToHelpPromptList
|
| 60 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.OnSuccess
|
| 61 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.getHelpCommandFromStr
|
| 62 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.isMainHelpCommand
|
| 63 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.makePromptItemUsage
|
|
|
|
| 65 |
import com.matthaigh27.chatgptwrapper.utils.helpers.ui.NoNewLineInputFilter
|
| 66 |
import org.json.JSONArray
|
| 67 |
|
| 68 |
+
/**
|
| 69 |
+
* A ChatMainFragment class is a class for chatting with users and show the result that
|
| 70 |
+
* our AI plugin - Brain returned.
|
| 71 |
+
*
|
| 72 |
+
* In this class, almost important features are implemented.
|
| 73 |
+
*/
|
| 74 |
class ChatMainFragment : Fragment(), OnClickListener {
|
| 75 |
|
| 76 |
+
/**
|
| 77 |
+
* These variables(TYPE_CHAT_XXX) are variables that present type of widget to display on chatting list.
|
| 78 |
+
*/
|
| 79 |
private val TYPE_CHAT_SENT = 0
|
| 80 |
private val TYPE_CHAT_RECEIVE = 1
|
| 81 |
private val TYPE_CHAT_WIDGET = 2
|
|
|
|
| 84 |
private lateinit var rootView: View
|
| 85 |
lateinit var viewModel: ChatViewModel
|
| 86 |
|
|
|
|
| 87 |
private var loadingRotate: RotateAnimation? = null
|
| 88 |
private var edtMessageInput: EditText? = null
|
| 89 |
|
| 90 |
+
/**
|
| 91 |
+
* These variables are for recyclerview that shows chatting list items.
|
| 92 |
+
*/
|
| 93 |
private var rvChatList: RecyclerView? = null
|
| 94 |
private var chatMainAdapter: ChatMainAdapter? = null
|
| 95 |
private var chatMessageList: ArrayList<ChatMessageModel> = ArrayList()
|
|
|
|
| 98 |
private var chatToolsWidget: ChatToolsWidget? = null
|
| 99 |
private var helpPromptList: ArrayList<HelpPromptModel>? = null
|
| 100 |
|
| 101 |
+
/**
|
| 102 |
+
* These variables are used to identify whether users picked an image to send to Brain.
|
| 103 |
+
*/
|
| 104 |
+
private var currentSelectedImage: ByteArray? =
|
| 105 |
+
null // bytearray data of a picked image by camera or gallery
|
| 106 |
+
private var currentUploadedImageName: String? =
|
| 107 |
+
null // resource name that is uploaded to firebase storage
|
| 108 |
+
private var isImagePicked: Boolean =
|
| 109 |
+
false // boolean variable that presents whether users picked an image
|
| 110 |
+
|
| 111 |
private var showLoadingCount = 0
|
| 112 |
|
| 113 |
override fun onCreateView(
|
|
|
|
| 119 |
}
|
| 120 |
|
| 121 |
private fun init() {
|
| 122 |
+
/**
|
| 123 |
+
* These are functions to init views
|
| 124 |
+
*/
|
| 125 |
initViewModel()
|
| 126 |
initLoadingRotate()
|
| 127 |
initButtonsClickListener()
|
|
|
|
| 132 |
fetchAllCommands()
|
| 133 |
}
|
| 134 |
|
| 135 |
+
/**
|
| 136 |
+
* This function is used to init viewmodel.
|
| 137 |
+
*/
|
| 138 |
private fun initViewModel() {
|
| 139 |
viewModel = ViewModelProvider(this)[ChatViewModel::class.java]
|
| 140 |
}
|
| 141 |
|
| 142 |
+
/**
|
| 143 |
+
* This function is used to init rotate animation for loading spinner.
|
| 144 |
+
*/
|
| 145 |
private fun initLoadingRotate() {
|
| 146 |
loadingRotate = RotateAnimation(/* fromDegrees = */ 0f, /* toDegrees = */
|
| 147 |
720f, /* pivotXType = */
|
|
|
|
| 156 |
}
|
| 157 |
}
|
| 158 |
|
| 159 |
+
/**
|
| 160 |
+
* In this function, click listener is set to buttons on main chat interface.
|
| 161 |
+
*/
|
| 162 |
private fun initButtonsClickListener() {
|
| 163 |
rootView.findViewById<View>(R.id.btn_open_chat_tools).setOnClickListener(this)
|
| 164 |
rootView.findViewById<View>(R.id.btn_audio_recognition).setOnClickListener(this)
|
| 165 |
}
|
| 166 |
|
| 167 |
+
/**
|
| 168 |
+
* Send text message to Brain when users finish typing text to EditText component.
|
| 169 |
+
*/
|
| 170 |
private fun initChatInputListener() {
|
| 171 |
edtMessageInput = rootView.findViewById(R.id.edt_message)
|
| 172 |
edtMessageInput?.filters = edtMessageInput?.filters?.plus(NoNewLineInputFilter())
|
|
|
|
| 179 |
}
|
| 180 |
}
|
| 181 |
|
| 182 |
+
/**
|
| 183 |
+
* This function is used to init recyclerview that stores chatting messages.
|
| 184 |
+
*/
|
| 185 |
private fun initChatRecyclerView() {
|
| 186 |
+
/**
|
| 187 |
+
* Init callback function that binds the event emitted in all chat widgets
|
| 188 |
+
*/
|
| 189 |
initChatInterface()
|
| 190 |
|
| 191 |
rvChatList = rootView.findViewById(R.id.rv_chat_list)
|
|
|
|
| 197 |
rvChatList?.layoutManager = LinearLayoutManager(context)
|
| 198 |
}
|
| 199 |
|
| 200 |
+
/**
|
| 201 |
+
* This function is used to init chat tool widget that pops up when users click plus button
|
| 202 |
+
* at the right bottom corner.
|
| 203 |
+
*/
|
| 204 |
private fun initChatToolsWidget() {
|
| 205 |
chatToolsWidget = ChatToolsWidget(requireContext(), requireActivity()).apply {
|
| 206 |
this.callback = chatMessageInterface
|
|
|
|
| 209 |
llToolBar.addView(chatToolsWidget)
|
| 210 |
}
|
| 211 |
|
| 212 |
+
/**
|
| 213 |
+
* This function is used to show loading spinner.
|
| 214 |
+
*
|
| 215 |
+
* If isLoading is true, loading spinner is displayed. But loading spinner might not be visible,
|
| 216 |
+
* even though isLoading is true. Current visible loading spinner count should be 0 to make loading spinner invisible.
|
| 217 |
+
*
|
| 218 |
+
* @param isLoading boolean parameter that presents whether loading spinner is visible
|
| 219 |
+
*/
|
| 220 |
private fun showLoading(isLoading: Boolean) {
|
| 221 |
val imgLoading = rootView.findViewById<ImageView>(R.id.sp_loading)
|
| 222 |
|
|
|
|
| 235 |
}
|
| 236 |
}
|
| 237 |
|
| 238 |
+
/**
|
| 239 |
+
* This function is used mostly to add messages to chatting list.
|
| 240 |
+
*
|
| 241 |
+
* According to type of message, messages can be common messages or widgets for sending sms, setting an alarm, sending help prompt, etc.
|
| 242 |
+
* Depending on whether an image is contained into message, different network functions are executed.
|
| 243 |
+
* If message start with '/', help prompt widget is displayed.
|
| 244 |
+
*
|
| 245 |
+
* @param type A variable that present type of chat messages
|
| 246 |
+
* @param content Contains content of message to present
|
| 247 |
+
* @param data Contains properties of widget as json string when type is widget.
|
| 248 |
+
* @param hasImage Presents whether an image is contained into message
|
| 249 |
+
* @param image If a message has an image, this variable is used to store the bytearray data of the contained image.
|
| 250 |
+
*/
|
| 251 |
private fun addMessage(
|
| 252 |
type: Int,
|
| 253 |
content: String? = null,
|
|
|
|
| 257 |
) {
|
| 258 |
when (type) {
|
| 259 |
TYPE_CHAT_SENT -> {
|
| 260 |
+
/**
|
| 261 |
+
* If message starts with '/', help prompt widget is displayed.
|
| 262 |
+
*/
|
| 263 |
if (content!!.isNotEmpty() && content.first() == '/') {
|
| 264 |
openHelpPromptWidget(content)
|
| 265 |
return
|
| 266 |
}
|
| 267 |
if (isImagePicked) {
|
| 268 |
+
/**
|
| 269 |
+
* If an image is contained into a message, image relatedness function is executed.
|
| 270 |
+
*/
|
| 271 |
addChatItemToList(
|
| 272 |
ChatMessageModel(
|
| 273 |
type = type,
|
|
|
|
| 280 |
fetchImageRelatedness(currentUploadedImageName!!, content)
|
| 281 |
isImagePicked = false
|
| 282 |
} else {
|
| 283 |
+
/**
|
| 284 |
+
* If not, send notification function is executed.
|
| 285 |
+
*/
|
| 286 |
addChatItemToList(ChatMessageModel(type, content, data, hasImage, image))
|
| 287 |
sendNotification(content)
|
| 288 |
}
|
|
|
|
| 294 |
}
|
| 295 |
}
|
| 296 |
|
| 297 |
+
/**
|
| 298 |
+
* This function is used to display messages to show errors in more detail to users
|
| 299 |
+
*/
|
| 300 |
private fun addErrorMessage(
|
| 301 |
message: String
|
| 302 |
) {
|
|
|
|
| 314 |
rvChatList?.scrollToPosition(chatMessageList.size - 1)
|
| 315 |
}
|
| 316 |
|
| 317 |
+
/**
|
| 318 |
+
* This function is used to process ApiResource data from viewmodel.
|
| 319 |
+
*
|
| 320 |
+
* When status is loading or error, default functions are executed. When success, onSuccess
|
| 321 |
+
* lambda function is executed.
|
| 322 |
+
*
|
| 323 |
+
* @param resource A ApiResource that is retrieved from ViewModel
|
| 324 |
+
* @param onSuccess A lambda function to process the resource data
|
| 325 |
+
*/
|
| 326 |
+
private fun <T> commonProcessResource(
|
| 327 |
+
resource: ApiResource<T>,
|
| 328 |
+
onSuccess: OnSuccess<ApiResource<T>>
|
| 329 |
+
) {
|
| 330 |
+
when (resource) {
|
| 331 |
+
is ApiResource.Loading -> {
|
| 332 |
+
showLoading(true)
|
| 333 |
}
|
|
|
|
|
|
|
| 334 |
|
| 335 |
+
is ApiResource.Success -> {
|
| 336 |
+
showLoading(false)
|
| 337 |
+
onSuccess(resource)
|
| 338 |
+
}
|
|
|
|
|
|
|
| 339 |
|
| 340 |
+
is ApiResource.Error -> {
|
| 341 |
+
showLoading(false)
|
| 342 |
+
resource.message?.let {
|
| 343 |
+
addErrorMessage(resource.message)
|
| 344 |
+
} ?: run {
|
| 345 |
+
addErrorMessage(ERROR_MSG_UNKNOWN_ERROR)
|
| 346 |
}
|
| 347 |
|
|
|
|
|
|
|
|
|
|
| 348 |
}
|
| 349 |
}
|
| 350 |
}
|
| 351 |
|
| 352 |
+
/**
|
| 353 |
+
* Open help prompt widgets when message is valid help command.
|
| 354 |
+
*
|
| 355 |
+
* @param message A String variable that contains message users sent
|
| 356 |
+
* If message is /help, all the description of help commands is displayed,
|
| 357 |
+
* If message is /help prompt name, the description of a given prompt help command is displayed.
|
| 358 |
+
* If message is /prompt name, A help prompt widget about the given name is displayed.
|
| 359 |
+
*/
|
| 360 |
private fun openHelpPromptWidget(message: String) {
|
| 361 |
try {
|
| 362 |
val command: HelpCommandModel = getHelpCommandFromStr(message)
|
|
|
|
| 406 |
}
|
| 407 |
}
|
| 408 |
} catch (e: Exception) {
|
|
|
|
| 409 |
addErrorMessage(e.message.toString())
|
| 410 |
}
|
| 411 |
}
|
| 412 |
|
| 413 |
|
| 414 |
+
/**
|
| 415 |
+
* This Network function is used to fetch all help commands
|
| 416 |
+
*/
|
| 417 |
private fun fetchAllCommands() {
|
| 418 |
viewModel.getAllHelpCommands().observe(viewLifecycleOwner) { resource ->
|
| 419 |
+
commonProcessResource(resource) {
|
| 420 |
+
resource.data?.let { data ->
|
| 421 |
+
helpPromptList = responseToHelpPromptList(data.result.content)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 422 |
}
|
| 423 |
}
|
| 424 |
}
|
| 425 |
}
|
| 426 |
|
| 427 |
+
/**
|
| 428 |
+
* This Network function is used to fetch a similar image to image that is stored with imageName parameter
|
| 429 |
+
* in Firebase storage.
|
| 430 |
+
*
|
| 431 |
+
* @param imageName The image name of a image that a user uploaded to the Firebase
|
| 432 |
+
* @param message The description about the image
|
| 433 |
+
*/
|
| 434 |
private fun fetchImageRelatedness(imageName: String, message: String) {
|
| 435 |
viewModel.getImageRelatedness(imageName, message).observe(viewLifecycleOwner) { resource ->
|
| 436 |
+
commonProcessResource(resource) {
|
| 437 |
+
addMessage(
|
| 438 |
+
type = TYPE_CHAT_RECEIVE,
|
| 439 |
+
content = resource.data?.description,
|
| 440 |
+
data = null,
|
| 441 |
+
hasImage = true,
|
| 442 |
+
image = resource.data?.image
|
| 443 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 444 |
}
|
| 445 |
}
|
| 446 |
}
|
| 447 |
|
| 448 |
+
/**
|
| 449 |
+
* This network function is used to retrieve a command analyzed with user's message by Brain
|
| 450 |
+
*
|
| 451 |
+
* @param message A message that users sent
|
| 452 |
+
*/
|
| 453 |
private fun sendNotification(message: String) {
|
| 454 |
viewModel.sendNotification(message).observe(viewLifecycleOwner) { resource ->
|
| 455 |
+
commonProcessResource(resource) {
|
| 456 |
+
val apiResponse = resource.data
|
| 457 |
+
when (apiResponse?.result?.program) {
|
| 458 |
+
TYPE_RESPONSE_MESSAGE -> addMessage(
|
| 459 |
+
TYPE_CHAT_RECEIVE,
|
| 460 |
+
apiResponse.result.content.asString
|
| 461 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 462 |
|
| 463 |
+
TYPE_RESPONSE_SMS -> addMessage(TYPE_CHAT_WIDGET, TYPE_WIDGET_SMS)
|
| 464 |
+
TYPE_RESPONSE_BROWSER -> fetchResponseBrowser(apiResponse)
|
| 465 |
+
TYPE_RESPONSE_CONTACT -> fetchResponseContact(apiResponse)
|
| 466 |
+
TYPE_RESPONSE_IMAGE -> fetchResponseImage(apiResponse)
|
| 467 |
+
TYPE_RESPONSE_ALARM -> fetchResponseAlarm(apiResponse)
|
| 468 |
+
TYPE_RESPONSE_MAIL_READ -> fetchResponseMail(TYPE_RESPONSE_MAIL_READ)
|
| 469 |
+
TYPE_RESPONSE_MAIL_WRITE -> fetchResponseMail(TYPE_RESPONSE_MAIL_WRITE)
|
| 470 |
+
TYPE_RESPONSE_MAIL_SEND -> fetchResponseMail(TYPE_RESPONSE_MAIL_SEND)
|
| 471 |
+
TYPE_RESPONSE_AUTO_TASK -> fetchResponseAutoTask(apiResponse)
|
| 472 |
+
else -> addMessage(TYPE_CHAT_RECEIVE, apiResponse!!.result.toString())
|
| 473 |
}
|
| 474 |
}
|
|
|
|
| 475 |
}
|
| 476 |
}
|
| 477 |
|
| 478 |
+
/**
|
| 479 |
+
* This function is used to process data from Brain that is for browser.
|
| 480 |
+
*/
|
| 481 |
private fun fetchResponseBrowser(apiResponse: ApiResponse<CommonResult>) {
|
| 482 |
addMessage(TYPE_CHAT_RECEIVE, apiResponse.result.content.asString)
|
| 483 |
}
|
| 484 |
|
| 485 |
+
/**
|
| 486 |
+
* This function is used to process data from Brain that is for image.
|
| 487 |
+
*/
|
| 488 |
private fun fetchResponseImage(apiResponse: ApiResponse<CommonResult>) {
|
| 489 |
val content = apiResponse.result.content.asJsonObject
|
| 490 |
+
viewModel.downloadImageFromFirebase(content["image_name"].asString)
|
| 491 |
+
.observe(viewLifecycleOwner) { resource ->
|
| 492 |
+
commonProcessResource(resource) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 493 |
addMessage(
|
| 494 |
type = TYPE_CHAT_RECEIVE,
|
| 495 |
content = null,
|
|
|
|
| 498 |
image = resource.data
|
| 499 |
)
|
| 500 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 501 |
}
|
|
|
|
| 502 |
}
|
| 503 |
|
| 504 |
+
/**
|
| 505 |
+
* This function is used to process data from Brain that is for contact.
|
| 506 |
+
*/
|
| 507 |
private fun fetchResponseContact(apiResponse: ApiResponse<CommonResult>) {
|
| 508 |
val contactIds = JSONArray(apiResponse.result.content.asString.replace("'", "\""))
|
| 509 |
if (contactIds.length() > 0) {
|
|
|
|
| 520 |
}
|
| 521 |
}
|
| 522 |
|
| 523 |
+
/**
|
| 524 |
+
* This function is used to process data from Brain that is for alarm.
|
| 525 |
+
*/
|
| 526 |
private fun fetchResponseAlarm(apiResponse: ApiResponse<CommonResult>) {
|
| 527 |
val time: Time =
|
| 528 |
Converter.stringToTime(apiResponse.result.content.asJsonObject.get("time").asString)
|
|
|
|
| 534 |
addMessage(TYPE_CHAT_WIDGET, TYPE_WIDGET_SCHEDULE_ALARM, widgetDesc)
|
| 535 |
}
|
| 536 |
|
| 537 |
+
/**
|
| 538 |
+
* This function is used to process data from Brain that is for mail.
|
| 539 |
+
*/
|
| 540 |
private fun fetchResponseMail(type: String) {
|
| 541 |
when (type) {
|
| 542 |
+
TYPE_RESPONSE_MAIL_READ -> addMessage(TYPE_CHAT_WIDGET, TYPE_WIDGET_MAIL_READ)
|
| 543 |
+
TYPE_RESPONSE_MAIL_SEND -> addMessage(TYPE_CHAT_WIDGET, TYPE_WIDGET_MAIL_WRITE)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 544 |
}
|
| 545 |
}
|
| 546 |
|
|
|
|
| 556 |
).observe(viewLifecycleOwner) { resource ->
|
| 557 |
when (resource) {
|
| 558 |
is ApiResource.Loading -> {
|
| 559 |
+
showLoading(true)
|
| 560 |
resource.data?.let { data ->
|
| 561 |
if (data.result == null) {
|
| 562 |
data.thoughts?.let { thoughts ->
|
| 563 |
addMessage(
|
| 564 |
+
type = TYPE_CHAT_RECEIVE, content = thoughts.speak
|
|
|
|
| 565 |
)
|
| 566 |
}
|
| 567 |
} else {
|
| 568 |
addMessage(
|
| 569 |
+
type = TYPE_CHAT_RECEIVE, content = data.result
|
|
|
|
| 570 |
)
|
| 571 |
}
|
| 572 |
}
|
| 573 |
}
|
| 574 |
|
| 575 |
is ApiResource.Success -> {
|
| 576 |
+
showLoading(false)
|
| 577 |
addMessage(TYPE_CHAT_RECEIVE, "Task is finished.")
|
| 578 |
}
|
| 579 |
|
| 580 |
is ApiResource.Error -> {
|
| 581 |
+
showLoading(false)
|
| 582 |
+
resource.message?.let {
|
| 583 |
+
addErrorMessage(resource.message)
|
| 584 |
+
} ?: run {
|
| 585 |
+
addErrorMessage(ERROR_MSG_UNKNOWN_ERROR)
|
| 586 |
+
}
|
| 587 |
}
|
| 588 |
}
|
| 589 |
}
|
| 590 |
}
|
| 591 |
|
| 592 |
+
/**
|
| 593 |
+
* This interface is a callback function that retrieves the results of chat widgets.
|
| 594 |
+
*/
|
| 595 |
private fun initChatInterface() {
|
| 596 |
chatMessageInterface = object : ChatMessageInterface {
|
| 597 |
+
/**
|
| 598 |
+
* When a user sends sms using SMS Widget, this function is called.
|
| 599 |
+
*/
|
| 600 |
override fun sentSms(phoneNumber: String, message: String) {
|
| 601 |
addMessage(
|
| 602 |
type = TYPE_CHAT_RECEIVE,
|
|
|
|
| 604 |
)
|
| 605 |
}
|
| 606 |
|
| 607 |
+
/**
|
| 608 |
+
* When a user cancels sms using SMS Widget, this function is called.
|
| 609 |
+
*/
|
| 610 |
override fun canceledSms() {
|
| 611 |
addMessage(
|
| 612 |
type = TYPE_CHAT_RECEIVE,
|
|
|
|
| 614 |
)
|
| 615 |
}
|
| 616 |
|
| 617 |
+
/**
|
| 618 |
+
* When a user sends help prompt using help Prompt Widget, this function is called.
|
| 619 |
+
*/
|
| 620 |
override fun sentHelpPrompt(prompt: String) {
|
| 621 |
addMessage(
|
| 622 |
type = TYPE_CHAT_SENT, content = prompt
|
| 623 |
)
|
| 624 |
}
|
| 625 |
|
| 626 |
+
/**
|
| 627 |
+
* When a user cancels help prompt using help prompt Widget, this function is called.
|
| 628 |
+
*/
|
| 629 |
override fun canceledHelpPrompt() {
|
| 630 |
addMessage(
|
| 631 |
type = TYPE_CHAT_RECEIVE, content = "You canceled Help prompt."
|
| 632 |
)
|
| 633 |
}
|
| 634 |
|
| 635 |
+
/**
|
| 636 |
+
* When a user makes a voice call after searching for contacts, this function is called.
|
| 637 |
+
*/
|
| 638 |
override fun doVoiceCall(phoneNumber: String) {
|
| 639 |
addMessage(
|
| 640 |
type = TYPE_CHAT_RECEIVE, content = "You made a voice call to $phoneNumber"
|
| 641 |
)
|
| 642 |
}
|
| 643 |
|
| 644 |
+
/**
|
| 645 |
+
* When a user makes a video call after searching for contacts, this function is called.
|
| 646 |
+
*/
|
| 647 |
override fun doVideoCall(phoneNumber: String) {
|
| 648 |
addMessage(
|
| 649 |
type = TYPE_CHAT_RECEIVE, content = "You made a video call to $phoneNumber"
|
| 650 |
)
|
| 651 |
}
|
| 652 |
|
| 653 |
+
/**
|
| 654 |
+
* When a user sends sms with phone number after searching for contacts,
|
| 655 |
+
* this function is called.
|
| 656 |
+
*/
|
| 657 |
override fun sendSmsWithPhoneNumber(phoneNumber: String) {
|
| 658 |
val widgetDesc = JsonObject().apply {
|
| 659 |
this.addProperty(PROPS_WIDGET_DESC, phoneNumber)
|
|
|
|
| 663 |
)
|
| 664 |
}
|
| 665 |
|
| 666 |
+
/**
|
| 667 |
+
* When a user picks an image to send to Brain to search or compare similarity,
|
| 668 |
+
* this function is called.
|
| 669 |
+
*/
|
| 670 |
override fun pickImage(isSuccess: Boolean, data: ByteArray?) {
|
| 671 |
if (!isSuccess) addErrorMessage("Fail to pick image")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 672 |
|
| 673 |
+
viewModel.uploadImageToFirebase(data!!).observe(viewLifecycleOwner) { resource ->
|
| 674 |
+
commonProcessResource(resource) {
|
| 675 |
+
currentSelectedImage = data
|
| 676 |
+
currentUploadedImageName = resource.data
|
| 677 |
+
isImagePicked = true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 678 |
}
|
| 679 |
}
|
| 680 |
}
|
| 681 |
|
| 682 |
+
/**
|
| 683 |
+
* When a user sets an alarm by using alarm widget, this function is called.
|
| 684 |
+
*/
|
| 685 |
override fun setAlarm(hours: Int, minutes: Int, label: String) {
|
| 686 |
addMessage(
|
| 687 |
type = TYPE_CHAT_RECEIVE,
|
|
|
|
| 689 |
)
|
| 690 |
}
|
| 691 |
|
| 692 |
+
/**
|
| 693 |
+
* When a user cancels an alarm by using alarm widget, this function is called.
|
| 694 |
+
*/
|
| 695 |
override fun cancelAlarm() {
|
| 696 |
addMessage(
|
| 697 |
type = TYPE_CHAT_RECEIVE, content = "You canceled setting an alarm."
|
| 698 |
)
|
| 699 |
}
|
| 700 |
+
|
| 701 |
+
/**
|
| 702 |
+
* When a user reads mail by using read mail widget, this function is called.
|
| 703 |
+
*/
|
| 704 |
+
override fun readMail(from: String, password: String, imap_folder: String) {
|
| 705 |
+
viewModel.readMails(from, password, imap_folder)
|
| 706 |
+
.observe(viewLifecycleOwner) { resource ->
|
| 707 |
+
commonProcessResource(resource) {
|
| 708 |
+
val props = MailsProps(resource.data!!)
|
| 709 |
+
val widgetDesc = JsonObject().apply {
|
| 710 |
+
this.addProperty(PROPS_WIDGET_DESC, props.toString())
|
| 711 |
+
}
|
| 712 |
+
addMessage(
|
| 713 |
+
type = TYPE_CHAT_WIDGET,
|
| 714 |
+
content = TYPE_WIDGET_MAILS,
|
| 715 |
+
data = widgetDesc
|
| 716 |
+
)
|
| 717 |
+
}
|
| 718 |
+
}
|
| 719 |
+
}
|
| 720 |
+
|
| 721 |
+
/**
|
| 722 |
+
* When a user sends mail by using compose mail widget, this function is called.
|
| 723 |
+
*/
|
| 724 |
+
override fun sendMail(
|
| 725 |
+
from: String,
|
| 726 |
+
password: String,
|
| 727 |
+
to: String,
|
| 728 |
+
subject: String,
|
| 729 |
+
body: String,
|
| 730 |
+
isInbox: Boolean,
|
| 731 |
+
filename: String,
|
| 732 |
+
fileContent: String
|
| 733 |
+
) {
|
| 734 |
+
|
| 735 |
+
viewModel.sendMail(
|
| 736 |
+
sender = from,
|
| 737 |
+
pwd = password,
|
| 738 |
+
to = to,
|
| 739 |
+
subject = subject,
|
| 740 |
+
body = body,
|
| 741 |
+
to_send = isInbox,
|
| 742 |
+
filename = filename,
|
| 743 |
+
file_content = fileContent
|
| 744 |
+
).observe(viewLifecycleOwner) { resource -> commonProcessResource(resource) {} }
|
| 745 |
+
}
|
| 746 |
+
|
| 747 |
+
override fun readMailInDetail(mail: MailModel) {
|
| 748 |
+
|
| 749 |
+
}
|
| 750 |
}
|
| 751 |
}
|
| 752 |
|
|
|
|
| 757 |
}
|
| 758 |
|
| 759 |
R.id.btn_audio_recognition -> {
|
| 760 |
+
//Here are some codes.
|
| 761 |
}
|
| 762 |
}
|
| 763 |
}
|
| 764 |
|
| 765 |
override fun onResume() {
|
| 766 |
super.onResume()
|
| 767 |
+
|
| 768 |
+
/**
|
| 769 |
+
* when main fragment resumes, search for changed images and contacts in mobile and send the changed data
|
| 770 |
+
* to Brain to train.
|
| 771 |
+
*/
|
| 772 |
+
viewModel.trainContacts()
|
| 773 |
+
.observe(viewLifecycleOwner) { resource -> commonProcessResource(resource) {} }
|
| 774 |
+
viewModel.trainImages()
|
| 775 |
+
.observe(viewLifecycleOwner) { resource -> commonProcessResource(resource) {} }
|
| 776 |
}
|
| 777 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/ChatMessageInterface.kt
CHANGED
|
@@ -1,5 +1,10 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
interface ChatMessageInterface {
|
| 4 |
fun sentSms(phoneNumber: String, message: String)
|
| 5 |
fun canceledSms()
|
|
@@ -9,6 +14,19 @@ interface ChatMessageInterface {
|
|
| 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 |
}
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces
|
| 2 |
|
| 3 |
+
import com.matthaigh27.chatgptwrapper.data.models.chat.MailModel
|
| 4 |
+
|
| 5 |
+
/**
|
| 6 |
+
* This interface is a callback function that retrieves the results of chat widgets.
|
| 7 |
+
*/
|
| 8 |
interface ChatMessageInterface {
|
| 9 |
fun sentSms(phoneNumber: String, message: String)
|
| 10 |
fun canceledSms()
|
|
|
|
| 14 |
fun doVideoCall(phoneNumber: String)
|
| 15 |
fun sendSmsWithPhoneNumber(phoneNumber: String)
|
| 16 |
fun pickImage(isSuccess: Boolean, data: ByteArray? = null)
|
| 17 |
+
fun setAlarm(hours: Int, minutes: Int, label: String)
|
| 18 |
fun cancelAlarm()
|
| 19 |
+
fun readMail(from: String, password: String, imap_folder: String)
|
| 20 |
+
fun sendMail(
|
| 21 |
+
from: String,
|
| 22 |
+
password: String,
|
| 23 |
+
to: String,
|
| 24 |
+
subject: String,
|
| 25 |
+
body: String,
|
| 26 |
+
isInbox: Boolean,
|
| 27 |
+
filename: String,
|
| 28 |
+
fileContent: String
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
fun readMailInDetail(mail: MailModel)
|
| 32 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/OnHideListener.kt
CHANGED
|
@@ -1,5 +1,8 @@
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces
|
| 2 |
|
|
|
|
|
|
|
|
|
|
| 3 |
interface OnHideListener {
|
| 4 |
fun hide()
|
| 5 |
}
|
|
|
|
| 1 |
package com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces
|
| 2 |
|
| 3 |
+
/**
|
| 4 |
+
* This interface is used to retrieve hide event when a user closes chat widgets.
|
| 5 |
+
*/
|
| 6 |
interface OnHideListener {
|
| 7 |
fun hide()
|
| 8 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptKeyEditText.kt
DELETED
|
@@ -1,44 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.helpprompt
|
| 2 |
-
|
| 3 |
-
import android.annotation.SuppressLint
|
| 4 |
-
import android.content.Context
|
| 5 |
-
import android.view.ViewGroup
|
| 6 |
-
import android.widget.EditText
|
| 7 |
-
import android.widget.LinearLayout
|
| 8 |
-
import androidx.annotation.Dimension
|
| 9 |
-
import com.matthaigh27.chatgptwrapper.R
|
| 10 |
-
|
| 11 |
-
@SuppressLint("AppCompatCustomView")
|
| 12 |
-
class HelpPromptKeyEditText(context: Context) : EditText(context) {
|
| 13 |
-
init {
|
| 14 |
-
val layoutParams: LinearLayout.LayoutParams = LinearLayout.LayoutParams(
|
| 15 |
-
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
|
| 16 |
-
)
|
| 17 |
-
val marginBottom =
|
| 18 |
-
context.resources.getDimensionPixelSize(R.dimen.spacing_tiny)
|
| 19 |
-
layoutParams.setMargins(0, 0, 0, marginBottom)
|
| 20 |
-
this.layoutParams = layoutParams
|
| 21 |
-
|
| 22 |
-
minHeight =
|
| 23 |
-
context.resources.getDimensionPixelSize(R.dimen.height_edittext_normal)
|
| 24 |
-
|
| 25 |
-
val paddingStart =
|
| 26 |
-
context.resources.getDimensionPixelSize(R.dimen.spacing_tiny)
|
| 27 |
-
setPadding(paddingStart, 0, 0, 0)
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
setTextSize(
|
| 31 |
-
Dimension.DP,
|
| 32 |
-
context.resources.getDimensionPixelSize(R.dimen.font_normal)
|
| 33 |
-
.toFloat()
|
| 34 |
-
)
|
| 35 |
-
setTextColor(context.getColor(R.color.color_accent))
|
| 36 |
-
setHintTextColor(context.getColor(R.color.color_primary_dark))
|
| 37 |
-
background = context.getDrawable(R.drawable.bg_edittext_radius_small)
|
| 38 |
-
}
|
| 39 |
-
|
| 40 |
-
fun initView(keyName: String) {
|
| 41 |
-
hint = keyName
|
| 42 |
-
tag = keyName
|
| 43 |
-
}
|
| 44 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptKeyItem.kt
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.helpprompt
|
| 2 |
+
|
| 3 |
+
import android.annotation.SuppressLint
|
| 4 |
+
import android.content.Context
|
| 5 |
+
import android.view.LayoutInflater
|
| 6 |
+
import android.widget.FrameLayout
|
| 7 |
+
import com.google.android.material.textfield.TextInputLayout
|
| 8 |
+
import com.matthaigh27.chatgptwrapper.R
|
| 9 |
+
|
| 10 |
+
@SuppressLint("AppCompatCustomView")
|
| 11 |
+
class HelpPromptKeyItem(context: Context) : FrameLayout(context) {
|
| 12 |
+
|
| 13 |
+
private val edtKey: TextInputLayout
|
| 14 |
+
|
| 15 |
+
init {
|
| 16 |
+
LayoutInflater.from(context).inflate(R.layout.item_help_prompt_key, this, true)
|
| 17 |
+
|
| 18 |
+
edtKey = findViewById(R.id.edt_key)
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
fun initView(keyName: String) {
|
| 22 |
+
if(keyName.isNotEmpty())
|
| 23 |
+
edtKey.hint = keyName.subSequence(1, keyName.length)
|
| 24 |
+
tag = keyName
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
fun getText(): String {
|
| 28 |
+
return edtKey.editText?.text.toString()
|
| 29 |
+
}
|
| 30 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/helpprompt/HelpPromptWidget.kt
CHANGED
|
@@ -6,6 +6,7 @@ import android.view.View
|
|
| 6 |
import android.view.ViewGroup
|
| 7 |
import android.widget.Button
|
| 8 |
import android.widget.EditText
|
|
|
|
| 9 |
import android.widget.LinearLayout
|
| 10 |
import android.widget.TextView
|
| 11 |
import androidx.constraintlayout.widget.ConstraintLayout
|
|
@@ -19,7 +20,7 @@ class HelpPromptWidget(context: Context, model: HelpPromptModel) : ConstraintLay
|
|
| 19 |
private lateinit var llPromptKeys: LinearLayout
|
| 20 |
private lateinit var txtKeysTitle: TextView
|
| 21 |
|
| 22 |
-
private var promptEditTextList: ArrayList<
|
| 23 |
private val promptModel: HelpPromptModel
|
| 24 |
var callback: ChatMessageInterface? = null
|
| 25 |
var hideListener: OnHideListener? = null
|
|
@@ -41,8 +42,8 @@ class HelpPromptWidget(context: Context, model: HelpPromptModel) : ConstraintLay
|
|
| 41 |
txtKeysTitle = findViewById(R.id.txt_keys_title)
|
| 42 |
txtKeysTitle.text = promptModel.name
|
| 43 |
|
| 44 |
-
findViewById<
|
| 45 |
-
findViewById<
|
| 46 |
|
| 47 |
initPromptList()
|
| 48 |
|
|
@@ -54,7 +55,7 @@ class HelpPromptWidget(context: Context, model: HelpPromptModel) : ConstraintLay
|
|
| 54 |
promptEditTextList = ArrayList()
|
| 55 |
|
| 56 |
for (i in 0 until promptModel.tags.size) {
|
| 57 |
-
val edtKey =
|
| 58 |
edtKey.initView(promptModel.tags[i])
|
| 59 |
llPromptKeys.addView(edtKey)
|
| 60 |
promptEditTextList?.add(edtKey)
|
|
@@ -78,7 +79,7 @@ class HelpPromptWidget(context: Context, model: HelpPromptModel) : ConstraintLay
|
|
| 78 |
var promptTemplate = promptModel.prompt
|
| 79 |
if(promptModel.tags.size > 0) {
|
| 80 |
promptEditTextList?.forEach { edtKeyPrompt ->
|
| 81 |
-
val prompt = edtKeyPrompt.
|
| 82 |
if(prompt.isEmpty()) return
|
| 83 |
promptTemplate = promptTemplate.replace(edtKeyPrompt.tag.toString(), prompt)
|
| 84 |
}
|
|
|
|
| 6 |
import android.view.ViewGroup
|
| 7 |
import android.widget.Button
|
| 8 |
import android.widget.EditText
|
| 9 |
+
import android.widget.ImageView
|
| 10 |
import android.widget.LinearLayout
|
| 11 |
import android.widget.TextView
|
| 12 |
import androidx.constraintlayout.widget.ConstraintLayout
|
|
|
|
| 20 |
private lateinit var llPromptKeys: LinearLayout
|
| 21 |
private lateinit var txtKeysTitle: TextView
|
| 22 |
|
| 23 |
+
private var promptEditTextList: ArrayList<HelpPromptKeyItem>? = null
|
| 24 |
private val promptModel: HelpPromptModel
|
| 25 |
var callback: ChatMessageInterface? = null
|
| 26 |
var hideListener: OnHideListener? = null
|
|
|
|
| 42 |
txtKeysTitle = findViewById(R.id.txt_keys_title)
|
| 43 |
txtKeysTitle.text = promptModel.name
|
| 44 |
|
| 45 |
+
findViewById<ImageView>(R.id.btn_ok).setOnClickListener(this)
|
| 46 |
+
findViewById<ImageView>(R.id.btn_cancel).setOnClickListener(this)
|
| 47 |
|
| 48 |
initPromptList()
|
| 49 |
|
|
|
|
| 55 |
promptEditTextList = ArrayList()
|
| 56 |
|
| 57 |
for (i in 0 until promptModel.tags.size) {
|
| 58 |
+
val edtKey = HelpPromptKeyItem(context)
|
| 59 |
edtKey.initView(promptModel.tags[i])
|
| 60 |
llPromptKeys.addView(edtKey)
|
| 61 |
promptEditTextList?.add(edtKey)
|
|
|
|
| 79 |
var promptTemplate = promptModel.prompt
|
| 80 |
if(promptModel.tags.size > 0) {
|
| 81 |
promptEditTextList?.forEach { edtKeyPrompt ->
|
| 82 |
+
val prompt = edtKeyPrompt.getText()
|
| 83 |
if(prompt.isEmpty()) return
|
| 84 |
promptTemplate = promptTemplate.replace(edtKeyPrompt.tag.toString(), prompt)
|
| 85 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/mail/{compose/ComposeMailWidget.kt → ComposeMailWidget.kt}
RENAMED
|
@@ -1,18 +1,23 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.mail
|
| 2 |
|
| 3 |
import android.content.Context
|
|
|
|
| 4 |
import android.util.AttributeSet
|
| 5 |
import android.view.KeyEvent
|
| 6 |
import android.view.LayoutInflater
|
| 7 |
import android.view.View
|
| 8 |
import android.view.ViewGroup
|
| 9 |
import android.widget.ImageView
|
|
|
|
| 10 |
import androidx.constraintlayout.widget.ConstraintLayout
|
|
|
|
| 11 |
import com.google.android.material.chip.Chip
|
| 12 |
import com.google.android.material.chip.ChipGroup
|
|
|
|
| 13 |
import com.google.android.material.textfield.TextInputLayout
|
| 14 |
import com.matthaigh27.chatgptwrapper.R
|
| 15 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
|
|
|
|
| 16 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.MailHelper.isGmail
|
| 17 |
|
| 18 |
class ComposeMailWidget(
|
|
@@ -22,12 +27,19 @@ class ComposeMailWidget(
|
|
| 22 |
private var context: Context
|
| 23 |
var callback: ChatMessageInterface? = null
|
| 24 |
|
|
|
|
|
|
|
|
|
|
| 25 |
private var edtMailTo: TextInputLayout
|
| 26 |
private var edtMailSubject: TextInputLayout
|
| 27 |
private var edtMailContent: TextInputLayout
|
| 28 |
private var mailChipGroup: ChipGroup
|
| 29 |
private var attachmentChipGroup: ChipGroup
|
| 30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
init {
|
| 32 |
LayoutInflater.from(context).inflate(R.layout.widget_mail_compose, this, true)
|
| 33 |
this.context = context
|
|
@@ -40,7 +52,6 @@ class ComposeMailWidget(
|
|
| 40 |
this.setOnClickListener(this)
|
| 41 |
findViewById<ImageView>(R.id.btn_send).setOnClickListener(this)
|
| 42 |
findViewById<ImageView>(R.id.btn_send_cancel).setOnClickListener(this)
|
| 43 |
-
findViewById<ImageView>(R.id.btn_draft).setOnClickListener(this)
|
| 44 |
findViewById<ImageView>(R.id.btn_attachment).setOnClickListener(this)
|
| 45 |
|
| 46 |
mailChipGroup = findViewById(R.id.mail_chip_group)
|
|
@@ -48,6 +59,9 @@ class ComposeMailWidget(
|
|
| 48 |
edtMailTo = findViewById(R.id.edt_mail_to)
|
| 49 |
edtMailSubject = findViewById(R.id.edt_mail_subject)
|
| 50 |
edtMailContent = findViewById(R.id.edt_mail_content)
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
edtMailTo.editText?.setOnKeyListener(View.OnKeyListener { _, keyCode, event ->
|
| 53 |
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) {
|
|
@@ -76,6 +90,64 @@ class ComposeMailWidget(
|
|
| 76 |
}
|
| 77 |
|
| 78 |
override fun onClick(view: View?) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
}
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.mail
|
| 2 |
|
| 3 |
import android.content.Context
|
| 4 |
+
import android.content.Intent
|
| 5 |
import android.util.AttributeSet
|
| 6 |
import android.view.KeyEvent
|
| 7 |
import android.view.LayoutInflater
|
| 8 |
import android.view.View
|
| 9 |
import android.view.ViewGroup
|
| 10 |
import android.widget.ImageView
|
| 11 |
+
import androidx.appcompat.app.AlertDialog
|
| 12 |
import androidx.constraintlayout.widget.ConstraintLayout
|
| 13 |
+
import androidx.core.app.ActivityCompat.startActivityForResult
|
| 14 |
import com.google.android.material.chip.Chip
|
| 15 |
import com.google.android.material.chip.ChipGroup
|
| 16 |
+
import com.google.android.material.switchmaterial.SwitchMaterial
|
| 17 |
import com.google.android.material.textfield.TextInputLayout
|
| 18 |
import com.matthaigh27.chatgptwrapper.R
|
| 19 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
|
| 20 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.OnHideListener
|
| 21 |
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.MailHelper.isGmail
|
| 22 |
|
| 23 |
class ComposeMailWidget(
|
|
|
|
| 27 |
private var context: Context
|
| 28 |
var callback: ChatMessageInterface? = null
|
| 29 |
|
| 30 |
+
private var edtMailFrom: TextInputLayout
|
| 31 |
+
private var edtMailPassword: TextInputLayout
|
| 32 |
+
private var swhMailType: SwitchMaterial
|
| 33 |
private var edtMailTo: TextInputLayout
|
| 34 |
private var edtMailSubject: TextInputLayout
|
| 35 |
private var edtMailContent: TextInputLayout
|
| 36 |
private var mailChipGroup: ChipGroup
|
| 37 |
private var attachmentChipGroup: ChipGroup
|
| 38 |
|
| 39 |
+
var hideListener: OnHideListener? = null
|
| 40 |
+
|
| 41 |
+
// private val REQUEST_CODE_LOCAL_STORAGE = 1
|
| 42 |
+
|
| 43 |
init {
|
| 44 |
LayoutInflater.from(context).inflate(R.layout.widget_mail_compose, this, true)
|
| 45 |
this.context = context
|
|
|
|
| 52 |
this.setOnClickListener(this)
|
| 53 |
findViewById<ImageView>(R.id.btn_send).setOnClickListener(this)
|
| 54 |
findViewById<ImageView>(R.id.btn_send_cancel).setOnClickListener(this)
|
|
|
|
| 55 |
findViewById<ImageView>(R.id.btn_attachment).setOnClickListener(this)
|
| 56 |
|
| 57 |
mailChipGroup = findViewById(R.id.mail_chip_group)
|
|
|
|
| 59 |
edtMailTo = findViewById(R.id.edt_mail_to)
|
| 60 |
edtMailSubject = findViewById(R.id.edt_mail_subject)
|
| 61 |
edtMailContent = findViewById(R.id.edt_mail_content)
|
| 62 |
+
edtMailFrom = findViewById(R.id.edt_mail_from)
|
| 63 |
+
edtMailPassword = findViewById(R.id.edt_mail_password)
|
| 64 |
+
swhMailType = findViewById(R.id.swh_mail_type)
|
| 65 |
|
| 66 |
edtMailTo.editText?.setOnKeyListener(View.OnKeyListener { _, keyCode, event ->
|
| 67 |
if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) {
|
|
|
|
| 90 |
}
|
| 91 |
|
| 92 |
override fun onClick(view: View?) {
|
| 93 |
+
when (view?.id) {
|
| 94 |
+
R.id.btn_send -> {
|
| 95 |
+
callback?.sendMail(
|
| 96 |
+
from = edtMailFrom.editText?.text.toString(),
|
| 97 |
+
password = edtMailFrom.editText?.text.toString(),
|
| 98 |
+
to = edtMailTo.editText?.text.toString(),
|
| 99 |
+
subject = edtMailSubject.editText?.text.toString(),
|
| 100 |
+
body = edtMailContent.editText?.text.toString(),
|
| 101 |
+
isInbox = swhMailType.isChecked,
|
| 102 |
+
filename = "",
|
| 103 |
+
fileContent = "",
|
| 104 |
+
)
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
R.id.btn_cancel -> {
|
| 108 |
+
hideListener?.hide()
|
| 109 |
+
}
|
| 110 |
|
| 111 |
+
R.id.btn_attachment -> {
|
| 112 |
+
// val choice = arrayOf("Local Storage", "Google Drive")
|
| 113 |
+
// val builder = AlertDialog.Builder(context)
|
| 114 |
+
// builder.setItems(choice) { dialog, which ->
|
| 115 |
+
// when (which) {
|
| 116 |
+
// 0 -> selectFileFromLocalStorage()
|
| 117 |
+
// 1 -> selectFileFromGoogleDrive()
|
| 118 |
+
// }
|
| 119 |
+
// }
|
| 120 |
+
// builder.show()
|
| 121 |
+
}
|
| 122 |
+
}
|
| 123 |
}
|
| 124 |
+
|
| 125 |
+
// fun selectFileFromLocalStorage() {
|
| 126 |
+
// val intent = Intent(Intent.ACTION_GET_CONTENT)
|
| 127 |
+
// intent.type = "*/*"
|
| 128 |
+
// startActivityForResult(intent, REQUEST_CODE_LOCAL_STORAGE)
|
| 129 |
+
// }
|
| 130 |
+
//
|
| 131 |
+
// fun selectFileFromGoogleDrive() {
|
| 132 |
+
// val intent = driveClient.newOpenFileActivityIntentBuilder()
|
| 133 |
+
// .setMimeType(new String[] {"text/plain"})
|
| 134 |
+
// .build();
|
| 135 |
+
// startActivityForResult(intent, REQUEST_CODE_GOOGLE_DRIVE);
|
| 136 |
+
// }
|
| 137 |
+
//
|
| 138 |
+
// override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
| 139 |
+
// super.onActivityResult(requestCode, resultCode, data)
|
| 140 |
+
// if (requestCode == REQUEST_CODE_LOCAL_STORAGE && resultCode == Activity.RESULT_OK && data != null) {
|
| 141 |
+
// fileName = data.data
|
| 142 |
+
// }
|
| 143 |
+
// }
|
| 144 |
+
//
|
| 145 |
+
// override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
| 146 |
+
// super.onActivityResult(requestCode, resultCode, data)
|
| 147 |
+
// // handle onActivityResult for local storage
|
| 148 |
+
// if (requestCode == REQUEST_CODE_GOOGLE_DRIVE && resultCode == Activity.RESULT_OK && data != null) {
|
| 149 |
+
// val driveId = data.getParcelableExtra<DriveId>(OpenFileActivityOptions.EXTRA_RESPONSE_DRIVE_ID);
|
| 150 |
+
// // use this driveId to handle file
|
| 151 |
+
// }
|
| 152 |
+
// }
|
| 153 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/mail/MailWidget.kt
CHANGED
|
@@ -5,31 +5,42 @@ import android.util.AttributeSet
|
|
| 5 |
import android.view.LayoutInflater
|
| 6 |
import android.view.View
|
| 7 |
import android.view.ViewGroup
|
|
|
|
| 8 |
import androidx.constraintlayout.widget.ConstraintLayout
|
| 9 |
import com.matthaigh27.chatgptwrapper.R
|
|
|
|
| 10 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
|
| 11 |
|
| 12 |
|
| 13 |
class MailWidget(
|
| 14 |
-
context: Context, attrs: AttributeSet? = null
|
| 15 |
) : ConstraintLayout(context, attrs), View.OnClickListener {
|
| 16 |
|
| 17 |
-
private var context: Context
|
| 18 |
var callback: ChatMessageInterface? = null
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
init {
|
| 21 |
LayoutInflater.from(context).inflate(R.layout.widget_mail, this, true)
|
| 22 |
-
this.context = context
|
| 23 |
|
| 24 |
layoutParams = LayoutParams(
|
| 25 |
-
ViewGroup.LayoutParams.WRAP_CONTENT,
|
| 26 |
-
ViewGroup.LayoutParams.WRAP_CONTENT
|
| 27 |
)
|
| 28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
this.setOnClickListener(this)
|
| 30 |
}
|
| 31 |
|
| 32 |
override fun onClick(view: View?) {
|
| 33 |
-
|
| 34 |
}
|
| 35 |
}
|
|
|
|
| 5 |
import android.view.LayoutInflater
|
| 6 |
import android.view.View
|
| 7 |
import android.view.ViewGroup
|
| 8 |
+
import android.widget.TextView
|
| 9 |
import androidx.constraintlayout.widget.ConstraintLayout
|
| 10 |
import com.matthaigh27.chatgptwrapper.R
|
| 11 |
+
import com.matthaigh27.chatgptwrapper.data.models.chat.MailModel
|
| 12 |
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
|
| 13 |
|
| 14 |
|
| 15 |
class MailWidget(
|
| 16 |
+
private val context: Context, private val mail: MailModel, attrs: AttributeSet? = null
|
| 17 |
) : ConstraintLayout(context, attrs), View.OnClickListener {
|
| 18 |
|
|
|
|
| 19 |
var callback: ChatMessageInterface? = null
|
| 20 |
|
| 21 |
+
private val txtTitle:TextView
|
| 22 |
+
private val txtContent: TextView
|
| 23 |
+
private val txtDate: TextView
|
| 24 |
+
|
| 25 |
init {
|
| 26 |
LayoutInflater.from(context).inflate(R.layout.widget_mail, this, true)
|
|
|
|
| 27 |
|
| 28 |
layoutParams = LayoutParams(
|
| 29 |
+
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT
|
|
|
|
| 30 |
)
|
| 31 |
|
| 32 |
+
txtTitle = findViewById(R.id.txt_title)
|
| 33 |
+
txtContent = findViewById(R.id.txt_content)
|
| 34 |
+
txtDate = findViewById(R.id.txt_date)
|
| 35 |
+
|
| 36 |
+
txtTitle.text = mail.subject
|
| 37 |
+
txtContent.text = mail.body
|
| 38 |
+
txtDate.text = mail.date
|
| 39 |
+
|
| 40 |
this.setOnClickListener(this)
|
| 41 |
}
|
| 42 |
|
| 43 |
override fun onClick(view: View?) {
|
| 44 |
+
callback?.readMailInDetail(mail)
|
| 45 |
}
|
| 46 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/mail/ReadMailWidget.kt
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.mail
|
| 2 |
+
|
| 3 |
+
import android.content.Context
|
| 4 |
+
import android.util.AttributeSet
|
| 5 |
+
import android.view.LayoutInflater
|
| 6 |
+
import android.view.View
|
| 7 |
+
import android.view.ViewGroup
|
| 8 |
+
import android.widget.ImageView
|
| 9 |
+
import androidx.constraintlayout.widget.ConstraintLayout
|
| 10 |
+
import com.google.android.material.switchmaterial.SwitchMaterial
|
| 11 |
+
import com.google.android.material.textfield.TextInputLayout
|
| 12 |
+
import com.matthaigh27.chatgptwrapper.R
|
| 13 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
|
| 14 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.OnHideListener
|
| 15 |
+
|
| 16 |
+
class ReadMailWidget(
|
| 17 |
+
context: Context, attrs: AttributeSet? = null
|
| 18 |
+
) : ConstraintLayout(context, attrs), View.OnClickListener {
|
| 19 |
+
|
| 20 |
+
private var context: Context
|
| 21 |
+
var callback: ChatMessageInterface? = null
|
| 22 |
+
|
| 23 |
+
private var edtMailFrom: TextInputLayout
|
| 24 |
+
private var edtMailPassword: TextInputLayout
|
| 25 |
+
private var swhMailType: SwitchMaterial
|
| 26 |
+
|
| 27 |
+
var hideListener: OnHideListener? = null
|
| 28 |
+
|
| 29 |
+
init {
|
| 30 |
+
LayoutInflater.from(context).inflate(R.layout.widget_mail_read, this, true)
|
| 31 |
+
this.context = context
|
| 32 |
+
|
| 33 |
+
layoutParams = LayoutParams(
|
| 34 |
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
| 35 |
+
ViewGroup.LayoutParams.WRAP_CONTENT
|
| 36 |
+
)
|
| 37 |
+
|
| 38 |
+
this.setOnClickListener(this)
|
| 39 |
+
findViewById<ImageView>(R.id.btn_send).setOnClickListener(this)
|
| 40 |
+
findViewById<ImageView>(R.id.btn_send_cancel).setOnClickListener(this)
|
| 41 |
+
|
| 42 |
+
edtMailFrom = findViewById(R.id.edt_mail_from)
|
| 43 |
+
edtMailPassword = findViewById(R.id.edt_mail_password)
|
| 44 |
+
swhMailType = findViewById(R.id.swh_mail_type)
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
override fun onClick(view: View?) {
|
| 48 |
+
when (view?.id) {
|
| 49 |
+
R.id.btn_send -> {
|
| 50 |
+
val from = edtMailFrom.editText?.text.toString()
|
| 51 |
+
val password = edtMailPassword.editText?.text.toString()
|
| 52 |
+
if(from == "" || password == "") return
|
| 53 |
+
val imapFolder = if (swhMailType.isChecked) "inbox" else "draft"
|
| 54 |
+
callback?.readMail(
|
| 55 |
+
from = edtMailFrom.editText?.text.toString(),
|
| 56 |
+
password = edtMailPassword.editText?.text.toString(),
|
| 57 |
+
imap_folder = imapFolder
|
| 58 |
+
)
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
R.id.btn_cancel -> {
|
| 62 |
+
hideListener?.hide()
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
hideListener?.hide()
|
| 66 |
+
}
|
| 67 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/viewmodel/ChatViewModel.kt
CHANGED
|
@@ -13,9 +13,14 @@ import com.matthaigh27.chatgptwrapper.RisingApplication.Companion.appContext
|
|
| 13 |
import com.matthaigh27.chatgptwrapper.data.local.entity.ImageEntity
|
| 14 |
import com.matthaigh27.chatgptwrapper.data.models.chat.AutoTaskModel
|
| 15 |
import com.matthaigh27.chatgptwrapper.data.models.chat.ImageRelatenessModel
|
|
|
|
| 16 |
import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
|
|
|
|
|
|
|
| 17 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.ImageRelatednessApiRequest
|
| 18 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
|
|
|
|
|
|
|
| 19 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainContactsApiRequest
|
| 20 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainImageApiRequest
|
| 21 |
import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
|
|
@@ -40,6 +45,9 @@ import kotlinx.coroutines.withContext
|
|
| 40 |
|
| 41 |
class ChatViewModel : ViewModel() {
|
| 42 |
|
|
|
|
|
|
|
|
|
|
| 43 |
fun getAllHelpCommands(): MutableLiveData<ApiResource<ApiResponse<HelpCommandResult>>> {
|
| 44 |
val resource: MutableLiveData<ApiResource<ApiResponse<HelpCommandResult>>> =
|
| 45 |
MutableLiveData()
|
|
@@ -54,6 +62,9 @@ class ChatViewModel : ViewModel() {
|
|
| 54 |
return resource
|
| 55 |
}
|
| 56 |
|
|
|
|
|
|
|
|
|
|
| 57 |
fun sendNotification(message: String): MutableLiveData<ApiResource<ApiResponse<CommonResult>>> {
|
| 58 |
val request = NotificationApiRequest(
|
| 59 |
message = message, confs = RemoteRepository.getKeys()
|
|
@@ -71,6 +82,11 @@ class ChatViewModel : ViewModel() {
|
|
| 71 |
return resource
|
| 72 |
}
|
| 73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
fun downloadImageFromFirebase(name: String): MutableLiveData<ApiResource<ByteArray>> {
|
| 75 |
val resource: MutableLiveData<ApiResource<ByteArray>> = MutableLiveData()
|
| 76 |
resource.value = ApiResource.Loading()
|
|
@@ -84,6 +100,12 @@ class ChatViewModel : ViewModel() {
|
|
| 84 |
return resource
|
| 85 |
}
|
| 86 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
fun uploadImageToFirebase(imageByteArray: ByteArray): MutableLiveData<ApiResource<String>> {
|
| 88 |
val resource: MutableLiveData<ApiResource<String>> = MutableLiveData()
|
| 89 |
resource.value = ApiResource.Loading()
|
|
@@ -97,11 +119,22 @@ class ChatViewModel : ViewModel() {
|
|
| 97 |
return resource
|
| 98 |
}
|
| 99 |
|
|
|
|
|
|
|
|
|
|
| 100 |
fun trainImages(): MutableLiveData<ApiResource<Int>> {
|
| 101 |
val state: MutableLiveData<ApiResource<Int>> = MutableLiveData()
|
| 102 |
state.value = ApiResource.Loading()
|
| 103 |
CoroutineScope(Dispatchers.IO).launch {
|
|
|
|
|
|
|
|
|
|
| 104 |
val images = getImagesFromExternalStorage(appContext.contentResolver)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
val originalImages = RoomRepository.getAllImages().value
|
| 106 |
|
| 107 |
val existImageStatus = BooleanArray(originalImages!!.size) { false }
|
|
@@ -113,6 +146,10 @@ class ChatViewModel : ViewModel() {
|
|
| 113 |
for (i in originalImages.indices) {
|
| 114 |
val entity: ImageEntity = originalImages[i]
|
| 115 |
if (entity.path == path) {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
if (entity.dataModified != image.modifiedDate) {
|
| 117 |
val byteArray = getBytesFromPath(path)
|
| 118 |
val task = async {
|
|
@@ -136,10 +173,18 @@ class ChatViewModel : ViewModel() {
|
|
| 136 |
tasks.add(task)
|
| 137 |
}
|
| 138 |
isExist = true
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
existImageStatus[i] = true
|
| 140 |
break
|
| 141 |
}
|
| 142 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
if (!isExist) {
|
| 144 |
path?.let {
|
| 145 |
val byteArray = getBytesFromPath(it)
|
|
@@ -166,6 +211,9 @@ class ChatViewModel : ViewModel() {
|
|
| 166 |
}
|
| 167 |
}
|
| 168 |
|
|
|
|
|
|
|
|
|
|
| 169 |
for (i in existImageStatus.indices) {
|
| 170 |
if (!existImageStatus[i]) {
|
| 171 |
val task = async {
|
|
@@ -185,7 +233,6 @@ class ChatViewModel : ViewModel() {
|
|
| 185 |
}
|
| 186 |
|
| 187 |
tasks.awaitAll()
|
| 188 |
-
Log.d("Brain", "Finish")
|
| 189 |
withContext(Dispatchers.Main) {
|
| 190 |
state.value = ApiResource.Success(0)
|
| 191 |
}
|
|
@@ -193,13 +240,28 @@ class ChatViewModel : ViewModel() {
|
|
| 193 |
return state
|
| 194 |
}
|
| 195 |
|
|
|
|
|
|
|
|
|
|
| 196 |
fun trainContacts(): MutableLiveData<ApiResource<ApiResponse<String>>> {
|
| 197 |
val state: MutableLiveData<ApiResource<ApiResponse<String>>> = MutableLiveData()
|
| 198 |
state.value = ApiResource.Loading()
|
|
|
|
|
|
|
|
|
|
| 199 |
val contacts = getContacts(appContext)
|
| 200 |
CoroutineScope(Dispatchers.Main).launch {
|
| 201 |
val resource: MutableLiveData<Boolean> = MutableLiveData()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
val changedContacts = getChangedContacts(contacts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
val request = TrainContactsApiRequest(changedContacts, RemoteRepository.getKeys())
|
| 204 |
withContext(Dispatchers.Main) {
|
| 205 |
RemoteRepository.trainContacts(request, onSuccess = { apiResponse ->
|
|
@@ -212,6 +274,9 @@ class ChatViewModel : ViewModel() {
|
|
| 212 |
return state
|
| 213 |
}
|
| 214 |
|
|
|
|
|
|
|
|
|
|
| 215 |
fun getImageRelatedness(
|
| 216 |
imageName: String,
|
| 217 |
message: String
|
|
@@ -223,16 +288,23 @@ class ChatViewModel : ViewModel() {
|
|
| 223 |
)
|
| 224 |
resource.value = ApiResource.Loading()
|
| 225 |
|
|
|
|
|
|
|
|
|
|
| 226 |
RemoteRepository.getImageRelatedness(request, onSuccess = { apiResponse ->
|
| 227 |
val resultImageName = apiResponse.result.content.image_name
|
| 228 |
val resultImageDesc = apiResponse.result.content.image_desc
|
| 229 |
|
|
|
|
|
|
|
|
|
|
| 230 |
FirebaseRepository.downloadImageWithName(
|
| 231 |
name = resultImageName,
|
| 232 |
onSuccess = { response ->
|
| 233 |
resource.value =
|
| 234 |
ApiResource.Success(ImageRelatenessModel(response, resultImageDesc))
|
| 235 |
-
},
|
|
|
|
| 236 |
resource.value = ApiResource.Error(throwable)
|
| 237 |
}
|
| 238 |
)
|
|
@@ -243,6 +315,74 @@ class ChatViewModel : ViewModel() {
|
|
| 243 |
return resource
|
| 244 |
}
|
| 245 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
/**
|
| 247 |
* This function is used to retrieve real-time data for the auto task.
|
| 248 |
* Whenever data in the Firebase real-time database changes,
|
|
@@ -260,7 +400,7 @@ class ChatViewModel : ViewModel() {
|
|
| 260 |
val data = snapshot.getValue<AutoTaskModel>()
|
| 261 |
data?.let {
|
| 262 |
data.command?.let { command ->
|
| 263 |
-
if(command.name == "finish") {
|
| 264 |
resource.value = ApiResource.Success(data)
|
| 265 |
} else {
|
| 266 |
resource.value = ApiResource.Loading(data)
|
|
@@ -285,7 +425,7 @@ class ChatViewModel : ViewModel() {
|
|
| 285 |
val data = snapshot.getValue<AutoTaskModel>()
|
| 286 |
data?.let {
|
| 287 |
data.command?.let { command ->
|
| 288 |
-
if(command.name == "finish") {
|
| 289 |
resource.value = ApiResource.Success(data)
|
| 290 |
} else {
|
| 291 |
resource.value = ApiResource.Loading(data)
|
|
|
|
| 13 |
import com.matthaigh27.chatgptwrapper.data.local.entity.ImageEntity
|
| 14 |
import com.matthaigh27.chatgptwrapper.data.models.chat.AutoTaskModel
|
| 15 |
import com.matthaigh27.chatgptwrapper.data.models.chat.ImageRelatenessModel
|
| 16 |
+
import com.matthaigh27.chatgptwrapper.data.models.chat.MailModel
|
| 17 |
import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
|
| 18 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.ComposeMailApiRequest
|
| 19 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.ComposeMailData
|
| 20 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.ImageRelatednessApiRequest
|
| 21 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
|
| 22 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.ReadMailApiRequest
|
| 23 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.ReadMailData
|
| 24 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainContactsApiRequest
|
| 25 |
import com.matthaigh27.chatgptwrapper.data.remote.requests.TrainImageApiRequest
|
| 26 |
import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
|
|
|
|
| 45 |
|
| 46 |
class ChatViewModel : ViewModel() {
|
| 47 |
|
| 48 |
+
/**
|
| 49 |
+
* This function is used to fetch all help commands from Brain.
|
| 50 |
+
*/
|
| 51 |
fun getAllHelpCommands(): MutableLiveData<ApiResource<ApiResponse<HelpCommandResult>>> {
|
| 52 |
val resource: MutableLiveData<ApiResource<ApiResponse<HelpCommandResult>>> =
|
| 53 |
MutableLiveData()
|
|
|
|
| 62 |
return resource
|
| 63 |
}
|
| 64 |
|
| 65 |
+
/**
|
| 66 |
+
* This function is used to send user's message to Brain to analyze the user's query.
|
| 67 |
+
*/
|
| 68 |
fun sendNotification(message: String): MutableLiveData<ApiResource<ApiResponse<CommonResult>>> {
|
| 69 |
val request = NotificationApiRequest(
|
| 70 |
message = message, confs = RemoteRepository.getKeys()
|
|
|
|
| 82 |
return resource
|
| 83 |
}
|
| 84 |
|
| 85 |
+
/**
|
| 86 |
+
* This function is used to download image from Firebase Storage.
|
| 87 |
+
*
|
| 88 |
+
* @param name An image name that is stored in Firebase storage
|
| 89 |
+
*/
|
| 90 |
fun downloadImageFromFirebase(name: String): MutableLiveData<ApiResource<ByteArray>> {
|
| 91 |
val resource: MutableLiveData<ApiResource<ByteArray>> = MutableLiveData()
|
| 92 |
resource.value = ApiResource.Loading()
|
|
|
|
| 100 |
return resource
|
| 101 |
}
|
| 102 |
|
| 103 |
+
/**
|
| 104 |
+
* This function is used to upload image to Firebase storage and return uuid of uploaded image name.
|
| 105 |
+
*
|
| 106 |
+
* @param imageByteArray A bytearray of image to upload
|
| 107 |
+
* @return A uuid that is generated to keep unique when the image is uploaded.
|
| 108 |
+
*/
|
| 109 |
fun uploadImageToFirebase(imageByteArray: ByteArray): MutableLiveData<ApiResource<String>> {
|
| 110 |
val resource: MutableLiveData<ApiResource<String>> = MutableLiveData()
|
| 111 |
resource.value = ApiResource.Loading()
|
|
|
|
| 119 |
return resource
|
| 120 |
}
|
| 121 |
|
| 122 |
+
/**
|
| 123 |
+
* This function is used to train changed images in user's mobile local storage.
|
| 124 |
+
*/
|
| 125 |
fun trainImages(): MutableLiveData<ApiResource<Int>> {
|
| 126 |
val state: MutableLiveData<ApiResource<Int>> = MutableLiveData()
|
| 127 |
state.value = ApiResource.Loading()
|
| 128 |
CoroutineScope(Dispatchers.IO).launch {
|
| 129 |
+
/**
|
| 130 |
+
* Get images from external storage
|
| 131 |
+
*/
|
| 132 |
val images = getImagesFromExternalStorage(appContext.contentResolver)
|
| 133 |
+
|
| 134 |
+
/**
|
| 135 |
+
* Get images from room database, in which previous images are stores so we can find changed
|
| 136 |
+
* images by comparing the two image array data.
|
| 137 |
+
*/
|
| 138 |
val originalImages = RoomRepository.getAllImages().value
|
| 139 |
|
| 140 |
val existImageStatus = BooleanArray(originalImages!!.size) { false }
|
|
|
|
| 146 |
for (i in originalImages.indices) {
|
| 147 |
val entity: ImageEntity = originalImages[i]
|
| 148 |
if (entity.path == path) {
|
| 149 |
+
/**
|
| 150 |
+
* If path of images is same and modified date of images is different,
|
| 151 |
+
* update the image in Room database and send update request to Brain.
|
| 152 |
+
*/
|
| 153 |
if (entity.dataModified != image.modifiedDate) {
|
| 154 |
val byteArray = getBytesFromPath(path)
|
| 155 |
val task = async {
|
|
|
|
| 173 |
tasks.add(task)
|
| 174 |
}
|
| 175 |
isExist = true
|
| 176 |
+
/**
|
| 177 |
+
* Indexes of existed images are stored in below BooleanArray variable so that
|
| 178 |
+
* after this loop, it is possible to search for new images that created in local storage.
|
| 179 |
+
*/
|
| 180 |
existImageStatus[i] = true
|
| 181 |
break
|
| 182 |
}
|
| 183 |
}
|
| 184 |
+
|
| 185 |
+
/**
|
| 186 |
+
* New images are inserted into Room database and send create request to Brain.
|
| 187 |
+
*/
|
| 188 |
if (!isExist) {
|
| 189 |
path?.let {
|
| 190 |
val byteArray = getBytesFromPath(it)
|
|
|
|
| 211 |
}
|
| 212 |
}
|
| 213 |
|
| 214 |
+
/**
|
| 215 |
+
* Images that doesn't exist in existImageStatus BooleanArray are deleted from database.
|
| 216 |
+
*/
|
| 217 |
for (i in existImageStatus.indices) {
|
| 218 |
if (!existImageStatus[i]) {
|
| 219 |
val task = async {
|
|
|
|
| 233 |
}
|
| 234 |
|
| 235 |
tasks.awaitAll()
|
|
|
|
| 236 |
withContext(Dispatchers.Main) {
|
| 237 |
state.value = ApiResource.Success(0)
|
| 238 |
}
|
|
|
|
| 240 |
return state
|
| 241 |
}
|
| 242 |
|
| 243 |
+
/**
|
| 244 |
+
* This function is used to train changed contacts.
|
| 245 |
+
*/
|
| 246 |
fun trainContacts(): MutableLiveData<ApiResource<ApiResponse<String>>> {
|
| 247 |
val state: MutableLiveData<ApiResource<ApiResponse<String>>> = MutableLiveData()
|
| 248 |
state.value = ApiResource.Loading()
|
| 249 |
+
/**
|
| 250 |
+
* Get current contacts from user's phone
|
| 251 |
+
*/
|
| 252 |
val contacts = getContacts(appContext)
|
| 253 |
CoroutineScope(Dispatchers.Main).launch {
|
| 254 |
val resource: MutableLiveData<Boolean> = MutableLiveData()
|
| 255 |
+
|
| 256 |
+
/**
|
| 257 |
+
* Get changed contacts
|
| 258 |
+
*/
|
| 259 |
val changedContacts = getChangedContacts(contacts)
|
| 260 |
+
|
| 261 |
+
/**
|
| 262 |
+
* Send request to Server
|
| 263 |
+
*
|
| 264 |
+
*/
|
| 265 |
val request = TrainContactsApiRequest(changedContacts, RemoteRepository.getKeys())
|
| 266 |
withContext(Dispatchers.Main) {
|
| 267 |
RemoteRepository.trainContacts(request, onSuccess = { apiResponse ->
|
|
|
|
| 274 |
return state
|
| 275 |
}
|
| 276 |
|
| 277 |
+
/**
|
| 278 |
+
* This function is used to get similar image to one that a user uploaded.
|
| 279 |
+
*/
|
| 280 |
fun getImageRelatedness(
|
| 281 |
imageName: String,
|
| 282 |
message: String
|
|
|
|
| 288 |
)
|
| 289 |
resource.value = ApiResource.Loading()
|
| 290 |
|
| 291 |
+
/**
|
| 292 |
+
* Get the uuid of the similar image
|
| 293 |
+
*/
|
| 294 |
RemoteRepository.getImageRelatedness(request, onSuccess = { apiResponse ->
|
| 295 |
val resultImageName = apiResponse.result.content.image_name
|
| 296 |
val resultImageDesc = apiResponse.result.content.image_desc
|
| 297 |
|
| 298 |
+
/**
|
| 299 |
+
* With the uuid of the image, download the image data from Firebase Storage
|
| 300 |
+
*/
|
| 301 |
FirebaseRepository.downloadImageWithName(
|
| 302 |
name = resultImageName,
|
| 303 |
onSuccess = { response ->
|
| 304 |
resource.value =
|
| 305 |
ApiResource.Success(ImageRelatenessModel(response, resultImageDesc))
|
| 306 |
+
},
|
| 307 |
+
onFailure = { throwable ->
|
| 308 |
resource.value = ApiResource.Error(throwable)
|
| 309 |
}
|
| 310 |
)
|
|
|
|
| 315 |
return resource
|
| 316 |
}
|
| 317 |
|
| 318 |
+
/**
|
| 319 |
+
* This function is used to read mails
|
| 320 |
+
*/
|
| 321 |
+
fun readMails(
|
| 322 |
+
from: String,
|
| 323 |
+
password: String,
|
| 324 |
+
imapFolder: String
|
| 325 |
+
): MutableLiveData<ApiResource<ArrayList<MailModel>>> {
|
| 326 |
+
val resource: MutableLiveData<ApiResource<ArrayList<MailModel>>> =
|
| 327 |
+
MutableLiveData()
|
| 328 |
+
val request = ReadMailApiRequest(
|
| 329 |
+
data = ReadMailData(
|
| 330 |
+
sender = from,
|
| 331 |
+
pwd = password,
|
| 332 |
+
imap_folder = imapFolder
|
| 333 |
+
), confs = RemoteRepository.getKeys()
|
| 334 |
+
)
|
| 335 |
+
resource.value = ApiResource.Loading()
|
| 336 |
+
|
| 337 |
+
RemoteRepository.readEmails(request, onSuccess = { apiResponse ->
|
| 338 |
+
resource.value =
|
| 339 |
+
ApiResource.Success(apiResponse.result)
|
| 340 |
+
}, onFailure = { throwable ->
|
| 341 |
+
resource.value = ApiResource.Error(throwable)
|
| 342 |
+
})
|
| 343 |
+
|
| 344 |
+
return resource
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
/**
|
| 348 |
+
* this function is used to send mails
|
| 349 |
+
*/
|
| 350 |
+
fun sendMail(
|
| 351 |
+
sender: String,
|
| 352 |
+
pwd: String,
|
| 353 |
+
to: String,
|
| 354 |
+
subject: String,
|
| 355 |
+
body: String,
|
| 356 |
+
to_send: Boolean,
|
| 357 |
+
filename: String,
|
| 358 |
+
file_content: String
|
| 359 |
+
): MutableLiveData<ApiResource<String>> {
|
| 360 |
+
val resource: MutableLiveData<ApiResource<String>> =
|
| 361 |
+
MutableLiveData()
|
| 362 |
+
val request = ComposeMailApiRequest(
|
| 363 |
+
data = ComposeMailData(
|
| 364 |
+
sender = sender,
|
| 365 |
+
pwd = pwd,
|
| 366 |
+
to = to,
|
| 367 |
+
subject = subject,
|
| 368 |
+
body = body,
|
| 369 |
+
to_send = to_send,
|
| 370 |
+
filename = filename,
|
| 371 |
+
file_content = file_content
|
| 372 |
+
), confs = RemoteRepository.getKeys()
|
| 373 |
+
)
|
| 374 |
+
resource.value = ApiResource.Loading()
|
| 375 |
+
|
| 376 |
+
RemoteRepository.sendEmail(request, onSuccess = { apiResponse ->
|
| 377 |
+
resource.value =
|
| 378 |
+
ApiResource.Success(apiResponse.result)
|
| 379 |
+
}, onFailure = { throwable ->
|
| 380 |
+
resource.value = ApiResource.Error(throwable)
|
| 381 |
+
})
|
| 382 |
+
|
| 383 |
+
return resource
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
/**
|
| 387 |
* This function is used to retrieve real-time data for the auto task.
|
| 388 |
* Whenever data in the Firebase real-time database changes,
|
|
|
|
| 400 |
val data = snapshot.getValue<AutoTaskModel>()
|
| 401 |
data?.let {
|
| 402 |
data.command?.let { command ->
|
| 403 |
+
if (command.name == "finish") {
|
| 404 |
resource.value = ApiResource.Success(data)
|
| 405 |
} else {
|
| 406 |
resource.value = ApiResource.Loading(data)
|
|
|
|
| 425 |
val data = snapshot.getValue<AutoTaskModel>()
|
| 426 |
data?.let {
|
| 427 |
data.command?.let { command ->
|
| 428 |
+
if (command.name == "finish") {
|
| 429 |
resource.value = ApiResource.Success(data)
|
| 430 |
} else {
|
| 431 |
resource.value = ApiResource.Loading(data)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/setting/viewmodel/SettingViewModel.kt
CHANGED
|
@@ -7,6 +7,11 @@ import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
|
|
| 7 |
import com.matthaigh27.chatgptwrapper.data.repository.SharedPreferencesRepository
|
| 8 |
|
| 9 |
class SettingViewModel : ViewModel() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
fun setSettingData(model: SettingModel): MutableLiveData<ApiResource<Boolean>> {
|
| 11 |
val state: MutableLiveData<ApiResource<Boolean>> = MutableLiveData()
|
| 12 |
state.value = ApiResource.Loading()
|
|
@@ -15,6 +20,9 @@ class SettingViewModel : ViewModel() {
|
|
| 15 |
return state
|
| 16 |
}
|
| 17 |
|
|
|
|
|
|
|
|
|
|
| 18 |
fun getSettingData(): MutableLiveData<ApiResource<SettingModel>> {
|
| 19 |
val state: MutableLiveData<ApiResource<SettingModel>> = MutableLiveData()
|
| 20 |
state.value = ApiResource.Loading()
|
|
|
|
| 7 |
import com.matthaigh27.chatgptwrapper.data.repository.SharedPreferencesRepository
|
| 8 |
|
| 9 |
class SettingViewModel : ViewModel() {
|
| 10 |
+
/**
|
| 11 |
+
* By using SharedPreferences, keys to configure backend are stored and retrieved.
|
| 12 |
+
*
|
| 13 |
+
* This function is used to set the keys.
|
| 14 |
+
*/
|
| 15 |
fun setSettingData(model: SettingModel): MutableLiveData<ApiResource<Boolean>> {
|
| 16 |
val state: MutableLiveData<ApiResource<Boolean>> = MutableLiveData()
|
| 17 |
state.value = ApiResource.Loading()
|
|
|
|
| 20 |
return state
|
| 21 |
}
|
| 22 |
|
| 23 |
+
/**
|
| 24 |
+
* This function is used to get the keys.
|
| 25 |
+
*/
|
| 26 |
fun getSettingData(): MutableLiveData<ApiResource<SettingModel>> {
|
| 27 |
val state: MutableLiveData<ApiResource<SettingModel>> = MutableLiveData()
|
| 28 |
state.value = ApiResource.Loading()
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/splash/SplashActivity.kt
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.splash
|
| 2 |
+
|
| 3 |
+
import android.Manifest
|
| 4 |
+
import android.annotation.SuppressLint
|
| 5 |
+
import android.content.Intent
|
| 6 |
+
import android.content.pm.PackageManager
|
| 7 |
+
import android.os.Build
|
| 8 |
+
import androidx.appcompat.app.AppCompatActivity
|
| 9 |
+
import android.os.Bundle
|
| 10 |
+
import android.os.Handler
|
| 11 |
+
import com.matthaigh27.chatgptwrapper.R
|
| 12 |
+
import com.matthaigh27.chatgptwrapper.ui.base.BaseActivity
|
| 13 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.ChatActivity
|
| 14 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.dialogs.ConfirmDialog
|
| 15 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.fragments.ChatMainFragment
|
| 16 |
+
|
| 17 |
+
/**
|
| 18 |
+
* An Activity class for splash screen
|
| 19 |
+
*
|
| 20 |
+
* This class not only shows splash screen, but send permission requests to users.
|
| 21 |
+
*/
|
| 22 |
+
class SplashActivity : BaseActivity() {
|
| 23 |
+
|
| 24 |
+
private val PERMISSIONS_REQUEST_CODE = 1
|
| 25 |
+
private val SPLASH_DELAY_TIME = 3500L
|
| 26 |
+
/**
|
| 27 |
+
* This is string array variable to store a list of permissions to send to users.
|
| 28 |
+
*/
|
| 29 |
+
private lateinit var permissions: Array<String>
|
| 30 |
+
/**
|
| 31 |
+
* This is string variable to present warning when users didn't accept all given permissions.
|
| 32 |
+
*/
|
| 33 |
+
private lateinit var confirmMessage: String
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
override fun onCreate(savedInstanceState: Bundle?) {
|
| 37 |
+
super.onCreate(savedInstanceState)
|
| 38 |
+
setContentView(R.layout.activity_splash)
|
| 39 |
+
|
| 40 |
+
requestPermissions()
|
| 41 |
+
confirmMessage = getString(R.string.message_confirm_permission)
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
/**
|
| 45 |
+
* Send permission requests to users.
|
| 46 |
+
*
|
| 47 |
+
* This function is used to send permission requests to users for the normal operation of our app.
|
| 48 |
+
* If you refuse even one request, confirm dialog that recommend users to accept the refused requests again
|
| 49 |
+
* are showed.
|
| 50 |
+
*/
|
| 51 |
+
private fun requestPermissions() {
|
| 52 |
+
/**
|
| 53 |
+
* In mobile phones that use Google API 33 or higher, the permission for reading external storage
|
| 54 |
+
* is disabled because the phones don't support the feature.
|
| 55 |
+
*/
|
| 56 |
+
permissions = if(Build.VERSION.SDK_INT > Build.VERSION_CODES.S_V2) {
|
| 57 |
+
arrayOf(
|
| 58 |
+
Manifest.permission.SEND_SMS,
|
| 59 |
+
Manifest.permission.READ_CONTACTS,
|
| 60 |
+
Manifest.permission.CALL_PHONE
|
| 61 |
+
)
|
| 62 |
+
} else {
|
| 63 |
+
arrayOf(
|
| 64 |
+
Manifest.permission.SEND_SMS,
|
| 65 |
+
Manifest.permission.READ_CONTACTS,
|
| 66 |
+
Manifest.permission.CALL_PHONE,
|
| 67 |
+
Manifest.permission.READ_EXTERNAL_STORAGE
|
| 68 |
+
)
|
| 69 |
+
}
|
| 70 |
+
val notGrantedPermissions = permissions.filter {
|
| 71 |
+
checkSelfPermission(it) != PackageManager.PERMISSION_GRANTED
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
if (notGrantedPermissions.isNotEmpty()) {
|
| 76 |
+
/**
|
| 77 |
+
* If some permissions that users didn't accept exist, this code block are executed.
|
| 78 |
+
*/
|
| 79 |
+
if (shouldShowRequestPermissionRationale(notGrantedPermissions[0])) {
|
| 80 |
+
// show custom permission rationale
|
| 81 |
+
val confirmDialog = ConfirmDialog(this@SplashActivity)
|
| 82 |
+
confirmDialog.setOnClickListener(object :
|
| 83 |
+
ConfirmDialog.OnDialogButtonClickListener {
|
| 84 |
+
override fun onPositiveButtonClick() {
|
| 85 |
+
requestPermissions(
|
| 86 |
+
notGrantedPermissions.toTypedArray(), PERMISSIONS_REQUEST_CODE
|
| 87 |
+
)
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
override fun onNegativeButtonClick() {
|
| 91 |
+
finish()
|
| 92 |
+
}
|
| 93 |
+
})
|
| 94 |
+
|
| 95 |
+
confirmDialog.show()
|
| 96 |
+
confirmDialog.setMessage(confirmMessage)
|
| 97 |
+
|
| 98 |
+
} else {
|
| 99 |
+
requestPermissions(notGrantedPermissions.toTypedArray(), PERMISSIONS_REQUEST_CODE)
|
| 100 |
+
}
|
| 101 |
+
} else {
|
| 102 |
+
/**
|
| 103 |
+
* Permissions already granted, navigate to your desired activity
|
| 104 |
+
*/
|
| 105 |
+
moveToChatActivity()
|
| 106 |
+
}
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
@SuppressLint("MissingSuperCall")
|
| 110 |
+
override fun onRequestPermissionsResult(
|
| 111 |
+
requestCode: Int, permissions: Array<out String>, grantResults: IntArray
|
| 112 |
+
) {
|
| 113 |
+
when (requestCode) {
|
| 114 |
+
PERMISSIONS_REQUEST_CODE -> {
|
| 115 |
+
if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
|
| 116 |
+
/**
|
| 117 |
+
* Permissions granted, navigate to your desired activity
|
| 118 |
+
*/
|
| 119 |
+
moveToChatActivity()
|
| 120 |
+
} else {
|
| 121 |
+
requestPermissions()
|
| 122 |
+
}
|
| 123 |
+
return
|
| 124 |
+
}
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
private fun moveToChatActivity() {
|
| 129 |
+
Handler().postDelayed({
|
| 130 |
+
startActivity(Intent(this@SplashActivity, ChatActivity::class.java))
|
| 131 |
+
}, SPLASH_DELAY_TIME)
|
| 132 |
+
}
|
| 133 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/constants/CommonConstants.kt
CHANGED
|
@@ -13,11 +13,7 @@ object CommonConstants {
|
|
| 13 |
|
| 14 |
val ERROR_MSG_JSON = "Json Parsing Error"
|
| 15 |
val ERROR_MSG_NOEXIST_COMMAND = "No such command name exists."
|
|
|
|
| 16 |
|
| 17 |
val PROPS_WIDGET_DESC = "widget description"
|
| 18 |
-
|
| 19 |
-
val TIME_OUT_CALL = 60L
|
| 20 |
-
val TIME_OUT_CONNECT = 60L
|
| 21 |
-
val TIME_OUT_READ = 60L
|
| 22 |
-
val TIME_OUT_WRITE = 60L
|
| 23 |
}
|
|
|
|
| 13 |
|
| 14 |
val ERROR_MSG_JSON = "Json Parsing Error"
|
| 15 |
val ERROR_MSG_NOEXIST_COMMAND = "No such command name exists."
|
| 16 |
+
val ERROR_MSG_UNKNOWN_ERROR = "Unknown Error happened"
|
| 17 |
|
| 18 |
val PROPS_WIDGET_DESC = "widget description"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/constants/TypeChatWidgetConstants.kt
CHANGED
|
@@ -6,6 +6,7 @@ object TypeChatWidgetConstants {
|
|
| 6 |
val TYPE_WIDGET_FEEDBACK = "feedback"
|
| 7 |
val TYPE_WIDGET_SEARCH_CONTACT = "search_contact"
|
| 8 |
val TYPE_WIDGET_SCHEDULE_ALARM = "schedule_alarm"
|
|
|
|
| 9 |
val TYPE_WIDGET_MAIL_READ = "mail_read"
|
| 10 |
val TYPE_WIDGET_MAIL_WRITE = "mail_write"
|
| 11 |
val TYPE_WIDGET_MAIL_SEND = "mail_send"
|
|
|
|
| 6 |
val TYPE_WIDGET_FEEDBACK = "feedback"
|
| 7 |
val TYPE_WIDGET_SEARCH_CONTACT = "search_contact"
|
| 8 |
val TYPE_WIDGET_SCHEDULE_ALARM = "schedule_alarm"
|
| 9 |
+
val TYPE_WIDGET_MAILS = "mails"
|
| 10 |
val TYPE_WIDGET_MAIL_READ = "mail_read"
|
| 11 |
val TYPE_WIDGET_MAIL_WRITE = "mail_write"
|
| 12 |
val TYPE_WIDGET_MAIL_SEND = "mail_send"
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/constants/TypeResponseConstants.kt
CHANGED
|
@@ -10,7 +10,7 @@ object TypeResponseConstants {
|
|
| 10 |
val TYPE_RESPONSE_SMS = "sms"
|
| 11 |
val TYPE_RESPONSE_ALARM = "alarm"
|
| 12 |
val TYPE_RESPONSE_CONTACT = "contact"
|
| 13 |
-
val TYPE_RESPONSE_MAIL_READ = "
|
| 14 |
val TYPE_RESPONSE_MAIL_WRITE = "writeemail"
|
| 15 |
val TYPE_RESPONSE_MAIL_SEND = "sendemail"
|
| 16 |
val TYPE_RESPONSE_AUTO_TASK = "autotask"
|
|
|
|
| 10 |
val TYPE_RESPONSE_SMS = "sms"
|
| 11 |
val TYPE_RESPONSE_ALARM = "alarm"
|
| 12 |
val TYPE_RESPONSE_CONTACT = "contact"
|
| 13 |
+
val TYPE_RESPONSE_MAIL_READ = "reademails"
|
| 14 |
val TYPE_RESPONSE_MAIL_WRITE = "writeemail"
|
| 15 |
val TYPE_RESPONSE_MAIL_SEND = "sendemail"
|
| 16 |
val TYPE_RESPONSE_AUTO_TASK = "autotask"
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/AlarmHelper.kt
CHANGED
|
@@ -11,6 +11,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 |
|
|
|
|
| 11 |
|
| 12 |
|
| 13 |
object AlarmHelper {
|
| 14 |
+
|
| 15 |
+
/**
|
| 16 |
+
* This function is used to set an alarm with time and label
|
| 17 |
+
*/
|
| 18 |
fun createAlarm(context: Context, hour: Int, minute: Int, label: String) {
|
| 19 |
val calendar = Calendar.getInstance()
|
| 20 |
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/CommandHelper.kt
CHANGED
|
@@ -8,10 +8,16 @@ import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.HELP_COMMA
|
|
| 8 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.HELP_COMMAND_ERROR_NO_MAIN
|
| 9 |
|
| 10 |
object CommandHelper {
|
|
|
|
|
|
|
|
|
|
| 11 |
fun isMainHelpCommand(model: HelpCommandModel): Boolean {
|
| 12 |
return model.main != HELP_COMMAND
|
| 13 |
}
|
| 14 |
|
|
|
|
|
|
|
|
|
|
| 15 |
fun getHelpCommandFromStr(strCommand: String): HelpCommandModel {
|
| 16 |
val commandModel = HelpCommandModel()
|
| 17 |
if (strCommand == "/$HELP_COMMAND") {
|
|
@@ -39,6 +45,9 @@ object CommandHelper {
|
|
| 39 |
return commandModel
|
| 40 |
}
|
| 41 |
|
|
|
|
|
|
|
|
|
|
| 42 |
fun makePromptUsage(list: ArrayList<HelpPromptModel>) : String {
|
| 43 |
val usage = "usage:\n" +
|
| 44 |
"- help command: /help [command name]\n" +
|
|
@@ -51,6 +60,9 @@ object CommandHelper {
|
|
| 51 |
return strHelpList
|
| 52 |
}
|
| 53 |
|
|
|
|
|
|
|
|
|
|
| 54 |
fun makePromptItemUsage(list: ArrayList<HelpPromptModel>, assistName: String): String {
|
| 55 |
var strHelpDesc = ""
|
| 56 |
list.forEach { model ->
|
|
|
|
| 8 |
import com.matthaigh27.chatgptwrapper.utils.constants.CommonConstants.HELP_COMMAND_ERROR_NO_MAIN
|
| 9 |
|
| 10 |
object CommandHelper {
|
| 11 |
+
/**
|
| 12 |
+
* This function is used to identify whether helpcommand model is main help command.
|
| 13 |
+
*/
|
| 14 |
fun isMainHelpCommand(model: HelpCommandModel): Boolean {
|
| 15 |
return model.main != HELP_COMMAND
|
| 16 |
}
|
| 17 |
|
| 18 |
+
/**
|
| 19 |
+
* This function is used to convert user's help prompt to HelpCommandModel.
|
| 20 |
+
*/
|
| 21 |
fun getHelpCommandFromStr(strCommand: String): HelpCommandModel {
|
| 22 |
val commandModel = HelpCommandModel()
|
| 23 |
if (strCommand == "/$HELP_COMMAND") {
|
|
|
|
| 45 |
return commandModel
|
| 46 |
}
|
| 47 |
|
| 48 |
+
/**
|
| 49 |
+
* This function is used to make usage of all prompts to be showed to users with a list of Help Prompt Models.
|
| 50 |
+
*/
|
| 51 |
fun makePromptUsage(list: ArrayList<HelpPromptModel>) : String {
|
| 52 |
val usage = "usage:\n" +
|
| 53 |
"- help command: /help [command name]\n" +
|
|
|
|
| 60 |
return strHelpList
|
| 61 |
}
|
| 62 |
|
| 63 |
+
/**
|
| 64 |
+
* This function is used to make usage of given prompt.
|
| 65 |
+
*/
|
| 66 |
fun makePromptItemUsage(list: ArrayList<HelpPromptModel>, assistName: String): String {
|
| 67 |
var strHelpDesc = ""
|
| 68 |
list.forEach { model ->
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ContactHelper.kt
CHANGED
|
@@ -12,6 +12,9 @@ import kotlinx.coroutines.Dispatchers
|
|
| 12 |
import kotlinx.coroutines.async
|
| 13 |
|
| 14 |
object ContactHelper {
|
|
|
|
|
|
|
|
|
|
| 15 |
@SuppressLint("Range")
|
| 16 |
fun getContacts(context: Context): ArrayList<ContactModel> {
|
| 17 |
val resolver: ContentResolver = context.contentResolver;
|
|
@@ -61,6 +64,11 @@ object ContactHelper {
|
|
| 61 |
return contacts
|
| 62 |
}
|
| 63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
suspend fun getChangedContacts(
|
| 65 |
contacts: ArrayList<ContactModel>
|
| 66 |
): ArrayList<ContactModel> {
|
|
@@ -133,6 +141,9 @@ object ContactHelper {
|
|
| 133 |
}.await()
|
| 134 |
}
|
| 135 |
|
|
|
|
|
|
|
|
|
|
| 136 |
fun getContactModelById(contactId: String, contacts: ArrayList<ContactModel>): ContactModel {
|
| 137 |
var contactModel = ContactModel()
|
| 138 |
val searchResults = contacts.filter { contact ->
|
|
|
|
| 12 |
import kotlinx.coroutines.async
|
| 13 |
|
| 14 |
object ContactHelper {
|
| 15 |
+
/**
|
| 16 |
+
* This function is used to get contacts from user's phone.
|
| 17 |
+
*/
|
| 18 |
@SuppressLint("Range")
|
| 19 |
fun getContacts(context: Context): ArrayList<ContactModel> {
|
| 20 |
val resolver: ContentResolver = context.contentResolver;
|
|
|
|
| 64 |
return contacts
|
| 65 |
}
|
| 66 |
|
| 67 |
+
/**
|
| 68 |
+
* This function is used to get changed contacts by comparing images from user's contacts and
|
| 69 |
+
* ones from room database. After comparing, contacts table in room database is updated with the changed
|
| 70 |
+
* contacts.
|
| 71 |
+
*/
|
| 72 |
suspend fun getChangedContacts(
|
| 73 |
contacts: ArrayList<ContactModel>
|
| 74 |
): ArrayList<ContactModel> {
|
|
|
|
| 141 |
}.await()
|
| 142 |
}
|
| 143 |
|
| 144 |
+
/**
|
| 145 |
+
* This function is used to get contact model by id from user's current contacts.
|
| 146 |
+
*/
|
| 147 |
fun getContactModelById(contactId: String, contacts: ArrayList<ContactModel>): ContactModel {
|
| 148 |
var contactModel = ContactModel()
|
| 149 |
val searchResults = contacts.filter { contact ->
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/utils/helpers/chat/ImageHelper.kt
CHANGED
|
@@ -27,6 +27,9 @@ import java.util.Date
|
|
| 27 |
import java.util.Locale
|
| 28 |
|
| 29 |
object ImageHelper {
|
|
|
|
|
|
|
|
|
|
| 30 |
fun createSDCardFile(): File {
|
| 31 |
val timeStamp: String =
|
| 32 |
SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
|
|
@@ -40,6 +43,9 @@ object ImageHelper {
|
|
| 40 |
)
|
| 41 |
}
|
| 42 |
|
|
|
|
|
|
|
|
|
|
| 43 |
@Suppress("UNREACHABLE_CODE")
|
| 44 |
fun getBytesFromPath(path: String): ByteArray {
|
| 45 |
val byteArray: ByteArray
|
|
@@ -54,6 +60,9 @@ object ImageHelper {
|
|
| 54 |
return byteArray
|
| 55 |
}
|
| 56 |
|
|
|
|
|
|
|
|
|
|
| 57 |
fun convertImageToByte(uri: Uri): ByteArray? {
|
| 58 |
val data: ByteArray
|
| 59 |
try {
|
|
@@ -69,6 +78,13 @@ object ImageHelper {
|
|
| 69 |
return data
|
| 70 |
}
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
fun getRoundedCornerBitmap(bitmap: Bitmap, pixels: Int): Bitmap? {
|
| 73 |
val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
|
| 74 |
val canvas = Canvas(output)
|
|
@@ -86,6 +102,10 @@ object ImageHelper {
|
|
| 86 |
return output
|
| 87 |
}
|
| 88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
fun getImagesFromExternalStorage(contentResolver: ContentResolver): ArrayList<ImageModel> {
|
| 90 |
val listOfImages = ArrayList<ImageModel>()
|
| 91 |
|
|
@@ -112,6 +132,9 @@ object ImageHelper {
|
|
| 112 |
return listOfImages
|
| 113 |
}
|
| 114 |
|
|
|
|
|
|
|
|
|
|
| 115 |
fun getLocalPathFromUri(context: Context, contentUri: Uri?): String? {
|
| 116 |
var cursor: Cursor? = null
|
| 117 |
return try {
|
|
|
|
| 27 |
import java.util.Locale
|
| 28 |
|
| 29 |
object ImageHelper {
|
| 30 |
+
/**
|
| 31 |
+
* This function is used to save images with name generated by current date.
|
| 32 |
+
*/
|
| 33 |
fun createSDCardFile(): File {
|
| 34 |
val timeStamp: String =
|
| 35 |
SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
|
|
|
|
| 43 |
)
|
| 44 |
}
|
| 45 |
|
| 46 |
+
/**
|
| 47 |
+
* This function is used to convert files to ByteArray data.
|
| 48 |
+
*/
|
| 49 |
@Suppress("UNREACHABLE_CODE")
|
| 50 |
fun getBytesFromPath(path: String): ByteArray {
|
| 51 |
val byteArray: ByteArray
|
|
|
|
| 60 |
return byteArray
|
| 61 |
}
|
| 62 |
|
| 63 |
+
/**
|
| 64 |
+
* This function is used to convert image to ByteArray data with its Uri.
|
| 65 |
+
*/
|
| 66 |
fun convertImageToByte(uri: Uri): ByteArray? {
|
| 67 |
val data: ByteArray
|
| 68 |
try {
|
|
|
|
| 78 |
return data
|
| 79 |
}
|
| 80 |
|
| 81 |
+
/**
|
| 82 |
+
* This function is used to convert rectangle image to rounded image.
|
| 83 |
+
*
|
| 84 |
+
* @param bitmap A bitmap to convert
|
| 85 |
+
* @param pixels A round size of image to convert
|
| 86 |
+
* @return A rounded bitmap
|
| 87 |
+
*/
|
| 88 |
fun getRoundedCornerBitmap(bitmap: Bitmap, pixels: Int): Bitmap? {
|
| 89 |
val output = Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
|
| 90 |
val canvas = Canvas(output)
|
|
|
|
| 102 |
return output
|
| 103 |
}
|
| 104 |
|
| 105 |
+
/**
|
| 106 |
+
* This function is used to get images from external storage.
|
| 107 |
+
* First, get images with its path and modified date and then convert to ImageModel
|
| 108 |
+
*/
|
| 109 |
fun getImagesFromExternalStorage(contentResolver: ContentResolver): ArrayList<ImageModel> {
|
| 110 |
val listOfImages = ArrayList<ImageModel>()
|
| 111 |
|
|
|
|
| 132 |
return listOfImages
|
| 133 |
}
|
| 134 |
|
| 135 |
+
/**
|
| 136 |
+
* This function is used to get local path from Uri of image.
|
| 137 |
+
*/
|
| 138 |
fun getLocalPathFromUri(context: Context, contentUri: Uri?): String? {
|
| 139 |
var cursor: Cursor? = null
|
| 140 |
return try {
|
Android/app/src/main/res/drawable/image_logo.png
ADDED
|
Android/app/src/main/res/layout/activity_chat.xml
CHANGED
|
@@ -1,16 +1,10 @@
|
|
| 1 |
<?xml version="1.0" encoding="utf-8"?>
|
| 2 |
-
<
|
| 3 |
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
|
|
| 4 |
xmlns:tools="http://schemas.android.com/tools"
|
| 5 |
android:layout_width="match_parent"
|
| 6 |
android:layout_height="match_parent"
|
| 7 |
android:animateLayoutChanges="true"
|
| 8 |
android:background="@color/color_primary_dark"
|
| 9 |
-
tools:context=".ui.chat.view.ChatActivity">
|
| 10 |
-
|
| 11 |
-
<FrameLayout
|
| 12 |
-
android:id="@+id/fl_container"
|
| 13 |
-
android:layout_width="match_parent"
|
| 14 |
-
android:layout_height="match_parent" />
|
| 15 |
-
|
| 16 |
-
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
|
|
| 1 |
<?xml version="1.0" encoding="utf-8"?>
|
| 2 |
+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
| 3 |
xmlns:app="http://schemas.android.com/apk/res-auto"
|
| 4 |
+
android:id="@+id/fl_container"
|
| 5 |
xmlns:tools="http://schemas.android.com/tools"
|
| 6 |
android:layout_width="match_parent"
|
| 7 |
android:layout_height="match_parent"
|
| 8 |
android:animateLayoutChanges="true"
|
| 9 |
android:background="@color/color_primary_dark"
|
| 10 |
+
tools:context=".ui.chat.view.ChatActivity" />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/res/layout/activity_splash.xml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?xml version="1.0" encoding="utf-8"?>
|
| 2 |
+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
| 3 |
+
xmlns:app="http://schemas.android.com/apk/res-auto"
|
| 4 |
+
xmlns:tools="http://schemas.android.com/tools"
|
| 5 |
+
android:layout_width="match_parent"
|
| 6 |
+
android:layout_height="match_parent"
|
| 7 |
+
tools:context=".ui.splash.SplashActivity"
|
| 8 |
+
android:background="@color/bg_color_splash_screen" >
|
| 9 |
+
|
| 10 |
+
<ImageView
|
| 11 |
+
android:layout_width="0dp"
|
| 12 |
+
android:layout_height="wrap_content"
|
| 13 |
+
android:src="@drawable/image_logo"
|
| 14 |
+
app:layout_constraintBottom_toBottomOf="parent"
|
| 15 |
+
app:layout_constraintEnd_toEndOf="parent"
|
| 16 |
+
app:layout_constraintStart_toStartOf="parent"
|
| 17 |
+
app:layout_constraintTop_toTopOf="parent"
|
| 18 |
+
app:layout_constraintWidth_percent="0.9"/>
|
| 19 |
+
|
| 20 |
+
</androidx.constraintlayout.widget.ConstraintLayout>
|
Android/app/src/main/res/layout/item_help_prompt_key.xml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?xml version="1.0" encoding="utf-8"?>
|
| 2 |
+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
| 3 |
+
android:layout_width="match_parent"
|
| 4 |
+
android:layout_height="match_parent">
|
| 5 |
+
<com.google.android.material.textfield.TextInputLayout
|
| 6 |
+
android:id="@+id/edt_key"
|
| 7 |
+
style="@style/CommonEditText"
|
| 8 |
+
android:layout_marginBottom="@dimen/spacing_tiny">
|
| 9 |
+
|
| 10 |
+
<com.google.android.material.textfield.TextInputEditText
|
| 11 |
+
android:layout_width="match_parent"
|
| 12 |
+
android:layout_height="wrap_content" />
|
| 13 |
+
|
| 14 |
+
</com.google.android.material.textfield.TextInputLayout>
|
| 15 |
+
</FrameLayout>
|
Android/app/src/main/res/layout/widget_help_prompt.xml
CHANGED
|
@@ -16,7 +16,7 @@
|
|
| 16 |
app:layout_constraintStart_toStartOf="parent"
|
| 17 |
app:layout_constraintTop_toTopOf="parent">
|
| 18 |
|
| 19 |
-
<
|
| 20 |
android:layout_width="match_parent"
|
| 21 |
android:layout_height="wrap_content"
|
| 22 |
android:orientation="vertical"
|
|
@@ -24,16 +24,50 @@
|
|
| 24 |
android:paddingTop="@dimen/spacing_normal"
|
| 25 |
android:paddingBottom="@dimen/spacing_tiny">
|
| 26 |
|
| 27 |
-
<
|
| 28 |
-
android:id="@+id/
|
| 29 |
android:layout_width="match_parent"
|
| 30 |
-
android:layout_height="wrap_content"
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
<LinearLayout
|
| 39 |
android:id="@+id/ll_prompt_keys"
|
|
@@ -43,26 +77,7 @@
|
|
| 43 |
android:orientation="vertical"
|
| 44 |
app:layout_constraintTop_toBottomOf="@+id/txt_keys_title" />
|
| 45 |
|
| 46 |
-
|
| 47 |
-
android:id="@+id/linearLayout"
|
| 48 |
-
android:layout_width="match_parent"
|
| 49 |
-
android:layout_height="wrap_content"
|
| 50 |
-
android:layout_marginTop="@dimen/spacing_small"
|
| 51 |
-
android:gravity="end"
|
| 52 |
-
app:layout_constraintTop_toBottomOf="@+id/ll_prompt_keys">
|
| 53 |
-
|
| 54 |
-
<Button
|
| 55 |
-
android:id="@+id/btn_ok"
|
| 56 |
-
style="@style/ChatWidgetCommonButton"
|
| 57 |
-
android:text="@string/text_button_ok" />
|
| 58 |
-
|
| 59 |
-
<Button
|
| 60 |
-
android:id="@+id/btn_cancel"
|
| 61 |
-
style="@style/ChatWidgetCommonButton"
|
| 62 |
-
android:text="@string/text_button_cancel" />
|
| 63 |
-
</LinearLayout>
|
| 64 |
-
|
| 65 |
-
</androidx.constraintlayout.widget.ConstraintLayout>
|
| 66 |
</androidx.cardview.widget.CardView>
|
| 67 |
|
| 68 |
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
|
|
| 16 |
app:layout_constraintStart_toStartOf="parent"
|
| 17 |
app:layout_constraintTop_toTopOf="parent">
|
| 18 |
|
| 19 |
+
<LinearLayout
|
| 20 |
android:layout_width="match_parent"
|
| 21 |
android:layout_height="wrap_content"
|
| 22 |
android:orientation="vertical"
|
|
|
|
| 24 |
android:paddingTop="@dimen/spacing_normal"
|
| 25 |
android:paddingBottom="@dimen/spacing_tiny">
|
| 26 |
|
| 27 |
+
<androidx.constraintlayout.widget.ConstraintLayout
|
| 28 |
+
android:id="@+id/cl_header"
|
| 29 |
android:layout_width="match_parent"
|
| 30 |
+
android:layout_height="wrap_content">
|
| 31 |
+
|
| 32 |
+
<TextView
|
| 33 |
+
android:id="@+id/txt_keys_title"
|
| 34 |
+
android:layout_width="wrap_content"
|
| 35 |
+
android:layout_height="wrap_content"
|
| 36 |
+
android:text="@string/title_chat_widget"
|
| 37 |
+
android:textColor="@color/color_accent"
|
| 38 |
+
android:textSize="@dimen/font_big"
|
| 39 |
+
android:textStyle="bold"
|
| 40 |
+
app:layout_constraintBottom_toBottomOf="parent"
|
| 41 |
+
app:layout_constraintStart_toStartOf="parent"
|
| 42 |
+
app:layout_constraintTop_toTopOf="parent" />
|
| 43 |
+
|
| 44 |
+
<ImageView
|
| 45 |
+
android:id="@+id/btn_ok"
|
| 46 |
+
android:layout_width="@dimen/size_button_normal"
|
| 47 |
+
android:layout_height="@dimen/size_button_normal"
|
| 48 |
+
android:padding="@dimen/spacing_tiny"
|
| 49 |
+
android:src="@drawable/ic_send"
|
| 50 |
+
app:layout_constraintBottom_toBottomOf="@+id/txt_keys_title"
|
| 51 |
+
app:layout_constraintEnd_toEndOf="parent"
|
| 52 |
+
app:layout_constraintTop_toTopOf="@+id/txt_keys_title"
|
| 53 |
+
app:tint="@color/color_accent" />
|
| 54 |
+
|
| 55 |
+
<ImageView
|
| 56 |
+
android:id="@+id/btn_cancel"
|
| 57 |
+
android:layout_width="@dimen/size_button_normal"
|
| 58 |
+
android:layout_height="@dimen/size_button_normal"
|
| 59 |
+
android:padding="@dimen/spacing_tiny"
|
| 60 |
+
android:src="@drawable/ic_cancel_schedule_send"
|
| 61 |
+
app:layout_constraintBottom_toBottomOf="@+id/txt_keys_title"
|
| 62 |
+
app:layout_constraintEnd_toStartOf="@+id/btn_ok"
|
| 63 |
+
app:layout_constraintTop_toTopOf="@+id/txt_keys_title"
|
| 64 |
+
app:tint="@color/color_accent" />
|
| 65 |
+
|
| 66 |
+
</androidx.constraintlayout.widget.ConstraintLayout>
|
| 67 |
+
|
| 68 |
+
<View
|
| 69 |
+
style="@style/HorizontalDividerStyle"
|
| 70 |
+
android:layout_marginVertical="@dimen/spacing_tiny" />
|
| 71 |
|
| 72 |
<LinearLayout
|
| 73 |
android:id="@+id/ll_prompt_keys"
|
|
|
|
| 77 |
android:orientation="vertical"
|
| 78 |
app:layout_constraintTop_toBottomOf="@+id/txt_keys_title" />
|
| 79 |
|
| 80 |
+
</LinearLayout>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
</androidx.cardview.widget.CardView>
|
| 82 |
|
| 83 |
</androidx.constraintlayout.widget.ConstraintLayout>
|