Merge pull request #94 from ttt246/feature/mvvm_new_55
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- Android/app/build.gradle +49 -39
- Android/app/src/main/AndroidManifest.xml +21 -16
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/MyApplication.kt +0 -105
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/RisingApplication.kt +45 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/adapters/ChatAdapter.kt +0 -337
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{database/MyDatabase.kt → data/local/AppDatabase.kt} +13 -11
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ContactDao.kt +20 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ImageDao.kt +20 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{database → data/local}/entity/ContactEntity.kt +1 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{database → data/local}/entity/ImageEntity.kt +2 -1
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/AlarmModel.kt +3 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ChatMessageModel.kt +36 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ContactModel.kt +8 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/HelpCommandModel.kt +6 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/HelpPromptModel.kt +8 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ImageModel.kt +8 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiClient.kt +25 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiResource.kt +10 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiService.kt +15 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/BaseApiRequest.kt +8 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/NotificationApiRequest.kt +8 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/common/Keys.kt +11 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/common/Settings.kt +5 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/ApiResponse.kt +15 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/FirebaseRepository.kt +23 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RemoteRepository.kt +59 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RoomRepository.kt +47 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/database/dao/ContactDao.kt +0 -20
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/database/dao/ImageDao.kt +0 -20
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/fragments/ChatFragment.kt +0 -888
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/common/ContactModel.kt +0 -19
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/common/HelpCommandModel.kt +0 -10
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/common/HelpPromptModel.kt +0 -25
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/common/ImagePromptModel.kt +0 -11
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/requestmodels/RequestBodyModel.kt +0 -86
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/requestmodels/RequestTrainContactModel.kt +0 -79
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/viewmodels/ChatMessageModel.kt +0 -18
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/services/MessageService.kt +0 -32
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/services/api/HttpClient.kt +0 -117
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/services/api/HttpRisingInterface.kt +0 -7
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/base/BaseActivity.kt +18 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{activites/HomeActivity.kt → ui/chat/view/ChatActivity.kt} +25 -24
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/adapters/ChatMainAdapter.kt +179 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{dialogs/CommonConfirmDialog.kt → ui/chat/view/dialogs/ConfirmDialog.kt} +27 -30
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/fragments/ChatMainFragment.kt +383 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/ChatMessageInterface.kt +12 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/FeedbackWidget.kt +4 -0
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{widgets/SmsEditorWidget.kt → ui/chat/view/widgets/chatwidget/SendSmsWidget.kt} +26 -34
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{widgets → ui/chat/view/widgets/chatwidget/contact}/ContactDetailItem.kt +22 -34
- Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{widgets → ui/chat/view/widgets/chatwidget/contact}/ContactDetailWidget.kt +39 -30
Android/app/build.gradle
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
plugins {
|
| 2 |
id 'com.android.application'
|
| 3 |
-
id 'kotlin-android'
|
| 4 |
id 'com.google.gms.google-services'
|
| 5 |
id 'kotlin-kapt'
|
|
|
|
| 6 |
}
|
| 7 |
|
| 8 |
android {
|
|
@@ -13,19 +13,18 @@ android {
|
|
| 13 |
applicationId "com.matthaigh27.chatgptwrapper"
|
| 14 |
minSdk 28
|
| 15 |
targetSdk 33
|
| 16 |
-
versionCode
|
| 17 |
-
versionName "1.
|
| 18 |
|
| 19 |
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
| 20 |
}
|
| 21 |
|
| 22 |
buildTypes {
|
| 23 |
debug {
|
| 24 |
-
buildConfigField "String", "BASE_URL", "\"https://
|
| 25 |
}
|
| 26 |
release {
|
| 27 |
-
|
| 28 |
-
buildConfigField "String", "BASE_URL", "\"https://chatgptphone.herokuapp.com/\""
|
| 29 |
|
| 30 |
minifyEnabled true
|
| 31 |
shrinkResources true
|
|
@@ -41,6 +40,7 @@ android {
|
|
| 41 |
sourceCompatibility JavaVersion.VERSION_11
|
| 42 |
targetCompatibility JavaVersion.VERSION_11
|
| 43 |
}
|
|
|
|
| 44 |
kotlinOptions {
|
| 45 |
jvmTarget = JavaVersion.VERSION_11
|
| 46 |
}
|
|
@@ -51,63 +51,73 @@ android {
|
|
| 51 |
}
|
| 52 |
|
| 53 |
dependencies {
|
| 54 |
-
//
|
| 55 |
implementation 'androidx.core:core-ktx:1.9.0'
|
|
|
|
|
|
|
|
|
|
| 56 |
implementation 'androidx.appcompat:appcompat:1.6.0'
|
| 57 |
implementation 'com.google.android.material:material:1.8.0'
|
| 58 |
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
| 59 |
-
|
| 60 |
-
implementation platform('com.google.firebase:firebase-bom:31.4.0')
|
| 61 |
-
implementation 'com.google.android.gms:play-services-gcm:17.0.0'
|
| 62 |
-
|
| 63 |
-
implementation 'com.google.firebase:firebase-messaging'
|
| 64 |
-
implementation 'com.google.firebase:firebase-analytics'
|
| 65 |
-
implementation 'com.google.firebase:firebase-firestore-ktx:24.4.5'
|
| 66 |
-
implementation 'com.google.firebase:firebase-firestore:15.0.0'
|
| 67 |
-
|
| 68 |
-
implementation 'com.google.firebase:firebase-messaging-ktx'
|
| 69 |
-
implementation 'com.google.firebase:firebase-analytics-ktx'
|
| 70 |
-
implementation 'com.firebaseui:firebase-ui-storage:7.2.0'
|
| 71 |
-
|
| 72 |
-
implementation 'com.squareup.okhttp3:okhttp:3.0.1'
|
| 73 |
implementation 'com.github.soulqw:CoCo:1.1.2'
|
| 74 |
implementation 'com.github.dhaval2404:imagepicker:2.1'
|
| 75 |
-
implementation 'com.
|
|
|
|
|
|
|
| 76 |
testImplementation 'org.testng:testng:6.9.6'
|
| 77 |
|
| 78 |
// Testing-only dependencies
|
| 79 |
-
androidTestImplementation
|
| 80 |
-
androidTestImplementation
|
| 81 |
-
androidTestImplementation
|
| 82 |
|
| 83 |
testImplementation 'junit:junit:4.13.2'
|
| 84 |
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
| 85 |
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
| 86 |
|
| 87 |
// UiAutomator Testing
|
| 88 |
-
androidTestImplementation
|
| 89 |
androidTestImplementation 'org.hamcrest:hamcrest-integration:1.3'
|
| 90 |
|
| 91 |
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"
|
| 92 |
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"
|
| 93 |
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha05"
|
| 94 |
|
| 95 |
-
|
| 96 |
-
|
|
|
|
| 97 |
|
| 98 |
-
implementation 'com.google.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
|
| 100 |
-
implementation "androidx.room:room-runtime:$
|
| 101 |
-
annotationProcessor "androidx.room:room-compiler:$
|
| 102 |
|
| 103 |
// To use room database
|
| 104 |
-
implementation "androidx.room:room-ktx:$
|
| 105 |
-
kapt "androidx.room:room-compiler:$
|
| 106 |
-
implementation "androidx.room:room-rxjava2:$
|
| 107 |
-
implementation "androidx.room:room-rxjava3:$
|
| 108 |
-
implementation "androidx.room:room-guava:$
|
| 109 |
-
testImplementation "androidx.room:room-testing:$
|
| 110 |
-
implementation "androidx.room:room-paging:$
|
| 111 |
|
| 112 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
}
|
|
|
|
| 1 |
plugins {
|
| 2 |
id 'com.android.application'
|
|
|
|
| 3 |
id 'com.google.gms.google-services'
|
| 4 |
id 'kotlin-kapt'
|
| 5 |
+
id 'kotlin-android'
|
| 6 |
}
|
| 7 |
|
| 8 |
android {
|
|
|
|
| 13 |
applicationId "com.matthaigh27.chatgptwrapper"
|
| 14 |
minSdk 28
|
| 15 |
targetSdk 33
|
| 16 |
+
versionCode 1
|
| 17 |
+
versionName "1.6"
|
| 18 |
|
| 19 |
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
| 20 |
}
|
| 21 |
|
| 22 |
buildTypes {
|
| 23 |
debug {
|
| 24 |
+
buildConfigField "String", "BASE_URL", "\"https://ttt246-brain.hf.space/\""
|
| 25 |
}
|
| 26 |
release {
|
| 27 |
+
buildConfigField "String", "BASE_URL", "\"https://ttt246-brain.hf.space/\""
|
|
|
|
| 28 |
|
| 29 |
minifyEnabled true
|
| 30 |
shrinkResources true
|
|
|
|
| 40 |
sourceCompatibility JavaVersion.VERSION_11
|
| 41 |
targetCompatibility JavaVersion.VERSION_11
|
| 42 |
}
|
| 43 |
+
|
| 44 |
kotlinOptions {
|
| 45 |
jvmTarget = JavaVersion.VERSION_11
|
| 46 |
}
|
|
|
|
| 51 |
}
|
| 52 |
|
| 53 |
dependencies {
|
| 54 |
+
//Core
|
| 55 |
implementation 'androidx.core:core-ktx:1.9.0'
|
| 56 |
+
implementation 'com.google.code.gson:gson:2.8.5'
|
| 57 |
+
|
| 58 |
+
//UI & UX
|
| 59 |
implementation 'androidx.appcompat:appcompat:1.6.0'
|
| 60 |
implementation 'com.google.android.material:material:1.8.0'
|
| 61 |
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
| 62 |
+
implementation 'de.hdodenhof:circleimageview:3.1.0'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
implementation 'com.github.soulqw:CoCo:1.1.2'
|
| 64 |
implementation 'com.github.dhaval2404:imagepicker:2.1'
|
| 65 |
+
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
| 66 |
+
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
| 67 |
+
|
| 68 |
testImplementation 'org.testng:testng:6.9.6'
|
| 69 |
|
| 70 |
// Testing-only dependencies
|
| 71 |
+
androidTestImplementation "androidx.test:core:$rootProject.coreVersion"
|
| 72 |
+
androidTestImplementation "androidx.test.ext:junit:$rootProject.extJUnitVersion"
|
| 73 |
+
androidTestImplementation "androidx.test:runner:$rootProject.runnerVersion"
|
| 74 |
|
| 75 |
testImplementation 'junit:junit:4.13.2'
|
| 76 |
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
| 77 |
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
| 78 |
|
| 79 |
// UiAutomator Testing
|
| 80 |
+
androidTestImplementation "androidx.test.uiautomator:uiautomator:$rootProject.uiAutomatorVersion"
|
| 81 |
androidTestImplementation 'org.hamcrest:hamcrest-integration:1.3'
|
| 82 |
|
| 83 |
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"
|
| 84 |
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"
|
| 85 |
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha05"
|
| 86 |
|
| 87 |
+
//Firebase
|
| 88 |
+
implementation platform('com.google.firebase:firebase-bom:31.4.0')
|
| 89 |
+
implementation 'com.google.android.gms:play-services-gcm:17.0.0'
|
| 90 |
|
| 91 |
+
implementation 'com.google.firebase:firebase-messaging'
|
| 92 |
+
implementation 'com.google.firebase:firebase-analytics'
|
| 93 |
+
implementation 'com.google.firebase:firebase-firestore-ktx:24.4.5'
|
| 94 |
+
implementation 'com.google.firebase:firebase-firestore:15.0.0'
|
| 95 |
+
implementation 'com.google.firebase:firebase-storage-ktx:20.1.0'
|
| 96 |
+
implementation 'com.google.firebase:firebase-messaging-ktx'
|
| 97 |
+
implementation 'com.google.firebase:firebase-analytics-ktx'
|
| 98 |
+
implementation 'com.firebaseui:firebase-ui-storage:7.2.0'
|
| 99 |
|
| 100 |
+
implementation "androidx.room:room-runtime:$rootProject.roomVersion"
|
| 101 |
+
annotationProcessor "androidx.room:room-compiler:$rootProject.roomVersion"
|
| 102 |
|
| 103 |
// To use room database
|
| 104 |
+
implementation "androidx.room:room-ktx:$rootProject.roomVersion"
|
| 105 |
+
kapt "androidx.room:room-compiler:$rootProject.roomVersion"
|
| 106 |
+
implementation "androidx.room:room-rxjava2:$rootProject.roomVersion"
|
| 107 |
+
implementation "androidx.room:room-rxjava3:$rootProject.roomVersion"
|
| 108 |
+
implementation "androidx.room:room-guava:$rootProject.roomVersion"
|
| 109 |
+
testImplementation "androidx.room:room-testing:$rootProject.roomVersion"
|
| 110 |
+
implementation "androidx.room:room-paging:$rootProject.roomVersion"
|
| 111 |
|
| 112 |
+
//To use Retrofit
|
| 113 |
+
|
| 114 |
+
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycleVersion"
|
| 115 |
+
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$rootProject.lifecycleVersion"
|
| 116 |
+
|
| 117 |
+
implementation "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
|
| 118 |
+
implementation "com.squareup.retrofit2:converter-gson:$rootProject.retrofitVersion"
|
| 119 |
+
|
| 120 |
+
implementation "com.squareup.okhttp3:okhttp:$rootProject.okHttpVersion"
|
| 121 |
+
implementation "com.squareup.okhttp3:logging-interceptor:$rootProject.okHttpVersion"
|
| 122 |
+
implementation "com.squareup.okhttp3:okhttp-urlconnection:$rootProject.okHttpVersion"
|
| 123 |
}
|
Android/app/src/main/AndroidManifest.xml
CHANGED
|
@@ -9,40 +9,45 @@
|
|
| 9 |
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
|
| 10 |
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
| 11 |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
| 12 |
-
<uses-permission
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
| 15 |
-
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
| 16 |
-
<uses-permission android:name="android.permission.SEND_SMS"/>
|
| 17 |
<uses-permission android:name="android.permission.CALL_PHONE" />
|
| 18 |
|
| 19 |
<uses-feature android:name="android.hardware.audio.low_latency" />
|
| 20 |
<uses-feature android:name="android.hardware.audio.pro" />
|
| 21 |
<uses-feature android:name="android.hardware.microphone" />
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
<application
|
| 24 |
-
android:name=".
|
| 25 |
android:hardwareAccelerated="true"
|
| 26 |
android:icon="@mipmap/gpt_icon"
|
| 27 |
android:label="@string/app_name"
|
| 28 |
android:roundIcon="@mipmap/gpt_icon_round"
|
| 29 |
android:supportsRtl="true"
|
| 30 |
-
android:theme="@style/
|
| 31 |
<activity
|
| 32 |
-
android:name=".
|
| 33 |
-
android:
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
| 35 |
<intent-filter>
|
| 36 |
<action android:name="android.intent.action.MAIN" />
|
|
|
|
| 37 |
<category android:name="android.intent.category.LAUNCHER" />
|
| 38 |
</intent-filter>
|
| 39 |
</activity>
|
| 40 |
-
<service
|
| 41 |
-
android:name=".services.MessageService"
|
| 42 |
-
android:exported="false">
|
| 43 |
-
<intent-filter>
|
| 44 |
-
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
| 45 |
-
</intent-filter>
|
| 46 |
-
</service>
|
| 47 |
</application>
|
|
|
|
| 48 |
</manifest>
|
|
|
|
| 9 |
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
|
| 10 |
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
| 11 |
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
| 12 |
+
<uses-permission
|
| 13 |
+
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
| 14 |
+
android:maxSdkVersion="32" />
|
| 15 |
+
<uses-permission
|
| 16 |
+
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
| 17 |
+
android:maxSdkVersion="32" />
|
| 18 |
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
| 19 |
+
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
| 20 |
+
<uses-permission android:name="android.permission.SEND_SMS" />
|
| 21 |
<uses-permission android:name="android.permission.CALL_PHONE" />
|
| 22 |
|
| 23 |
<uses-feature android:name="android.hardware.audio.low_latency" />
|
| 24 |
<uses-feature android:name="android.hardware.audio.pro" />
|
| 25 |
<uses-feature android:name="android.hardware.microphone" />
|
| 26 |
+
<uses-feature
|
| 27 |
+
android:name="android.hardware.telephony"
|
| 28 |
+
android:required="false" />
|
| 29 |
|
| 30 |
<application
|
| 31 |
+
android:name=".RisingApplication"
|
| 32 |
android:hardwareAccelerated="true"
|
| 33 |
android:icon="@mipmap/gpt_icon"
|
| 34 |
android:label="@string/app_name"
|
| 35 |
android:roundIcon="@mipmap/gpt_icon_round"
|
| 36 |
android:supportsRtl="true"
|
| 37 |
+
android:theme="@style/AppTheme">
|
| 38 |
<activity
|
| 39 |
+
android:name=".ui.setting.view.SettingActivity"
|
| 40 |
+
android:exported="false" />
|
| 41 |
+
<activity
|
| 42 |
+
android:name=".ui.chat.view.ChatActivity"
|
| 43 |
+
android:exported="true"
|
| 44 |
+
android:windowSoftInputMode="adjustResize">
|
| 45 |
<intent-filter>
|
| 46 |
<action android:name="android.intent.action.MAIN" />
|
| 47 |
+
|
| 48 |
<category android:name="android.intent.category.LAUNCHER" />
|
| 49 |
</intent-filter>
|
| 50 |
</activity>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
</application>
|
| 52 |
+
|
| 53 |
</manifest>
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/MyApplication.kt
DELETED
|
@@ -1,105 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper
|
| 2 |
-
|
| 3 |
-
import android.Manifest
|
| 4 |
-
import android.annotation.SuppressLint
|
| 5 |
-
import android.app.Application
|
| 6 |
-
import android.app.NotificationChannel
|
| 7 |
-
import android.app.NotificationManager
|
| 8 |
-
import android.content.pm.PackageManager
|
| 9 |
-
import android.util.Log
|
| 10 |
-
import com.google.android.gms.tasks.OnCompleteListener
|
| 11 |
-
import com.google.firebase.messaging.FirebaseMessaging
|
| 12 |
-
import com.matthaigh27.chatgptwrapper.utils.Constants
|
| 13 |
-
import android.provider.Settings
|
| 14 |
-
import androidx.core.app.ActivityCompat
|
| 15 |
-
import androidx.core.app.NotificationCompat
|
| 16 |
-
import androidx.core.app.NotificationManagerCompat
|
| 17 |
-
import java.util.Random
|
| 18 |
-
|
| 19 |
-
class MyApplication : Application() {
|
| 20 |
-
|
| 21 |
-
private var mFCMToken: String = String()
|
| 22 |
-
private var mUUID: String = String()
|
| 23 |
-
@SuppressLint("HardwareIds")
|
| 24 |
-
override fun onCreate() {
|
| 25 |
-
super.onCreate()
|
| 26 |
-
|
| 27 |
-
initToken()
|
| 28 |
-
// on below line we are getting device id.
|
| 29 |
-
mUUID = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
|
| 30 |
-
appContext = applicationContext as MyApplication
|
| 31 |
-
|
| 32 |
-
Log.v("risingandroid mUUID: ", mUUID)
|
| 33 |
-
Log.v("risingandroid FCMToken: ", mFCMToken)
|
| 34 |
-
}
|
| 35 |
-
|
| 36 |
-
private fun initToken() {
|
| 37 |
-
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
|
| 38 |
-
if (!task.isSuccessful) {
|
| 39 |
-
Log.w(Constants.TAG, "Fetching FCM registration token failed", task.exception)
|
| 40 |
-
return@OnCompleteListener
|
| 41 |
-
}
|
| 42 |
-
|
| 43 |
-
/**
|
| 44 |
-
* Get new FCM registration token
|
| 45 |
-
*/
|
| 46 |
-
|
| 47 |
-
/**
|
| 48 |
-
* Get new FCM registration token
|
| 49 |
-
*/
|
| 50 |
-
mFCMToken = task.result
|
| 51 |
-
Log.d(Constants.TAG, mFCMToken)
|
| 52 |
-
})
|
| 53 |
-
}
|
| 54 |
-
|
| 55 |
-
fun getFCMToken(): String {
|
| 56 |
-
return this.mFCMToken
|
| 57 |
-
}
|
| 58 |
-
|
| 59 |
-
fun getUUID(): String {
|
| 60 |
-
return this.mUUID
|
| 61 |
-
}
|
| 62 |
-
|
| 63 |
-
/**
|
| 64 |
-
* this shows system notification with message
|
| 65 |
-
* @param message to be shown with system notification
|
| 66 |
-
*/
|
| 67 |
-
fun showNotification(message: String) {
|
| 68 |
-
val notificationId: Int = Random().nextInt()
|
| 69 |
-
val channelId = "chat_message"
|
| 70 |
-
|
| 71 |
-
val builder = NotificationCompat.Builder(this, channelId)
|
| 72 |
-
builder.setSmallIcon(R.drawable.ic_notification)
|
| 73 |
-
builder.setContentTitle(Constants.TAG)
|
| 74 |
-
builder.setContentText(message)
|
| 75 |
-
builder.setStyle(
|
| 76 |
-
NotificationCompat.BigTextStyle().bigText(
|
| 77 |
-
message
|
| 78 |
-
)
|
| 79 |
-
)
|
| 80 |
-
builder.priority = NotificationCompat.PRIORITY_DEFAULT
|
| 81 |
-
builder.setAutoCancel(true)
|
| 82 |
-
|
| 83 |
-
val channelName: CharSequence = "Chat Message"
|
| 84 |
-
val channelDescription = "This notification channel is used for chat message notifications"
|
| 85 |
-
val importance = NotificationManager.IMPORTANCE_DEFAULT
|
| 86 |
-
val channel = NotificationChannel(channelId, channelName, importance)
|
| 87 |
-
channel.description = channelDescription
|
| 88 |
-
val notificationManager = getSystemService(
|
| 89 |
-
NotificationManager::class.java
|
| 90 |
-
)
|
| 91 |
-
notificationManager.createNotificationChannel(channel)
|
| 92 |
-
val notificationManagerCompat = NotificationManagerCompat.from(this)
|
| 93 |
-
if (ActivityCompat.checkSelfPermission(
|
| 94 |
-
this, Manifest.permission.POST_NOTIFICATIONS
|
| 95 |
-
) != PackageManager.PERMISSION_GRANTED
|
| 96 |
-
) {
|
| 97 |
-
return
|
| 98 |
-
}
|
| 99 |
-
notificationManagerCompat.notify(notificationId, builder.build())
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
companion object {
|
| 103 |
-
lateinit var appContext: MyApplication
|
| 104 |
-
}
|
| 105 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/RisingApplication.kt
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper
|
| 2 |
+
|
| 3 |
+
import android.annotation.SuppressLint
|
| 4 |
+
import android.app.Application
|
| 5 |
+
import android.provider.Settings
|
| 6 |
+
import com.google.android.gms.tasks.OnCompleteListener
|
| 7 |
+
import com.google.firebase.messaging.FirebaseMessaging
|
| 8 |
+
|
| 9 |
+
class RisingApplication : Application() {
|
| 10 |
+
|
| 11 |
+
private var fcmToken: String = String()
|
| 12 |
+
private var uuid: String = String()
|
| 13 |
+
|
| 14 |
+
@SuppressLint("HardwareIds")
|
| 15 |
+
override fun onCreate() {
|
| 16 |
+
super.onCreate()
|
| 17 |
+
|
| 18 |
+
initToken()
|
| 19 |
+
// on below line we are getting device id.
|
| 20 |
+
uuid = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
|
| 21 |
+
appContext = applicationContext as RisingApplication
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
private fun initToken() {
|
| 25 |
+
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
|
| 26 |
+
if (!task.isSuccessful) {
|
| 27 |
+
return@OnCompleteListener
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
fcmToken = task.result
|
| 31 |
+
})
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
fun getFCMToken(): String {
|
| 35 |
+
return this.fcmToken
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
fun getUUID(): String {
|
| 39 |
+
return this.uuid
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
companion object {
|
| 43 |
+
lateinit var appContext: RisingApplication
|
| 44 |
+
}
|
| 45 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/adapters/ChatAdapter.kt
DELETED
|
@@ -1,337 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.adapters
|
| 2 |
-
|
| 3 |
-
import android.annotation.SuppressLint
|
| 4 |
-
import android.app.Dialog
|
| 5 |
-
import android.content.Context
|
| 6 |
-
import android.graphics.Bitmap
|
| 7 |
-
import android.graphics.BitmapFactory
|
| 8 |
-
import android.view.LayoutInflater
|
| 9 |
-
import android.view.View
|
| 10 |
-
import android.view.ViewGroup
|
| 11 |
-
import android.widget.FrameLayout
|
| 12 |
-
import android.widget.ImageView
|
| 13 |
-
import android.widget.LinearLayout
|
| 14 |
-
import android.widget.TextView
|
| 15 |
-
import androidx.constraintlayout.widget.ConstraintLayout
|
| 16 |
-
import androidx.recyclerview.widget.RecyclerView
|
| 17 |
-
import com.matthaigh27.chatgptwrapper.R
|
| 18 |
-
import com.matthaigh27.chatgptwrapper.models.common.ContactModel
|
| 19 |
-
import com.matthaigh27.chatgptwrapper.models.common.HelpPromptModel
|
| 20 |
-
import com.matthaigh27.chatgptwrapper.models.viewmodels.ChatMessageModel
|
| 21 |
-
import com.matthaigh27.chatgptwrapper.utils.Constants.MSG_WIDGET_TYPE_HELP_PRMOPT
|
| 22 |
-
import com.matthaigh27.chatgptwrapper.utils.Constants.MSG_WIDGET_TYPE_SEARCH_CONTACT
|
| 23 |
-
import com.matthaigh27.chatgptwrapper.utils.Constants.MSG_WIDGET_TYPE_SMS
|
| 24 |
-
import com.matthaigh27.chatgptwrapper.utils.ImageHelper
|
| 25 |
-
import com.matthaigh27.chatgptwrapper.utils.Utils
|
| 26 |
-
import com.matthaigh27.chatgptwrapper.widgets.ContactDetailItem
|
| 27 |
-
import com.matthaigh27.chatgptwrapper.widgets.ContactDetailWidget
|
| 28 |
-
import com.matthaigh27.chatgptwrapper.widgets.HelpPromptWidget
|
| 29 |
-
import com.matthaigh27.chatgptwrapper.widgets.SearchContactWidget
|
| 30 |
-
import com.matthaigh27.chatgptwrapper.widgets.SmsEditorWidget
|
| 31 |
-
import org.json.JSONArray
|
| 32 |
-
|
| 33 |
-
class ChatAdapter(list: ArrayList<ChatMessageModel>, context: Context) :
|
| 34 |
-
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
| 35 |
-
|
| 36 |
-
private var mChatModelList: ArrayList<ChatMessageModel> = ArrayList()
|
| 37 |
-
private var mContext: Context
|
| 38 |
-
|
| 39 |
-
private var mListener: MessageWidgetListener? = null
|
| 40 |
-
var mOnSMSClickListener: ContactDetailItem.OnSMSClickListener? = null
|
| 41 |
-
|
| 42 |
-
private val feedbackData = arrayOf(
|
| 43 |
-
arrayOf(R.drawable.ic_thumb_up_disable, R.drawable.ic_thumb_down),
|
| 44 |
-
arrayOf(R.drawable.ic_thumb_up_disable, R.drawable.ic_thumb_down_disable),
|
| 45 |
-
arrayOf(R.drawable.ic_thumb_up, R.drawable.ic_thumb_down_disable),
|
| 46 |
-
)
|
| 47 |
-
|
| 48 |
-
init {
|
| 49 |
-
mChatModelList = list
|
| 50 |
-
mContext = context
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
| 54 |
-
val context = parent.context
|
| 55 |
-
val inflater = LayoutInflater.from(context)
|
| 56 |
-
|
| 57 |
-
/**
|
| 58 |
-
* Inflate the custom layout and Return a new holder instance
|
| 59 |
-
*/
|
| 60 |
-
return if (viewType == 0) {
|
| 61 |
-
SendMessageViewHolder(
|
| 62 |
-
inflater.inflate(
|
| 63 |
-
R.layout.item_container_sent_message, parent, false
|
| 64 |
-
)
|
| 65 |
-
)
|
| 66 |
-
} else {
|
| 67 |
-
ReceiveMessageViewHolder(
|
| 68 |
-
inflater.inflate(
|
| 69 |
-
R.layout.item_container_received_message, parent, false
|
| 70 |
-
)
|
| 71 |
-
)
|
| 72 |
-
}
|
| 73 |
-
}
|
| 74 |
-
|
| 75 |
-
/**
|
| 76 |
-
* Involves populating data into the item through holder
|
| 77 |
-
*/
|
| 78 |
-
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
| 79 |
-
/**
|
| 80 |
-
* Get the data model based on position
|
| 81 |
-
*/
|
| 82 |
-
val index = holder.adapterPosition
|
| 83 |
-
val messageModel: ChatMessageModel = mChatModelList[index]
|
| 84 |
-
if (messageModel.isMe) {
|
| 85 |
-
setSentMessageData(holder as SendMessageViewHolder, messageModel)
|
| 86 |
-
} else {
|
| 87 |
-
setReceiveMessageData(holder as ReceiveMessageViewHolder, messageModel)
|
| 88 |
-
}
|
| 89 |
-
}
|
| 90 |
-
|
| 91 |
-
private fun setSentMessageData(holder: SendMessageViewHolder, messageModel: ChatMessageModel) {
|
| 92 |
-
/**
|
| 93 |
-
* Set item views based on your views and data model
|
| 94 |
-
*/
|
| 95 |
-
if (messageModel.message.isEmpty()) {
|
| 96 |
-
holder.textMessage.visibility = View.GONE
|
| 97 |
-
} else {
|
| 98 |
-
holder.textMessage.text = messageModel.message
|
| 99 |
-
holder.textMessage.visibility = View.VISIBLE
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
if (messageModel.image != null) {
|
| 104 |
-
val radius = mContext.resources.getDimensionPixelSize(R.dimen.chat_message_item_radius)
|
| 105 |
-
|
| 106 |
-
val originBmp = BitmapFactory.decodeByteArray(messageModel.image, 0, messageModel.image!!.size)
|
| 107 |
-
val bmp = ImageHelper.getRoundedCornerBitmap(originBmp, radius)
|
| 108 |
-
holder.imgMessage.visibility = View.VISIBLE
|
| 109 |
-
holder.imgMessage.setImageBitmap(bmp)
|
| 110 |
-
holder.imgMessage.setOnClickListener {
|
| 111 |
-
onImageClick(originBmp)
|
| 112 |
-
}
|
| 113 |
-
} else {
|
| 114 |
-
holder.imgMessage.visibility = View.GONE
|
| 115 |
-
}
|
| 116 |
-
|
| 117 |
-
if (messageModel.isWidget) {
|
| 118 |
-
when (messageModel.widgetType) {
|
| 119 |
-
MSG_WIDGET_TYPE_HELP_PRMOPT -> {
|
| 120 |
-
val model: HelpPromptModel =
|
| 121 |
-
HelpPromptModel.initModelWithString(messageModel.widgetDescription)
|
| 122 |
-
val helpPromptWidget = HelpPromptWidget(mContext, model)
|
| 123 |
-
val helpPromptListener = object : HelpPromptWidget.OnHelpPromptListener {
|
| 124 |
-
override fun onSuccess(prompt: String) {
|
| 125 |
-
mChatModelList[holder.adapterPosition].isWidget = false
|
| 126 |
-
holder.llMessageWidget.visibility = View.GONE
|
| 127 |
-
holder.llMessageWidget.removeAllViews()
|
| 128 |
-
mListener!!.sentHelpPrompt(prompt)
|
| 129 |
-
}
|
| 130 |
-
|
| 131 |
-
override fun onCancel() {
|
| 132 |
-
mChatModelList[holder.adapterPosition].isWidget = false
|
| 133 |
-
holder.llMessageWidget.visibility = View.GONE
|
| 134 |
-
holder.llMessageWidget.removeAllViews()
|
| 135 |
-
mListener!!.canceledHelpPrompt()
|
| 136 |
-
}
|
| 137 |
-
}
|
| 138 |
-
helpPromptWidget.setOnClickListener(helpPromptListener)
|
| 139 |
-
holder.llMessageWidget.addView(helpPromptWidget)
|
| 140 |
-
holder.llMessageWidget.visibility = View.VISIBLE
|
| 141 |
-
}
|
| 142 |
-
}
|
| 143 |
-
} else {
|
| 144 |
-
holder.llMessageWidget.visibility = View.GONE
|
| 145 |
-
}
|
| 146 |
-
}
|
| 147 |
-
|
| 148 |
-
@SuppressLint("UseCompatLoadingForDrawables")
|
| 149 |
-
fun setReceiveMessageData(holder: ReceiveMessageViewHolder, messageModel: ChatMessageModel) {
|
| 150 |
-
/**
|
| 151 |
-
* Set item views based on your views and data model
|
| 152 |
-
*/
|
| 153 |
-
if (messageModel.message.isEmpty()) {
|
| 154 |
-
holder.textMessage.visibility = View.GONE
|
| 155 |
-
} else {
|
| 156 |
-
holder.textMessage.text = messageModel.message
|
| 157 |
-
holder.textMessage.visibility = View.VISIBLE
|
| 158 |
-
}
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
if (messageModel.image != null) {
|
| 162 |
-
val radius = mContext.resources.getDimensionPixelSize(R.dimen.chat_message_item_radius)
|
| 163 |
-
|
| 164 |
-
val originBmp = BitmapFactory.decodeByteArray(messageModel.image, 0, messageModel.image!!.size)
|
| 165 |
-
val bmp = ImageHelper.getRoundedCornerBitmap(originBmp, radius)
|
| 166 |
-
holder.imgMessage.visibility = View.VISIBLE
|
| 167 |
-
holder.imgMessage.setImageBitmap(bmp)
|
| 168 |
-
holder.imgMessage.setOnClickListener {
|
| 169 |
-
onImageClick(originBmp)
|
| 170 |
-
}
|
| 171 |
-
} else {
|
| 172 |
-
holder.imgMessage.visibility = View.GONE
|
| 173 |
-
}
|
| 174 |
-
|
| 175 |
-
holder.llFeedback.visibility = if (messageModel.visibleFeedback) {
|
| 176 |
-
View.VISIBLE
|
| 177 |
-
} else {
|
| 178 |
-
View.GONE
|
| 179 |
-
}
|
| 180 |
-
|
| 181 |
-
setThumb(holder)
|
| 182 |
-
|
| 183 |
-
holder.itemLayout.setOnLongClickListener {
|
| 184 |
-
if (holder.llFeedback.visibility == View.VISIBLE) {
|
| 185 |
-
holder.llFeedback.visibility = View.GONE
|
| 186 |
-
mChatModelList[holder.adapterPosition].visibleFeedback = false
|
| 187 |
-
} else {
|
| 188 |
-
holder.llFeedback.visibility = View.VISIBLE
|
| 189 |
-
mChatModelList[holder.adapterPosition].visibleFeedback = true
|
| 190 |
-
}
|
| 191 |
-
return@setOnLongClickListener true
|
| 192 |
-
}
|
| 193 |
-
|
| 194 |
-
holder.btnThumbUp.setOnClickListener {
|
| 195 |
-
mChatModelList[holder.adapterPosition].feedback = 1
|
| 196 |
-
setThumb(holder)
|
| 197 |
-
|
| 198 |
-
}
|
| 199 |
-
|
| 200 |
-
holder.btnThumbDown.setOnClickListener {
|
| 201 |
-
mChatModelList[holder.adapterPosition].feedback = -1
|
| 202 |
-
setThumb(holder)
|
| 203 |
-
}
|
| 204 |
-
|
| 205 |
-
if (messageModel.isWidget) {
|
| 206 |
-
holder.llContactWidget.removeAllViews()
|
| 207 |
-
when (messageModel.widgetType) {
|
| 208 |
-
MSG_WIDGET_TYPE_SMS -> {
|
| 209 |
-
val smsWidget = SmsEditorWidget(mContext, null)
|
| 210 |
-
if(messageModel.widgetDescription.isNotEmpty()) {
|
| 211 |
-
smsWidget.setToUserName(messageModel.widgetDescription)
|
| 212 |
-
}
|
| 213 |
-
holder.llMessageWidget.addView(smsWidget)
|
| 214 |
-
holder.llMessageWidget.visibility = View.VISIBLE
|
| 215 |
-
|
| 216 |
-
val smsListener = object : SmsEditorWidget.OnClickListener {
|
| 217 |
-
override fun confirmSMS(phonenumber: String, message: String) {
|
| 218 |
-
mChatModelList[holder.adapterPosition].isWidget = false
|
| 219 |
-
holder.llMessageWidget.visibility = View.GONE
|
| 220 |
-
holder.llMessageWidget.removeAllViews()
|
| 221 |
-
mListener!!.sentSMS(phonenumber, message)
|
| 222 |
-
}
|
| 223 |
-
|
| 224 |
-
override fun cancelSMS() {
|
| 225 |
-
mChatModelList[holder.adapterPosition].isWidget = false
|
| 226 |
-
holder.llMessageWidget.visibility = View.GONE
|
| 227 |
-
holder.llMessageWidget.removeAllViews()
|
| 228 |
-
mListener!!.canceledSMS()
|
| 229 |
-
}
|
| 230 |
-
}
|
| 231 |
-
|
| 232 |
-
smsWidget.setOnClickListener(smsListener)
|
| 233 |
-
}
|
| 234 |
-
|
| 235 |
-
MSG_WIDGET_TYPE_SEARCH_CONTACT -> {
|
| 236 |
-
val contacts = Utils.instance.getContacts(mContext)
|
| 237 |
-
|
| 238 |
-
val contactIds = JSONArray(messageModel.widgetDescription)
|
| 239 |
-
for (i in 0 until contactIds.length()) {
|
| 240 |
-
val contactId = contactIds[i].toString()
|
| 241 |
-
val contact = Utils.instance.getContactModelById(contactId, contacts)
|
| 242 |
-
|
| 243 |
-
val searchContactWidget = SearchContactWidget(mContext, contact, null)
|
| 244 |
-
searchContactWidget.mSMSOnClickListener = mOnSMSClickListener
|
| 245 |
-
holder.llContactWidget.addView(searchContactWidget)
|
| 246 |
-
}
|
| 247 |
-
holder.llContactWidget.visibility = View.VISIBLE
|
| 248 |
-
}
|
| 249 |
-
}
|
| 250 |
-
} else {
|
| 251 |
-
holder.llMessageWidget.visibility = View.GONE
|
| 252 |
-
holder.llContactWidget.visibility = View.GONE
|
| 253 |
-
}
|
| 254 |
-
}
|
| 255 |
-
|
| 256 |
-
@SuppressLint("UseCompatLoadingForDrawables")
|
| 257 |
-
fun setThumb(holder: ReceiveMessageViewHolder) {
|
| 258 |
-
holder.btnThumbUp.setImageDrawable(
|
| 259 |
-
mContext.getDrawable(
|
| 260 |
-
feedbackData[mChatModelList[holder.adapterPosition].feedback + 1][0]
|
| 261 |
-
)
|
| 262 |
-
)
|
| 263 |
-
holder.btnThumbDown.setImageDrawable(
|
| 264 |
-
mContext.getDrawable(
|
| 265 |
-
feedbackData[mChatModelList[holder.adapterPosition].feedback + 1][1]
|
| 266 |
-
)
|
| 267 |
-
)
|
| 268 |
-
}
|
| 269 |
-
|
| 270 |
-
/**
|
| 271 |
-
* Returns the total count of items in the list
|
| 272 |
-
*/
|
| 273 |
-
override fun getItemCount(): Int {
|
| 274 |
-
return mChatModelList.size
|
| 275 |
-
}
|
| 276 |
-
|
| 277 |
-
override fun getItemViewType(position: Int): Int {
|
| 278 |
-
return if (mChatModelList[position].isMe) 0 else 1
|
| 279 |
-
}
|
| 280 |
-
|
| 281 |
-
private fun onImageClick(bitmap: Bitmap) {
|
| 282 |
-
val dialog = Dialog(mContext)
|
| 283 |
-
dialog.setContentView(R.layout.view_full_image)
|
| 284 |
-
val fullImage = dialog.findViewById(R.id.fullImage) as ImageView
|
| 285 |
-
fullImage.setImageBitmap(bitmap)
|
| 286 |
-
dialog.show()
|
| 287 |
-
}
|
| 288 |
-
|
| 289 |
-
inner class ReceiveMessageViewHolder internal constructor(itemView: View) :
|
| 290 |
-
RecyclerView.ViewHolder(itemView) {
|
| 291 |
-
var textMessage: TextView
|
| 292 |
-
var imgMessage: ImageView
|
| 293 |
-
var llFeedback: LinearLayout
|
| 294 |
-
var btnThumbUp: ImageView
|
| 295 |
-
var btnThumbDown: ImageView
|
| 296 |
-
var itemLayout: ConstraintLayout
|
| 297 |
-
var llMessageWidget: LinearLayout
|
| 298 |
-
var llContactWidget: LinearLayout
|
| 299 |
-
|
| 300 |
-
init {
|
| 301 |
-
textMessage = itemView.findViewById<View>(R.id.textMessage) as TextView
|
| 302 |
-
imgMessage = itemView.findViewById<View>(R.id.imgMessage) as ImageView
|
| 303 |
-
btnThumbUp = itemView.findViewById<View>(R.id.btn_thumb_up) as ImageView
|
| 304 |
-
btnThumbDown = itemView.findViewById<View>(R.id.btn_thumb_down) as ImageView
|
| 305 |
-
llFeedback = itemView.findViewById<View>(R.id.ll_feedback) as LinearLayout
|
| 306 |
-
itemLayout = itemView.findViewById<View>(R.id.cl_receive_message) as ConstraintLayout
|
| 307 |
-
llMessageWidget = itemView.findViewById<View>(R.id.ll_message_widget) as LinearLayout
|
| 308 |
-
llContactWidget = itemView.findViewById<View>(R.id.ll_contacts_widget) as LinearLayout
|
| 309 |
-
}
|
| 310 |
-
}
|
| 311 |
-
|
| 312 |
-
inner class SendMessageViewHolder internal constructor(itemView: View) :
|
| 313 |
-
RecyclerView.ViewHolder(itemView) {
|
| 314 |
-
var textMessage: TextView
|
| 315 |
-
var imgMessage: ImageView
|
| 316 |
-
var itemLayout: ConstraintLayout
|
| 317 |
-
var llMessageWidget: LinearLayout
|
| 318 |
-
|
| 319 |
-
init {
|
| 320 |
-
textMessage = itemView.findViewById<View>(R.id.textMessage) as TextView
|
| 321 |
-
imgMessage = itemView.findViewById<View>(R.id.imgMessage) as ImageView
|
| 322 |
-
itemLayout = itemView.findViewById<View>(R.id.cl_sent_message) as ConstraintLayout
|
| 323 |
-
llMessageWidget = itemView.findViewById<View>(R.id.ll_message_widget) as LinearLayout
|
| 324 |
-
}
|
| 325 |
-
}
|
| 326 |
-
|
| 327 |
-
interface MessageWidgetListener {
|
| 328 |
-
fun sentSMS(phonenumber: String, message: String)
|
| 329 |
-
fun canceledSMS()
|
| 330 |
-
fun sentHelpPrompt(prompt: String)
|
| 331 |
-
fun canceledHelpPrompt()
|
| 332 |
-
}
|
| 333 |
-
|
| 334 |
-
fun setMessageWidgetListener(listener: MessageWidgetListener) {
|
| 335 |
-
mListener = listener
|
| 336 |
-
}
|
| 337 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{database/MyDatabase.kt → data/local/AppDatabase.kt}
RENAMED
|
@@ -1,34 +1,36 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.
|
| 2 |
|
| 3 |
import android.content.Context
|
| 4 |
import androidx.room.Database
|
| 5 |
import androidx.room.Room
|
| 6 |
import androidx.room.RoomDatabase
|
| 7 |
-
import com.matthaigh27.chatgptwrapper.
|
| 8 |
-
import com.matthaigh27.chatgptwrapper.
|
| 9 |
-
import com.matthaigh27.chatgptwrapper.
|
| 10 |
-
import com.matthaigh27.chatgptwrapper.
|
| 11 |
|
| 12 |
@Database(entities = [ImageEntity::class, ContactEntity::class], version = 1, exportSchema = false)
|
| 13 |
-
abstract class
|
| 14 |
|
| 15 |
abstract fun imageDao(): ImageDao
|
| 16 |
abstract fun contactDao(): ContactDao
|
| 17 |
|
| 18 |
companion object {
|
|
|
|
|
|
|
| 19 |
@Volatile
|
| 20 |
-
private var INSTANCE:
|
| 21 |
|
| 22 |
-
fun getDatabase(context: Context):
|
| 23 |
val tempInstance = INSTANCE
|
| 24 |
if (tempInstance != null) {
|
| 25 |
return tempInstance
|
| 26 |
}
|
| 27 |
synchronized(this) {
|
| 28 |
val instance = Room.databaseBuilder(
|
| 29 |
-
context.applicationContext,
|
| 30 |
-
|
| 31 |
-
|
| 32 |
).build()
|
| 33 |
INSTANCE = instance
|
| 34 |
return instance
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.local
|
| 2 |
|
| 3 |
import android.content.Context
|
| 4 |
import androidx.room.Database
|
| 5 |
import androidx.room.Room
|
| 6 |
import androidx.room.RoomDatabase
|
| 7 |
+
import com.matthaigh27.chatgptwrapper.data.local.dao.ContactDao
|
| 8 |
+
import com.matthaigh27.chatgptwrapper.data.local.dao.ImageDao
|
| 9 |
+
import com.matthaigh27.chatgptwrapper.data.local.entity.ContactEntity
|
| 10 |
+
import com.matthaigh27.chatgptwrapper.data.local.entity.ImageEntity
|
| 11 |
|
| 12 |
@Database(entities = [ImageEntity::class, ContactEntity::class], version = 1, exportSchema = false)
|
| 13 |
+
abstract class AppDatabase : RoomDatabase() {
|
| 14 |
|
| 15 |
abstract fun imageDao(): ImageDao
|
| 16 |
abstract fun contactDao(): ContactDao
|
| 17 |
|
| 18 |
companion object {
|
| 19 |
+
private val DATABASE_NAME = "RisingPhone"
|
| 20 |
+
|
| 21 |
@Volatile
|
| 22 |
+
private var INSTANCE: AppDatabase? = null
|
| 23 |
|
| 24 |
+
fun getDatabase(context: Context): AppDatabase {
|
| 25 |
val tempInstance = INSTANCE
|
| 26 |
if (tempInstance != null) {
|
| 27 |
return tempInstance
|
| 28 |
}
|
| 29 |
synchronized(this) {
|
| 30 |
val instance = Room.databaseBuilder(
|
| 31 |
+
context = context.applicationContext,
|
| 32 |
+
klass = AppDatabase::class.java,
|
| 33 |
+
name = DATABASE_NAME
|
| 34 |
).build()
|
| 35 |
INSTANCE = instance
|
| 36 |
return instance
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ContactDao.kt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
|
| 7 |
+
@Dao
|
| 8 |
+
interface ContactDao {
|
| 9 |
+
@Insert
|
| 10 |
+
fun insert(contact: ContactEntity)
|
| 11 |
+
|
| 12 |
+
@Update
|
| 13 |
+
fun update(contact: ContactEntity)
|
| 14 |
+
|
| 15 |
+
@Delete
|
| 16 |
+
fun delete(contact: ContactEntity)
|
| 17 |
+
|
| 18 |
+
@Query("SELECT * FROM contacts")
|
| 19 |
+
fun getAllData(): List<ContactEntity>
|
| 20 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/local/dao/ImageDao.kt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
|
| 7 |
+
@Dao
|
| 8 |
+
interface ImageDao {
|
| 9 |
+
@Insert
|
| 10 |
+
fun insert(image: ImageEntity)
|
| 11 |
+
|
| 12 |
+
@Update
|
| 13 |
+
fun update(image: ImageEntity)
|
| 14 |
+
|
| 15 |
+
@Delete
|
| 16 |
+
fun delete(image: ImageEntity)
|
| 17 |
+
|
| 18 |
+
@Query("SELECT * FROM images")
|
| 19 |
+
fun getAllData(): List<ImageEntity>
|
| 20 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{database → data/local}/entity/ContactEntity.kt
RENAMED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.
|
| 2 |
|
| 3 |
import androidx.room.Entity
|
| 4 |
import androidx.room.PrimaryKey
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.local.entity
|
| 2 |
|
| 3 |
import androidx.room.Entity
|
| 4 |
import androidx.room.PrimaryKey
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{database → data/local}/entity/ImageEntity.kt
RENAMED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.
|
| 2 |
|
| 3 |
import androidx.room.Entity
|
| 4 |
import androidx.room.PrimaryKey
|
|
@@ -8,4 +8,5 @@ data class ImageEntity (
|
|
| 8 |
@PrimaryKey(autoGenerate = true) val id: Int,
|
| 9 |
val path: String,
|
| 10 |
val name: String,
|
|
|
|
| 11 |
)
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.local.entity
|
| 2 |
|
| 3 |
import androidx.room.Entity
|
| 4 |
import androidx.room.PrimaryKey
|
|
|
|
| 8 |
@PrimaryKey(autoGenerate = true) val id: Int,
|
| 9 |
val path: String,
|
| 10 |
val name: String,
|
| 11 |
+
val dataModified: Long
|
| 12 |
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/AlarmModel.kt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.models
|
| 2 |
+
|
| 3 |
+
data class AlarmModel(val id: Int, val time: Long, val enabled: Boolean, val label: String)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ChatMessageModel.kt
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.models
|
| 2 |
+
|
| 3 |
+
import com.google.gson.JsonElement
|
| 4 |
+
|
| 5 |
+
data class ChatMessageModel(
|
| 6 |
+
val type: Int,
|
| 7 |
+
val content: String? = null,
|
| 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 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ContactModel.kt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.models
|
| 2 |
+
|
| 3 |
+
data class ContactModel(
|
| 4 |
+
var id: String = "",
|
| 5 |
+
var name: String = "",
|
| 6 |
+
var phoneList: ArrayList<String> = ArrayList(),
|
| 7 |
+
var status: String = ""
|
| 8 |
+
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/HelpCommandModel.kt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.models
|
| 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/HelpPromptModel.kt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.models
|
| 2 |
+
|
| 3 |
+
data class HelpPromptModel(
|
| 4 |
+
var name: String = "",
|
| 5 |
+
var description: String = "",
|
| 6 |
+
var prompt: String = "",
|
| 7 |
+
var tags: ArrayList<String> = ArrayList()
|
| 8 |
+
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/models/ImageModel.kt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.models
|
| 2 |
+
|
| 3 |
+
import android.net.Uri
|
| 4 |
+
|
| 5 |
+
data class ImageModel(
|
| 6 |
+
val uri: Uri,
|
| 7 |
+
val modifiedDate: Long
|
| 8 |
+
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiClient.kt
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.remote
|
| 2 |
+
|
| 3 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants.API_BASE_URL
|
| 4 |
+
import okhttp3.OkHttpClient
|
| 5 |
+
import okhttp3.logging.HttpLoggingInterceptor
|
| 6 |
+
import retrofit2.Retrofit
|
| 7 |
+
import retrofit2.converter.gson.GsonConverterFactory
|
| 8 |
+
import java.util.concurrent.TimeUnit
|
| 9 |
+
|
| 10 |
+
object ApiClient {
|
| 11 |
+
private val client = OkHttpClient.Builder()
|
| 12 |
+
.callTimeout(240, TimeUnit.SECONDS)
|
| 13 |
+
.connectTimeout(240, TimeUnit.SECONDS)
|
| 14 |
+
.readTimeout(240, TimeUnit.SECONDS)
|
| 15 |
+
.writeTimeout(240, TimeUnit.SECONDS)
|
| 16 |
+
.build()
|
| 17 |
+
|
| 18 |
+
private val retrofit = Retrofit.Builder()
|
| 19 |
+
.baseUrl(API_BASE_URL)
|
| 20 |
+
.addConverterFactory(GsonConverterFactory.create())
|
| 21 |
+
.client(client)
|
| 22 |
+
.build()
|
| 23 |
+
|
| 24 |
+
val apiService: ApiService = retrofit.create(ApiService::class.java)
|
| 25 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiResource.kt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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)
|
| 9 |
+
class Loading<T> : ApiResource<T>()
|
| 10 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/ApiService.kt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.remote
|
| 2 |
+
|
| 3 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.BaseApiRequest
|
| 4 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
|
| 5 |
+
import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
|
| 6 |
+
import retrofit2.Call
|
| 7 |
+
import retrofit2.http.Body
|
| 8 |
+
import retrofit2.http.POST
|
| 9 |
+
|
| 10 |
+
interface ApiService {
|
| 11 |
+
@POST("commands")
|
| 12 |
+
fun getAllHelpCommands(@Body request: BaseApiRequest) : Call<ApiResponse>
|
| 13 |
+
@POST("sendNotification")
|
| 14 |
+
fun sendNotification(@Body request: NotificationApiRequest) : Call<ApiResponse>
|
| 15 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/BaseApiRequest.kt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.remote.requests
|
| 2 |
+
|
| 3 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys
|
| 4 |
+
|
| 5 |
+
data class BaseApiRequest(
|
| 6 |
+
val confs: Keys
|
| 7 |
+
)
|
| 8 |
+
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/NotificationApiRequest.kt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.remote.requests
|
| 2 |
+
|
| 3 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.common.Keys
|
| 4 |
+
|
| 5 |
+
data class NotificationApiRequest(
|
| 6 |
+
val message: String,
|
| 7 |
+
val confs: Keys
|
| 8 |
+
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/common/Keys.kt
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.remote.requests.common
|
| 2 |
+
|
| 3 |
+
data class Keys(
|
| 4 |
+
val uuid: String,
|
| 5 |
+
val token: String,
|
| 6 |
+
val openai_key: String,
|
| 7 |
+
val pinecone_key: String,
|
| 8 |
+
val pinecone_env: String,
|
| 9 |
+
val firebase_key: String,
|
| 10 |
+
val settings: Settings,
|
| 11 |
+
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/requests/common/Settings.kt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.remote.requests.common
|
| 2 |
+
|
| 3 |
+
data class Settings(
|
| 4 |
+
val temperature: Float
|
| 5 |
+
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/remote/responses/ApiResponse.kt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.remote.responses
|
| 2 |
+
|
| 3 |
+
import com.google.gson.JsonElement
|
| 4 |
+
|
| 5 |
+
data class ApiResponse (
|
| 6 |
+
val status_code: Int,
|
| 7 |
+
val message: List<String>,
|
| 8 |
+
val result: Result
|
| 9 |
+
)
|
| 10 |
+
|
| 11 |
+
data class Result (
|
| 12 |
+
val program: String,
|
| 13 |
+
val content: JsonElement,
|
| 14 |
+
val url: String
|
| 15 |
+
)
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/FirebaseRepository.kt
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.repository
|
| 2 |
+
|
| 3 |
+
import com.google.firebase.storage.FirebaseStorage
|
| 4 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnFailure
|
| 5 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnSuccess
|
| 6 |
+
|
| 7 |
+
object FirebaseRepository {
|
| 8 |
+
fun downloadImageWithName(
|
| 9 |
+
name: String,
|
| 10 |
+
onSuccess: OnSuccess<ByteArray>,
|
| 11 |
+
onFailure: OnFailure<String>
|
| 12 |
+
) {
|
| 13 |
+
val reference = "images/$name"
|
| 14 |
+
|
| 15 |
+
val storageReference = FirebaseStorage.getInstance().getReference(reference)
|
| 16 |
+
storageReference.getBytes(Long.MAX_VALUE).addOnSuccessListener { bytes ->
|
| 17 |
+
onSuccess(bytes)
|
| 18 |
+
}.addOnFailureListener { e ->
|
| 19 |
+
onFailure(e.toString())
|
| 20 |
+
}
|
| 21 |
+
return
|
| 22 |
+
}
|
| 23 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RemoteRepository.kt
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.repository
|
| 2 |
+
|
| 3 |
+
import com.matthaigh27.chatgptwrapper.data.remote.ApiClient
|
| 4 |
+
import com.matthaigh27.chatgptwrapper.data.remote.requests.NotificationApiRequest
|
| 5 |
+
import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
|
| 6 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnFailure
|
| 7 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.network.OnSuccess
|
| 8 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.network.RequestFactory.buildBaseApiRequest
|
| 9 |
+
import retrofit2.Call
|
| 10 |
+
import retrofit2.Callback
|
| 11 |
+
import retrofit2.Response
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
object RemoteRepository {
|
| 15 |
+
private val apiService = ApiClient.apiService
|
| 16 |
+
|
| 17 |
+
fun getAllHelpCommands(
|
| 18 |
+
onSuccess: OnSuccess<ApiResponse>,
|
| 19 |
+
onFailure: OnFailure<String>
|
| 20 |
+
) {
|
| 21 |
+
val call = apiService.getAllHelpCommands(buildBaseApiRequest())
|
| 22 |
+
|
| 23 |
+
call.enqueue(object : Callback<ApiResponse> {
|
| 24 |
+
override fun onResponse(call: Call<ApiResponse>, response: Response<ApiResponse>) {
|
| 25 |
+
response.body()?.let {
|
| 26 |
+
onSuccess(ApiResponse(it.status_code, it.message, it.result))
|
| 27 |
+
}?: run {
|
| 28 |
+
onFailure(response.message())
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
override fun onFailure(call: Call<ApiResponse>, t: Throwable) {
|
| 33 |
+
onFailure(t.message.toString())
|
| 34 |
+
}
|
| 35 |
+
})
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
fun sendNotification(
|
| 39 |
+
request: NotificationApiRequest,
|
| 40 |
+
onSuccess: OnSuccess<ApiResponse>,
|
| 41 |
+
onFailure: OnFailure<String>
|
| 42 |
+
) {
|
| 43 |
+
val call = apiService.sendNotification(request)
|
| 44 |
+
|
| 45 |
+
call.enqueue(object : Callback<ApiResponse> {
|
| 46 |
+
override fun onResponse(call: Call<ApiResponse>, response: Response<ApiResponse>) {
|
| 47 |
+
response.body()?.let { data ->
|
| 48 |
+
onSuccess(ApiResponse(data.status_code, data.message, data.result))
|
| 49 |
+
}?: run {
|
| 50 |
+
onFailure(response.message())
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
override fun onFailure(call: Call<ApiResponse>, t: Throwable) {
|
| 55 |
+
onFailure(t.message.toString())
|
| 56 |
+
}
|
| 57 |
+
})
|
| 58 |
+
}
|
| 59 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/data/repository/RoomRepository.kt
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.data.repository
|
| 2 |
+
|
| 3 |
+
import androidx.lifecycle.MutableLiveData
|
| 4 |
+
import com.matthaigh27.chatgptwrapper.RisingApplication
|
| 5 |
+
import com.matthaigh27.chatgptwrapper.data.local.AppDatabase
|
| 6 |
+
import com.matthaigh27.chatgptwrapper.data.local.entity.ContactEntity
|
| 7 |
+
import com.matthaigh27.chatgptwrapper.data.local.entity.ImageEntity
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
object RoomRepository {
|
| 11 |
+
private var databaseHandler: AppDatabase = AppDatabase.getDatabase(RisingApplication.appContext)
|
| 12 |
+
|
| 13 |
+
private var imageDao = databaseHandler.imageDao()
|
| 14 |
+
private var contactDao = databaseHandler.contactDao()
|
| 15 |
+
|
| 16 |
+
fun getAllImages(): MutableLiveData<List<ImageEntity>> {
|
| 17 |
+
return MutableLiveData(imageDao.getAllData())
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
fun insertImage(entity: ImageEntity) {
|
| 21 |
+
imageDao.insert(entity)
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
fun updateImage(entity: ImageEntity) {
|
| 25 |
+
imageDao.update(entity)
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
fun deleteImage(entity: ImageEntity) {
|
| 29 |
+
imageDao.delete(entity)
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
fun getAllContacts(): MutableLiveData<List<ContactEntity>> {
|
| 33 |
+
return MutableLiveData(contactDao.getAllData())
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
fun insertImage(entity: ContactEntity) {
|
| 37 |
+
contactDao.insert(entity)
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
fun updateImage(entity: ContactEntity) {
|
| 41 |
+
contactDao.update(entity)
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
fun deleteImage(entity: ContactEntity) {
|
| 45 |
+
contactDao.delete(entity)
|
| 46 |
+
}
|
| 47 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/database/dao/ContactDao.kt
DELETED
|
@@ -1,20 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.database.dao
|
| 2 |
-
|
| 3 |
-
import androidx.lifecycle.LiveData
|
| 4 |
-
import androidx.room.*
|
| 5 |
-
import com.matthaigh27.chatgptwrapper.database.entity.ContactEntity
|
| 6 |
-
|
| 7 |
-
@Dao
|
| 8 |
-
interface ContactDao {
|
| 9 |
-
@Insert
|
| 10 |
-
suspend fun insertContact(contact: ContactEntity)
|
| 11 |
-
|
| 12 |
-
@Update
|
| 13 |
-
suspend fun updateContact(contact: ContactEntity)
|
| 14 |
-
|
| 15 |
-
@Delete
|
| 16 |
-
suspend fun deleteContact(contact: ContactEntity)
|
| 17 |
-
|
| 18 |
-
@Query("SELECT * FROM contacts")
|
| 19 |
-
fun getAllContacts(): List<ContactEntity>
|
| 20 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/database/dao/ImageDao.kt
DELETED
|
@@ -1,20 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.database.dao
|
| 2 |
-
|
| 3 |
-
import androidx.lifecycle.LiveData
|
| 4 |
-
import androidx.room.*
|
| 5 |
-
import com.matthaigh27.chatgptwrapper.database.entity.ImageEntity
|
| 6 |
-
|
| 7 |
-
@Dao
|
| 8 |
-
interface ImageDao {
|
| 9 |
-
@Insert
|
| 10 |
-
suspend fun insertImage(image: ImageEntity)
|
| 11 |
-
|
| 12 |
-
@Update
|
| 13 |
-
suspend fun updateImage(image: ImageEntity)
|
| 14 |
-
|
| 15 |
-
@Delete
|
| 16 |
-
suspend fun deleteImage(image: ImageEntity)
|
| 17 |
-
|
| 18 |
-
@Query("SELECT * FROM images")
|
| 19 |
-
fun getAllImages(): List<ImageEntity>
|
| 20 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/fragments/ChatFragment.kt
DELETED
|
@@ -1,888 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.fragments
|
| 2 |
-
|
| 3 |
-
import android.os.Bundle
|
| 4 |
-
import androidx.fragment.app.Fragment
|
| 5 |
-
import android.view.LayoutInflater
|
| 6 |
-
import android.view.View
|
| 7 |
-
import android.view.ViewGroup
|
| 8 |
-
import android.annotation.SuppressLint
|
| 9 |
-
import android.app.ActionBar.LayoutParams
|
| 10 |
-
import android.content.*
|
| 11 |
-
import android.graphics.Bitmap
|
| 12 |
-
import android.graphics.BitmapFactory
|
| 13 |
-
import android.net.Uri
|
| 14 |
-
import android.os.Build
|
| 15 |
-
import android.os.StrictMode
|
| 16 |
-
import android.os.StrictMode.ThreadPolicy
|
| 17 |
-
import android.provider.MediaStore
|
| 18 |
-
import android.telephony.SmsManager
|
| 19 |
-
import android.util.Log
|
| 20 |
-
import android.view.KeyEvent
|
| 21 |
-
import android.view.View.OnClickListener
|
| 22 |
-
import android.view.animation.AccelerateDecelerateInterpolator
|
| 23 |
-
import android.view.animation.AlphaAnimation
|
| 24 |
-
import android.view.animation.Animation
|
| 25 |
-
import android.view.animation.LinearInterpolator
|
| 26 |
-
import android.view.animation.RotateAnimation
|
| 27 |
-
import android.view.animation.TranslateAnimation
|
| 28 |
-
import android.widget.*
|
| 29 |
-
import androidx.annotation.RequiresApi
|
| 30 |
-
import androidx.recyclerview.widget.LinearLayoutManager
|
| 31 |
-
import androidx.recyclerview.widget.RecyclerView
|
| 32 |
-
import com.google.firebase.storage.FirebaseStorage
|
| 33 |
-
import com.matthaigh27.chatgptwrapper.MyApplication
|
| 34 |
-
import com.matthaigh27.chatgptwrapper.R
|
| 35 |
-
import com.matthaigh27.chatgptwrapper.adapters.ChatAdapter
|
| 36 |
-
import com.matthaigh27.chatgptwrapper.database.MyDatabase
|
| 37 |
-
import com.matthaigh27.chatgptwrapper.database.entity.ImageEntity
|
| 38 |
-
import com.matthaigh27.chatgptwrapper.widgets.ImagePickerWidget
|
| 39 |
-
import com.matthaigh27.chatgptwrapper.widgets.ImagePickerWidget.OnPositiveButtonClickListener
|
| 40 |
-
import com.matthaigh27.chatgptwrapper.models.*
|
| 41 |
-
import com.matthaigh27.chatgptwrapper.models.common.HelpCommandModel
|
| 42 |
-
import com.matthaigh27.chatgptwrapper.models.common.HelpPromptModel
|
| 43 |
-
import com.matthaigh27.chatgptwrapper.models.viewmodels.ChatMessageModel
|
| 44 |
-
import com.matthaigh27.chatgptwrapper.services.api.HttpClient
|
| 45 |
-
import com.matthaigh27.chatgptwrapper.services.api.HttpRisingInterface
|
| 46 |
-
import com.matthaigh27.chatgptwrapper.utils.Constants.*
|
| 47 |
-
import com.matthaigh27.chatgptwrapper.utils.Utils
|
| 48 |
-
import com.matthaigh27.chatgptwrapper.widgets.ContactDetailItem
|
| 49 |
-
import com.qw.photo.CoCo
|
| 50 |
-
import com.qw.photo.callback.CoCoAdapter
|
| 51 |
-
import com.qw.photo.callback.CoCoCallBack
|
| 52 |
-
import com.qw.photo.constant.Range
|
| 53 |
-
import com.qw.photo.pojo.PickResult
|
| 54 |
-
import com.qw.photo.pojo.TakeResult
|
| 55 |
-
import kotlinx.coroutines.CoroutineScope
|
| 56 |
-
import kotlinx.coroutines.Dispatchers
|
| 57 |
-
import kotlinx.coroutines.launch
|
| 58 |
-
import okhttp3.*
|
| 59 |
-
import org.json.JSONException
|
| 60 |
-
import org.json.JSONObject
|
| 61 |
-
import java.io.*
|
| 62 |
-
import java.util.*
|
| 63 |
-
import kotlin.collections.ArrayList
|
| 64 |
-
|
| 65 |
-
class ChatFragment : Fragment(), OnClickListener, HttpRisingInterface {
|
| 66 |
-
private lateinit var rootView: View
|
| 67 |
-
private var mContext: Context? = null
|
| 68 |
-
|
| 69 |
-
/** ui components for chatlist recyclerview */
|
| 70 |
-
private lateinit var mRvChatList: RecyclerView
|
| 71 |
-
private lateinit var mEtMessage: EditText
|
| 72 |
-
|
| 73 |
-
/** ui components for loading spinner */
|
| 74 |
-
private lateinit var mSpLoading: ImageView
|
| 75 |
-
private lateinit var mTvLoading: TextView
|
| 76 |
-
private lateinit var mLlLoading: LinearLayout
|
| 77 |
-
|
| 78 |
-
/** ui components for loading photo */
|
| 79 |
-
private lateinit var mLlLoadPhoto: LinearLayout
|
| 80 |
-
private lateinit var mIvLoadedPhoto: ImageView
|
| 81 |
-
private lateinit var mBtnCancelLoadPhoto: TextView
|
| 82 |
-
|
| 83 |
-
/** adapter for chat recyclerview and arraylist for store chatting history */
|
| 84 |
-
private var mMessageList: ArrayList<ChatMessageModel> = ArrayList()
|
| 85 |
-
private lateinit var mAdapter: ChatAdapter
|
| 86 |
-
|
| 87 |
-
/** when a user selects image by camera or gallery,
|
| 88 |
-
* these two variables are used to save image source and name */
|
| 89 |
-
private var mSelectedImage: ByteArray? = null
|
| 90 |
-
private var mSelectedImageName: String = ""
|
| 91 |
-
|
| 92 |
-
/**
|
| 93 |
-
* mImagePickerType is
|
| 94 |
-
* 'image_uplaod' when user is going to upload image
|
| 95 |
-
* 'image_picker' when user is going to pick image for prompting
|
| 96 |
-
*/
|
| 97 |
-
private lateinit var mImagePickerWidget: ImagePickerWidget
|
| 98 |
-
private var mImagePickerType: String = ""
|
| 99 |
-
|
| 100 |
-
/** HttpClient for restful apis */
|
| 101 |
-
private lateinit var httpClient: HttpClient
|
| 102 |
-
|
| 103 |
-
/** list of help prompt commands */
|
| 104 |
-
private var mHelpPromptList: ArrayList<HelpPromptModel>? = null
|
| 105 |
-
|
| 106 |
-
/** animation variable for loading spinner */
|
| 107 |
-
private val rotate = RotateAnimation(
|
| 108 |
-
0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f
|
| 109 |
-
)
|
| 110 |
-
|
| 111 |
-
/** room database handler for local database */
|
| 112 |
-
private lateinit var mRoomDataHandler: MyDatabase
|
| 113 |
-
|
| 114 |
-
/** status variable that checks if widget in chatting interface does exist */
|
| 115 |
-
private var mIsExistWidget: Boolean = false
|
| 116 |
-
|
| 117 |
-
/**
|
| 118 |
-
* this is invoked when users click the message icon to send sms on contact detail dialog
|
| 119 |
-
* that is shown when a user search contacts
|
| 120 |
-
*/
|
| 121 |
-
private var mSMSOnClickListener: ContactDetailItem.OnSMSClickListener? = null
|
| 122 |
-
|
| 123 |
-
override fun onCreateView(
|
| 124 |
-
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
| 125 |
-
): View {
|
| 126 |
-
rootView = inflater.inflate(R.layout.fragment_chat, container, false)
|
| 127 |
-
init()
|
| 128 |
-
return rootView
|
| 129 |
-
}
|
| 130 |
-
|
| 131 |
-
private fun init() {
|
| 132 |
-
initEnvironment()
|
| 133 |
-
initValues()
|
| 134 |
-
initView()
|
| 135 |
-
initDatabase()
|
| 136 |
-
|
| 137 |
-
trainImages()
|
| 138 |
-
getAllPromptCommands()
|
| 139 |
-
}
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
private fun getAllPromptCommands() {
|
| 143 |
-
showLoading(true, "Loading Help Prompt Data")
|
| 144 |
-
httpClient.getALlHelpPromptCommands()
|
| 145 |
-
}
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
private fun initEnvironment() {
|
| 149 |
-
val policy = ThreadPolicy.Builder().permitAll().build()
|
| 150 |
-
StrictMode.setThreadPolicy(policy)
|
| 151 |
-
}
|
| 152 |
-
|
| 153 |
-
private fun initValues() {
|
| 154 |
-
mContext = context
|
| 155 |
-
|
| 156 |
-
httpClient = HttpClient(this)
|
| 157 |
-
|
| 158 |
-
rotate.duration = 3000
|
| 159 |
-
rotate.repeatCount = Animation.INFINITE
|
| 160 |
-
rotate.interpolator = LinearInterpolator()
|
| 161 |
-
|
| 162 |
-
initSMSOnClickListener()
|
| 163 |
-
}
|
| 164 |
-
|
| 165 |
-
private fun initView() {
|
| 166 |
-
this.mAdapter = ChatAdapter(mMessageList, mContext!!)
|
| 167 |
-
this.mAdapter.mOnSMSClickListener = mSMSOnClickListener
|
| 168 |
-
mRvChatList = rootView.findViewById<View>(R.id.chatRecycleView) as RecyclerView
|
| 169 |
-
mRvChatList.adapter = mAdapter
|
| 170 |
-
|
| 171 |
-
val sendSMSListener = object : ChatAdapter.MessageWidgetListener {
|
| 172 |
-
override fun sentSMS(phonenumber: String, message: String) {
|
| 173 |
-
mIsExistWidget = false
|
| 174 |
-
sendSms(phonenumber, message)
|
| 175 |
-
addMessage(
|
| 176 |
-
"You sent SMS with belowing content.\n\n " + "To: $phonenumber\n " + "Message: $message",
|
| 177 |
-
false
|
| 178 |
-
)
|
| 179 |
-
}
|
| 180 |
-
|
| 181 |
-
override fun canceledSMS() {
|
| 182 |
-
mIsExistWidget = false
|
| 183 |
-
addMessage("You canceled SMS.", false)
|
| 184 |
-
}
|
| 185 |
-
|
| 186 |
-
override fun sentHelpPrompt(prompt: String) {
|
| 187 |
-
mIsExistWidget = false
|
| 188 |
-
addMessage(prompt, true)
|
| 189 |
-
}
|
| 190 |
-
|
| 191 |
-
override fun canceledHelpPrompt() {
|
| 192 |
-
mIsExistWidget = false
|
| 193 |
-
addMessage("You canceled help command.", false)
|
| 194 |
-
}
|
| 195 |
-
}
|
| 196 |
-
|
| 197 |
-
mAdapter.setMessageWidgetListener(sendSMSListener)
|
| 198 |
-
|
| 199 |
-
val linearLayoutManager = LinearLayoutManager(mContext)
|
| 200 |
-
mRvChatList.layoutManager = linearLayoutManager
|
| 201 |
-
|
| 202 |
-
this.mEtMessage = rootView.findViewById(R.id.et_message)
|
| 203 |
-
mEtMessage.setOnKeyListener { _, keyCode, keyEvent ->
|
| 204 |
-
if (keyEvent.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER) {
|
| 205 |
-
addMessage(mEtMessage.text.toString(), true)
|
| 206 |
-
}
|
| 207 |
-
return@setOnKeyListener false
|
| 208 |
-
}
|
| 209 |
-
|
| 210 |
-
rootView.findViewById<View>(R.id.btn_send_message).setOnClickListener(this)
|
| 211 |
-
rootView.findViewById<View>(R.id.btn_image_upload).setOnClickListener(this)
|
| 212 |
-
rootView.findViewById<View>(R.id.btn_image_picker).setOnClickListener(this)
|
| 213 |
-
|
| 214 |
-
mSpLoading = rootView.findViewById(R.id.sp_loading)
|
| 215 |
-
mTvLoading = rootView.findViewById(R.id.tv_loading)
|
| 216 |
-
mLlLoading = rootView.findViewById(R.id.ll_loading)
|
| 217 |
-
|
| 218 |
-
mLlLoadPhoto = rootView.findViewById(R.id.ll_load_photo)
|
| 219 |
-
mIvLoadedPhoto = rootView.findViewById(R.id.iv_load_photo)
|
| 220 |
-
mBtnCancelLoadPhoto = rootView.findViewById(R.id.btn_cancel_load_photo)
|
| 221 |
-
mBtnCancelLoadPhoto.setOnClickListener(this)
|
| 222 |
-
|
| 223 |
-
initImagePickerWidget()
|
| 224 |
-
}
|
| 225 |
-
|
| 226 |
-
private fun initDatabase() {
|
| 227 |
-
mRoomDataHandler = MyDatabase.getDatabase(mContext!!)
|
| 228 |
-
}
|
| 229 |
-
|
| 230 |
-
private fun initSMSOnClickListener() {
|
| 231 |
-
mSMSOnClickListener = object : ContactDetailItem.OnSMSClickListener {
|
| 232 |
-
override fun onSMSClickListener(phoneNumber: String) {
|
| 233 |
-
addMessage(
|
| 234 |
-
"SMS",
|
| 235 |
-
isMe = false,
|
| 236 |
-
isSend = false,
|
| 237 |
-
isWidget = true,
|
| 238 |
-
widgetType = MSG_WIDGET_TYPE_SMS,
|
| 239 |
-
widgetDescription = phoneNumber
|
| 240 |
-
)
|
| 241 |
-
}
|
| 242 |
-
|
| 243 |
-
override fun onVoiceCallListener(phoneNumber: String, toName: String) {
|
| 244 |
-
addMessage(
|
| 245 |
-
message = "You made a voice call to $toName($phoneNumber)",
|
| 246 |
-
isMe = false,
|
| 247 |
-
isSend = false
|
| 248 |
-
)
|
| 249 |
-
}
|
| 250 |
-
}
|
| 251 |
-
}
|
| 252 |
-
|
| 253 |
-
/**
|
| 254 |
-
* set loading spinner visible
|
| 255 |
-
*/
|
| 256 |
-
private fun setDisableActivity(enable: Boolean) {
|
| 257 |
-
runOnUIThread {
|
| 258 |
-
mEtMessage.isEnabled = enable
|
| 259 |
-
rootView.findViewById<View>(R.id.btn_send_message).isEnabled = enable
|
| 260 |
-
rootView.findViewById<View>(R.id.btn_image_upload).isEnabled = enable
|
| 261 |
-
rootView.findViewById<View>(R.id.btn_image_picker).isEnabled = enable
|
| 262 |
-
}
|
| 263 |
-
}
|
| 264 |
-
|
| 265 |
-
/**
|
| 266 |
-
* set loading spinner visible
|
| 267 |
-
*/
|
| 268 |
-
private fun showLoading(visible: Boolean, text: String = "") {
|
| 269 |
-
runOnUIThread {
|
| 270 |
-
setDisableActivity(!visible)
|
| 271 |
-
|
| 272 |
-
if (visible) {
|
| 273 |
-
mSpLoading.startAnimation(rotate)
|
| 274 |
-
mLlLoading.visibility = View.VISIBLE
|
| 275 |
-
mTvLoading.text = text
|
| 276 |
-
} else {
|
| 277 |
-
mSpLoading.clearAnimation()
|
| 278 |
-
mLlLoading.visibility = View.GONE
|
| 279 |
-
}
|
| 280 |
-
}
|
| 281 |
-
}
|
| 282 |
-
|
| 283 |
-
/**
|
| 284 |
-
* show overlay when you picked image and users can cancel to load photo if users want
|
| 285 |
-
*/
|
| 286 |
-
private fun showLoadPhotoOverlay(imageByteArray: ByteArray) {
|
| 287 |
-
mLlLoadPhoto.visibility = View.VISIBLE
|
| 288 |
-
|
| 289 |
-
mIvLoadedPhoto.setImageBitmap(
|
| 290 |
-
BitmapFactory.decodeByteArray(
|
| 291 |
-
/* data = */ imageByteArray, /* offset = */ 0, /* length = */ imageByteArray.size
|
| 292 |
-
)
|
| 293 |
-
)
|
| 294 |
-
}
|
| 295 |
-
|
| 296 |
-
/**
|
| 297 |
-
* Bind broadcast sent by MessageService
|
| 298 |
-
*/
|
| 299 |
-
private val receiver = object : BroadcastReceiver() {
|
| 300 |
-
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
| 301 |
-
override fun onReceive(context: Context, intent: Intent) {
|
| 302 |
-
Log.d(TAG, "Receive")
|
| 303 |
-
}
|
| 304 |
-
}
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
/**
|
| 308 |
-
* get download url from firebase imagename in response and generate download url from the imagename
|
| 309 |
-
* With getBitmapFromURL method, get bitmap of the image and set it to mSelectedImage to display it to chatlist
|
| 310 |
-
* Finally, run addmessage and insert it to chat recyclerview
|
| 311 |
-
*
|
| 312 |
-
* @param imageName the firebase store imagename
|
| 313 |
-
*/
|
| 314 |
-
private fun getImageResponse(imageName: String, imageDesc: String) {
|
| 315 |
-
if (imageName.isEmpty() && imageDesc.isNotEmpty()) {
|
| 316 |
-
addMessage(message = imageDesc, isMe = false)
|
| 317 |
-
return
|
| 318 |
-
}
|
| 319 |
-
|
| 320 |
-
showLoading(visible = true, text = LOADING_DOWNLOADING_IMAGE)
|
| 321 |
-
|
| 322 |
-
val imageNameToUpload = "images/$imageName"
|
| 323 |
-
|
| 324 |
-
val storageReference = FirebaseStorage.getInstance().getReference(imageNameToUpload)
|
| 325 |
-
storageReference.downloadUrl.addOnSuccessListener { uri ->
|
| 326 |
-
try {
|
| 327 |
-
val image = Utils.instance.getBitmapFromURL(uri.toString())
|
| 328 |
-
if (image == null) showToast("can not get bitmap from url")
|
| 329 |
-
val byteArrayOutputStream = ByteArrayOutputStream()
|
| 330 |
-
|
| 331 |
-
val isSuccess =
|
| 332 |
-
image!!.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream)
|
| 333 |
-
if (!isSuccess) {
|
| 334 |
-
showToast("Fail to compress image")
|
| 335 |
-
}
|
| 336 |
-
mSelectedImage = byteArrayOutputStream.toByteArray()
|
| 337 |
-
} catch (e: Exception) {
|
| 338 |
-
showToast("cannot get download url from firebase store")
|
| 339 |
-
e.printStackTrace()
|
| 340 |
-
}
|
| 341 |
-
|
| 342 |
-
addMessage(message = imageDesc, isMe = false)
|
| 343 |
-
showLoading(visible = false)
|
| 344 |
-
}
|
| 345 |
-
return
|
| 346 |
-
}
|
| 347 |
-
|
| 348 |
-
override fun onResume() {
|
| 349 |
-
super.onResume()
|
| 350 |
-
updateChangedUserData()
|
| 351 |
-
}
|
| 352 |
-
|
| 353 |
-
private fun updateChangedUserData() {
|
| 354 |
-
trainContacts()
|
| 355 |
-
}
|
| 356 |
-
|
| 357 |
-
/**
|
| 358 |
-
* Open Help Command Widget with analysing string command
|
| 359 |
-
*/
|
| 360 |
-
private fun openHelpCommandWidget(strCommand: String) {
|
| 361 |
-
try {
|
| 362 |
-
val command: HelpCommandModel = Utils.instance.getHelpCommandFromStr(strCommand)
|
| 363 |
-
if (command.isMainCommand()) {
|
| 364 |
-
when (command.mainCommandName) {
|
| 365 |
-
"sms" -> {
|
| 366 |
-
addMessage(
|
| 367 |
-
message = "SMS",
|
| 368 |
-
isMe = false,
|
| 369 |
-
isSend = false,
|
| 370 |
-
isWidget = true,
|
| 371 |
-
widgetType = MSG_WIDGET_TYPE_SMS
|
| 372 |
-
)
|
| 373 |
-
}
|
| 374 |
-
|
| 375 |
-
else -> {
|
| 376 |
-
mHelpPromptList!!.forEach { model ->
|
| 377 |
-
if (model.name == command.mainCommandName) {
|
| 378 |
-
addMessage(
|
| 379 |
-
"Help Prompt Command",
|
| 380 |
-
isMe = true,
|
| 381 |
-
isSend = false,
|
| 382 |
-
isWidget = true,
|
| 383 |
-
widgetType = MSG_WIDGET_TYPE_HELP_PRMOPT,
|
| 384 |
-
widgetDescription = model.toString()
|
| 385 |
-
)
|
| 386 |
-
return
|
| 387 |
-
}
|
| 388 |
-
}
|
| 389 |
-
addMessage(
|
| 390 |
-
message = "No such command name exists.", isMe = false, isSend = false
|
| 391 |
-
)
|
| 392 |
-
}
|
| 393 |
-
}
|
| 394 |
-
} else {
|
| 395 |
-
if (command.assistCommandName == "all") {
|
| 396 |
-
val usage =
|
| 397 |
-
"usage:\n" + "- help command: /help [command name]\n" + "- prompt command: /<command name>\n\n"
|
| 398 |
-
var strHelpList = "help prompt commands:"
|
| 399 |
-
mHelpPromptList!!.forEach { model ->
|
| 400 |
-
strHelpList += "\n- " + model.name
|
| 401 |
-
}
|
| 402 |
-
|
| 403 |
-
addMessage(message = usage + strHelpList, isMe = false, isSend = false)
|
| 404 |
-
} else {
|
| 405 |
-
var strHelpDesc = ""
|
| 406 |
-
mHelpPromptList!!.forEach { model ->
|
| 407 |
-
if (model.name == command.assistCommandName) {
|
| 408 |
-
var strTags = ""
|
| 409 |
-
model.tags!!.forEach { tag ->
|
| 410 |
-
strTags += " $tag"
|
| 411 |
-
}
|
| 412 |
-
strHelpDesc = "description: " + model.description + "\ntags:" + strTags
|
| 413 |
-
}
|
| 414 |
-
}
|
| 415 |
-
if (strHelpDesc.isEmpty()) addMessage(
|
| 416 |
-
message = "No such command name exists.", isMe = false, isSend = false
|
| 417 |
-
)
|
| 418 |
-
else addMessage(message = strHelpDesc, isMe = false, isSend = false)
|
| 419 |
-
}
|
| 420 |
-
}
|
| 421 |
-
} catch (e: Exception) {
|
| 422 |
-
e.printStackTrace()
|
| 423 |
-
showToast(e.message.toString())
|
| 424 |
-
}
|
| 425 |
-
}
|
| 426 |
-
|
| 427 |
-
/**
|
| 428 |
-
* add message to chat list
|
| 429 |
-
* if users picked image from camera or gallery, send post request to `sendNotification` to ask generally
|
| 430 |
-
* else do 'imageRelateness' to search image
|
| 431 |
-
*
|
| 432 |
-
* @param message message content for chat list
|
| 433 |
-
* @param isMe this identify if this is sent by langchain server or users send message to server
|
| 434 |
-
* @param isSend is boolean that checks if you send request to server
|
| 435 |
-
* @param isWidget is boolean that checks if message item has widget
|
| 436 |
-
* @param widgetType is type of Widget ex: SMS, HELP_COMMAND, etc
|
| 437 |
-
* @param widgetDescription is string that saves information for widget
|
| 438 |
-
*/
|
| 439 |
-
@SuppressLint("NotifyDataSetChanged")
|
| 440 |
-
private fun addMessage(
|
| 441 |
-
message: String,
|
| 442 |
-
isMe: Boolean,
|
| 443 |
-
isSend: Boolean = true,
|
| 444 |
-
isWidget: Boolean = false,
|
| 445 |
-
widgetType: String = "",
|
| 446 |
-
widgetDescription: String = ""
|
| 447 |
-
) {
|
| 448 |
-
if ((message.isEmpty() && mSelectedImage == null) || mIsExistWidget) return
|
| 449 |
-
if (isWidget) {
|
| 450 |
-
if (widgetType != MSG_WIDGET_TYPE_SEARCH_CONTACT) {
|
| 451 |
-
mIsExistWidget = true
|
| 452 |
-
}
|
| 453 |
-
}
|
| 454 |
-
|
| 455 |
-
val msg = ChatMessageModel()
|
| 456 |
-
msg.message = message
|
| 457 |
-
msg.isMe = isMe
|
| 458 |
-
msg.isWidget = isWidget
|
| 459 |
-
msg.widgetType = widgetType
|
| 460 |
-
msg.widgetDescription = widgetDescription
|
| 461 |
-
|
| 462 |
-
/**
|
| 463 |
-
* if users picked some image from camera or gallery, add the image to chatting message
|
| 464 |
-
*/
|
| 465 |
-
if (mSelectedImage != null) {
|
| 466 |
-
msg.image = mSelectedImage
|
| 467 |
-
mSelectedImage = null
|
| 468 |
-
}
|
| 469 |
-
|
| 470 |
-
/**
|
| 471 |
-
* if users picked some image from camera or gallery, the image upload to firebase store
|
| 472 |
-
* mSelectedImageName is uuid created uploading to firebase store
|
| 473 |
-
*/
|
| 474 |
-
if (mSelectedImageName.isNotEmpty()) {
|
| 475 |
-
msg.imageName = mSelectedImageName
|
| 476 |
-
mSelectedImageName = ""
|
| 477 |
-
}
|
| 478 |
-
|
| 479 |
-
runOnUIThread {
|
| 480 |
-
mLlLoadPhoto.visibility = View.GONE
|
| 481 |
-
|
| 482 |
-
mMessageList.add(msg)
|
| 483 |
-
mAdapter.notifyDataSetChanged()
|
| 484 |
-
mEtMessage.setText("")
|
| 485 |
-
mRvChatList.scrollTo(/* x = */ 1000, /* y = */ -1000)
|
| 486 |
-
mRvChatList.scrollToPosition(mMessageList.size - 1)
|
| 487 |
-
}
|
| 488 |
-
|
| 489 |
-
if ((message.isNotEmpty() && message.first() == '/') && isMe) {
|
| 490 |
-
openHelpCommandWidget(message)
|
| 491 |
-
return
|
| 492 |
-
}
|
| 493 |
-
|
| 494 |
-
if (isMe) {
|
| 495 |
-
if (!isSend) {
|
| 496 |
-
return
|
| 497 |
-
}
|
| 498 |
-
|
| 499 |
-
showLoading(visible = true, text = LOADING_ASKING_TO_GPT)
|
| 500 |
-
if (msg.image != null) {
|
| 501 |
-
httpClient.callImageRelatedness(msg.imageName)
|
| 502 |
-
} else {
|
| 503 |
-
httpClient.callSendNotification(message)
|
| 504 |
-
}
|
| 505 |
-
}
|
| 506 |
-
}
|
| 507 |
-
|
| 508 |
-
override fun onClick(view: View) {
|
| 509 |
-
when (view.id) {
|
| 510 |
-
R.id.btn_send_message -> {
|
| 511 |
-
addMessage(mEtMessage.text.toString(), true)
|
| 512 |
-
}
|
| 513 |
-
|
| 514 |
-
R.id.btn_image_upload -> {
|
| 515 |
-
mImagePickerType = PICKERTYPE_IMAGE_UPLOAD
|
| 516 |
-
if(rootView.findViewById<View>(R.id.ll_toolbar).visibility == View.VISIBLE)
|
| 517 |
-
hideSlidingWidget()
|
| 518 |
-
else
|
| 519 |
-
showSlidingWidget()
|
| 520 |
-
}
|
| 521 |
-
|
| 522 |
-
R.id.btn_image_picker -> {
|
| 523 |
-
mImagePickerType = PICKERTYPE_IMAGE_PICK
|
| 524 |
-
if(rootView.findViewById<View>(R.id.ll_toolbar).visibility == View.VISIBLE)
|
| 525 |
-
hideSlidingWidget()
|
| 526 |
-
else
|
| 527 |
-
showSlidingWidget()
|
| 528 |
-
}
|
| 529 |
-
|
| 530 |
-
R.id.btn_cancel_load_photo -> {
|
| 531 |
-
mLlLoadPhoto.visibility = View.GONE
|
| 532 |
-
mSelectedImageName = ""
|
| 533 |
-
mSelectedImage = null
|
| 534 |
-
}
|
| 535 |
-
}
|
| 536 |
-
}
|
| 537 |
-
|
| 538 |
-
/**
|
| 539 |
-
* open browser with url
|
| 540 |
-
* @param url to open with browser
|
| 541 |
-
*/
|
| 542 |
-
private fun openBrowser(url: String) {
|
| 543 |
-
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
| 544 |
-
startActivity(Intent.createChooser(intent, "Browse with"))
|
| 545 |
-
}
|
| 546 |
-
|
| 547 |
-
/**
|
| 548 |
-
* calls when finish picking image
|
| 549 |
-
*
|
| 550 |
-
* @param imageByteData is bytearray of picked image
|
| 551 |
-
* @param type if users are going to upload image or pick image for query
|
| 552 |
-
*/
|
| 553 |
-
private fun pickedImage(imageByteData: ByteArray, type: String) {
|
| 554 |
-
if (type == "image_upload") {
|
| 555 |
-
uploadImageToFirebaseStorage(imageByteData)
|
| 556 |
-
} else {
|
| 557 |
-
uploadSearchImage(imageByteData)
|
| 558 |
-
}
|
| 559 |
-
}
|
| 560 |
-
|
| 561 |
-
/**
|
| 562 |
-
* toast message is invoked when error happens
|
| 563 |
-
*/
|
| 564 |
-
private fun showToast(message: String) {
|
| 565 |
-
runOnUIThread {
|
| 566 |
-
Toast.makeText(
|
| 567 |
-
mContext, message, Toast.LENGTH_SHORT
|
| 568 |
-
).show()
|
| 569 |
-
}
|
| 570 |
-
}
|
| 571 |
-
|
| 572 |
-
|
| 573 |
-
/**
|
| 574 |
-
* this can show dialog with camera and gallery icon.
|
| 575 |
-
* when you click camera icon, camera application runs and users can get an image by capturing using camera.
|
| 576 |
-
* when you click gallery icon, users can select image in your storage.
|
| 577 |
-
* A picked image converts into bytearray data and upload to firebase storage.
|
| 578 |
-
*/
|
| 579 |
-
private fun initImagePickerWidget() {
|
| 580 |
-
mImagePickerWidget = ImagePickerWidget(mContext!!)
|
| 581 |
-
|
| 582 |
-
val myImplementation = object : OnPositiveButtonClickListener {
|
| 583 |
-
override fun onPositiveBtnClick(isCamera: Boolean?) {
|
| 584 |
-
if (isCamera == true) {
|
| 585 |
-
CoCo.with(activity!!).take(Utils.instance.createSDCardFile())
|
| 586 |
-
.start(object : CoCoAdapter<TakeResult>() {
|
| 587 |
-
override fun onSuccess(data: TakeResult) {
|
| 588 |
-
val byteArray: ByteArray =
|
| 589 |
-
Utils.instance.getBytesFromPath(data.savedFile!!.absolutePath)
|
| 590 |
-
pickedImage(
|
| 591 |
-
byteArray, mImagePickerType
|
| 592 |
-
)
|
| 593 |
-
}
|
| 594 |
-
|
| 595 |
-
override fun onFailed(exception: Exception) {
|
| 596 |
-
super.onFailed(exception)
|
| 597 |
-
showToast("Fail to pick image. Please try again.")
|
| 598 |
-
}
|
| 599 |
-
})
|
| 600 |
-
} else {
|
| 601 |
-
CoCo.with(activity!!).pick().range(Range.PICK_CONTENT)
|
| 602 |
-
.start(object : CoCoCallBack<PickResult> {
|
| 603 |
-
|
| 604 |
-
override fun onSuccess(data: PickResult) {
|
| 605 |
-
val byteArray: ByteArray? =
|
| 606 |
-
Utils.instance.convertImageToByte(data.originUri)
|
| 607 |
-
if (byteArray == null) showToast("can not find such a file")
|
| 608 |
-
pickedImage(byteArray!!, mImagePickerType)
|
| 609 |
-
}
|
| 610 |
-
|
| 611 |
-
override fun onFailed(exception: Exception) {
|
| 612 |
-
showToast("Fail to pick image. Please try again.")
|
| 613 |
-
}
|
| 614 |
-
})
|
| 615 |
-
}
|
| 616 |
-
}
|
| 617 |
-
}
|
| 618 |
-
|
| 619 |
-
mImagePickerWidget.setOnClickListener(myImplementation)
|
| 620 |
-
|
| 621 |
-
val slidingWidget = rootView.findViewById<LinearLayout>(R.id.ll_toolbar)
|
| 622 |
-
slidingWidget.addView(mImagePickerWidget)
|
| 623 |
-
}
|
| 624 |
-
|
| 625 |
-
private fun uploadSearchImage(imageByteArray: ByteArray) {
|
| 626 |
-
showLoading(true, LOADING_ANALYZING_IMAGE)
|
| 627 |
-
val storageRef = FirebaseStorage.getInstance().reference
|
| 628 |
-
val uuid = UUID.randomUUID()
|
| 629 |
-
val imageName = "images/${uuid}"
|
| 630 |
-
val imageRef = storageRef.child(imageName)
|
| 631 |
-
|
| 632 |
-
val uploadTask = imageRef.putBytes(imageByteArray)
|
| 633 |
-
uploadTask.addOnFailureListener {
|
| 634 |
-
showLoading(false)
|
| 635 |
-
}.addOnSuccessListener {
|
| 636 |
-
Log.d(TAG, "Success upload to firebase storage")
|
| 637 |
-
showLoading(false)
|
| 638 |
-
|
| 639 |
-
mSelectedImageName = "$uuid"
|
| 640 |
-
mSelectedImage = imageByteArray
|
| 641 |
-
|
| 642 |
-
showLoadPhotoOverlay(imageByteArray)
|
| 643 |
-
}
|
| 644 |
-
}
|
| 645 |
-
|
| 646 |
-
/**
|
| 647 |
-
* @param imageByteArray ByteArray data for image to upload to firebase storage
|
| 648 |
-
*/
|
| 649 |
-
private fun uploadImageToFirebaseStorage(imageByteArray: ByteArray) {
|
| 650 |
-
showLoading(true, LOADING_UPLOADING_IAMGE)
|
| 651 |
-
val storageRef = FirebaseStorage.getInstance().reference
|
| 652 |
-
val uuid = UUID.randomUUID()
|
| 653 |
-
val imageName = "images/${uuid}"
|
| 654 |
-
val imageRef = storageRef.child(imageName)
|
| 655 |
-
|
| 656 |
-
val uploadTask = imageRef.putBytes(imageByteArray)
|
| 657 |
-
uploadTask.addOnFailureListener {
|
| 658 |
-
showLoading(false)
|
| 659 |
-
}.addOnSuccessListener {
|
| 660 |
-
Log.d(TAG, "Success upload to firebase storage")
|
| 661 |
-
|
| 662 |
-
showLoading(false)
|
| 663 |
-
httpClient.callImageUpload("$uuid")
|
| 664 |
-
}
|
| 665 |
-
}
|
| 666 |
-
|
| 667 |
-
override fun onSuccessResult(msg: String) {
|
| 668 |
-
showLoading(false)
|
| 669 |
-
try {
|
| 670 |
-
val json = JSONObject(msg)
|
| 671 |
-
if (json.has(RESPONSE_TYPE_PROGRAM)) {
|
| 672 |
-
when (json.getString(RESPONSE_TYPE_PROGRAM)) {
|
| 673 |
-
RESPONSE_TYPE_BROWSER -> {
|
| 674 |
-
addMessage(json.getString(RESPONSE_TYPE_URL), false)
|
| 675 |
-
openBrowser(json.getString(RESPONSE_TYPE_URL))
|
| 676 |
-
return
|
| 677 |
-
}
|
| 678 |
-
|
| 679 |
-
RESPONSE_TYPE_ALERT -> {
|
| 680 |
-
MyApplication.appContext.showNotification(
|
| 681 |
-
json.getString(
|
| 682 |
-
RESPONSE_TYPE_CONTENT
|
| 683 |
-
)
|
| 684 |
-
)
|
| 685 |
-
return
|
| 686 |
-
}
|
| 687 |
-
|
| 688 |
-
RESPONSE_TYPE_MESSAGE -> {
|
| 689 |
-
addMessage(json.getString(RESPONSE_TYPE_CONTENT), false)
|
| 690 |
-
return
|
| 691 |
-
}
|
| 692 |
-
|
| 693 |
-
RESPONSE_TYPE_IMAGE -> {
|
| 694 |
-
try {
|
| 695 |
-
val imageRes = JSONObject(json.getString(RESPONSE_TYPE_CONTENT))
|
| 696 |
-
|
| 697 |
-
val imageName = if (imageRes.has("image_name")) {
|
| 698 |
-
imageRes["image_name"] as String
|
| 699 |
-
} else {
|
| 700 |
-
""
|
| 701 |
-
}
|
| 702 |
-
|
| 703 |
-
val imageDesc = if (imageRes.has("image_desc")) {
|
| 704 |
-
imageRes["image_desc"] as String
|
| 705 |
-
} else {
|
| 706 |
-
""
|
| 707 |
-
}
|
| 708 |
-
|
| 709 |
-
getImageResponse(imageName, imageDesc)
|
| 710 |
-
} catch (e: Exception) {
|
| 711 |
-
e.printStackTrace()
|
| 712 |
-
}
|
| 713 |
-
return
|
| 714 |
-
}
|
| 715 |
-
|
| 716 |
-
RESPONSE_TYPE_SMS -> {
|
| 717 |
-
addMessage(
|
| 718 |
-
json.getString(RESPONSE_TYPE_CONTENT),
|
| 719 |
-
false,
|
| 720 |
-
isSend = false,
|
| 721 |
-
isWidget = true,
|
| 722 |
-
widgetType = MSG_WIDGET_TYPE_SMS
|
| 723 |
-
)
|
| 724 |
-
}
|
| 725 |
-
|
| 726 |
-
RESPONSE_TYPE_HELP_COMMAND -> {
|
| 727 |
-
try {
|
| 728 |
-
mHelpPromptList = Utils.instance.getHelpCommandListFromJsonString(
|
| 729 |
-
json.getString(RESPONSE_TYPE_CONTENT)
|
| 730 |
-
)
|
| 731 |
-
} catch (e: java.lang.Exception) {
|
| 732 |
-
e.printStackTrace()
|
| 733 |
-
showToast("JSON Error occured")
|
| 734 |
-
}
|
| 735 |
-
}
|
| 736 |
-
|
| 737 |
-
RESPONSE_TYPE_CONTACT -> {
|
| 738 |
-
try {
|
| 739 |
-
addMessage(
|
| 740 |
-
message = "Contacts that you are looking for.",
|
| 741 |
-
isMe = false,
|
| 742 |
-
isSend = false,
|
| 743 |
-
isWidget = true,
|
| 744 |
-
widgetType = MSG_WIDGET_TYPE_SEARCH_CONTACT,
|
| 745 |
-
widgetDescription = json.getString(RESPONSE_TYPE_CONTENT)
|
| 746 |
-
)
|
| 747 |
-
} catch (e: Exception) {
|
| 748 |
-
e.printStackTrace()
|
| 749 |
-
}
|
| 750 |
-
}
|
| 751 |
-
}
|
| 752 |
-
}
|
| 753 |
-
} catch (e: JSONException) {
|
| 754 |
-
e.printStackTrace()
|
| 755 |
-
addMessage(msg, false)
|
| 756 |
-
}
|
| 757 |
-
}
|
| 758 |
-
|
| 759 |
-
override fun onFailureResult(msg: String) {
|
| 760 |
-
showLoading(false)
|
| 761 |
-
|
| 762 |
-
showToast(msg)
|
| 763 |
-
}
|
| 764 |
-
|
| 765 |
-
private fun queryImagesFromExternalStorage(contentResolver: ContentResolver): ArrayList<Uri> {
|
| 766 |
-
val listOfImageUris = ArrayList<Uri>()
|
| 767 |
-
|
| 768 |
-
val projection = arrayOf(MediaStore.Images.Media._ID)
|
| 769 |
-
|
| 770 |
-
val sortOrder = "${MediaStore.Images.Media.DATE_TAKEN} DESC"
|
| 771 |
-
|
| 772 |
-
contentResolver.query(
|
| 773 |
-
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, sortOrder
|
| 774 |
-
)?.use { cursor ->
|
| 775 |
-
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
|
| 776 |
-
while (cursor.moveToNext()) {
|
| 777 |
-
val id = cursor.getLong(idColumn)
|
| 778 |
-
val contentUri = Uri.withAppendedPath(
|
| 779 |
-
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id.toString()
|
| 780 |
-
)
|
| 781 |
-
listOfImageUris.add(contentUri)
|
| 782 |
-
}
|
| 783 |
-
}
|
| 784 |
-
return listOfImageUris
|
| 785 |
-
}
|
| 786 |
-
|
| 787 |
-
private fun trainImages() {
|
| 788 |
-
CoroutineScope(Dispatchers.IO).launch {
|
| 789 |
-
val images = queryImagesFromExternalStorage(requireContext().contentResolver)
|
| 790 |
-
val originalImages = mRoomDataHandler.imageDao().getAllImages()
|
| 791 |
-
|
| 792 |
-
images.forEach { uri ->
|
| 793 |
-
var isExist = false
|
| 794 |
-
val path = Utils.instance.getRealPathFromUri(requireContext(), uri)
|
| 795 |
-
for (i in originalImages.indices) {
|
| 796 |
-
val entity: ImageEntity = originalImages[i]
|
| 797 |
-
if (entity.path == path) {
|
| 798 |
-
isExist = true
|
| 799 |
-
break
|
| 800 |
-
}
|
| 801 |
-
}
|
| 802 |
-
if (!isExist) {
|
| 803 |
-
val byteArray = Utils.instance.getBytesFromPath(path)
|
| 804 |
-
val uuid = uploadImageToFirebaseStorage(byteArray)
|
| 805 |
-
|
| 806 |
-
if (path != null)
|
| 807 |
-
mRoomDataHandler.imageDao().insertImage(ImageEntity(0, path, "$uuid"))
|
| 808 |
-
}
|
| 809 |
-
}
|
| 810 |
-
}
|
| 811 |
-
}
|
| 812 |
-
|
| 813 |
-
private fun trainContacts() {
|
| 814 |
-
showLoading(true, "Train Contacts")
|
| 815 |
-
val contacts = Utils.instance.getContacts(mContext!!)
|
| 816 |
-
CoroutineScope(Dispatchers.Main).launch {
|
| 817 |
-
val changedContacts = Utils.instance.getChangedContacts(contacts, mRoomDataHandler)
|
| 818 |
-
httpClient.trainContacts(changedContacts)
|
| 819 |
-
}
|
| 820 |
-
}
|
| 821 |
-
|
| 822 |
-
fun sendSms(phoneNumber: String, message: String) {
|
| 823 |
-
try {
|
| 824 |
-
val smsManager = SmsManager.getDefault()
|
| 825 |
-
val parts = smsManager.divideMessage(message)
|
| 826 |
-
smsManager.sendMultipartTextMessage(/* destinationAddress = */ phoneNumber, /* scAddress = */
|
| 827 |
-
null, /* parts = */
|
| 828 |
-
parts, /* sentIntents = */
|
| 829 |
-
null, /* deliveryIntents = */
|
| 830 |
-
null)
|
| 831 |
-
} catch (e: SecurityException) {
|
| 832 |
-
e.printStackTrace()
|
| 833 |
-
} catch (e: Exception) {
|
| 834 |
-
e.printStackTrace()
|
| 835 |
-
}
|
| 836 |
-
}
|
| 837 |
-
|
| 838 |
-
@SuppressLint("UseRequireInsteadOfGet")
|
| 839 |
-
fun runOnUIThread(action: () -> Unit) {
|
| 840 |
-
requireActivity().runOnUiThread {
|
| 841 |
-
action()
|
| 842 |
-
}
|
| 843 |
-
}
|
| 844 |
-
|
| 845 |
-
private fun showSlidingWidget() {
|
| 846 |
-
val slidingWidget = rootView.findViewById<View>(R.id.ll_toolbar)
|
| 847 |
-
|
| 848 |
-
val dy = slidingWidget.measuredHeight.toFloat()
|
| 849 |
-
slidingWidget.visibility = View.VISIBLE
|
| 850 |
-
|
| 851 |
-
val anim = TranslateAnimation(0f, 0f, dy, 0f).apply {
|
| 852 |
-
duration = 150 // Set the animation duration, e.g., 300ms
|
| 853 |
-
interpolator = AccelerateDecelerateInterpolator()
|
| 854 |
-
setAnimationListener(object : Animation.AnimationListener {
|
| 855 |
-
override fun onAnimationStart(animation: Animation?) {
|
| 856 |
-
slidingWidget.visibility = View.VISIBLE
|
| 857 |
-
}
|
| 858 |
-
|
| 859 |
-
override fun onAnimationEnd(animation: Animation?) {}
|
| 860 |
-
|
| 861 |
-
override fun onAnimationRepeat(animation: Animation?) {}
|
| 862 |
-
})
|
| 863 |
-
}
|
| 864 |
-
|
| 865 |
-
slidingWidget.startAnimation(anim)
|
| 866 |
-
}
|
| 867 |
-
|
| 868 |
-
private fun hideSlidingWidget() {
|
| 869 |
-
val slidingWidget = rootView.findViewById<View>(R.id.ll_toolbar)
|
| 870 |
-
|
| 871 |
-
val anim = AlphaAnimation(1f, 0f).apply {
|
| 872 |
-
duration = 100 // Set the animation duration, e.g., 300ms
|
| 873 |
-
interpolator = AccelerateDecelerateInterpolator()
|
| 874 |
-
setAnimationListener(object : Animation.AnimationListener {
|
| 875 |
-
override fun onAnimationStart(animation: Animation?) {}
|
| 876 |
-
|
| 877 |
-
override fun onAnimationEnd(animation: Animation?) {
|
| 878 |
-
slidingWidget.visibility = View.GONE
|
| 879 |
-
}
|
| 880 |
-
|
| 881 |
-
override fun onAnimationRepeat(animation: Animation?) {}
|
| 882 |
-
})
|
| 883 |
-
}
|
| 884 |
-
|
| 885 |
-
slidingWidget.startAnimation(anim)
|
| 886 |
-
}
|
| 887 |
-
}
|
| 888 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/common/ContactModel.kt
DELETED
|
@@ -1,19 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.models.common
|
| 2 |
-
|
| 3 |
-
class ContactModel {
|
| 4 |
-
var id: String = ""
|
| 5 |
-
var name: String = ""
|
| 6 |
-
var phoneList: ArrayList<String>? = null
|
| 7 |
-
var status: String = ""
|
| 8 |
-
|
| 9 |
-
init {
|
| 10 |
-
phoneList = ArrayList()
|
| 11 |
-
}
|
| 12 |
-
|
| 13 |
-
fun setData(id: String, name: String, phoneList: ArrayList<String>, status: String) {
|
| 14 |
-
this.id = id
|
| 15 |
-
this.name = name
|
| 16 |
-
this.phoneList = phoneList
|
| 17 |
-
this.status = status
|
| 18 |
-
}
|
| 19 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/common/HelpCommandModel.kt
DELETED
|
@@ -1,10 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.models.common
|
| 2 |
-
|
| 3 |
-
class HelpCommandModel {
|
| 4 |
-
var mainCommandName: String = ""
|
| 5 |
-
var assistCommandName: String = ""
|
| 6 |
-
|
| 7 |
-
fun isMainCommand(): Boolean {
|
| 8 |
-
return mainCommandName != "help"
|
| 9 |
-
}
|
| 10 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/common/HelpPromptModel.kt
DELETED
|
@@ -1,25 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.models.common
|
| 2 |
-
|
| 3 |
-
import com.google.gson.Gson
|
| 4 |
-
import com.google.gson.GsonBuilder
|
| 5 |
-
|
| 6 |
-
class HelpPromptModel {
|
| 7 |
-
var name: String = ""
|
| 8 |
-
var description: String = ""
|
| 9 |
-
var prompt: String = ""
|
| 10 |
-
var tags: ArrayList<String>? = null
|
| 11 |
-
|
| 12 |
-
override fun toString(): String {
|
| 13 |
-
val gson = Gson()
|
| 14 |
-
val str = gson.toJson(this)
|
| 15 |
-
return str
|
| 16 |
-
}
|
| 17 |
-
|
| 18 |
-
companion object {
|
| 19 |
-
fun initModelWithString(strJson: String): HelpPromptModel {
|
| 20 |
-
val gson = Gson()
|
| 21 |
-
val model: HelpPromptModel = gson.fromJson(strJson, HelpPromptModel::class.java)
|
| 22 |
-
return model
|
| 23 |
-
}
|
| 24 |
-
}
|
| 25 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/common/ImagePromptModel.kt
DELETED
|
@@ -1,11 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.models.common
|
| 2 |
-
|
| 3 |
-
class ImagePromptModel {
|
| 4 |
-
var id: String = ""
|
| 5 |
-
var path: String = ""
|
| 6 |
-
|
| 7 |
-
constructor(id: String, path: String) {
|
| 8 |
-
this.id = id
|
| 9 |
-
this.path = path
|
| 10 |
-
}
|
| 11 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/requestmodels/RequestBodyModel.kt
DELETED
|
@@ -1,86 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.models.requestmodels
|
| 2 |
-
|
| 3 |
-
import com.matthaigh27.chatgptwrapper.MyApplication
|
| 4 |
-
import org.json.JSONException
|
| 5 |
-
import org.json.JSONObject
|
| 6 |
-
|
| 7 |
-
class RequestBodyModel(builder: Builder) {
|
| 8 |
-
|
| 9 |
-
/** this identify request type
|
| 10 |
-
* example: it will be 'message' when users send message, 'image' when users upload image
|
| 11 |
-
*/
|
| 12 |
-
var type: String = ""
|
| 13 |
-
var token: String = ""
|
| 14 |
-
var message: String = ""
|
| 15 |
-
var imageName: String = ""
|
| 16 |
-
var uuid: String = ""
|
| 17 |
-
|
| 18 |
-
init {
|
| 19 |
-
this.token = MyApplication.appContext.getFCMToken()
|
| 20 |
-
this.uuid = MyApplication.appContext.getUUID()
|
| 21 |
-
this.message = builder.message
|
| 22 |
-
this.imageName = builder.imageName
|
| 23 |
-
}
|
| 24 |
-
|
| 25 |
-
@Throws(JSONException::class)
|
| 26 |
-
fun buildJsonObject(): JSONObject {
|
| 27 |
-
|
| 28 |
-
val jsonObject = JSONObject()
|
| 29 |
-
jsonObject.accumulate("type", type)
|
| 30 |
-
jsonObject.accumulate("token", token)
|
| 31 |
-
jsonObject.accumulate("message", message)
|
| 32 |
-
jsonObject.accumulate("image_name", imageName)
|
| 33 |
-
jsonObject.accumulate("uuid", uuid)
|
| 34 |
-
|
| 35 |
-
return jsonObject
|
| 36 |
-
}
|
| 37 |
-
|
| 38 |
-
class Builder {
|
| 39 |
-
var type: String = ""
|
| 40 |
-
var token: String = ""
|
| 41 |
-
var message: String = ""
|
| 42 |
-
var imageName: String = ""
|
| 43 |
-
var uuid: String = ""
|
| 44 |
-
|
| 45 |
-
constructor() {
|
| 46 |
-
|
| 47 |
-
}
|
| 48 |
-
|
| 49 |
-
constructor(request: RequestBodyModel) {
|
| 50 |
-
this.type = request.type
|
| 51 |
-
this.token = request.token
|
| 52 |
-
this.message = request.message
|
| 53 |
-
this.imageName = request.imageName
|
| 54 |
-
this.uuid = request.uuid
|
| 55 |
-
}
|
| 56 |
-
|
| 57 |
-
fun type(type: String): Builder {
|
| 58 |
-
this.type = type
|
| 59 |
-
return this
|
| 60 |
-
}
|
| 61 |
-
|
| 62 |
-
fun token(token: String): Builder {
|
| 63 |
-
this.token = token
|
| 64 |
-
return this
|
| 65 |
-
}
|
| 66 |
-
|
| 67 |
-
fun message(message: String): Builder {
|
| 68 |
-
this.message = message
|
| 69 |
-
return this
|
| 70 |
-
}
|
| 71 |
-
|
| 72 |
-
fun imageName(imageName: String): Builder {
|
| 73 |
-
this.imageName = imageName
|
| 74 |
-
return this
|
| 75 |
-
}
|
| 76 |
-
|
| 77 |
-
fun uuid(uuid: String): Builder {
|
| 78 |
-
this.uuid = uuid
|
| 79 |
-
return this
|
| 80 |
-
}
|
| 81 |
-
|
| 82 |
-
fun build(): RequestBodyModel {
|
| 83 |
-
return RequestBodyModel(this)
|
| 84 |
-
}
|
| 85 |
-
}
|
| 86 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/requestmodels/RequestTrainContactModel.kt
DELETED
|
@@ -1,79 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.models.requestmodels
|
| 2 |
-
|
| 3 |
-
import com.matthaigh27.chatgptwrapper.MyApplication
|
| 4 |
-
import com.matthaigh27.chatgptwrapper.models.common.ContactModel
|
| 5 |
-
import com.matthaigh27.chatgptwrapper.utils.Utils
|
| 6 |
-
import org.json.JSONArray
|
| 7 |
-
import org.json.JSONException
|
| 8 |
-
import org.json.JSONObject
|
| 9 |
-
|
| 10 |
-
class RequestTrainContactModel(builder: Builder) {
|
| 11 |
-
|
| 12 |
-
/** this identify request type
|
| 13 |
-
* example: it will be 'message' when users send message, 'image' when users upload image
|
| 14 |
-
*/
|
| 15 |
-
var type: String = ""
|
| 16 |
-
var token: String = ""
|
| 17 |
-
var contacts = JSONArray()
|
| 18 |
-
var uuid: String = ""
|
| 19 |
-
|
| 20 |
-
init {
|
| 21 |
-
this.token = MyApplication.appContext.getFCMToken()
|
| 22 |
-
this.uuid = MyApplication.appContext.getUUID()
|
| 23 |
-
this.contacts = builder.contacts
|
| 24 |
-
}
|
| 25 |
-
|
| 26 |
-
@Throws(JSONException::class)
|
| 27 |
-
fun buildJsonObject(): JSONObject {
|
| 28 |
-
|
| 29 |
-
val jsonObject = JSONObject()
|
| 30 |
-
jsonObject.accumulate("type", type)
|
| 31 |
-
jsonObject.accumulate("token", token)
|
| 32 |
-
jsonObject.accumulate("contacts", contacts)
|
| 33 |
-
jsonObject.accumulate("uuid", uuid)
|
| 34 |
-
|
| 35 |
-
return jsonObject
|
| 36 |
-
}
|
| 37 |
-
|
| 38 |
-
class Builder {
|
| 39 |
-
var type: String = ""
|
| 40 |
-
var token: String = ""
|
| 41 |
-
var contacts = JSONArray()
|
| 42 |
-
var uuid: String = ""
|
| 43 |
-
|
| 44 |
-
constructor() {
|
| 45 |
-
|
| 46 |
-
}
|
| 47 |
-
|
| 48 |
-
constructor(request: RequestTrainContactModel) {
|
| 49 |
-
this.type = request.type
|
| 50 |
-
this.token = request.token
|
| 51 |
-
this.uuid = request.uuid
|
| 52 |
-
this.contacts = request.contacts
|
| 53 |
-
}
|
| 54 |
-
|
| 55 |
-
fun type(type: String): Builder {
|
| 56 |
-
this.type = type
|
| 57 |
-
return this
|
| 58 |
-
}
|
| 59 |
-
|
| 60 |
-
fun token(token: String): Builder {
|
| 61 |
-
this.token = token
|
| 62 |
-
return this
|
| 63 |
-
}
|
| 64 |
-
|
| 65 |
-
fun contacts(contacts: ArrayList<ContactModel>): Builder {
|
| 66 |
-
this.contacts = Utils.instance.convertContactModelToJsonArray(contacts)
|
| 67 |
-
return this
|
| 68 |
-
}
|
| 69 |
-
|
| 70 |
-
fun uuid(uuid: String): Builder {
|
| 71 |
-
this.uuid = uuid
|
| 72 |
-
return this
|
| 73 |
-
}
|
| 74 |
-
|
| 75 |
-
fun build(): RequestTrainContactModel {
|
| 76 |
-
return RequestTrainContactModel(this)
|
| 77 |
-
}
|
| 78 |
-
}
|
| 79 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/models/viewmodels/ChatMessageModel.kt
DELETED
|
@@ -1,18 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.models.viewmodels
|
| 2 |
-
|
| 3 |
-
import androidx.lifecycle.ViewModel
|
| 4 |
-
|
| 5 |
-
/**
|
| 6 |
-
* ChatModel for Chat RecyclerView
|
| 7 |
-
*/
|
| 8 |
-
class ChatMessageModel: ViewModel() {
|
| 9 |
-
var message: String = ""
|
| 10 |
-
var isMe: Boolean = true
|
| 11 |
-
var image: ByteArray? = null
|
| 12 |
-
var imageName: String = ""
|
| 13 |
-
var visibleFeedback = false
|
| 14 |
-
var feedback = 0
|
| 15 |
-
var isWidget: Boolean = false
|
| 16 |
-
var widgetType = ""
|
| 17 |
-
var widgetDescription = ""
|
| 18 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/services/MessageService.kt
DELETED
|
@@ -1,32 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.services
|
| 2 |
-
|
| 3 |
-
import android.content.Intent
|
| 4 |
-
import android.util.Log
|
| 5 |
-
import com.google.firebase.messaging.FirebaseMessagingService
|
| 6 |
-
import com.google.firebase.messaging.RemoteMessage
|
| 7 |
-
import com.matthaigh27.chatgptwrapper.utils.Constants.TAG
|
| 8 |
-
|
| 9 |
-
class MessageService : FirebaseMessagingService() {
|
| 10 |
-
|
| 11 |
-
/**
|
| 12 |
-
* this function is called when langchain server pushs notification into FCM
|
| 13 |
-
* @param remoteMessage is sent by FCM when langchain server pushs notification
|
| 14 |
-
*/
|
| 15 |
-
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
| 16 |
-
super.onMessageReceived(remoteMessage)
|
| 17 |
-
if (remoteMessage.notification != null) {
|
| 18 |
-
Log.d(
|
| 19 |
-
TAG, "Message Notification Body: " + remoteMessage.notification!!.body
|
| 20 |
-
)
|
| 21 |
-
|
| 22 |
-
/** intent for sending broadcast to ChatActivity */
|
| 23 |
-
val intent = Intent()
|
| 24 |
-
intent.action = "android.intent.action.MAIN"
|
| 25 |
-
intent.putExtra("message", remoteMessage.notification!!.body)
|
| 26 |
-
|
| 27 |
-
/** send broadcast to ChatActivity
|
| 28 |
-
* So ChatActivity can receive remoteMessage from this service */
|
| 29 |
-
sendBroadcast(intent)
|
| 30 |
-
}
|
| 31 |
-
}
|
| 32 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/services/api/HttpClient.kt
DELETED
|
@@ -1,117 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.services.api
|
| 2 |
-
|
| 3 |
-
import android.util.Log
|
| 4 |
-
import com.matthaigh27.chatgptwrapper.BuildConfig
|
| 5 |
-
import com.matthaigh27.chatgptwrapper.models.common.ContactModel
|
| 6 |
-
import com.matthaigh27.chatgptwrapper.models.requestmodels.RequestBodyModel
|
| 7 |
-
import com.matthaigh27.chatgptwrapper.models.requestmodels.RequestTrainContactModel
|
| 8 |
-
import com.matthaigh27.chatgptwrapper.utils.Constants
|
| 9 |
-
import com.matthaigh27.chatgptwrapper.utils.Constants.GET
|
| 10 |
-
import com.matthaigh27.chatgptwrapper.utils.Constants.POST
|
| 11 |
-
import com.matthaigh27.chatgptwrapper.utils.ReqType
|
| 12 |
-
import okhttp3.Call
|
| 13 |
-
import okhttp3.Callback
|
| 14 |
-
import okhttp3.OkHttpClient
|
| 15 |
-
import okhttp3.Request
|
| 16 |
-
import okhttp3.RequestBody
|
| 17 |
-
import okhttp3.Response
|
| 18 |
-
import org.json.JSONException
|
| 19 |
-
import org.json.JSONObject
|
| 20 |
-
import java.io.IOException
|
| 21 |
-
import java.util.concurrent.TimeUnit
|
| 22 |
-
|
| 23 |
-
class HttpClient {
|
| 24 |
-
/* Server URL and Api Endpoints */
|
| 25 |
-
val SERVER_URL = BuildConfig.BASE_URL
|
| 26 |
-
val SEND_NOTIFICATION_URL = SERVER_URL + "sendNotification"
|
| 27 |
-
val IMAGE_RELATEDNESS = SERVER_URL + "image_relatedness"
|
| 28 |
-
val UPLOAD_IMAGE = SERVER_URL + "uploadImage"
|
| 29 |
-
val GET_ALL_HELP_COMMANDS = SERVER_URL + "commands"
|
| 30 |
-
val TRAIN_CONTACTS = SERVER_URL + "train/contacts"
|
| 31 |
-
|
| 32 |
-
var mCallback: HttpRisingInterface
|
| 33 |
-
|
| 34 |
-
constructor(callback: HttpRisingInterface) {
|
| 35 |
-
mCallback = callback
|
| 36 |
-
}
|
| 37 |
-
|
| 38 |
-
private fun sendOkHttpRequest(postBody: String, postUrl: String, method: String) {
|
| 39 |
-
val body: RequestBody = RequestBody.create(Constants.JSON, postBody)
|
| 40 |
-
|
| 41 |
-
/**
|
| 42 |
-
* set okhttpclient timeout to 120s
|
| 43 |
-
*/
|
| 44 |
-
var request: Request? = null
|
| 45 |
-
if (method == POST) request = Request.Builder().url(postUrl).post(body).build()
|
| 46 |
-
else request = Request.Builder().url(postUrl).get().build()
|
| 47 |
-
|
| 48 |
-
val client =
|
| 49 |
-
OkHttpClient.Builder().connectTimeout(Constants.CUSTOM_TIMEOUT, TimeUnit.SECONDS)
|
| 50 |
-
.readTimeout(Constants.CUSTOM_TIMEOUT, TimeUnit.SECONDS)
|
| 51 |
-
.writeTimeout(Constants.CUSTOM_TIMEOUT, TimeUnit.SECONDS).build()
|
| 52 |
-
|
| 53 |
-
client.newCall(request).enqueue(object : Callback {
|
| 54 |
-
override fun onFailure(call: Call, e: IOException) {
|
| 55 |
-
/**
|
| 56 |
-
* Handle failure
|
| 57 |
-
*/
|
| 58 |
-
e.printStackTrace()
|
| 59 |
-
|
| 60 |
-
mCallback.onFailureResult("Fail to send request to server. Please ask again.")
|
| 61 |
-
}
|
| 62 |
-
|
| 63 |
-
override fun onResponse(call: Call, response: Response) {
|
| 64 |
-
val myResponse = response.body()!!.string()
|
| 65 |
-
Log.d(Constants.TAG, myResponse)
|
| 66 |
-
|
| 67 |
-
try {
|
| 68 |
-
val json = JSONObject(myResponse)["result"].toString()
|
| 69 |
-
mCallback.onSuccessResult(json)
|
| 70 |
-
} catch (e: JSONException) {
|
| 71 |
-
mCallback.onFailureResult(myResponse)
|
| 72 |
-
e.printStackTrace()
|
| 73 |
-
}
|
| 74 |
-
}
|
| 75 |
-
})
|
| 76 |
-
}
|
| 77 |
-
|
| 78 |
-
/* call sendNotification */
|
| 79 |
-
fun callSendNotification(message: String) {
|
| 80 |
-
sendOkHttpRequest(
|
| 81 |
-
RequestBodyModel.Builder().message(message).type(ReqType.instance.MESSAGE).build()
|
| 82 |
-
.buildJsonObject().toString(), SEND_NOTIFICATION_URL, POST
|
| 83 |
-
)
|
| 84 |
-
}
|
| 85 |
-
|
| 86 |
-
/* call image_relatedness */
|
| 87 |
-
fun callImageRelatedness(imageName: String) {
|
| 88 |
-
sendOkHttpRequest(
|
| 89 |
-
RequestBodyModel.Builder().imageName(imageName).type(ReqType.instance.MESSAGE).build()
|
| 90 |
-
.buildJsonObject().toString(), IMAGE_RELATEDNESS, POST
|
| 91 |
-
)
|
| 92 |
-
}
|
| 93 |
-
|
| 94 |
-
/* call image_upload */
|
| 95 |
-
fun callImageUpload(imageName: String) {
|
| 96 |
-
sendOkHttpRequest(
|
| 97 |
-
RequestBodyModel.Builder().imageName(imageName).type(ReqType.instance.IMAGE_UPLOAD)
|
| 98 |
-
.build().buildJsonObject().toString(), UPLOAD_IMAGE, POST
|
| 99 |
-
)
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
fun getALlHelpPromptCommands() {
|
| 103 |
-
sendOkHttpRequest(
|
| 104 |
-
RequestBodyModel.Builder().build().buildJsonObject().toString(),
|
| 105 |
-
GET_ALL_HELP_COMMANDS,
|
| 106 |
-
GET
|
| 107 |
-
)
|
| 108 |
-
}
|
| 109 |
-
|
| 110 |
-
fun trainContacts(contacts: ArrayList<ContactModel>) {
|
| 111 |
-
sendOkHttpRequest(
|
| 112 |
-
RequestTrainContactModel.Builder().contacts(contacts).build().buildJsonObject().toString(),
|
| 113 |
-
TRAIN_CONTACTS,
|
| 114 |
-
POST
|
| 115 |
-
)
|
| 116 |
-
}
|
| 117 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/services/api/HttpRisingInterface.kt
DELETED
|
@@ -1,7 +0,0 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.services.api;
|
| 2 |
-
|
| 3 |
-
interface HttpRisingInterface {
|
| 4 |
-
fun onSuccessResult(msg: String)
|
| 5 |
-
|
| 6 |
-
fun onFailureResult(msg: String)
|
| 7 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/base/BaseActivity.kt
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.base
|
| 2 |
+
|
| 3 |
+
import android.os.Bundle
|
| 4 |
+
import android.view.View
|
| 5 |
+
import androidx.appcompat.app.AppCompatActivity
|
| 6 |
+
|
| 7 |
+
open class BaseActivity : AppCompatActivity() {
|
| 8 |
+
|
| 9 |
+
override fun onCreate(savedInstanceState: Bundle?) {
|
| 10 |
+
super.onCreate(savedInstanceState)
|
| 11 |
+
|
| 12 |
+
// Hide the status bar (system toolbar)
|
| 13 |
+
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
|
| 14 |
+
|
| 15 |
+
// For hiding the action bar, if you have one
|
| 16 |
+
supportActionBar?.hide()
|
| 17 |
+
}
|
| 18 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{activites/HomeActivity.kt → ui/chat/view/ChatActivity.kt}
RENAMED
|
@@ -1,39 +1,38 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.
|
| 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 android.util.Log
|
| 9 |
-
import androidx.appcompat.app.AlertDialog
|
| 10 |
import androidx.appcompat.app.AppCompatActivity
|
| 11 |
-
import com.google.android.material.tabs.TabLayout.TabGravity
|
| 12 |
import com.matthaigh27.chatgptwrapper.R
|
| 13 |
-
import com.matthaigh27.chatgptwrapper.
|
| 14 |
-
import com.matthaigh27.chatgptwrapper.
|
| 15 |
-
import
|
| 16 |
|
| 17 |
|
| 18 |
-
class
|
| 19 |
|
| 20 |
private val PERMISSIONS_REQUEST_CODE = 1
|
| 21 |
-
|
| 22 |
private val PERMISSIONS = arrayOf(
|
| 23 |
Manifest.permission.SEND_SMS,
|
| 24 |
Manifest.permission.READ_CONTACTS,
|
| 25 |
Manifest.permission.CALL_PHONE,
|
| 26 |
Manifest.permission.READ_EXTERNAL_STORAGE
|
| 27 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
override fun onCreate(savedInstanceState: Bundle?) {
|
| 30 |
super.onCreate(savedInstanceState)
|
| 31 |
-
setContentView(R.layout.
|
| 32 |
|
| 33 |
-
|
| 34 |
}
|
| 35 |
|
| 36 |
-
private fun
|
| 37 |
val notGrantedPermissions = PERMISSIONS.filter {
|
| 38 |
checkSelfPermission(it) != PackageManager.PERMISSION_GRANTED
|
| 39 |
}
|
|
@@ -41,10 +40,9 @@ class HomeActivity : AppCompatActivity() {
|
|
| 41 |
if (notGrantedPermissions.isNotEmpty()) {
|
| 42 |
if (shouldShowRequestPermissionRationale(notGrantedPermissions[0])) {
|
| 43 |
// show custom permission rationale
|
| 44 |
-
val confirmDialog =
|
| 45 |
-
confirmDialog.setMessage("This app requires SMS, Contacts and Phone permissions to function properly. Please grant the necessary permissions.")
|
| 46 |
confirmDialog.setOnClickListener(object :
|
| 47 |
-
|
| 48 |
override fun onPositiveButtonClick() {
|
| 49 |
requestPermissions(
|
| 50 |
notGrantedPermissions.toTypedArray(), PERMISSIONS_REQUEST_CODE
|
|
@@ -55,21 +53,19 @@ class HomeActivity : AppCompatActivity() {
|
|
| 55 |
finish()
|
| 56 |
}
|
| 57 |
})
|
|
|
|
| 58 |
confirmDialog.show()
|
|
|
|
|
|
|
| 59 |
} else {
|
| 60 |
requestPermissions(notGrantedPermissions.toTypedArray(), PERMISSIONS_REQUEST_CODE)
|
| 61 |
}
|
| 62 |
} else {
|
| 63 |
// Permissions already granted, navigate to your desired fragment
|
| 64 |
-
|
| 65 |
}
|
| 66 |
}
|
| 67 |
|
| 68 |
-
private fun navigateToChatFragment() {
|
| 69 |
-
val fragmentTransaction = supportFragmentManager.beginTransaction()
|
| 70 |
-
fragmentTransaction.replace(R.id.frame_container, ChatFragment()).commit()
|
| 71 |
-
}
|
| 72 |
-
|
| 73 |
@SuppressLint("MissingSuperCall")
|
| 74 |
override fun onRequestPermissionsResult(
|
| 75 |
requestCode: Int, permissions: Array<out String>, grantResults: IntArray
|
|
@@ -78,14 +74,19 @@ class HomeActivity : AppCompatActivity() {
|
|
| 78 |
PERMISSIONS_REQUEST_CODE -> {
|
| 79 |
if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
|
| 80 |
// Permissions granted, navigate to your desired fragment
|
| 81 |
-
|
| 82 |
} else {
|
| 83 |
-
|
| 84 |
}
|
| 85 |
return
|
| 86 |
}
|
| 87 |
}
|
| 88 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
}
|
| 90 |
|
| 91 |
|
|
|
|
| 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.Bundle
|
|
|
|
|
|
|
| 7 |
import androidx.appcompat.app.AppCompatActivity
|
|
|
|
| 8 |
import com.matthaigh27.chatgptwrapper.R
|
| 9 |
+
import com.matthaigh27.chatgptwrapper.ui.base.BaseActivity
|
| 10 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.dialogs.ConfirmDialog
|
| 11 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.fragments.ChatMainFragment
|
| 12 |
|
| 13 |
|
| 14 |
+
class ChatActivity : BaseActivity() {
|
| 15 |
|
| 16 |
private val PERMISSIONS_REQUEST_CODE = 1
|
|
|
|
| 17 |
private val PERMISSIONS = arrayOf(
|
| 18 |
Manifest.permission.SEND_SMS,
|
| 19 |
Manifest.permission.READ_CONTACTS,
|
| 20 |
Manifest.permission.CALL_PHONE,
|
| 21 |
Manifest.permission.READ_EXTERNAL_STORAGE
|
| 22 |
)
|
| 23 |
+
private val CONFIRM_MESSAGE =
|
| 24 |
+
"This app requires SMS, Contacts and Phone " +
|
| 25 |
+
"permissions to function properly. " +
|
| 26 |
+
"Please grant the necessary permissions."
|
| 27 |
|
| 28 |
override fun onCreate(savedInstanceState: Bundle?) {
|
| 29 |
super.onCreate(savedInstanceState)
|
| 30 |
+
setContentView(R.layout.activity_chat)
|
| 31 |
|
| 32 |
+
requestPermissions()
|
| 33 |
}
|
| 34 |
|
| 35 |
+
private fun requestPermissions() {
|
| 36 |
val notGrantedPermissions = PERMISSIONS.filter {
|
| 37 |
checkSelfPermission(it) != PackageManager.PERMISSION_GRANTED
|
| 38 |
}
|
|
|
|
| 40 |
if (notGrantedPermissions.isNotEmpty()) {
|
| 41 |
if (shouldShowRequestPermissionRationale(notGrantedPermissions[0])) {
|
| 42 |
// show custom permission rationale
|
| 43 |
+
val confirmDialog = ConfirmDialog(this@ChatActivity)
|
|
|
|
| 44 |
confirmDialog.setOnClickListener(object :
|
| 45 |
+
ConfirmDialog.OnDialogButtonClickListener {
|
| 46 |
override fun onPositiveButtonClick() {
|
| 47 |
requestPermissions(
|
| 48 |
notGrantedPermissions.toTypedArray(), PERMISSIONS_REQUEST_CODE
|
|
|
|
| 53 |
finish()
|
| 54 |
}
|
| 55 |
})
|
| 56 |
+
|
| 57 |
confirmDialog.show()
|
| 58 |
+
confirmDialog.setMessage(CONFIRM_MESSAGE)
|
| 59 |
+
|
| 60 |
} else {
|
| 61 |
requestPermissions(notGrantedPermissions.toTypedArray(), PERMISSIONS_REQUEST_CODE)
|
| 62 |
}
|
| 63 |
} else {
|
| 64 |
// Permissions already granted, navigate to your desired fragment
|
| 65 |
+
navigateToChatMainFragment()
|
| 66 |
}
|
| 67 |
}
|
| 68 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
@SuppressLint("MissingSuperCall")
|
| 70 |
override fun onRequestPermissionsResult(
|
| 71 |
requestCode: Int, permissions: Array<out String>, grantResults: IntArray
|
|
|
|
| 74 |
PERMISSIONS_REQUEST_CODE -> {
|
| 75 |
if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
|
| 76 |
// Permissions granted, navigate to your desired fragment
|
| 77 |
+
navigateToChatMainFragment()
|
| 78 |
} else {
|
| 79 |
+
requestPermissions()
|
| 80 |
}
|
| 81 |
return
|
| 82 |
}
|
| 83 |
}
|
| 84 |
}
|
| 85 |
+
|
| 86 |
+
private fun navigateToChatMainFragment() {
|
| 87 |
+
val fragmentTransaction = supportFragmentManager.beginTransaction()
|
| 88 |
+
fragmentTransaction.replace(R.id.fl_container, ChatMainFragment()).commit()
|
| 89 |
+
}
|
| 90 |
}
|
| 91 |
|
| 92 |
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/adapters/ChatMainAdapter.kt
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.chat.view.adapters
|
| 2 |
+
|
| 3 |
+
import android.content.Context
|
| 4 |
+
import android.graphics.BitmapFactory
|
| 5 |
+
import android.view.LayoutInflater
|
| 6 |
+
import android.view.View
|
| 7 |
+
import android.view.ViewGroup
|
| 8 |
+
import android.widget.FrameLayout
|
| 9 |
+
import android.widget.ImageView
|
| 10 |
+
import android.widget.TextView
|
| 11 |
+
import androidx.constraintlayout.widget.ConstraintLayout
|
| 12 |
+
import androidx.recyclerview.widget.RecyclerView
|
| 13 |
+
import com.matthaigh27.chatgptwrapper.R
|
| 14 |
+
import com.matthaigh27.chatgptwrapper.data.models.ChatMessageModel
|
| 15 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
|
| 16 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.SendSmsWidget
|
| 17 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.helpprompt.HelpPromptWidget
|
| 18 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants
|
| 19 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.ImageHelper
|
| 20 |
+
|
| 21 |
+
class ChatMainAdapter(
|
| 22 |
+
context: Context, list: ArrayList<ChatMessageModel>, callbacks: ChatMessageInterface
|
| 23 |
+
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
| 24 |
+
|
| 25 |
+
private val VIEW_TYPE_MSG_SENT = 0
|
| 26 |
+
private val VIEW_TYPE_MSG_RECEIVED = 1
|
| 27 |
+
private val VIEW_TYPE_CHAT_WIDGET = 2
|
| 28 |
+
|
| 29 |
+
private var context: Context
|
| 30 |
+
private var callbacks: ChatMessageInterface
|
| 31 |
+
private var chatMessageList: ArrayList<ChatMessageModel> = ArrayList()
|
| 32 |
+
|
| 33 |
+
init {
|
| 34 |
+
this.context = context
|
| 35 |
+
this.chatMessageList = list
|
| 36 |
+
this.callbacks = callbacks
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
| 40 |
+
val inflater = LayoutInflater.from(context)
|
| 41 |
+
|
| 42 |
+
return when (viewType) {
|
| 43 |
+
VIEW_TYPE_MSG_SENT -> {
|
| 44 |
+
SentMessageViewHolder(
|
| 45 |
+
inflater.inflate(
|
| 46 |
+
R.layout.item_container_sent_message, parent, false
|
| 47 |
+
)
|
| 48 |
+
)
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
VIEW_TYPE_MSG_RECEIVED -> {
|
| 52 |
+
ReceivedMessageViewHolder(
|
| 53 |
+
inflater.inflate(
|
| 54 |
+
R.layout.item_container_received_message, parent, false
|
| 55 |
+
)
|
| 56 |
+
)
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
else -> {
|
| 60 |
+
ChatWidgetViewHolder(
|
| 61 |
+
inflater.inflate(
|
| 62 |
+
R.layout.item_container_chat_widget, parent, false
|
| 63 |
+
)
|
| 64 |
+
)
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
override fun getItemCount(): Int {
|
| 70 |
+
return chatMessageList.size
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
override fun getItemViewType(position: Int): Int {
|
| 74 |
+
return chatMessageList[position].type
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
| 78 |
+
val index = holder.adapterPosition
|
| 79 |
+
val chatMessageModel: ChatMessageModel = chatMessageList[index]
|
| 80 |
+
when (chatMessageModel.type) {
|
| 81 |
+
VIEW_TYPE_MSG_SENT -> {
|
| 82 |
+
setMessageData(holder as SentMessageViewHolder, chatMessageModel)
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
VIEW_TYPE_MSG_RECEIVED -> {
|
| 86 |
+
setMessageData(holder as ReceivedMessageViewHolder, chatMessageModel)
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
else -> {
|
| 90 |
+
setMessageData(holder as ChatWidgetViewHolder, chatMessageModel)
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
private fun setMessageData(holder: SentMessageViewHolder, data: ChatMessageModel) {
|
| 96 |
+
holder.txtMessage.text = data.content
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
private fun setMessageData(holder: ReceivedMessageViewHolder, data: ChatMessageModel) {
|
| 100 |
+
if (data.hasImage) {
|
| 101 |
+
data.image?.let { image ->
|
| 102 |
+
val originBitmap = BitmapFactory.decodeByteArray(image, 0, image.size)
|
| 103 |
+
val radius = context.resources.getDimensionPixelSize(R.dimen.radius_small)
|
| 104 |
+
val bmp = ImageHelper.getRoundedCornerBitmap(originBitmap, radius)
|
| 105 |
+
holder.imgMessage.visibility = View.VISIBLE
|
| 106 |
+
holder.imgMessage.setImageBitmap(bmp)
|
| 107 |
+
|
| 108 |
+
data.content?.let { message ->
|
| 109 |
+
holder.txtMessage.text = message
|
| 110 |
+
} ?: run {
|
| 111 |
+
holder.txtMessage.visibility = View.GONE
|
| 112 |
+
}
|
| 113 |
+
}
|
| 114 |
+
} else {
|
| 115 |
+
holder.txtMessage.text = data.content
|
| 116 |
+
holder.imgMessage.visibility = View.GONE
|
| 117 |
+
holder.txtMessage.visibility = View.VISIBLE
|
| 118 |
+
}
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
private fun setMessageData(holder: ChatWidgetViewHolder, data: ChatMessageModel) {
|
| 122 |
+
when (data.content) {
|
| 123 |
+
Constants.TYPE_WIDGET_SMS -> {
|
| 124 |
+
val sendSmsWidget = SendSmsWidget(context).apply {
|
| 125 |
+
this.callback = callbacks
|
| 126 |
+
}
|
| 127 |
+
holder.itemLayout.addView(sendSmsWidget)
|
| 128 |
+
holder.itemLayout.visibility = View.VISIBLE
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
Constants.TYPE_WIDGET_HELP_PROMPT -> {
|
| 132 |
+
// val helpPromptWidget = HelpPromptWidget(context)
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
Constants.TYPE_WIDGET_SEARCH_CONTACT -> {
|
| 136 |
+
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
Constants.TYPE_WIDGET_FEEDBACK -> {
|
| 140 |
+
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
inner class ReceivedMessageViewHolder internal constructor(itemView: View) :
|
| 146 |
+
RecyclerView.ViewHolder(itemView) {
|
| 147 |
+
var txtMessage: TextView
|
| 148 |
+
var imgMessage: ImageView
|
| 149 |
+
var itemLayout: ConstraintLayout
|
| 150 |
+
|
| 151 |
+
init {
|
| 152 |
+
txtMessage = itemView.findViewById<View>(R.id.txt_message) as TextView
|
| 153 |
+
imgMessage = itemView.findViewById<View>(R.id.img_message) as ImageView
|
| 154 |
+
itemLayout = itemView.findViewById<View>(R.id.cl_received_message) as ConstraintLayout
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
inner class SentMessageViewHolder internal constructor(itemView: View) :
|
| 159 |
+
RecyclerView.ViewHolder(itemView) {
|
| 160 |
+
var txtMessage: TextView
|
| 161 |
+
var imgMessage: ImageView
|
| 162 |
+
var itemLayout: ConstraintLayout
|
| 163 |
+
|
| 164 |
+
init {
|
| 165 |
+
txtMessage = itemView.findViewById<View>(R.id.txt_message) as TextView
|
| 166 |
+
imgMessage = itemView.findViewById<View>(R.id.img_message) as ImageView
|
| 167 |
+
itemLayout = itemView.findViewById<View>(R.id.cl_sent_message) as ConstraintLayout
|
| 168 |
+
}
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
inner class ChatWidgetViewHolder internal constructor(itemView: View) :
|
| 172 |
+
RecyclerView.ViewHolder(itemView) {
|
| 173 |
+
var itemLayout: FrameLayout
|
| 174 |
+
|
| 175 |
+
init {
|
| 176 |
+
itemLayout = itemView.findViewById<View>(R.id.fl_widget_message) as FrameLayout
|
| 177 |
+
}
|
| 178 |
+
}
|
| 179 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{dialogs/CommonConfirmDialog.kt → ui/chat/view/dialogs/ConfirmDialog.kt}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.dialogs
|
| 2 |
|
| 3 |
import android.app.Dialog
|
| 4 |
import android.content.Context
|
|
@@ -12,62 +12,59 @@ import android.widget.Button
|
|
| 12 |
import android.widget.TextView
|
| 13 |
import com.matthaigh27.chatgptwrapper.R
|
| 14 |
|
| 15 |
-
class
|
| 16 |
|
| 17 |
-
private var
|
| 18 |
-
private var
|
| 19 |
-
private lateinit var mClickListener: OnConfirmButtonClickListener
|
| 20 |
|
| 21 |
init {
|
| 22 |
setCancelable(false)
|
| 23 |
}
|
| 24 |
|
| 25 |
-
fun setOnClickListener(listener: OnConfirmButtonClickListener) {
|
| 26 |
-
mClickListener = listener
|
| 27 |
-
}
|
| 28 |
-
|
| 29 |
override fun onCreate(savedInstanceState: Bundle?) {
|
| 30 |
super.onCreate(savedInstanceState)
|
| 31 |
|
| 32 |
initView()
|
| 33 |
}
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
private fun initView() {
|
| 36 |
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
| 37 |
-
setContentView(R.layout.
|
| 38 |
|
| 39 |
-
window
|
| 40 |
-
window
|
| 41 |
|
| 42 |
findViewById<Button>(R.id.btn_ok).setOnClickListener(this)
|
| 43 |
findViewById<Button>(R.id.btn_cancel).setOnClickListener(this)
|
| 44 |
|
| 45 |
-
|
| 46 |
|
| 47 |
setCanceledOnTouchOutside(true)
|
| 48 |
}
|
| 49 |
|
| 50 |
-
fun
|
| 51 |
-
|
| 52 |
-
mTvMessage?.text = mMessage
|
| 53 |
}
|
| 54 |
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
when (view?.id) {
|
| 58 |
-
R.id.btn_ok -> {
|
| 59 |
-
mClickListener.onPositiveButtonClick()
|
| 60 |
-
}
|
| 61 |
-
|
| 62 |
-
R.id.btn_cancel -> {
|
| 63 |
-
mClickListener.onNegativeButtonClick()
|
| 64 |
-
}
|
| 65 |
-
}
|
| 66 |
-
|
| 67 |
-
this.dismiss()
|
| 68 |
}
|
| 69 |
|
| 70 |
-
|
|
|
|
| 71 |
fun onPositiveButtonClick()
|
| 72 |
fun onNegativeButtonClick()
|
| 73 |
}
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.chat.view.dialogs
|
| 2 |
|
| 3 |
import android.app.Dialog
|
| 4 |
import android.content.Context
|
|
|
|
| 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
|
| 18 |
+
private lateinit var btnClickListener: OnDialogButtonClickListener
|
|
|
|
| 19 |
|
| 20 |
init {
|
| 21 |
setCancelable(false)
|
| 22 |
}
|
| 23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
override fun onCreate(savedInstanceState: Bundle?) {
|
| 25 |
super.onCreate(savedInstanceState)
|
| 26 |
|
| 27 |
initView()
|
| 28 |
}
|
| 29 |
|
| 30 |
+
override fun onClick(view: View?) {
|
| 31 |
+
when (view?.id) {
|
| 32 |
+
R.id.btn_ok -> {
|
| 33 |
+
btnClickListener.onPositiveButtonClick()
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
R.id.btn_cancel -> {
|
| 37 |
+
btnClickListener.onNegativeButtonClick()
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
this.dismiss()
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
private fun initView() {
|
| 44 |
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
| 45 |
+
setContentView(R.layout.dialog_confirm)
|
| 46 |
|
| 47 |
+
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
| 48 |
+
window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
| 49 |
|
| 50 |
findViewById<Button>(R.id.btn_ok).setOnClickListener(this)
|
| 51 |
findViewById<Button>(R.id.btn_cancel).setOnClickListener(this)
|
| 52 |
|
| 53 |
+
txtMessage = findViewById(R.id.txt_confirm_message)
|
| 54 |
|
| 55 |
setCanceledOnTouchOutside(true)
|
| 56 |
}
|
| 57 |
|
| 58 |
+
fun setOnClickListener(listener: OnDialogButtonClickListener) {
|
| 59 |
+
btnClickListener = listener
|
|
|
|
| 60 |
}
|
| 61 |
|
| 62 |
+
fun setMessage(message: String) {
|
| 63 |
+
txtMessage?.text = message
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
}
|
| 65 |
|
| 66 |
+
|
| 67 |
+
interface OnDialogButtonClickListener {
|
| 68 |
fun onPositiveButtonClick()
|
| 69 |
fun onNegativeButtonClick()
|
| 70 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/fragments/ChatMainFragment.kt
ADDED
|
@@ -0,0 +1,383 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.chat.view.fragments
|
| 2 |
+
|
| 3 |
+
import android.annotation.SuppressLint
|
| 4 |
+
import android.os.Bundle
|
| 5 |
+
import android.view.KeyEvent
|
| 6 |
+
import android.view.LayoutInflater
|
| 7 |
+
import android.view.View
|
| 8 |
+
import android.view.View.OnClickListener
|
| 9 |
+
import android.view.ViewGroup
|
| 10 |
+
import android.view.animation.Animation
|
| 11 |
+
import android.view.animation.LinearInterpolator
|
| 12 |
+
import android.view.animation.RotateAnimation
|
| 13 |
+
import android.widget.EditText
|
| 14 |
+
import android.widget.ImageView
|
| 15 |
+
import android.widget.LinearLayout
|
| 16 |
+
import android.widget.Toast
|
| 17 |
+
import androidx.fragment.app.Fragment
|
| 18 |
+
import androidx.lifecycle.Observer
|
| 19 |
+
import androidx.lifecycle.ViewModelProvider
|
| 20 |
+
import androidx.recyclerview.widget.LinearLayoutManager
|
| 21 |
+
import androidx.recyclerview.widget.RecyclerView
|
| 22 |
+
import com.google.gson.JsonElement
|
| 23 |
+
import com.matthaigh27.chatgptwrapper.R
|
| 24 |
+
import com.matthaigh27.chatgptwrapper.data.models.ChatMessageModel
|
| 25 |
+
import com.matthaigh27.chatgptwrapper.data.models.HelpCommandModel
|
| 26 |
+
import com.matthaigh27.chatgptwrapper.data.models.HelpPromptModel
|
| 27 |
+
import com.matthaigh27.chatgptwrapper.data.remote.ApiResource
|
| 28 |
+
import com.matthaigh27.chatgptwrapper.data.remote.responses.ApiResponse
|
| 29 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.adapters.ChatMainAdapter
|
| 30 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
|
| 31 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.toolbar.ChatToolsWidget
|
| 32 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.viewmodel.ChatViewModel
|
| 33 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants.ERROR_MSG_NOEXIST_COMMAND
|
| 34 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants.HELP_COMMAND_ALL
|
| 35 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_ALERT
|
| 36 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_BROWSER
|
| 37 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_CONTACT
|
| 38 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_IMAGE
|
| 39 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_MESSAGE
|
| 40 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_RESPONSE_SMS
|
| 41 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_HELP_PROMPT
|
| 42 |
+
import com.matthaigh27.chatgptwrapper.utils.Constants.TYPE_WIDGET_SMS
|
| 43 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.Converter.stringToHelpPromptList
|
| 44 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.getHelpCommandFromStr
|
| 45 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.isMainHelpCommand
|
| 46 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.makePromptItemUsage
|
| 47 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.chat.CommandHelper.makePromptUsage
|
| 48 |
+
import com.matthaigh27.chatgptwrapper.utils.helpers.ui.NoNewLineInputFilter
|
| 49 |
+
|
| 50 |
+
class ChatMainFragment : Fragment(), OnClickListener {
|
| 51 |
+
|
| 52 |
+
private val TYPE_CHAT_SENT = 0
|
| 53 |
+
private val TYPE_CHAT_RECEIVE = 1
|
| 54 |
+
private val TYPE_CHAT_WIDGET = 2
|
| 55 |
+
|
| 56 |
+
private lateinit var rootView: View
|
| 57 |
+
lateinit var viewModel: ChatViewModel
|
| 58 |
+
|
| 59 |
+
/** View Components */
|
| 60 |
+
private var loadingRotate: RotateAnimation? = null
|
| 61 |
+
private var edtMessageInput: EditText? = null
|
| 62 |
+
|
| 63 |
+
private var rvChatList: RecyclerView? = null
|
| 64 |
+
private var chatMainAdapter: ChatMainAdapter? = null
|
| 65 |
+
private var chatMessageList: ArrayList<ChatMessageModel> = ArrayList()
|
| 66 |
+
private lateinit var chatMessageInterface: ChatMessageInterface
|
| 67 |
+
|
| 68 |
+
private var chatToolsWidget: ChatToolsWidget? = null
|
| 69 |
+
private var helpPromptList: ArrayList<HelpPromptModel>? = null
|
| 70 |
+
|
| 71 |
+
override fun onCreateView(
|
| 72 |
+
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
| 73 |
+
): View {
|
| 74 |
+
rootView = inflater.inflate(R.layout.fragment_chat_main, container, false)
|
| 75 |
+
init()
|
| 76 |
+
return rootView
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
private fun init() {
|
| 80 |
+
initViewModel()
|
| 81 |
+
initLoadingRotate()
|
| 82 |
+
initButtonsClickListener()
|
| 83 |
+
initChatInputListener()
|
| 84 |
+
initChatRecyclerView()
|
| 85 |
+
initChatToolsWidget()
|
| 86 |
+
|
| 87 |
+
fetchAllCommands()
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
private fun initViewModel() {
|
| 91 |
+
viewModel = ViewModelProvider(this)[ChatViewModel::class.java]
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
private fun initLoadingRotate() {
|
| 95 |
+
loadingRotate = RotateAnimation(/* fromDegrees = */ 0f, /* toDegrees = */
|
| 96 |
+
360f, /* pivotXType = */
|
| 97 |
+
Animation.RELATIVE_TO_SELF, /* pivotXValue = */
|
| 98 |
+
0.5f, /* pivotYType = */
|
| 99 |
+
Animation.RELATIVE_TO_SELF, /* pivotYValue = */
|
| 100 |
+
0.5f
|
| 101 |
+
).apply {
|
| 102 |
+
duration = 3000
|
| 103 |
+
repeatCount = Animation.INFINITE
|
| 104 |
+
interpolator = LinearInterpolator()
|
| 105 |
+
}
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
private fun initButtonsClickListener() {
|
| 109 |
+
rootView.findViewById<View>(R.id.btn_open_chat_tools).setOnClickListener(this)
|
| 110 |
+
rootView.findViewById<View>(R.id.btn_audio_recognition).setOnClickListener(this)
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
private fun initChatInputListener() {
|
| 114 |
+
edtMessageInput = rootView.findViewById(R.id.edt_message)
|
| 115 |
+
edtMessageInput?.filters = edtMessageInput?.filters?.plus(NoNewLineInputFilter())
|
| 116 |
+
|
| 117 |
+
edtMessageInput?.setOnKeyListener { _, keyCode, keyEvent ->
|
| 118 |
+
if (keyEvent.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER) {
|
| 119 |
+
addMessage(TYPE_CHAT_SENT, edtMessageInput?.text.toString())
|
| 120 |
+
}
|
| 121 |
+
return@setOnKeyListener false
|
| 122 |
+
}
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
private fun initChatRecyclerView() {
|
| 126 |
+
initChatInterface()
|
| 127 |
+
|
| 128 |
+
rvChatList = rootView.findViewById(R.id.rv_chat_list)
|
| 129 |
+
chatMainAdapter = ChatMainAdapter(
|
| 130 |
+
requireContext(), chatMessageList, chatMessageInterface
|
| 131 |
+
)
|
| 132 |
+
|
| 133 |
+
rvChatList?.adapter = chatMainAdapter
|
| 134 |
+
rvChatList?.layoutManager = LinearLayoutManager(context)
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
private fun initChatToolsWidget() {
|
| 138 |
+
chatToolsWidget = ChatToolsWidget(requireContext(), requireActivity())
|
| 139 |
+
val llToolBar = rootView.findViewById<LinearLayout>(R.id.ll_toolbar)
|
| 140 |
+
llToolBar.addView(chatToolsWidget)
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
private fun showToast(message: String) {
|
| 144 |
+
Toast.makeText(requireContext(), message, Toast.LENGTH_LONG).show()
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
private fun showLoading(isLoading: Boolean) {
|
| 148 |
+
val imgLoading = rootView.findViewById<ImageView>(R.id.sp_loading)
|
| 149 |
+
|
| 150 |
+
if (isLoading) {
|
| 151 |
+
imgLoading.startAnimation(loadingRotate)
|
| 152 |
+
imgLoading.visibility = View.VISIBLE
|
| 153 |
+
} else {
|
| 154 |
+
imgLoading.clearAnimation()
|
| 155 |
+
imgLoading.visibility = View.GONE
|
| 156 |
+
}
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
private fun addMessage(
|
| 160 |
+
type: Int,
|
| 161 |
+
content: String? = null,
|
| 162 |
+
data: JsonElement? = null,
|
| 163 |
+
hasImage: Boolean = false,
|
| 164 |
+
image: ByteArray? = null
|
| 165 |
+
) {
|
| 166 |
+
addChatItemToList(ChatMessageModel(type, content, data, hasImage, image))
|
| 167 |
+
when (type) {
|
| 168 |
+
TYPE_CHAT_SENT -> {
|
| 169 |
+
if (content!!.isNotEmpty() && content.first() == '/') {
|
| 170 |
+
openHelpPromptWidget(content)
|
| 171 |
+
return
|
| 172 |
+
}
|
| 173 |
+
sendNotification(content)
|
| 174 |
+
}
|
| 175 |
+
}
|
| 176 |
+
}
|
| 177 |
+
|
| 178 |
+
@SuppressLint("NotifyDataSetChanged")
|
| 179 |
+
private fun addChatItemToList(chatModel: ChatMessageModel) {
|
| 180 |
+
edtMessageInput?.setText("")
|
| 181 |
+
|
| 182 |
+
chatMessageList.add(chatModel)
|
| 183 |
+
chatMainAdapter?.notifyDataSetChanged()
|
| 184 |
+
rvChatList?.scrollToPosition(chatMessageList.size - 1)
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
private fun openHelpPromptWidget(message: String) {
|
| 188 |
+
try {
|
| 189 |
+
val command: HelpCommandModel = getHelpCommandFromStr(message)
|
| 190 |
+
if (isMainHelpCommand(command)) {
|
| 191 |
+
when (command.main) {
|
| 192 |
+
TYPE_WIDGET_SMS -> {
|
| 193 |
+
addMessage(
|
| 194 |
+
type = TYPE_CHAT_WIDGET, content = TYPE_WIDGET_SMS
|
| 195 |
+
)
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
else -> {
|
| 199 |
+
helpPromptList?.let { list ->
|
| 200 |
+
val data = list.filter { model ->
|
| 201 |
+
model.name == command.main
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
if(data.isEmpty()) {
|
| 205 |
+
addMessage(
|
| 206 |
+
type = TYPE_CHAT_RECEIVE, content = ERROR_MSG_NOEXIST_COMMAND
|
| 207 |
+
)
|
| 208 |
+
} else {
|
| 209 |
+
addMessage(
|
| 210 |
+
type = TYPE_CHAT_WIDGET,
|
| 211 |
+
content = TYPE_WIDGET_HELP_PROMPT,
|
| 212 |
+
data = data[0].toString() as JsonElement
|
| 213 |
+
)
|
| 214 |
+
}
|
| 215 |
+
}
|
| 216 |
+
}
|
| 217 |
+
}
|
| 218 |
+
} else {
|
| 219 |
+
if (command.assist == HELP_COMMAND_ALL) {
|
| 220 |
+
addMessage(
|
| 221 |
+
type = TYPE_CHAT_RECEIVE, content = makePromptUsage(helpPromptList!!)
|
| 222 |
+
)
|
| 223 |
+
} else {
|
| 224 |
+
addMessage(
|
| 225 |
+
type = TYPE_CHAT_RECEIVE,
|
| 226 |
+
content = makePromptItemUsage(helpPromptList!!, command.assist!!)
|
| 227 |
+
)
|
| 228 |
+
}
|
| 229 |
+
}
|
| 230 |
+
} catch (e: Exception) {
|
| 231 |
+
e.printStackTrace()
|
| 232 |
+
showToast(e.message.toString())
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
private fun fetchAllCommands() {
|
| 238 |
+
viewModel.getAllHelpCommands().observe(viewLifecycleOwner, Observer { resource ->
|
| 239 |
+
when (resource) {
|
| 240 |
+
is ApiResource.Loading -> {
|
| 241 |
+
showLoading(true)
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
is ApiResource.Success -> {
|
| 245 |
+
showLoading(false)
|
| 246 |
+
resource.data?.let { data ->
|
| 247 |
+
helpPromptList =
|
| 248 |
+
stringToHelpPromptList(data.result.content.asJsonArray.toString())
|
| 249 |
+
}
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
is ApiResource.Error -> {
|
| 253 |
+
showLoading(false)
|
| 254 |
+
showToast(resource.message!!)
|
| 255 |
+
}
|
| 256 |
+
}
|
| 257 |
+
})
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
private fun sendNotification(message: String) {
|
| 261 |
+
viewModel.sendNotification(message).observe(viewLifecycleOwner, Observer { resource ->
|
| 262 |
+
when (resource) {
|
| 263 |
+
is ApiResource.Loading -> {
|
| 264 |
+
showLoading(true)
|
| 265 |
+
}
|
| 266 |
+
is ApiResource.Success -> {
|
| 267 |
+
showLoading(false)
|
| 268 |
+
val apiResponse = resource.data
|
| 269 |
+
when (apiResponse?.result?.program) {
|
| 270 |
+
TYPE_RESPONSE_MESSAGE -> {
|
| 271 |
+
addMessage(TYPE_CHAT_RECEIVE, apiResponse.result.content.toString())
|
| 272 |
+
}
|
| 273 |
+
TYPE_RESPONSE_BROWSER -> {
|
| 274 |
+
fetchResponseBrowser(apiResponse)
|
| 275 |
+
}
|
| 276 |
+
TYPE_RESPONSE_ALERT -> {
|
| 277 |
+
|
| 278 |
+
}
|
| 279 |
+
TYPE_RESPONSE_CONTACT -> {
|
| 280 |
+
|
| 281 |
+
}
|
| 282 |
+
TYPE_RESPONSE_IMAGE -> {
|
| 283 |
+
fetchResponseImage(apiResponse)
|
| 284 |
+
}
|
| 285 |
+
TYPE_RESPONSE_SMS -> {
|
| 286 |
+
|
| 287 |
+
}
|
| 288 |
+
else -> {
|
| 289 |
+
|
| 290 |
+
}
|
| 291 |
+
}
|
| 292 |
+
}
|
| 293 |
+
is ApiResource.Error -> {
|
| 294 |
+
showToast(resource.message!!)
|
| 295 |
+
showLoading(false)
|
| 296 |
+
}
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
})
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
private fun fetchResponseBrowser(apiResponse: ApiResponse) {
|
| 303 |
+
addMessage(TYPE_CHAT_RECEIVE, apiResponse.result.url)
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
private fun fetchResponseImage(apiResponse: ApiResponse) {
|
| 307 |
+
val content = apiResponse.result.content.asJsonObject
|
| 308 |
+
viewModel.downloadImageFromFirebase(
|
| 309 |
+
content["image_name"].asString
|
| 310 |
+
).observe(viewLifecycleOwner, Observer { resource ->
|
| 311 |
+
when (resource) {
|
| 312 |
+
is ApiResource.Loading -> {
|
| 313 |
+
showLoading(true)
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
is ApiResource.Success -> {
|
| 317 |
+
showLoading(false)
|
| 318 |
+
addMessage(
|
| 319 |
+
type = TYPE_CHAT_RECEIVE,
|
| 320 |
+
content = null,
|
| 321 |
+
data = null,
|
| 322 |
+
hasImage = true,
|
| 323 |
+
image = resource.data
|
| 324 |
+
)
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
is ApiResource.Error -> {
|
| 328 |
+
showToast(resource.message!!)
|
| 329 |
+
showLoading(false)
|
| 330 |
+
}
|
| 331 |
+
}
|
| 332 |
+
})
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
private fun initChatInterface() {
|
| 337 |
+
chatMessageInterface = object : ChatMessageInterface {
|
| 338 |
+
override fun sentSms(phoneNumber: String, message: String) {
|
| 339 |
+
addMessage(
|
| 340 |
+
type = TYPE_CHAT_RECEIVE,
|
| 341 |
+
content = "You sent SMS with belowing content.\n\n " + "To: $phoneNumber\n " + "Message: $message",
|
| 342 |
+
)
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
override fun canceledSms() {
|
| 346 |
+
addMessage(
|
| 347 |
+
type = TYPE_CHAT_RECEIVE,
|
| 348 |
+
content = "You canceled SMS.",
|
| 349 |
+
)
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
override fun sentHelpPrompt(prompt: String) {
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
override fun canceledHelpPrompt() {
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
override fun doVoiceCall(phoneNumber: String) {
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
override fun doVideoCall(phoneNumber: String) {
|
| 362 |
+
}
|
| 363 |
+
|
| 364 |
+
override fun sendSmsWithPhoneNumber(phoneNumber: String) {
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
override fun pickImage(isSuccess: Boolean, data: ByteArray?) {
|
| 368 |
+
}
|
| 369 |
+
}
|
| 370 |
+
}
|
| 371 |
+
|
| 372 |
+
override fun onClick(view: View?) {
|
| 373 |
+
when (view?.id) {
|
| 374 |
+
R.id.btn_open_chat_tools -> {
|
| 375 |
+
chatToolsWidget?.toggle()
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
R.id.btn_audio_recognition -> {
|
| 379 |
+
|
| 380 |
+
}
|
| 381 |
+
}
|
| 382 |
+
}
|
| 383 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/interfaces/ChatMessageInterface.kt
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces
|
| 2 |
+
|
| 3 |
+
interface ChatMessageInterface {
|
| 4 |
+
fun sentSms(phoneNumber: String, message: String)
|
| 5 |
+
fun canceledSms()
|
| 6 |
+
fun sentHelpPrompt(prompt: String)
|
| 7 |
+
fun canceledHelpPrompt()
|
| 8 |
+
fun doVoiceCall(phoneNumber: String)
|
| 9 |
+
fun doVideoCall(phoneNumber: String)
|
| 10 |
+
fun sendSmsWithPhoneNumber(phoneNumber: String)
|
| 11 |
+
fun pickImage(isSuccess: Boolean, data: ByteArray? = null)
|
| 12 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/ui/chat/view/widgets/chatwidget/FeedbackWidget.kt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget
|
| 2 |
+
|
| 3 |
+
class FeedbackWidget {
|
| 4 |
+
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{widgets/SmsEditorWidget.kt → ui/chat/view/widgets/chatwidget/SendSmsWidget.kt}
RENAMED
|
@@ -1,77 +1,69 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.widgets
|
| 2 |
|
| 3 |
import android.content.Context
|
| 4 |
import android.util.AttributeSet
|
| 5 |
import android.view.View
|
|
|
|
| 6 |
import android.widget.Button
|
| 7 |
import android.widget.EditText
|
| 8 |
import android.widget.Toast
|
| 9 |
import androidx.constraintlayout.widget.ConstraintLayout
|
| 10 |
import com.matthaigh27.chatgptwrapper.R
|
|
|
|
| 11 |
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
context: Context, attrs: AttributeSet?
|
| 15 |
) : ConstraintLayout(context, attrs) {
|
| 16 |
|
| 17 |
-
private val
|
| 18 |
|
| 19 |
-
private val
|
| 20 |
-
private val
|
| 21 |
|
| 22 |
-
private val
|
| 23 |
private val btnCancel: Button
|
| 24 |
|
| 25 |
-
|
| 26 |
|
| 27 |
init {
|
| 28 |
-
inflate(context, R.layout.
|
| 29 |
-
|
| 30 |
|
| 31 |
layoutParams = LayoutParams(
|
| 32 |
-
|
| 33 |
-
|
| 34 |
)
|
| 35 |
|
| 36 |
-
|
| 37 |
-
|
| 38 |
|
| 39 |
-
|
| 40 |
btnCancel = findViewById(R.id.btn_cancel)
|
| 41 |
|
| 42 |
-
|
| 43 |
-
if (
|
| 44 |
Toast.makeText(
|
| 45 |
-
|
| 46 |
).show()
|
| 47 |
return@setOnClickListener
|
| 48 |
}
|
| 49 |
-
mListener!!.confirmSMS(etToName.text.toString(), etMessage.text.toString())
|
| 50 |
hide()
|
|
|
|
| 51 |
}
|
| 52 |
|
| 53 |
btnCancel.setOnClickListener {
|
| 54 |
hide()
|
| 55 |
-
|
| 56 |
}
|
| 57 |
}
|
| 58 |
|
| 59 |
-
fun
|
| 60 |
-
|
| 61 |
}
|
| 62 |
|
| 63 |
fun hide() {
|
| 64 |
this.visibility = View.GONE
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
}
|
| 68 |
-
|
| 69 |
-
fun setOnClickListener(listener: OnClickListener) {
|
| 70 |
-
mListener = listener
|
| 71 |
-
}
|
| 72 |
-
|
| 73 |
-
interface OnClickListener {
|
| 74 |
-
fun confirmSMS(phonenumber: String, message: String);
|
| 75 |
-
fun cancelSMS();
|
| 76 |
}
|
| 77 |
}
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget
|
| 2 |
|
| 3 |
import android.content.Context
|
| 4 |
import android.util.AttributeSet
|
| 5 |
import android.view.View
|
| 6 |
+
import android.view.ViewGroup
|
| 7 |
import android.widget.Button
|
| 8 |
import android.widget.EditText
|
| 9 |
import android.widget.Toast
|
| 10 |
import androidx.constraintlayout.widget.ConstraintLayout
|
| 11 |
import com.matthaigh27.chatgptwrapper.R
|
| 12 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
|
| 13 |
|
| 14 |
+
class SendSmsWidget(
|
| 15 |
+
context: Context, attrs: AttributeSet? = null
|
|
|
|
| 16 |
) : ConstraintLayout(context, attrs) {
|
| 17 |
|
| 18 |
+
private val context: Context
|
| 19 |
|
| 20 |
+
private val edtPhoneNumber: EditText
|
| 21 |
+
private val edtMessage: EditText
|
| 22 |
|
| 23 |
+
private val btnOk: Button
|
| 24 |
private val btnCancel: Button
|
| 25 |
|
| 26 |
+
var callback: ChatMessageInterface? = null
|
| 27 |
|
| 28 |
init {
|
| 29 |
+
inflate(context, R.layout.widget_send_sms, this)
|
| 30 |
+
this.context = context
|
| 31 |
|
| 32 |
layoutParams = LayoutParams(
|
| 33 |
+
ViewGroup.LayoutParams.MATCH_PARENT,
|
| 34 |
+
ViewGroup.LayoutParams.WRAP_CONTENT
|
| 35 |
)
|
| 36 |
|
| 37 |
+
edtPhoneNumber = findViewById(R.id.edt_phone_to_send)
|
| 38 |
+
edtMessage = findViewById(R.id.edt_message)
|
| 39 |
|
| 40 |
+
btnOk = findViewById(R.id.btn_ok)
|
| 41 |
btnCancel = findViewById(R.id.btn_cancel)
|
| 42 |
|
| 43 |
+
btnOk.setOnClickListener {
|
| 44 |
+
if (edtPhoneNumber.text.toString().isEmpty() || edtMessage.text.toString().isEmpty()) {
|
| 45 |
Toast.makeText(
|
| 46 |
+
context, "Please input phone number and message.", Toast.LENGTH_SHORT
|
| 47 |
).show()
|
| 48 |
return@setOnClickListener
|
| 49 |
}
|
|
|
|
| 50 |
hide()
|
| 51 |
+
callback?.sentSms(edtPhoneNumber.text.toString(), edtMessage.text.toString())
|
| 52 |
}
|
| 53 |
|
| 54 |
btnCancel.setOnClickListener {
|
| 55 |
hide()
|
| 56 |
+
callback?.canceledSms()
|
| 57 |
}
|
| 58 |
}
|
| 59 |
|
| 60 |
+
fun setPhoneNumber(phonenumber: String) {
|
| 61 |
+
edtPhoneNumber.setText(phonenumber)
|
| 62 |
}
|
| 63 |
|
| 64 |
fun hide() {
|
| 65 |
this.visibility = View.GONE
|
| 66 |
+
edtMessage.setText("")
|
| 67 |
+
edtPhoneNumber.setText("")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
}
|
| 69 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{widgets → ui/chat/view/widgets/chatwidget/contact}/ContactDetailItem.kt
RENAMED
|
@@ -1,11 +1,9 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.widgets
|
| 2 |
|
| 3 |
-
import android.content.ContentUris
|
| 4 |
import android.content.Context
|
| 5 |
import android.content.Intent
|
| 6 |
import android.content.pm.PackageManager
|
| 7 |
import android.net.Uri
|
| 8 |
-
import android.provider.ContactsContract
|
| 9 |
import android.telecom.VideoProfile
|
| 10 |
import android.util.AttributeSet
|
| 11 |
import android.view.LayoutInflater
|
|
@@ -14,66 +12,61 @@ import android.widget.ImageView
|
|
| 14 |
import android.widget.TextView
|
| 15 |
import androidx.constraintlayout.widget.ConstraintLayout
|
| 16 |
import com.matthaigh27.chatgptwrapper.R
|
| 17 |
-
import com.matthaigh27.chatgptwrapper.
|
| 18 |
|
| 19 |
class ContactDetailItem(
|
| 20 |
context: Context, attrs: AttributeSet? = null
|
| 21 |
) : ConstraintLayout(context, attrs), View.OnClickListener {
|
| 22 |
-
private lateinit var
|
| 23 |
-
private lateinit var
|
| 24 |
-
private var
|
| 25 |
-
private var
|
| 26 |
|
| 27 |
-
private var
|
| 28 |
-
private var
|
| 29 |
-
|
| 30 |
|
| 31 |
init {
|
| 32 |
initView()
|
| 33 |
}
|
| 34 |
|
| 35 |
-
fun
|
| 36 |
-
|
| 37 |
-
}
|
| 38 |
-
|
| 39 |
-
fun setOnContactDetailVisibilityListener(listener: OnContactDetailVisibilityListener) {
|
| 40 |
-
mContactDetailVisibilityListener = listener
|
| 41 |
}
|
| 42 |
|
| 43 |
private fun initView() {
|
| 44 |
LayoutInflater.from(context).inflate(R.layout.item_contact_detail, this, true)
|
| 45 |
|
| 46 |
-
|
| 47 |
-
|
| 48 |
|
| 49 |
findViewById<ImageView>(R.id.btn_voice_call).setOnClickListener(this)
|
| 50 |
findViewById<ImageView>(R.id.btn_send_message).setOnClickListener(this)
|
| 51 |
}
|
| 52 |
|
| 53 |
fun setContactDetailItemInfo(phoneNumber: String, username: String) {
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
}
|
| 58 |
|
| 59 |
override fun onClick(view: View?) {
|
| 60 |
when (view!!.id) {
|
| 61 |
R.id.btn_voice_call -> {
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
doVoiceCall(mPhoneNumber)
|
| 65 |
}
|
| 66 |
|
| 67 |
R.id.btn_send_message -> {
|
| 68 |
-
|
| 69 |
-
mContactDetailVisibilityListener!!.invisible()
|
| 70 |
}
|
| 71 |
}
|
|
|
|
| 72 |
}
|
| 73 |
|
| 74 |
private fun doVoiceCall(phoneNumber: String) {
|
| 75 |
val callIntent = Intent(Intent.ACTION_CALL, Uri.parse("tel:$phoneNumber"))
|
| 76 |
-
|
| 77 |
return
|
| 78 |
}
|
| 79 |
|
|
@@ -82,7 +75,7 @@ class ContactDetailItem(
|
|
| 82 |
val intent = Intent(Intent.ACTION_VIEW, uri).apply {
|
| 83 |
putExtra("sms_body", message)
|
| 84 |
}
|
| 85 |
-
|
| 86 |
}
|
| 87 |
|
| 88 |
private fun doVideoCall(phoneNumber: String) {
|
|
@@ -102,11 +95,6 @@ class ContactDetailItem(
|
|
| 102 |
}
|
| 103 |
}
|
| 104 |
|
| 105 |
-
interface OnSMSClickListener {
|
| 106 |
-
fun onSMSClickListener(phoneNumber: String)
|
| 107 |
-
fun onVoiceCallListener(phoneNumber: String, toName: String)
|
| 108 |
-
}
|
| 109 |
-
|
| 110 |
interface OnContactDetailVisibilityListener {
|
| 111 |
fun invisible()
|
| 112 |
}
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.contact
|
| 2 |
|
|
|
|
| 3 |
import android.content.Context
|
| 4 |
import android.content.Intent
|
| 5 |
import android.content.pm.PackageManager
|
| 6 |
import android.net.Uri
|
|
|
|
| 7 |
import android.telecom.VideoProfile
|
| 8 |
import android.util.AttributeSet
|
| 9 |
import android.view.LayoutInflater
|
|
|
|
| 12 |
import android.widget.TextView
|
| 13 |
import androidx.constraintlayout.widget.ConstraintLayout
|
| 14 |
import com.matthaigh27.chatgptwrapper.R
|
| 15 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
|
| 16 |
|
| 17 |
class ContactDetailItem(
|
| 18 |
context: Context, attrs: AttributeSet? = null
|
| 19 |
) : ConstraintLayout(context, attrs), View.OnClickListener {
|
| 20 |
+
private lateinit var txtPhoneNumber: TextView
|
| 21 |
+
private lateinit var txtPhoneType: TextView
|
| 22 |
+
private var phoneNumber: String = ""
|
| 23 |
+
private var userName: String = ""
|
| 24 |
|
| 25 |
+
private var context = context
|
| 26 |
+
private var visibilityListener: OnContactDetailVisibilityListener? = null
|
| 27 |
+
var callback: ChatMessageInterface? = null
|
| 28 |
|
| 29 |
init {
|
| 30 |
initView()
|
| 31 |
}
|
| 32 |
|
| 33 |
+
fun setVisibilityListener(listener: OnContactDetailVisibilityListener) {
|
| 34 |
+
visibilityListener = listener
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
}
|
| 36 |
|
| 37 |
private fun initView() {
|
| 38 |
LayoutInflater.from(context).inflate(R.layout.item_contact_detail, this, true)
|
| 39 |
|
| 40 |
+
txtPhoneNumber = findViewById(R.id.txt_phone_number)
|
| 41 |
+
txtPhoneType = findViewById(R.id.txt_phone_type)
|
| 42 |
|
| 43 |
findViewById<ImageView>(R.id.btn_voice_call).setOnClickListener(this)
|
| 44 |
findViewById<ImageView>(R.id.btn_send_message).setOnClickListener(this)
|
| 45 |
}
|
| 46 |
|
| 47 |
fun setContactDetailItemInfo(phoneNumber: String, username: String) {
|
| 48 |
+
this.phoneNumber = phoneNumber
|
| 49 |
+
this.userName = username
|
| 50 |
+
txtPhoneNumber.text = phoneNumber
|
| 51 |
}
|
| 52 |
|
| 53 |
override fun onClick(view: View?) {
|
| 54 |
when (view!!.id) {
|
| 55 |
R.id.btn_voice_call -> {
|
| 56 |
+
callback?.doVoiceCall(phoneNumber)
|
| 57 |
+
doVoiceCall(phoneNumber)
|
|
|
|
| 58 |
}
|
| 59 |
|
| 60 |
R.id.btn_send_message -> {
|
| 61 |
+
callback?.sendSmsWithPhoneNumber(phoneNumber)
|
|
|
|
| 62 |
}
|
| 63 |
}
|
| 64 |
+
visibilityListener?.invisible()
|
| 65 |
}
|
| 66 |
|
| 67 |
private fun doVoiceCall(phoneNumber: String) {
|
| 68 |
val callIntent = Intent(Intent.ACTION_CALL, Uri.parse("tel:$phoneNumber"))
|
| 69 |
+
context.startActivity(callIntent)
|
| 70 |
return
|
| 71 |
}
|
| 72 |
|
|
|
|
| 75 |
val intent = Intent(Intent.ACTION_VIEW, uri).apply {
|
| 76 |
putExtra("sms_body", message)
|
| 77 |
}
|
| 78 |
+
context.startActivity(intent)
|
| 79 |
}
|
| 80 |
|
| 81 |
private fun doVideoCall(phoneNumber: String) {
|
|
|
|
| 95 |
}
|
| 96 |
}
|
| 97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
interface OnContactDetailVisibilityListener {
|
| 99 |
fun invisible()
|
| 100 |
}
|
Android/app/src/main/java/com/matthaigh27/chatgptwrapper/{widgets → ui/chat/view/widgets/chatwidget/contact}/ContactDetailWidget.kt
RENAMED
|
@@ -1,72 +1,81 @@
|
|
| 1 |
-
package com.matthaigh27.chatgptwrapper.widgets
|
| 2 |
|
| 3 |
import android.content.ContentUris
|
| 4 |
import android.content.Context
|
| 5 |
import android.content.Intent
|
| 6 |
import android.provider.ContactsContract
|
| 7 |
-
import android.util.AttributeSet
|
| 8 |
-
import android.view.LayoutInflater
|
| 9 |
import android.view.View
|
| 10 |
import android.widget.ImageView
|
| 11 |
import android.widget.LinearLayout
|
| 12 |
import android.widget.TextView
|
| 13 |
-
import
|
| 14 |
-
import androidx.core.view.forEach
|
| 15 |
import com.google.android.material.bottomsheet.BottomSheetDialog
|
| 16 |
import com.matthaigh27.chatgptwrapper.R
|
| 17 |
-
import com.matthaigh27.chatgptwrapper.models.
|
| 18 |
-
import com.matthaigh27.chatgptwrapper.
|
| 19 |
|
| 20 |
class ContactDetailWidget(
|
| 21 |
-
context: Context, contactModel: ContactModel
|
| 22 |
) : BottomSheetDialog(context), View.OnClickListener {
|
| 23 |
|
| 24 |
-
private
|
| 25 |
-
private
|
| 26 |
-
private
|
| 27 |
-
private
|
| 28 |
|
| 29 |
-
private var
|
| 30 |
|
| 31 |
-
|
| 32 |
|
| 33 |
init {
|
| 34 |
initView()
|
| 35 |
}
|
| 36 |
|
| 37 |
-
|
| 38 |
private fun initView() {
|
| 39 |
-
setContentView(R.layout.
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
val contactDetailItem = ContactDetailItem(context)
|
| 49 |
-
contactDetailItem.setContactDetailItemInfo(phoneNumber,
|
| 50 |
-
contactDetailItem.
|
| 51 |
-
contactDetailItem.setOnContactDetailVisibilityListener(object:
|
| 52 |
ContactDetailItem.OnContactDetailVisibilityListener {
|
| 53 |
override fun invisible() {
|
| 54 |
this@ContactDetailWidget.dismiss()
|
| 55 |
}
|
| 56 |
})
|
| 57 |
-
|
| 58 |
}
|
| 59 |
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
}
|
| 64 |
|
| 65 |
override fun onClick(view: View?) {
|
| 66 |
when (view!!.id) {
|
| 67 |
R.id.btn_edit_contact -> {
|
| 68 |
-
goToContactEditor(
|
| 69 |
}
|
|
|
|
| 70 |
R.id.btn_send_message -> {
|
| 71 |
}
|
| 72 |
}
|
|
|
|
| 1 |
+
package com.matthaigh27.chatgptwrapper.ui.chat.view.widgets.chatwidget.contact
|
| 2 |
|
| 3 |
import android.content.ContentUris
|
| 4 |
import android.content.Context
|
| 5 |
import android.content.Intent
|
| 6 |
import android.provider.ContactsContract
|
|
|
|
|
|
|
| 7 |
import android.view.View
|
| 8 |
import android.widget.ImageView
|
| 9 |
import android.widget.LinearLayout
|
| 10 |
import android.widget.TextView
|
| 11 |
+
import com.bumptech.glide.Glide
|
|
|
|
| 12 |
import com.google.android.material.bottomsheet.BottomSheetDialog
|
| 13 |
import com.matthaigh27.chatgptwrapper.R
|
| 14 |
+
import com.matthaigh27.chatgptwrapper.data.models.ContactModel
|
| 15 |
+
import com.matthaigh27.chatgptwrapper.ui.chat.view.interfaces.ChatMessageInterface
|
| 16 |
|
| 17 |
class ContactDetailWidget(
|
| 18 |
+
context: Context, contactModel: ContactModel
|
| 19 |
) : BottomSheetDialog(context), View.OnClickListener {
|
| 20 |
|
| 21 |
+
private var imgAvatar: ImageView? = null
|
| 22 |
+
private var txtDisplayName: TextView? = null
|
| 23 |
+
private var btnEditContact: ImageView? = null
|
| 24 |
+
private var llPhones: LinearLayout? = null
|
| 25 |
|
| 26 |
+
private var contactModel = contactModel
|
| 27 |
|
| 28 |
+
var callback: ChatMessageInterface? = null
|
| 29 |
|
| 30 |
init {
|
| 31 |
initView()
|
| 32 |
}
|
| 33 |
|
|
|
|
| 34 |
private fun initView() {
|
| 35 |
+
setContentView(R.layout.widget_contact_detail)
|
| 36 |
|
| 37 |
+
txtDisplayName = findViewById(R.id.txt_display_name)
|
| 38 |
+
btnEditContact = findViewById(R.id.btn_edit_contact)
|
| 39 |
+
llPhones = findViewById(R.id.ll_contacts)
|
| 40 |
|
| 41 |
+
llPhones?.removeAllViews()
|
| 42 |
+
txtDisplayName?.text = contactModel.name
|
| 43 |
+
contactModel.phoneList.forEach { phoneNumber ->
|
| 44 |
val contactDetailItem = ContactDetailItem(context)
|
| 45 |
+
contactDetailItem.setContactDetailItemInfo(phoneNumber, contactModel.name)
|
| 46 |
+
contactDetailItem.setVisibilityListener(object :
|
|
|
|
| 47 |
ContactDetailItem.OnContactDetailVisibilityListener {
|
| 48 |
override fun invisible() {
|
| 49 |
this@ContactDetailWidget.dismiss()
|
| 50 |
}
|
| 51 |
})
|
| 52 |
+
llPhones?.addView(contactDetailItem)
|
| 53 |
}
|
| 54 |
|
| 55 |
+
btnEditContact?.setOnClickListener(this)
|
| 56 |
+
imgAvatar = findViewById(R.id.img_avatar)
|
| 57 |
+
imgAvatar?.setContactAvatar(contactModel.id.toLong())
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
private fun ImageView.setContactAvatar(contactId: Long) {
|
| 61 |
+
val uri = ContentUris.withAppendedId(
|
| 62 |
+
ContactsContract.Contacts.CONTENT_URI, contactId
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
Glide.with(context)
|
| 66 |
+
.load(uri)
|
| 67 |
+
.placeholder(R.drawable.image_default_avatar) // Set placeholder image
|
| 68 |
+
.error(R.drawable.image_default_avatar) // Set error image
|
| 69 |
+
.fallback(R.drawable.image_default_avatar) // Set fallback image
|
| 70 |
+
.into(this)
|
| 71 |
}
|
| 72 |
|
| 73 |
override fun onClick(view: View?) {
|
| 74 |
when (view!!.id) {
|
| 75 |
R.id.btn_edit_contact -> {
|
| 76 |
+
goToContactEditor(contactModel.id)
|
| 77 |
}
|
| 78 |
+
|
| 79 |
R.id.btn_send_message -> {
|
| 80 |
}
|
| 81 |
}
|