├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── io
│ │ └── edna
│ │ └── threads
│ │ └── demo
│ │ ├── MockTestRunner.kt
│ │ └── snapshot
│ │ ├── AttachmentsSnapshotTest.kt
│ │ ├── ChatBotSnapshotTest.kt
│ │ ├── ChatErrorsSnapshotTest.kt
│ │ ├── ChatFilesSnapshotTest.kt
│ │ ├── ChatImagesSnapshotTest1.kt
│ │ ├── ChatImagesSnapshotTest2.kt
│ │ ├── ChatImagesSnapshotTest3.kt
│ │ ├── ChatImagesSnapshotTest4.kt
│ │ ├── ChatSystemSnapshotTest.kt
│ │ ├── ChatTextSnapshotTest1.kt
│ │ ├── ChatTextSnapshotTest2.kt
│ │ ├── ChatTextSnapshotTest3.kt
│ │ ├── ChatVoiceSnapshotTest.kt
│ │ ├── ConsultActivitySnapshotTest.kt
│ │ ├── GalleryActivitySnapshotTest.kt
│ │ ├── ReplySnapshotTest.kt
│ │ ├── SnapshotBaseTest.kt
│ │ ├── SnapshotsCommonCode.kt
│ │ └── ToolbarIconsSnapshotTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── fonts
│ │ │ ├── lato-bold.ttf
│ │ │ ├── lato-light.ttf
│ │ │ └── lato-regular.ttf
│ │ ├── servers_config.json
│ │ └── test_files
│ │ │ ├── client_text1.ogg
│ │ │ ├── client_text2.ogg
│ │ │ ├── client_text3.ogg
│ │ │ ├── client_text4.ogg
│ │ │ ├── operator_text1.ogg
│ │ │ ├── operator_text2.ogg
│ │ │ ├── operator_text3.ogg
│ │ │ ├── operator_text4.ogg
│ │ │ ├── test_image1.jpg
│ │ │ ├── test_image2.jpg
│ │ │ ├── test_image3.jpg
│ │ │ ├── test_image4.jpg
│ │ │ ├── test_image5.jpg
│ │ │ ├── test_image6.jpg
│ │ │ ├── test_pdf1.pdf
│ │ │ └── test_pdf2.pdf
│ ├── ic_launcher-playstore.png
│ ├── java
│ │ └── io
│ │ │ └── edna
│ │ │ └── threads
│ │ │ └── demo
│ │ │ ├── appCode
│ │ │ ├── activity
│ │ │ │ ├── MainActivity.kt
│ │ │ │ └── SplashScreenActivity.kt
│ │ │ ├── adapters
│ │ │ │ ├── EccTouchHelperCallBack.kt
│ │ │ │ ├── ListItemClickListener.kt
│ │ │ │ ├── demoSamplesList
│ │ │ │ │ ├── DemoSamplesAdapter.kt
│ │ │ │ │ ├── DemoSamplesDiffCallback.kt
│ │ │ │ │ └── SampleListItemOnClick.kt
│ │ │ │ ├── serverList
│ │ │ │ │ ├── ServerListAdapter.kt
│ │ │ │ │ └── ServerListDiffCallback.kt
│ │ │ │ └── userList
│ │ │ │ │ ├── UserListAdapter.kt
│ │ │ │ │ └── UserListDiffCallback.kt
│ │ │ ├── business
│ │ │ │ ├── AfterTextChangedTextWatcher.kt
│ │ │ │ ├── Extensions.kt
│ │ │ │ ├── KoinModules.kt
│ │ │ │ ├── PreferencesProvider.kt
│ │ │ │ ├── ServersProvider.kt
│ │ │ │ ├── SingleLiveEvent.kt
│ │ │ │ ├── StringsProvider.kt
│ │ │ │ ├── TouchHelper.kt
│ │ │ │ ├── UiThemeProvider.kt
│ │ │ │ ├── VolatileLiveData.kt
│ │ │ │ └── mockJsonProvider
│ │ │ │ │ ├── CurrentJsonProvider.kt
│ │ │ │ │ └── SamplesJsonProvider.kt
│ │ │ ├── extensions
│ │ │ │ └── UIExtensions.kt
│ │ │ ├── fragments
│ │ │ │ ├── BaseAppFragment.kt
│ │ │ │ ├── demoSamplesFragment
│ │ │ │ │ ├── DemoSamplesFragment.kt
│ │ │ │ │ └── DemoSamplesViewModel.kt
│ │ │ │ ├── demoSamplesList
│ │ │ │ │ ├── DemoSamplesListFragment.kt
│ │ │ │ │ └── DemoSamplesListViewModel.kt
│ │ │ │ ├── server
│ │ │ │ │ ├── AddServerFragment.kt
│ │ │ │ │ ├── AddServerViewModel.kt
│ │ │ │ │ ├── ServerListFragment.kt
│ │ │ │ │ └── ServerListViewModel.kt
│ │ │ │ └── user
│ │ │ │ │ ├── AddUserFragment.kt
│ │ │ │ │ ├── AddUserViewModel.kt
│ │ │ │ │ ├── UserListFragment.kt
│ │ │ │ │ └── UserListViewModel.kt
│ │ │ ├── models
│ │ │ │ ├── DemoSamplesListItem.kt
│ │ │ │ ├── ServerConfig.kt
│ │ │ │ ├── TestData.kt
│ │ │ │ ├── UiTheme.kt
│ │ │ │ └── UserInfo.kt
│ │ │ ├── push
│ │ │ │ ├── CustomPushFcmIntentService.kt
│ │ │ │ ├── CustomPushHcmIntentService.kt
│ │ │ │ └── HCMTokenRefresher.kt
│ │ │ ├── test
│ │ │ │ └── TestChatActivity.kt
│ │ │ ├── themes
│ │ │ │ └── ChatThemes.kt
│ │ │ └── views
│ │ │ │ ├── InputField.kt
│ │ │ │ └── ItemDecorator.kt
│ │ │ └── integrationCode
│ │ │ ├── EdnaThreadsApplication.kt
│ │ │ ├── ThreadsLibInitializer.kt
│ │ │ └── fragments
│ │ │ ├── chatFragment
│ │ │ └── ChatAppFragment.kt
│ │ │ └── launch
│ │ │ ├── LaunchFragment.kt
│ │ │ └── LaunchViewModel.kt
│ └── res
│ │ ├── drawable-hdpi
│ │ ├── alt_thread_incoming_bubble.9.png
│ │ ├── alt_thread_outgoing_bubble.9.png
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_round.webp
│ │ └── logo.png
│ │ ├── drawable-mdpi
│ │ ├── alt_thread_incoming_bubble.9.png
│ │ ├── alt_thread_outgoing_bubble.9.png
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_round.webp
│ │ └── logo.png
│ │ ├── drawable-night
│ │ └── splash_background.xml
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable-xhdpi
│ │ ├── alt_thread_incoming_bubble.9.png
│ │ ├── alt_thread_outgoing_bubble.9.png
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_round.webp
│ │ ├── im_empty_users.png
│ │ └── logo.png
│ │ ├── drawable-xxhdpi
│ │ ├── alt_thread_incoming_bubble.9.png
│ │ ├── alt_thread_outgoing_bubble.9.png
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_round.webp
│ │ └── logo.png
│ │ ├── drawable
│ │ ├── alt_thread_incoming_image_mask.9.png
│ │ ├── alt_thread_outgoing_image_mask.9.png
│ │ ├── alt_threads_scroll_down_icon_black.xml
│ │ ├── alt_threads_scroll_down_icon_light.xml
│ │ ├── app_logo.png
│ │ ├── buttons_bg_selector.xml
│ │ ├── buttons_bg_selector_dark.xml
│ │ ├── buttons_text_color_selector.xml
│ │ ├── dark_theme.xml
│ │ ├── ic_back.xml
│ │ ├── ic_chevron_right.xml
│ │ ├── ic_cloud.xml
│ │ ├── ic_edit.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_ok.xml
│ │ ├── ic_ok_desable.xml
│ │ ├── ic_ok_pressed.xml
│ │ ├── ic_ok_selector.xml
│ │ ├── ic_plus.xml
│ │ ├── ic_remove.xml
│ │ ├── ic_settings.xml
│ │ ├── ic_user.xml
│ │ ├── im_users_empty.xml
│ │ ├── light_theme.xml
│ │ ├── red_cyrcle.xml
│ │ ├── secondary_buttons_bg_selector.xml
│ │ ├── secondary_buttons_text_color_selector.xml
│ │ ├── splash_background.xml
│ │ ├── text_button_bg_selector.xml
│ │ └── text_button_text_color_selector.xml
│ │ ├── font
│ │ └── roboto_medium.ttf
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_test_chat.xml
│ │ ├── fragment_add_server.xml
│ │ ├── fragment_add_user.xml
│ │ ├── fragment_chat.xml
│ │ ├── fragment_launch.xml
│ │ ├── fragment_samples_list.xml
│ │ ├── fragment_server_list.xml
│ │ ├── fragment_user_list.xml
│ │ ├── holder_demo_samples_text.xml
│ │ ├── holder_demo_samples_title.xml
│ │ ├── holder_horizontal_line.xml
│ │ ├── input_field.xml
│ │ ├── server_list_item.xml
│ │ └── user_list_item.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── navigation
│ │ └── nav_graph.xml
│ │ ├── raw
│ │ ├── history_bot_response.json
│ │ ├── history_deleted_and_edited_messages.json
│ │ ├── history_errors_response.json
│ │ ├── history_files_response.json
│ │ ├── history_images_response.json
│ │ ├── history_system_response.json
│ │ ├── history_text_response.json
│ │ ├── history_voice_response.json
│ │ ├── snapshot_test_errors_response.json
│ │ ├── snapshot_test_history_bot_response.json
│ │ ├── snapshot_test_history_images_response_1.json
│ │ ├── snapshot_test_history_images_response_2.json
│ │ ├── snapshot_test_history_images_response_3.json
│ │ ├── snapshot_test_history_images_response_4.json
│ │ ├── snapshot_test_history_system_response.json
│ │ ├── snapshot_test_history_text_response_1.json
│ │ ├── snapshot_test_history_text_response_2.json
│ │ ├── snapshot_test_history_text_response_3.json
│ │ └── snapshot_test_history_voice_response.json
│ │ ├── values-hdpi
│ │ └── dimens.xml
│ │ ├── values-land
│ │ └── dimens.xml
│ │ ├── values-night
│ │ └── themes.xml
│ │ ├── values-w1240dp
│ │ └── dimens.xml
│ │ ├── values-w600dp
│ │ └── dimens.xml
│ │ ├── values
│ │ ├── attr.xml
│ │ ├── bools.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── backup_rules.xml
│ │ ├── data_extraction_rules.xml
│ │ └── network_security_config.xml
│ └── test
│ └── java
│ └── io
│ └── edna
│ └── threads
│ └── demo
│ └── ExampleUnitTest.kt
├── build.gradle
├── docs
├── image1.jpg
├── image2.jpg
├── image3.jpg
├── image4.png
├── image5.png
├── image6.png
├── image7.png
└── image8.png
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── push-lib
├── Android_SDK_autodraw_3.3.0.docx
├── MFMSPushLite.pdf
└── edna-PushService-MobileSDK-Android-Lite_3.3.0.docx
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # User-specific configurations
2 | .idea/libraries/
3 | .idea/workspace.xml
4 | .idea/tasks.xml
5 | .idea/.name
6 | .idea/compiler.xml
7 | .idea/copyright/profiles_settings.xml
8 | .idea/encodings.xml
9 | .idea/misc.xml
10 | .idea/modules.xml
11 | .idea/scopes/scope_settings.xml
12 | .idea/vcs.xml
13 |
14 | *.iml
15 | .gradle
16 | /local.properties
17 | */.idea
18 | .DS_Store
19 | /build
20 | /captures
21 | /.idea
22 | /threads/src/main/assets/crashlytics-build.properties
23 | /threads/src/main/res/values/com_crashlytics_export_strings.xml
24 |
25 | /fastlane/report.xml
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # edna Android SDK
2 | edna Android SDK libraries and Demo project
3 |
4 | [Documentation and Guides](https://edna-io.github.io/android/intro)
5 |
6 | Contacts:
7 | https://edna.ru/
support@edna.ru
8 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in H:\AndroidSDK/tools/proguard/proguard-android.txt
4 | # You can edit the include text and order by changing the proguardFiles
5 | # directive in buildBundle.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 | ##---------------Begin: proguard configuration for Gson ----------
19 | # Gson uses generic type information stored in a class file when working with fields. Proguard
20 | # removes such information by default, so configure it to keep all of it.
21 | -keepattributes Signature
22 |
23 | # For using GSON @Expose annotation
24 | -keepattributes *Annotation*
25 |
26 | # Gson specific classes
27 | -dontwarn sun.misc.**
28 | #-keep class com.google.gson.stream.** { *; }
29 |
30 | # Application classes that will be serialized/deserialized over Gson
31 | -keep class im.threads.** { *; }
32 |
33 | # Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
34 | # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
35 | -keep class * extends com.google.gson.TypeAdapter
36 | -keep class * implements com.google.gson.TypeAdapterFactory
37 | -keep class * implements com.google.gson.JsonSerializer
38 | -keep class * implements com.google.gson.JsonDeserializer
39 |
40 | # Prevent R8 from leaving Data object members always null
41 | -keepclassmembers,allowobfuscation class * {
42 | @com.google.gson.annotations.SerializedName ;
43 | }
44 |
45 | ##---------------End: proguard configuration for Gson ----------
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/MockTestRunner.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import androidx.test.runner.AndroidJUnitRunner
6 | import io.edna.threads.demo.integrationCode.EdnaThreadsApplication
7 |
8 | class MockTestRunner : AndroidJUnitRunner() {
9 |
10 | override fun newApplication(
11 | cl: ClassLoader?,
12 | className: String?,
13 | context: Context?
14 | ): Application {
15 | return super.newApplication(cl, EdnaThreadsApplication::class.java.name, context)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/AttachmentsSnapshotTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import android.os.Build
4 | import androidx.test.espresso.Espresso.onView
5 | import androidx.test.espresso.action.ViewActions.click
6 | import androidx.test.espresso.matcher.ViewMatchers.withTagValue
7 | import androidx.test.ext.junit.runners.AndroidJUnit4
8 | import androidx.test.rule.GrantPermissionRule
9 | import dev.testify.annotation.ScreenshotInstrumentation
10 | import io.edna.threads.demo.R
11 | import org.hamcrest.Matchers.`is`
12 | import org.junit.Rule
13 | import org.junit.Test
14 | import org.junit.runner.RunWith
15 |
16 | @RunWith(AndroidJUnit4::class)
17 | class AttachmentsSnapshotTest : SnapshotBaseTest(R.raw.snapshot_test_history_text_response_1) {
18 | @get:Rule
19 | var permissionRule = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
20 | GrantPermissionRule.grant(
21 | android.Manifest.permission.READ_MEDIA_IMAGES,
22 | android.Manifest.permission.READ_MEDIA_VIDEO,
23 | android.Manifest.permission.READ_MEDIA_AUDIO
24 | )
25 | } else {
26 | GrantPermissionRule.grant(android.Manifest.permission.READ_EXTERNAL_STORAGE)
27 | }
28 |
29 | @ScreenshotInstrumentation
30 | @Test
31 | override fun testChat() {
32 | rule.setEspressoActions {
33 | onView(withTagValue(`is`("add_attachment"))).perform(click())
34 | }.assertSame()
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ChatBotSnapshotTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import io.edna.threads.demo.R
5 | import org.junit.runner.RunWith
6 |
7 | @RunWith(AndroidJUnit4::class)
8 | class ChatBotSnapshotTest : SnapshotBaseTest(R.raw.snapshot_test_history_system_response)
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ChatErrorsSnapshotTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import io.edna.threads.demo.R
5 | import org.junit.runner.RunWith
6 |
7 | @RunWith(AndroidJUnit4::class)
8 | class ChatErrorsSnapshotTest : SnapshotBaseTest(R.raw.snapshot_test_errors_response)
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ChatFilesSnapshotTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import io.edna.threads.demo.R
5 | import org.junit.runner.RunWith
6 |
7 | @RunWith(AndroidJUnit4::class)
8 | class ChatFilesSnapshotTest : SnapshotBaseTest(R.raw.history_files_response)
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ChatImagesSnapshotTest1.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import io.edna.threads.demo.R
5 | import org.junit.runner.RunWith
6 |
7 | @RunWith(AndroidJUnit4::class)
8 | class ChatImagesSnapshotTest1 : SnapshotBaseTest(R.raw.snapshot_test_history_images_response_1)
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ChatImagesSnapshotTest2.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import io.edna.threads.demo.R
5 | import org.junit.runner.RunWith
6 |
7 | @RunWith(AndroidJUnit4::class)
8 | class ChatImagesSnapshotTest2 : SnapshotBaseTest(R.raw.snapshot_test_history_images_response_2)
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ChatImagesSnapshotTest3.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import io.edna.threads.demo.R
5 | import org.junit.runner.RunWith
6 |
7 | @RunWith(AndroidJUnit4::class)
8 | class ChatImagesSnapshotTest3 : SnapshotBaseTest(R.raw.snapshot_test_history_images_response_3)
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ChatImagesSnapshotTest4.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import io.edna.threads.demo.R
5 | import org.junit.runner.RunWith
6 |
7 | @RunWith(AndroidJUnit4::class)
8 | class ChatImagesSnapshotTest4 : SnapshotBaseTest(R.raw.snapshot_test_history_images_response_4)
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ChatSystemSnapshotTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import io.edna.threads.demo.R
5 | import org.junit.runner.RunWith
6 |
7 | @RunWith(AndroidJUnit4::class)
8 | class ChatSystemSnapshotTest : SnapshotBaseTest(R.raw.snapshot_test_history_system_response)
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ChatTextSnapshotTest1.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import io.edna.threads.demo.R
5 | import org.junit.runner.RunWith
6 |
7 | @RunWith(AndroidJUnit4::class)
8 | class ChatTextSnapshotTest1 : SnapshotBaseTest(R.raw.snapshot_test_history_text_response_1)
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ChatTextSnapshotTest2.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import io.edna.threads.demo.R
5 | import org.junit.runner.RunWith
6 |
7 | @RunWith(AndroidJUnit4::class)
8 | class ChatTextSnapshotTest2 : SnapshotBaseTest(R.raw.snapshot_test_history_text_response_2)
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ChatVoiceSnapshotTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import io.edna.threads.demo.R
5 | import org.junit.runner.RunWith
6 |
7 | @RunWith(AndroidJUnit4::class)
8 | class ChatVoiceSnapshotTest : SnapshotBaseTest(R.raw.snapshot_test_history_voice_response)
9 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ConsultActivitySnapshotTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import dev.testify.ScreenshotRule
5 | import dev.testify.annotation.ScreenshotInstrumentation
6 | import im.threads.business.models.ConsultInfo
7 | import im.threads.ui.activities.ConsultActivity
8 | import org.junit.Rule
9 | import org.junit.Test
10 | import org.junit.runner.RunWith
11 |
12 | @RunWith(AndroidJUnit4::class)
13 | class ConsultActivitySnapshotTest {
14 | private val avatarUrl = "https://noednaimage.ru/1.jpg"
15 | private val status = "Active"
16 | private val name = "Operator Alisa"
17 |
18 | @get:Rule
19 | val rule = ScreenshotRule(ConsultActivity::class.java).apply {
20 | addIntentExtras {
21 | it.putParcelable(
22 | ConsultActivity.consultInfoKey,
23 | ConsultInfo(
24 | photoUrl = avatarUrl,
25 | status = status,
26 | name = name
27 | )
28 | )
29 | }
30 | }
31 |
32 | @ScreenshotInstrumentation
33 | @Test
34 | fun testConsultActivity() {
35 | rule.assertSame()
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/GalleryActivitySnapshotTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import dev.testify.ScreenshotRule
5 | import dev.testify.annotation.ScreenshotInstrumentation
6 | import im.threads.ui.activities.GalleryActivity
7 | import org.junit.Rule
8 | import org.junit.Test
9 | import org.junit.runner.RunWith
10 |
11 | @RunWith(AndroidJUnit4::class)
12 | class GalleryActivitySnapshotTest {
13 | @get:Rule
14 | val rule = ScreenshotRule(GalleryActivity::class.java).apply {
15 | addIntentExtras {
16 | it.putInt(PHOTOS_REQUEST_CODE_TAG, 2345)
17 | }
18 | }
19 |
20 | @ScreenshotInstrumentation
21 | @Test
22 | fun testGalleryActivity() {
23 | rule.assertSame()
24 | }
25 | }
26 |
27 | private const val PHOTOS_REQUEST_CODE_TAG = "PHOTOS_REQUEST_CODE_TAG"
28 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ReplySnapshotTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.espresso.Espresso
4 | import androidx.test.espresso.action.ViewActions
5 | import androidx.test.espresso.matcher.ViewMatchers
6 | import androidx.test.ext.junit.runners.AndroidJUnit4
7 | import dev.testify.annotation.ScreenshotInstrumentation
8 | import io.edna.threads.demo.R
9 | import org.hamcrest.Matchers
10 | import org.junit.Test
11 | import org.junit.runner.RunWith
12 |
13 | @RunWith(AndroidJUnit4::class)
14 | class ReplySnapshotTest : SnapshotBaseTest(R.raw.snapshot_test_history_text_response_1) {
15 | @ScreenshotInstrumentation
16 | @Test
17 | override fun testChat() {
18 | rule.setEspressoActions {
19 | Espresso.onView(ViewMatchers.withTagValue(Matchers.`is`("bubble")))
20 | .perform(ViewActions.longClick())
21 | Espresso.onView(ViewMatchers.withTagValue(Matchers.`is`("replyIcon")))
22 | .perform(ViewActions.click())
23 | }.assertSame()
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/SnapshotBaseTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import dev.testify.ScreenshotRule
4 | import dev.testify.annotation.ScreenshotInstrumentation
5 | import io.edna.threads.demo.appCode.test.TestChatActivity
6 | import org.junit.Ignore
7 | import org.junit.Rule
8 | import org.junit.Test
9 |
10 | @Ignore("Base class, run it in descendants")
11 | open class SnapshotBaseTest(private val jsonResourceId: Int) {
12 | @get:Rule
13 | val rule = ScreenshotRule(TestChatActivity::class.java).apply {
14 | saveJsonMock(jsonResourceId, this)
15 | }
16 |
17 | @ScreenshotInstrumentation
18 | @Test
19 | open fun testChat() {
20 | rule.setEspressoActions {
21 | Thread.sleep(2000)
22 | }.assertSame()
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/SnapshotsCommonCode.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import dev.testify.ScreenshotRule
5 | import io.edna.threads.demo.appCode.test.TestChatActivity
6 | import java.io.BufferedReader
7 | import java.io.IOException
8 | import java.io.InputStream
9 | import java.io.InputStreamReader
10 |
11 | internal fun saveJsonMock(resourceId: Int, rule: ScreenshotRule) {
12 | var string: String? = ""
13 | val stringBuilder = StringBuilder()
14 | val context = InstrumentationRegistry.getInstrumentation().targetContext
15 | val inputStream: InputStream = context.resources.openRawResource(resourceId)
16 | val reader = BufferedReader(InputStreamReader(inputStream))
17 |
18 | while (true) {
19 | try {
20 | if (reader.readLine().also { string = it } == null) break
21 | } catch (e: IOException) {
22 | e.printStackTrace()
23 | }
24 | stringBuilder.append(string).append("\n")
25 | }
26 |
27 | inputStream.close()
28 | rule.addIntentExtras {
29 | it.putString(TestChatActivity.jsonMockExtraKey, stringBuilder.toString())
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/io/edna/threads/demo/snapshot/ToolbarIconsSnapshotTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.snapshot
2 |
3 | import androidx.test.espresso.Espresso
4 | import androidx.test.espresso.action.ViewActions
5 | import androidx.test.espresso.matcher.ViewMatchers
6 | import androidx.test.ext.junit.runners.AndroidJUnit4
7 | import dev.testify.annotation.ScreenshotInstrumentation
8 | import io.edna.threads.demo.R
9 | import org.hamcrest.Matchers
10 | import org.junit.Test
11 | import org.junit.runner.RunWith
12 |
13 | @RunWith(AndroidJUnit4::class)
14 | class ToolbarIconsSnapshotTest : SnapshotBaseTest(R.raw.snapshot_test_history_text_response_1) {
15 | @ScreenshotInstrumentation
16 | @Test
17 | override fun testChat() {
18 | rule.setEspressoActions {
19 | Espresso.onView(ViewMatchers.withTagValue(Matchers.`is`("bubble")))
20 | .perform(ViewActions.longClick())
21 | }.assertSame()
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
60 |
61 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/lato-bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/fonts/lato-bold.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/lato-light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/fonts/lato-light.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/lato-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/fonts/lato-regular.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/servers_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "servers": [
3 | {
4 | "name": "Default",
5 | "threadsGateProviderUid": "MOBILE1_93jLrvripZeDXSKJzdRfEu9QpMMvIe5LKKHQl",
6 | "serverBaseUrl": "http://mobile1.chc.dte/",
7 | "datastoreUrl": "http://datastore.mobile1.chc.dte/",
8 | "threadsGateUrl": "ws://mobile1.chc.dte/socket"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/client_text1.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/client_text1.ogg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/client_text2.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/client_text2.ogg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/client_text3.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/client_text3.ogg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/client_text4.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/client_text4.ogg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/operator_text1.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/operator_text1.ogg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/operator_text2.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/operator_text2.ogg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/operator_text3.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/operator_text3.ogg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/operator_text4.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/operator_text4.ogg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/test_image1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/test_image1.jpg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/test_image2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/test_image2.jpg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/test_image3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/test_image3.jpg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/test_image4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/test_image4.jpg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/test_image5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/test_image5.jpg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/test_image6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/test_image6.jpg
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/test_pdf1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/test_pdf1.pdf
--------------------------------------------------------------------------------
/app/src/main/assets/test_files/test_pdf2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/assets/test_files/test_pdf2.pdf
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/activity/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.activity
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.navigation.findNavController
6 | import androidx.navigation.ui.AppBarConfiguration
7 | import androidx.navigation.ui.navigateUp
8 | import io.edna.threads.demo.R
9 | import io.edna.threads.demo.databinding.ActivityMainBinding
10 |
11 | class MainActivity : AppCompatActivity() {
12 |
13 | private lateinit var appBarConfiguration: AppBarConfiguration
14 | private lateinit var binding: ActivityMainBinding
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | binding = ActivityMainBinding.inflate(layoutInflater)
19 | setContentView(binding.root)
20 | }
21 |
22 | override fun onSupportNavigateUp(): Boolean {
23 | val navController = findNavController(R.id.nav_host_fragment_content_main)
24 | return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/activity/SplashScreenActivity.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.activity
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.appcompat.app.AppCompatActivity
7 |
8 | @SuppressLint("CustomSplashScreen")
9 | class SplashScreenActivity : AppCompatActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | startActivity(Intent(this, MainActivity::class.java))
13 | finish()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/adapters/EccTouchHelperCallBack.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.adapters
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import androidx.core.content.ContextCompat
6 | import androidx.recyclerview.widget.ItemTouchHelper
7 | import androidx.recyclerview.widget.RecyclerView
8 | import io.edna.threads.demo.R
9 | import io.edna.threads.demo.appCode.extensions.isDarkThemeOn
10 | import io.edna.threads.demo.appCode.views.ItemDecorator
11 |
12 | class EccTouchHelperCallBack(
13 | private val context: Context,
14 | private val listener: ListItemClickListener,
15 | dragDirs: Int,
16 | swipeDirs: Int
17 | ) : ItemTouchHelper.SimpleCallback(dragDirs, swipeDirs) {
18 |
19 | override fun onMove(
20 | recyclerView: RecyclerView,
21 | viewHolder: RecyclerView.ViewHolder,
22 | target: RecyclerView.ViewHolder
23 | ): Boolean = false
24 |
25 | override fun onChildDraw(
26 | canvas: Canvas,
27 | recyclerView: RecyclerView,
28 | viewHolder: RecyclerView.ViewHolder,
29 | dX: Float,
30 | dY: Float,
31 | actionState: Int,
32 | isCurrentlyActive: Boolean
33 | ) {
34 | val defaultWhiteColor = if (context.isDarkThemeOn()) {
35 | ContextCompat.getColor(context, R.color.white_color_fa)
36 | } else {
37 | ContextCompat.getColor(context, R.color.black_color)
38 | }
39 |
40 | val teal200 = ContextCompat.getColor(context, R.color.blue_color)
41 | val colorAlert = ContextCompat.getColor(context, R.color.red_color)
42 |
43 | ItemDecorator.Builder(canvas, recyclerView, viewHolder, dX, actionState).set(
44 | backgroundColorFromStartToEnd = colorAlert,
45 | backgroundColorFromEndToStart = teal200,
46 | textFromStartToEnd = context.getString(R.string.remove),
47 | textFromEndToStart = context.getString(R.string.edit),
48 | textColorFromStartToEnd = defaultWhiteColor,
49 | textColorFromEndToStart = defaultWhiteColor,
50 | iconTintColorFromStartToEnd = defaultWhiteColor,
51 | iconTintColorFromEndToStart = defaultWhiteColor,
52 | iconResIdFromStartToEnd = R.drawable.ic_remove,
53 | iconResIdFromEndToStart = R.drawable.ic_edit
54 | )
55 |
56 | super.onChildDraw(
57 | canvas,
58 | recyclerView,
59 | viewHolder,
60 | dX,
61 | dY,
62 | actionState,
63 | isCurrentlyActive
64 | )
65 | }
66 |
67 | override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
68 | val position = viewHolder.adapterPosition
69 | when (direction) {
70 | ItemTouchHelper.LEFT -> {
71 | listener.onEditItem(position)
72 | }
73 | ItemTouchHelper.RIGHT -> {
74 | listener.onRemoveItem(position)
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/adapters/ListItemClickListener.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.adapters
2 |
3 | interface ListItemClickListener {
4 | fun onClick(position: Int)
5 | fun onEditItem(position: Int)
6 | fun onRemoveItem(position: Int)
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/adapters/demoSamplesList/DemoSamplesAdapter.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.adapters.demoSamplesList
2 |
3 | import android.content.Context
4 | import android.view.LayoutInflater
5 | import android.view.ViewGroup
6 | import androidx.core.content.ContextCompat
7 | import androidx.recyclerview.widget.DiffUtil
8 | import androidx.recyclerview.widget.RecyclerView
9 | import io.edna.threads.demo.R
10 | import io.edna.threads.demo.appCode.business.UiThemeProvider
11 | import io.edna.threads.demo.appCode.business.ordinal
12 | import io.edna.threads.demo.appCode.models.DemoSamplesListItem
13 | import io.edna.threads.demo.appCode.models.DemoSamplesListItem.DIVIDER
14 | import io.edna.threads.demo.appCode.models.DemoSamplesListItem.TEXT
15 | import io.edna.threads.demo.appCode.models.DemoSamplesListItem.TITLE
16 | import io.edna.threads.demo.databinding.HolderDemoSamplesTextBinding
17 | import io.edna.threads.demo.databinding.HolderDemoSamplesTitleBinding
18 | import io.edna.threads.demo.databinding.HolderHorizontalLineBinding
19 | import org.koin.java.KoinJavaComponent.inject
20 |
21 | class DemoSamplesAdapter(private val onItemClickListener: SampleListItemOnClick) : RecyclerView.Adapter() {
22 | private val list: MutableList = mutableListOf()
23 | private val uiThemeProvider: UiThemeProvider by inject(UiThemeProvider::class.java)
24 | private lateinit var context: Context
25 |
26 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
27 | val inflater = LayoutInflater.from(parent.context)
28 | context = parent.context
29 | return when (viewType) {
30 | DIVIDER.ordinal() -> {
31 | LineDividerHolder(HolderHorizontalLineBinding.inflate(inflater))
32 | }
33 | TITLE.ordinal() -> {
34 | TitleHolder(HolderDemoSamplesTitleBinding.inflate(inflater))
35 | }
36 | TEXT.ordinal() -> {
37 | TextHolder(HolderDemoSamplesTextBinding.inflate(inflater))
38 | }
39 | else -> throw IllegalStateException()
40 | }
41 | }
42 |
43 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
44 | (holder as? DemoSamplesHolder)?.onBind(position)
45 | }
46 |
47 | override fun getItemCount() = list.count()
48 |
49 | override fun getItemViewType(position: Int) = list[position].ordinal()
50 |
51 | fun addItems(newItems: List) {
52 | notifyDatasetChangedWithDiffUtil(newItems)
53 | }
54 |
55 | private fun notifyDatasetChangedWithDiffUtil(newList: List) {
56 | val diffResult = DiffUtil.calculateDiff(DemoSamplesDiffCallback(list, newList))
57 | list.clear()
58 | list.addAll(newList)
59 | diffResult.dispatchUpdatesTo(this)
60 | }
61 |
62 | private inner class LineDividerHolder(binding: HolderHorizontalLineBinding) :
63 | RecyclerView.ViewHolder(binding.root), DemoSamplesHolder
64 |
65 | private inner class TitleHolder(val binding: HolderDemoSamplesTitleBinding) :
66 | RecyclerView.ViewHolder(binding.root), DemoSamplesHolder {
67 |
68 | override fun onBind(position: Int) {
69 | (list[position] as? TITLE)?.let { binding.titleTextView.text = it.text }
70 | }
71 | }
72 |
73 | private inner class TextHolder(val binding: HolderDemoSamplesTextBinding) :
74 | RecyclerView.ViewHolder(binding.root), DemoSamplesHolder {
75 |
76 | override fun onBind(position: Int) {
77 | (list[position] as? TEXT)?.let { item ->
78 | binding.textTextView.apply {
79 | text = item.text
80 | if (uiThemeProvider.isDarkThemeOn()) {
81 | setTextColor(ContextCompat.getColor(context, R.color.white_color_fa))
82 | } else {
83 | setTextColor(ContextCompat.getColor(context, R.color.black_color))
84 | }
85 | setOnClickListener { onItemClickListener.onClick(item) }
86 | }
87 | }
88 | }
89 | }
90 |
91 | private interface DemoSamplesHolder {
92 | fun onBind(position: Int) {}
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/adapters/demoSamplesList/DemoSamplesDiffCallback.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.adapters.demoSamplesList
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 | import io.edna.threads.demo.appCode.models.DemoSamplesListItem
5 |
6 | class DemoSamplesDiffCallback(
7 | private val oldList: List,
8 | private val newList: List
9 | ) : DiffUtil.Callback() {
10 |
11 | override fun getOldListSize() = oldList.size
12 |
13 | override fun getNewListSize() = newList.size
14 |
15 | override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
16 | return oldList[oldItemPosition] == newList[newItemPosition]
17 | }
18 |
19 | override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
20 | val oldItem = oldList[oldItemPosition]
21 | val newItem = newList[newItemPosition]
22 |
23 | if (oldItem is DemoSamplesListItem.DIVIDER && newItem is DemoSamplesListItem.DIVIDER) {
24 | return true
25 | }
26 |
27 | return oldItem.toString() == newItem.toString()
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/adapters/demoSamplesList/SampleListItemOnClick.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.adapters.demoSamplesList
2 |
3 | import io.edna.threads.demo.appCode.models.DemoSamplesListItem
4 |
5 | interface SampleListItemOnClick {
6 | fun onClick(item: DemoSamplesListItem)
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/adapters/serverList/ServerListAdapter.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.adapters.serverList
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.core.content.ContextCompat
6 | import androidx.recyclerview.widget.DiffUtil
7 | import androidx.recyclerview.widget.RecyclerView
8 | import im.threads.ui.utils.ColorsHelper
9 | import io.edna.threads.demo.R
10 | import io.edna.threads.demo.appCode.adapters.ListItemClickListener
11 | import io.edna.threads.demo.appCode.extensions.isDarkThemeOn
12 | import io.edna.threads.demo.appCode.models.ServerConfig
13 | import io.edna.threads.demo.databinding.ServerListItemBinding
14 |
15 | class ServerListAdapter(private val onItemClickListener: ListItemClickListener) :
16 | RecyclerView.Adapter() {
17 |
18 | private val list: MutableList = mutableListOf()
19 |
20 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ServerItemHolder {
21 | val inflater = LayoutInflater.from(parent.context)
22 | return ServerItemHolder(ServerListItemBinding.inflate(inflater))
23 | }
24 |
25 | override fun onBindViewHolder(holder: ServerItemHolder, position: Int) {
26 | holder.onBind(position)
27 | }
28 |
29 | override fun getItemCount() = list.count()
30 |
31 | fun addItems(newItems: List) {
32 | notifyDatasetChangedWithDiffUtil(newItems)
33 | }
34 |
35 | fun getItem(position: Int): ServerConfig {
36 | return list[position]
37 | }
38 |
39 | private fun notifyDatasetChangedWithDiffUtil(newList: List) {
40 | val diffResult = DiffUtil.calculateDiff(ServerListDiffCallback(list, newList))
41 | list.clear()
42 | list.addAll(newList)
43 | diffResult.dispatchUpdatesTo(this)
44 | }
45 |
46 | inner class ServerItemHolder(val binding: ServerListItemBinding) :
47 | RecyclerView.ViewHolder(binding.root) {
48 |
49 | fun onBind(position: Int) {
50 | (list[position] as? ServerConfig)?.let { item ->
51 | binding.name.text = item.name
52 | binding.description.text = item.serverBaseUrl
53 | if (binding.root.context.isDarkThemeOn()) {
54 | binding.name.setTextColor(
55 | ContextCompat.getColor(
56 | binding.root.context,
57 | R.color.white_color_fa
58 | )
59 | )
60 | binding.description.setTextColor(
61 | ContextCompat.getColor(
62 | binding.root.context,
63 | R.color.white_color_fa
64 | )
65 | )
66 | ColorsHelper.setTint(
67 | binding.root.context,
68 | binding.image,
69 | R.color.white_color_fa
70 | )
71 | } else {
72 | binding.name.setTextColor(
73 | ContextCompat.getColor(
74 | binding.root.context,
75 | R.color.black_color
76 | )
77 | )
78 | binding.description.setTextColor(
79 | ContextCompat.getColor(
80 | binding.root.context,
81 | R.color.black_color
82 | )
83 | )
84 | ColorsHelper.setTint(binding.root.context, binding.image, R.color.black_color)
85 | }
86 | binding.rootLayout.setOnClickListener { onItemClickListener.onClick(position) }
87 | }
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/adapters/serverList/ServerListDiffCallback.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.adapters.serverList
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 | import io.edna.threads.demo.appCode.models.ServerConfig
5 |
6 | class ServerListDiffCallback(
7 | private val oldList: List,
8 | private val newList: List
9 | ) : DiffUtil.Callback() {
10 |
11 | override fun getOldListSize() = oldList.size
12 |
13 | override fun getNewListSize() = newList.size
14 |
15 | override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
16 | return oldList[oldItemPosition] == newList[newItemPosition]
17 | }
18 |
19 | override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
20 | val oldItem = oldList[oldItemPosition]
21 | val newItem = newList[newItemPosition]
22 | return oldItem == newItem
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/adapters/userList/UserListAdapter.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.adapters.userList
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.core.content.ContextCompat
6 | import androidx.recyclerview.widget.DiffUtil
7 | import androidx.recyclerview.widget.RecyclerView
8 | import im.threads.ui.utils.ColorsHelper
9 | import io.edna.threads.demo.R
10 | import io.edna.threads.demo.appCode.adapters.ListItemClickListener
11 | import io.edna.threads.demo.appCode.extensions.isDarkThemeOn
12 | import io.edna.threads.demo.appCode.models.UserInfo
13 | import io.edna.threads.demo.databinding.UserListItemBinding
14 | import java.lang.ref.WeakReference
15 |
16 | class UserListAdapter(private val onItemClickListener: WeakReference) :
17 | RecyclerView.Adapter() {
18 |
19 | private val list: MutableList = mutableListOf()
20 |
21 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserItemHolder {
22 | val inflater = LayoutInflater.from(parent.context)
23 | return UserItemHolder(UserListItemBinding.inflate(inflater))
24 | }
25 |
26 | override fun onBindViewHolder(holder: UserItemHolder, position: Int) {
27 | holder.onBind(position)
28 | }
29 |
30 | override fun getItemCount() = list.count()
31 |
32 | fun addItems(newItems: List) {
33 | notifyDatasetChangedWithDiffUtil(newItems)
34 | }
35 |
36 | fun getItem(position: Int): UserInfo {
37 | return list[position]
38 | }
39 |
40 | private fun notifyDatasetChangedWithDiffUtil(newList: List) {
41 | val diffResult = DiffUtil.calculateDiff(UserListDiffCallback(list, newList))
42 | list.clear()
43 | list.addAll(newList)
44 | diffResult.dispatchUpdatesTo(this)
45 | }
46 |
47 | inner class UserItemHolder(private val binding: UserListItemBinding) :
48 | RecyclerView.ViewHolder(binding.root) {
49 |
50 | fun onBind(position: Int) {
51 | (list[position] as? UserInfo)?.let { item ->
52 | binding.userId.text = item.userId
53 | if (binding.root.context.isDarkThemeOn()) {
54 | binding.userId.setTextColor(ContextCompat.getColor(binding.root.context, R.color.white_color_fa))
55 | ColorsHelper.setTint(binding.root.context, binding.image, R.color.white_color_fa)
56 | } else {
57 | binding.userId.setTextColor(ContextCompat.getColor(binding.root.context, R.color.black_color))
58 | ColorsHelper.setTint(binding.root.context, binding.image, R.color.black_color)
59 | }
60 | binding.rootLayout.setOnClickListener { onItemClickListener.get()?.onClick(position) }
61 | }
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/adapters/userList/UserListDiffCallback.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.adapters.userList
2 |
3 | import androidx.recyclerview.widget.DiffUtil
4 | import io.edna.threads.demo.appCode.models.UserInfo
5 |
6 | class UserListDiffCallback(
7 | private val oldList: List,
8 | private val newList: List
9 | ) : DiffUtil.Callback() {
10 |
11 | override fun getOldListSize() = oldList.size
12 |
13 | override fun getNewListSize() = newList.size
14 |
15 | override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
16 | return oldList[oldItemPosition] == newList[newItemPosition]
17 | }
18 |
19 | override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
20 | val oldItem = oldList[oldItemPosition]
21 | val newItem = newList[newItemPosition]
22 | return oldItem == newItem
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/business/AfterTextChangedTextWatcher.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.business
2 |
3 | import android.text.TextWatcher
4 |
5 | interface AfterTextChangedTextWatcher : TextWatcher {
6 | override fun beforeTextChanged(str: CharSequence?, start: Int, count: Int, after: Int) {}
7 | override fun onTextChanged(str: CharSequence?, start: Int, before: Int, count: Int) {}
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/business/Extensions.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.business
2 |
3 | inline fun T.ordinal(): Int {
4 | if (T::class.isSealed) {
5 | return T::class.java.classes.indexOfFirst { sub -> sub == javaClass }
6 | }
7 | val klass = if (T::class.isCompanion) {
8 | javaClass.declaringClass
9 | } else {
10 | javaClass
11 | }
12 |
13 | return klass.superclass?.classes?.indexOfFirst { it == klass } ?: -1
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/business/KoinModules.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.business
2 |
3 | import io.edna.threads.demo.appCode.business.mockJsonProvider.CurrentJsonProvider
4 | import io.edna.threads.demo.appCode.business.mockJsonProvider.SamplesJsonProvider
5 | import io.edna.threads.demo.appCode.fragments.demoSamplesFragment.DemoSamplesViewModel
6 | import io.edna.threads.demo.appCode.fragments.demoSamplesList.DemoSamplesListViewModel
7 | import io.edna.threads.demo.appCode.fragments.server.AddServerViewModel
8 | import io.edna.threads.demo.appCode.fragments.server.ServerListViewModel
9 | import io.edna.threads.demo.appCode.fragments.user.AddUserViewModel
10 | import io.edna.threads.demo.appCode.fragments.user.UserListViewModel
11 | import io.edna.threads.demo.integrationCode.fragments.launch.LaunchViewModel
12 | import org.koin.androidx.viewmodel.dsl.viewModel
13 | import org.koin.dsl.module
14 |
15 | val appModule = module {
16 | single { CurrentJsonProvider(get()) }
17 | single { SamplesJsonProvider(get()) }
18 | single { StringsProvider(get()) }
19 | single { PreferencesProvider(get()) }
20 | single { UiThemeProvider(get()) }
21 | factory { ServersProvider(get(), get()) }
22 | viewModel { LaunchViewModel(get(), get(), get()) }
23 | viewModel { UserListViewModel(get()) }
24 | viewModel { AddUserViewModel(get()) }
25 | viewModel { ServerListViewModel(get(), get()) }
26 | viewModel { AddServerViewModel(get()) }
27 | viewModel { DemoSamplesViewModel(get(), get()) }
28 | viewModel { DemoSamplesListViewModel(get(), get(), get()) }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/business/ServersProvider.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.business
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import io.edna.threads.demo.appCode.models.ServerConfig
6 | import org.json.JSONObject
7 | import java.io.BufferedReader
8 | import java.io.InputStream
9 |
10 | class ServersProvider(
11 | private val context: Context,
12 | private val preferences: PreferencesProvider
13 | ) {
14 | @SuppressLint("DiscouragedApi")
15 | fun readServersFromFile(): ArrayList {
16 | val inputStream: InputStream = context.assets.open("servers_config.json")
17 | val content = StringBuilder()
18 | val reader = BufferedReader(inputStream.reader())
19 | inputStream.use { stream ->
20 | kotlin.runCatching {
21 | var line = reader.readLine()
22 | while (line != null) {
23 | content.append(line.trim())
24 | line = reader.readLine()
25 | }
26 | stream.close()
27 | }
28 | }
29 | val jsonArray = JSONObject(content.toString()).getJSONArray("servers")
30 | val servers = ArrayList(jsonArray.length())
31 | for (i in 0 until jsonArray.length()) {
32 | val jsonObj = jsonArray.getJSONObject(i)
33 | servers.add(
34 | ServerConfig(
35 | name = jsonObj.getString("name"),
36 | threadsGateProviderUid = jsonObj.getString("threadsGateProviderUid"),
37 | datastoreUrl = jsonObj.getString("datastoreUrl"),
38 | serverBaseUrl = jsonObj.getString("serverBaseUrl"),
39 | threadsGateUrl = jsonObj.getString("threadsGateUrl"),
40 | trustedSSLCertificates = if (jsonObj.has("trustedSSLCertificates")) {
41 | val certificates = ArrayList()
42 | for (j in 0 until jsonObj.getJSONArray("trustedSSLCertificates").length()) {
43 | val certName = jsonObj.getJSONArray("trustedSSLCertificates").get(j).toString()
44 | val certId: Int = context.resources.getIdentifier(certName, "raw", context.packageName)
45 | if (certId > 0) {
46 | certificates.add(certId)
47 | }
48 | }
49 | certificates
50 | } else {
51 | null
52 | },
53 | allowUntrustedSSLCertificate = if (jsonObj.has("allowUntrustedSSLCertificate")) {
54 | jsonObj.getBoolean("allowUntrustedSSLCertificate")
55 | } else {
56 | false
57 | }
58 | )
59 | )
60 | }
61 | return servers
62 | }
63 |
64 | fun saveServersToPreferences(servers: ArrayList) {
65 | preferences.saveServers(servers)
66 | }
67 |
68 | fun saveSelectedServer(server: ServerConfig) {
69 | preferences.saveSelectedServer(server)
70 | }
71 |
72 | fun getSelectedServer(): ServerConfig? {
73 | val selected = preferences.getSelectedServer()
74 | val servers = readServersFromFile()
75 | return if (selected != null && selected.isAllFieldsFilled()) {
76 | servers.find { it.name == selected.name } ?: selected
77 | } else {
78 | if (servers.isNotEmpty()) {
79 | servers[0]
80 | } else {
81 | null
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/business/SingleLiveEvent.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.business
2 |
3 | import androidx.annotation.MainThread
4 | import androidx.lifecycle.LifecycleOwner
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.Observer
7 | import im.threads.business.logger.LoggerEdna
8 | import java.util.concurrent.atomic.AtomicBoolean
9 |
10 | class SingleLiveEvent : MutableLiveData() {
11 | private val pending = AtomicBoolean(false)
12 |
13 | @MainThread
14 | override fun observe(owner: LifecycleOwner, observer: Observer) {
15 | if (hasActiveObservers()) {
16 | LoggerEdna.warning("Multiple observers registered but only one will be notified of changes.")
17 | }
18 | super.observe(owner) { t ->
19 | if (pending.compareAndSet(true, false)) {
20 | observer.onChanged(t)
21 | }
22 | }
23 | }
24 |
25 | @MainThread
26 | override fun setValue(t: T?) {
27 | pending.set(true)
28 | super.setValue(t)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/business/StringsProvider.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.business
2 |
3 | import android.content.Context
4 | import io.edna.threads.demo.R
5 |
6 | class StringsProvider(context: Context) {
7 | val textMessages = context.getString(R.string.text_messages)
8 | val connectionErrors = context.getString(R.string.connection_errors)
9 | val voiceMessages = context.getString(R.string.voice_messages)
10 | val images = context.getString(R.string.images)
11 | val files = context.getString(R.string.files)
12 | val systemMessages = context.getString(R.string.system_messages)
13 | val chatWithBot = context.getString(R.string.chat_with_bot)
14 | val chatWithEditAndDeletedMessages = context.getString(R.string.deleted_and_edited_messages)
15 | val selectTheme = context.getString(R.string.select_theme)
16 | val defaultTheme = context.getString(R.string.default_theme)
17 | val darkTheme = context.getString(R.string.dark_theme)
18 | val lightTheme = context.getString(R.string.light_theme)
19 | val ok = context.getString(R.string.ok)
20 | val requiredField = context.getString(R.string.required_field)
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/business/TouchHelper.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.business
2 |
3 | import android.graphics.Canvas
4 | import android.graphics.Color
5 | import android.graphics.drawable.ColorDrawable
6 | import androidx.recyclerview.widget.ItemTouchHelper
7 | import androidx.recyclerview.widget.RecyclerView
8 | import org.koin.java.KoinJavaComponent
9 |
10 | class TouchHelper(listener: OnSwipeItemListener) {
11 |
12 | private val uiThemeProvider: UiThemeProvider by KoinJavaComponent.inject(UiThemeProvider::class.java)
13 |
14 | var touchHelperCallback: ItemTouchHelper.SimpleCallback =
15 | object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT) {
16 |
17 | private val background = if (uiThemeProvider.isDarkThemeOn()) {
18 | ColorDrawable(Color.BLACK)
19 | } else {
20 | ColorDrawable(Color.WHITE)
21 | }
22 |
23 | override fun onMove(
24 | recyclerView: RecyclerView,
25 | viewHolder: RecyclerView.ViewHolder,
26 | target: RecyclerView.ViewHolder
27 | ): Boolean {
28 | return false
29 | }
30 |
31 | override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
32 | listener.onSwiped(viewHolder.adapterPosition)
33 | }
34 |
35 | override fun onChildDraw(
36 | c: Canvas,
37 | recyclerView: RecyclerView,
38 | viewHolder: RecyclerView.ViewHolder,
39 | dX: Float,
40 | dY: Float,
41 | actionState: Int,
42 | isCurrentlyActive: Boolean
43 | ) {
44 | super.onChildDraw(
45 | c,
46 | recyclerView,
47 | viewHolder,
48 | dX,
49 | dY,
50 | actionState,
51 | isCurrentlyActive
52 | )
53 | val itemView = viewHolder.itemView
54 | if (dX > 0) {
55 | background.setBounds(
56 | itemView.left,
57 | itemView.top,
58 | itemView.left + dX.toInt(),
59 | itemView.bottom
60 | )
61 | } else if (dX < 0) {
62 | background.setBounds(
63 | itemView.right + dX.toInt(),
64 | itemView.top,
65 | itemView.right,
66 | itemView.bottom
67 | )
68 | } else {
69 | background.setBounds(0, 0, 0, 0)
70 | }
71 | background.draw(c)
72 | }
73 | }
74 |
75 | interface OnSwipeItemListener {
76 | fun onSwiped(position: Int)
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/business/UiThemeProvider.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.business
2 |
3 | import android.content.Context
4 | import im.threads.ui.extensions.isDarkThemeOn
5 |
6 | class UiThemeProvider(private val context: Context) {
7 | fun isDarkThemeOn() = context.isDarkThemeOn()
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/business/VolatileLiveData.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.business
2 |
3 | import androidx.annotation.MainThread
4 | import androidx.lifecycle.LifecycleOwner
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.Observer
7 | import java.util.concurrent.atomic.AtomicInteger
8 |
9 | open class VolatileLiveData : MutableLiveData() {
10 | private val lastValueSeq = AtomicInteger(0)
11 | private val wrappers = HashMap, Observer>()
12 |
13 | @MainThread
14 | override fun setValue(value: T) {
15 | lastValueSeq.incrementAndGet()
16 | super.setValue(value)
17 | }
18 |
19 | @MainThread
20 | override fun observe(owner: LifecycleOwner, observer: Observer) {
21 | val observerWrapper = ObserverWrapper(lastValueSeq, observer)
22 | wrappers[observer] = observerWrapper
23 | super.observe(owner, observerWrapper)
24 | }
25 |
26 | @MainThread
27 | override fun observeForever(observer: Observer) {
28 | val observerWrapper = ObserverWrapper(lastValueSeq, observer)
29 | wrappers[observer] = observerWrapper
30 | super.observeForever(observerWrapper)
31 | }
32 |
33 | @MainThread
34 | override fun removeObserver(observer: Observer) {
35 | val observerWrapper = wrappers[observer]
36 | observerWrapper?.let {
37 | wrappers.remove(observerWrapper)
38 | super.removeObserver(observerWrapper)
39 | }
40 | }
41 | }
42 |
43 | private class ObserverWrapper(private var currentSeq: AtomicInteger, private val observer: Observer) : Observer {
44 | private val initialSeq = currentSeq.get()
45 | private var _observer: Observer = Observer {
46 | if (currentSeq.get() != initialSeq) {
47 | _observer = observer
48 | _observer.onChanged(it)
49 | }
50 | }
51 |
52 | override fun onChanged(value: T) {
53 | _observer.onChanged(value)
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/business/mockJsonProvider/CurrentJsonProvider.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.business.mockJsonProvider
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 |
6 | class CurrentJsonProvider(private val context: Context) {
7 | private val preferences = context.getSharedPreferences("JsonPreferences", Context.MODE_PRIVATE)
8 |
9 | @SuppressLint("ApplySharedPref")
10 | fun saveCurrentJson(json: String) {
11 | preferences
12 | .edit()
13 | .putString(JSON_KEY, json)
14 | .commit()
15 | }
16 |
17 | fun getCurrentJson() = preferences.getString(JSON_KEY, "") ?: ""
18 | }
19 |
20 | private const val JSON_KEY = "JSON_KEY"
21 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/business/mockJsonProvider/SamplesJsonProvider.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.business.mockJsonProvider
2 |
3 | import android.content.Context
4 | import io.edna.threads.demo.R
5 | import java.io.BufferedReader
6 | import java.io.IOException
7 | import java.io.InputStream
8 | import java.io.InputStreamReader
9 |
10 | class SamplesJsonProvider(private val context: Context) {
11 | fun getTextChatJson() = readTextFileFromRawResourceId(R.raw.history_text_response)
12 |
13 | fun getConnectionErrorJson() = readTextFileFromRawResourceId(R.raw.history_errors_response)
14 |
15 | fun getVoicesChatJson() = readTextFileFromRawResourceId(R.raw.history_voice_response)
16 |
17 | fun getImagesChatJson() = readTextFileFromRawResourceId(R.raw.history_images_response)
18 |
19 | fun getFilesChatJson() = readTextFileFromRawResourceId(R.raw.history_files_response)
20 |
21 | fun getSystemChatJson() = readTextFileFromRawResourceId(R.raw.history_system_response)
22 |
23 | fun getChatBotJson() = readTextFileFromRawResourceId(R.raw.history_bot_response)
24 |
25 | fun getChatWithEditAndDeletedMessages() = readTextFileFromRawResourceId(R.raw.history_deleted_and_edited_messages)
26 |
27 | private fun readTextFileFromRawResourceId(resourceId: Int): String {
28 | var string: String? = ""
29 | val stringBuilder = StringBuilder()
30 | val inputStream: InputStream = context.resources.openRawResource(resourceId)
31 | val reader = BufferedReader(InputStreamReader(inputStream))
32 | while (true) {
33 | try {
34 | if (reader.readLine().also { string = it } == null) break
35 | } catch (e: IOException) {
36 | e.printStackTrace()
37 | }
38 | stringBuilder.append(string).append("\n")
39 | }
40 | inputStream.close()
41 | return stringBuilder.toString()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/extensions/UIExtensions.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.extensions
2 |
3 | import android.content.Context
4 | import android.content.res.Configuration
5 |
6 | fun Context.isDarkThemeOn(): Boolean {
7 | return resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/fragments/demoSamplesFragment/DemoSamplesFragment.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.fragments.demoSamplesFragment
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import io.edna.threads.demo.R
6 | import io.edna.threads.demo.appCode.fragments.BaseAppFragment
7 | import io.edna.threads.demo.databinding.FragmentChatBinding
8 | import org.koin.androidx.viewmodel.ext.android.viewModel
9 | import java.lang.ref.WeakReference
10 |
11 | class DemoSamplesFragment : BaseAppFragment(FragmentChatBinding::inflate) {
12 | private val viewModel: DemoSamplesViewModel by viewModel()
13 |
14 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
15 | super.onViewCreated(view, savedInstanceState)
16 | subscribeToData()
17 | subscribeToGlobalBackClick()
18 | viewLifecycleOwner.lifecycle.addObserver(viewModel)
19 | }
20 |
21 | private fun subscribeToData() {
22 | viewModel.chatFragmentLiveData.observe(viewLifecycleOwner) {
23 | fragment = WeakReference(it)
24 | childFragmentManager
25 | .beginTransaction()
26 | .add(R.id.chatFragmentContainer, it)
27 | .commit()
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/fragments/demoSamplesFragment/DemoSamplesViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.fragments.demoSamplesFragment
2 |
3 | import androidx.lifecycle.DefaultLifecycleObserver
4 | import androidx.lifecycle.LifecycleOwner
5 | import androidx.lifecycle.LiveData
6 | import androidx.lifecycle.ViewModel
7 | import im.threads.business.annotation.OpenWay
8 | import im.threads.ui.core.ThreadsLib
9 | import im.threads.ui.fragments.ChatFragment
10 | import io.edna.threads.demo.appCode.business.PreferencesProvider
11 | import io.edna.threads.demo.appCode.business.SingleLiveEvent
12 | import io.edna.threads.demo.appCode.business.mockJsonProvider.CurrentJsonProvider
13 |
14 | class DemoSamplesViewModel(
15 | private val jsonProvider: CurrentJsonProvider,
16 | private val preferencesProvider: PreferencesProvider
17 | ) : ViewModel(), DefaultLifecycleObserver {
18 | private val chatFragmentMutableLiveData: SingleLiveEvent = SingleLiveEvent()
19 | val chatFragmentLiveData: LiveData get() = chatFragmentMutableLiveData
20 |
21 | override fun onCreate(owner: LifecycleOwner) {
22 | super.onCreate(owner)
23 | setJsonMock()
24 | prepareFragment()
25 | }
26 |
27 | override fun onDestroy(owner: LifecycleOwner) {
28 | super.onDestroy(owner)
29 | preferencesProvider.cleanJsonOnPreferences()
30 | ThreadsLib.getInstance().logoutClient()
31 | }
32 |
33 | private fun setJsonMock() {
34 | val json = jsonProvider.getCurrentJson()
35 | preferencesProvider.putJsonToPreferences(json)
36 | }
37 |
38 | private fun prepareFragment() {
39 | chatFragmentMutableLiveData.value = ChatFragment.newInstance(OpenWay.DEFAULT)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/fragments/demoSamplesList/DemoSamplesListFragment.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.fragments.demoSamplesList
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.core.content.ContextCompat
6 | import androidx.navigation.fragment.findNavController
7 | import im.threads.ui.core.ThreadsLib
8 | import io.edna.threads.demo.R
9 | import io.edna.threads.demo.appCode.adapters.demoSamplesList.DemoSamplesAdapter
10 | import io.edna.threads.demo.appCode.adapters.demoSamplesList.SampleListItemOnClick
11 | import io.edna.threads.demo.appCode.fragments.BaseAppFragment
12 | import io.edna.threads.demo.appCode.models.DemoSamplesListItem
13 | import io.edna.threads.demo.databinding.FragmentSamplesListBinding
14 | import org.koin.androidx.viewmodel.ext.android.viewModel
15 | import java.lang.ref.WeakReference
16 |
17 | class DemoSamplesListFragment : BaseAppFragment(FragmentSamplesListBinding::inflate), SampleListItemOnClick {
18 | private val viewModel: DemoSamplesListViewModel by viewModel()
19 | private var adapter: WeakReference? = null
20 |
21 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
22 | super.onViewCreated(view, savedInstanceState)
23 | createAdapter()
24 | setNavigationIcon()
25 | subscribeForData()
26 | subscribeToGlobalBackClick()
27 | viewLifecycleOwner.lifecycle.addObserver(viewModel)
28 | }
29 |
30 | override fun onClick(item: DemoSamplesListItem) {
31 | viewModel.onItemClick(item)
32 | }
33 |
34 | private fun createAdapter() = getBinding()?.apply {
35 | val newAdapter = DemoSamplesAdapter(this@DemoSamplesListFragment)
36 | adapter = WeakReference(newAdapter)
37 | recyclerView.adapter = newAdapter
38 | }
39 |
40 | private fun setNavigationIcon() = getBinding()?.apply {
41 | toolbar.navigationIcon?.setTint(ContextCompat.getColor(requireContext(), R.color.white_color_ec))
42 | toolbar.setNavigationOnClickListener {
43 | ThreadsLib.getInstance().logoutClient()
44 | findNavController().navigateUp()
45 | }
46 | }
47 |
48 | private fun subscribeForData() {
49 | viewModel.demoSamplesLiveData.observe(viewLifecycleOwner) { adapter?.get()?.addItems(it) }
50 | viewModel.navigationLiveData.observe(viewLifecycleOwner) { findNavController().navigate(it) }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/fragments/demoSamplesList/DemoSamplesListViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.fragments.demoSamplesList
2 |
3 | import androidx.lifecycle.DefaultLifecycleObserver
4 | import androidx.lifecycle.LifecycleOwner
5 | import androidx.lifecycle.LiveData
6 | import androidx.lifecycle.MutableLiveData
7 | import androidx.lifecycle.ViewModel
8 | import im.threads.business.UserInfoBuilder
9 | import im.threads.business.core.ContextHolder
10 | import im.threads.ui.config.ConfigBuilder
11 | import im.threads.ui.core.ThreadsLib
12 | import io.edna.threads.demo.R
13 | import io.edna.threads.demo.appCode.business.StringsProvider
14 | import io.edna.threads.demo.appCode.business.VolatileLiveData
15 | import io.edna.threads.demo.appCode.business.mockJsonProvider.CurrentJsonProvider
16 | import io.edna.threads.demo.appCode.business.mockJsonProvider.SamplesJsonProvider
17 | import io.edna.threads.demo.appCode.models.DemoSamplesListItem
18 | import io.edna.threads.demo.appCode.models.DemoSamplesListItem.TEXT
19 | import io.edna.threads.demo.appCode.models.ServerConfig
20 | import io.edna.threads.demo.appCode.themes.ChatThemes
21 | import io.edna.threads.demo.integrationCode.ednaMockThreadsGateProviderUid
22 | import io.edna.threads.demo.integrationCode.ednaMockThreadsGateUrl
23 | import io.edna.threads.demo.integrationCode.ednaMockUrl
24 |
25 | class DemoSamplesListViewModel(
26 | private val stringsProvider: StringsProvider,
27 | private val samplesJsonProvider: SamplesJsonProvider,
28 | private val currentJsonProvider: CurrentJsonProvider
29 | ) : ViewModel(), DefaultLifecycleObserver {
30 | private val mutableDemoSamplesLiveData = MutableLiveData>()
31 | val demoSamplesLiveData: LiveData> = mutableDemoSamplesLiveData
32 | val navigationLiveData = VolatileLiveData()
33 |
34 | override fun onCreate(owner: LifecycleOwner) {
35 | super.onCreate(owner)
36 | checkSdkInit()
37 | createData()
38 | }
39 |
40 | private fun checkSdkInit() {
41 | if (!ThreadsLib.isInitialized()) {
42 | val demoServerConfig = getDefaultServerConfig()
43 | val config = ConfigBuilder(ContextHolder.context).apply {
44 | threadsGateUrl(demoServerConfig.threadsGateUrl)
45 | datastoreUrl(demoServerConfig.datastoreUrl)
46 | serverBaseUrl(demoServerConfig.serverBaseUrl)
47 | threadsGateProviderUid(demoServerConfig.threadsGateProviderUid)
48 | }
49 | ThreadsLib.init(config)
50 | ThreadsLib.getInstance().apply {
51 | // Кастомизация внешнего вида. Поддержка темной темы
52 | val themes = ChatThemes()
53 | applyLightTheme(themes.getLightChatTheme())
54 | applyDarkTheme(themes.getDarkChatTheme())
55 | }
56 | }
57 | }
58 |
59 | fun onItemClick(item: DemoSamplesListItem) {
60 | if (item is TEXT) {
61 | currentJsonProvider.saveCurrentJson(item.json)
62 | ThreadsLib.getInstance().initUser(UserInfoBuilder("333"))
63 | navigationLiveData.setValue(R.id.action_DemoSamplesListFragment_to_DemoSamplesFragment)
64 | }
65 | }
66 |
67 | private fun createData() {
68 | mutableDemoSamplesLiveData.postValue(
69 | listOf(
70 | TEXT(stringsProvider.textMessages, samplesJsonProvider.getTextChatJson()),
71 | TEXT(stringsProvider.connectionErrors, samplesJsonProvider.getConnectionErrorJson()),
72 | TEXT(stringsProvider.voiceMessages, samplesJsonProvider.getVoicesChatJson()),
73 | TEXT(stringsProvider.images, samplesJsonProvider.getImagesChatJson()),
74 | TEXT(stringsProvider.files, samplesJsonProvider.getFilesChatJson()),
75 | TEXT(stringsProvider.systemMessages, samplesJsonProvider.getSystemChatJson()),
76 | TEXT(stringsProvider.chatWithBot, samplesJsonProvider.getChatBotJson()),
77 | TEXT(stringsProvider.chatWithEditAndDeletedMessages, samplesJsonProvider.getChatWithEditAndDeletedMessages())
78 | )
79 | )
80 | }
81 |
82 | private fun getDefaultServerConfig() = ServerConfig(
83 | name = "TestServer",
84 | threadsGateProviderUid = ednaMockThreadsGateProviderUid,
85 | datastoreUrl = ednaMockUrl,
86 | serverBaseUrl = ednaMockUrl,
87 | threadsGateUrl = ednaMockThreadsGateUrl,
88 | isShowMenu = true
89 | )
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/fragments/server/AddServerFragment.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.fragments.server
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.setFragmentResult
6 | import io.edna.threads.demo.appCode.fragments.BaseAppFragment
7 | import io.edna.threads.demo.appCode.fragments.server.ServerListFragment.Companion.SERVER_CONFIG_KEY
8 | import io.edna.threads.demo.appCode.fragments.server.ServerListFragment.Companion.SRC_SERVER_NAME_KEY
9 | import io.edna.threads.demo.databinding.FragmentAddServerBinding
10 | import org.koin.androidx.viewmodel.ext.android.viewModel
11 | import org.parceler.Parcels
12 |
13 | class AddServerFragment : BaseAppFragment(FragmentAddServerBinding::inflate) {
14 |
15 | private val viewModel: AddServerViewModel by viewModel()
16 |
17 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
18 | super.onViewCreated(view, savedInstanceState)
19 | subscribeToGlobalBackClick()
20 | subscribeForTextWatchers()
21 | subscribeForData()
22 | setOnClickListeners()
23 | viewModel.initData(arguments)
24 | }
25 |
26 | private fun subscribeForTextWatchers() = getBinding()?.apply {
27 | name.setTextChangedListener(viewModel.nameTextWatcher)
28 | providerId.setTextChangedListener(viewModel.providerIdTextWatcher)
29 | baseUrl.setTextChangedListener(viewModel.baseUrlTextWatcher)
30 | datastoreUrl.setTextChangedListener(viewModel.datastoreUrlTextWatcher)
31 | threadsGateUrl.setTextChangedListener(viewModel.threadsGateUrlTextWatcher)
32 | }
33 |
34 | private fun subscribeForData() = getBinding()?.apply {
35 | viewModel.finalServerConfigLiveData.observe(viewLifecycleOwner) {
36 | val args = Bundle()
37 | args.putParcelable(SERVER_CONFIG_KEY, Parcels.wrap(it))
38 | viewModel.srcServerConfig?.name?.let { name ->
39 | args.putString(SRC_SERVER_NAME_KEY, name)
40 | }
41 | setFragmentResult(SERVER_CONFIG_KEY, args)
42 | }
43 | viewModel.serverConfigLiveData.observe(viewLifecycleOwner) {
44 | name.text = it.name
45 | providerId.text = it.threadsGateProviderUid
46 | baseUrl.text = it.serverBaseUrl
47 | datastoreUrl.text = it.datastoreUrl
48 | threadsGateUrl.text = it.threadsGateUrl
49 | }
50 | viewModel.errorStringForServerNameFieldLiveData.observe(viewLifecycleOwner) {
51 | name.error = it
52 | }
53 | viewModel.errorStringForProviderIdFieldLiveData.observe(viewLifecycleOwner) {
54 | providerId.error = it
55 | }
56 | viewModel.errorStringForBaseUrlFieldLiveData.observe(viewLifecycleOwner) {
57 | baseUrl.error = it
58 | }
59 | viewModel.errorStringForDatastoreUrlFieldLiveData.observe(viewLifecycleOwner) {
60 | datastoreUrl.error = it
61 | }
62 | viewModel.errorStringForThreadsGateUrlFieldLiveData.observe(viewLifecycleOwner) {
63 | datastoreUrl.error = it
64 | }
65 | }
66 |
67 | private fun setOnClickListeners() = getBinding()?.apply {
68 | backButton.setOnClickListener { viewModel.click(backButton) }
69 | okButton.setOnClickListener { viewModel.click(okButton) }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/fragments/user/AddUserFragment.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.fragments.user
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.fragment.app.setFragmentResult
6 | import io.edna.threads.demo.appCode.fragments.BaseAppFragment
7 | import io.edna.threads.demo.appCode.fragments.user.UserListFragment.Companion.SRC_USER_ID_KEY
8 | import io.edna.threads.demo.appCode.fragments.user.UserListFragment.Companion.USER_KEY
9 | import io.edna.threads.demo.databinding.FragmentAddUserBinding
10 | import org.koin.androidx.viewmodel.ext.android.viewModel
11 | import org.parceler.Parcels
12 |
13 | class AddUserFragment : BaseAppFragment(FragmentAddUserBinding::inflate) {
14 |
15 | private val viewModel: AddUserViewModel by viewModel()
16 |
17 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
18 | super.onViewCreated(view, savedInstanceState)
19 | subscribeToGlobalBackClick()
20 | subscribeForClickListeners()
21 | subscribeForTextWatchers()
22 | subscribeForData()
23 | initData()
24 | }
25 |
26 | private fun subscribeForTextWatchers() = getBinding()?.apply {
27 | userId.setTextChangedListener(viewModel.userIdTextWatcher)
28 | userData.setTextChangedListener(viewModel.userDataTextWatcher)
29 | appMarker.setTextChangedListener(viewModel.appMarkerTextWatcher)
30 | signature.setTextChangedListener(viewModel.signatureTextWatcher)
31 | authorizationHeader.setTextChangedListener(viewModel.authorizationHeaderTextWatcher)
32 | xAuthSchemaHeader.setTextChangedListener(viewModel.xAuthSchemaHeaderTextWatcher)
33 | }
34 |
35 | private fun subscribeForClickListeners() = getBinding()?.apply {
36 | backButton.setOnClickListener { viewModel.click(backButton) }
37 | okButton.setOnClickListener { viewModel.click(okButton) }
38 | }
39 |
40 | private fun subscribeForData() = getBinding()?.apply {
41 | viewModel.finalUserLiveData.observe(viewLifecycleOwner) {
42 | val args = Bundle()
43 | args.putParcelable(USER_KEY, Parcels.wrap(it))
44 | viewModel.srcUser?.let { user ->
45 | args.putString(SRC_USER_ID_KEY, user.userId)
46 | }
47 | setFragmentResult(USER_KEY, args)
48 | }
49 | viewModel.userLiveData.observe(viewLifecycleOwner) {
50 | userId.text = it.userId
51 | userData.text = it.userData
52 | appMarker.text = it.appMarker
53 | signature.text = it.signature
54 | authorizationHeader.text = it.authorizationHeader
55 | xAuthSchemaHeader.text = it.xAuthSchemaHeader
56 | }
57 | viewModel.errorStringForUserIdFieldLiveData.observe(viewLifecycleOwner) {
58 | userId.error = it
59 | }
60 | }
61 |
62 | private fun initData() {
63 | viewModel.initData(arguments)
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/models/DemoSamplesListItem.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.models
2 |
3 | sealed class DemoSamplesListItem {
4 | object DIVIDER : DemoSamplesListItem()
5 |
6 | data class TITLE(val text: String) : DemoSamplesListItem() {
7 | override fun toString() = text
8 | companion object
9 | }
10 |
11 | data class TEXT(val text: String, val json: String) : DemoSamplesListItem() {
12 | override fun toString() = text
13 | companion object
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/models/ServerConfig.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class ServerConfig(
8 | var name: String? = null,
9 | var threadsGateProviderUid: String? = null,
10 | var datastoreUrl: String? = null,
11 | var serverBaseUrl: String? = null,
12 | var threadsGateUrl: String? = null,
13 | var isFromApp: Boolean = false,
14 | var isShowMenu: Boolean = false,
15 | var filesAndMediaMenuItemEnabled: Boolean = true,
16 | var trustedSSLCertificates: List? = null,
17 | var allowUntrustedSSLCertificate: Boolean = false
18 | ) : Parcelable {
19 |
20 | override fun toString() = "Server config:\n = $name, " +
21 | "\nthreadsGateProviderUid = $threadsGateProviderUid, " +
22 | "\ndatastoreUrl = $datastoreUrl, " +
23 | "\nserverBaseUrl = $serverBaseUrl, " +
24 | "\nthreadsGateUrl = $threadsGateUrl, " +
25 | "\nisFromApp = $isFromApp, " +
26 | "\nisShowMenu = $isShowMenu, " +
27 | "\nfilesAndMediaMenuItemEnabled = $filesAndMediaMenuItemEnabled, " +
28 | "\ntrustedSSLCertificates = $trustedSSLCertificates, " +
29 | "\nallowUntrustedSSLCertificate = $allowUntrustedSSLCertificate"
30 |
31 | fun isAllFieldsFilled(): Boolean {
32 | return !name.isNullOrEmpty() &&
33 | !threadsGateProviderUid.isNullOrEmpty() &&
34 | !datastoreUrl.isNullOrEmpty() &&
35 | !serverBaseUrl.isNullOrEmpty() &&
36 | !threadsGateUrl.isNullOrEmpty()
37 | }
38 |
39 | fun copy(): ServerConfig {
40 | return ServerConfig(
41 | name,
42 | threadsGateProviderUid,
43 | datastoreUrl,
44 | serverBaseUrl,
45 | threadsGateUrl,
46 | isFromApp,
47 | isShowMenu,
48 | filesAndMediaMenuItemEnabled,
49 | trustedSSLCertificates,
50 | allowUntrustedSSLCertificate
51 | )
52 | }
53 |
54 | override fun hashCode(): Int {
55 | return super.hashCode()
56 | }
57 |
58 | override fun equals(other: Any?): Boolean {
59 | if (other is ServerConfig) {
60 | return other.name == name &&
61 | other.threadsGateProviderUid == threadsGateProviderUid &&
62 | other.datastoreUrl == datastoreUrl &&
63 | other.serverBaseUrl == serverBaseUrl &&
64 | other.threadsGateUrl == threadsGateUrl
65 | }
66 | return false
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/models/TestData.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.models
2 |
3 | import com.google.gson.Gson
4 |
5 | data class TestData(
6 | val userInfo: UserInfo? = null,
7 | val serverConfig: ServerConfig? = null
8 | ) {
9 | fun toJson() = Gson().toJson(this)
10 |
11 | companion object {
12 | fun fromJson(json: String) = Gson().fromJson(json, TestData::class.java)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/models/UiTheme.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.models
2 |
3 | enum class UiTheme {
4 | LIGHT, DARK
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/models/UserInfo.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class UserInfo(
8 | var userId: String? = null,
9 | var userData: String? = null,
10 | var appMarker: String? = null,
11 | var signature: String? = null,
12 | var authorizationHeader: String? = null,
13 | var xAuthSchemaHeader: String? = null,
14 | var userName: String? = null,
15 | var isShowMenu: Boolean = false
16 | ) : Parcelable {
17 |
18 | override fun toString() = "$userId," +
19 | "$userData," +
20 | "$appMarker," +
21 | "$signature," +
22 | "$authorizationHeader," +
23 | "$xAuthSchemaHeader," +
24 | "$userName, " +
25 | "$isShowMenu"
26 |
27 | fun isAllFieldsFilled(): Boolean {
28 | return !userId.isNullOrEmpty()
29 | }
30 |
31 | override fun hashCode(): Int {
32 | return super.hashCode()
33 | }
34 |
35 | override fun equals(other: Any?): Boolean {
36 | if (other is UserInfo) {
37 | return other.userId == userId &&
38 | other.appMarker == appMarker &&
39 | other.signature == signature &&
40 | other.authorizationHeader == authorizationHeader &&
41 | other.xAuthSchemaHeader == xAuthSchemaHeader &&
42 | other.userData == userData &&
43 | other.userName == userName
44 | }
45 | return false
46 | }
47 |
48 | fun clone(): UserInfo {
49 | return UserInfo(
50 | userId,
51 | userData,
52 | appMarker,
53 | signature,
54 | authorizationHeader,
55 | xAuthSchemaHeader,
56 | userName,
57 | isShowMenu
58 | )
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/push/CustomPushFcmIntentService.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.push
2 |
3 | import com.google.firebase.messaging.FirebaseMessagingService
4 | import com.google.firebase.messaging.RemoteMessage
5 | import im.threads.ui.ChatCenterPushMessageHelper
6 |
7 | class CustomPushFcmIntentService : FirebaseMessagingService() {
8 | private val chatCenterPushMessageHelper = ChatCenterPushMessageHelper()
9 |
10 | override fun onNewToken(token: String) {
11 | super.onNewToken(token)
12 | chatCenterPushMessageHelper.setFcmToken(token)
13 | }
14 |
15 | override fun onMessageReceived(message: RemoteMessage) {
16 | super.onMessageReceived(message)
17 | chatCenterPushMessageHelper.process(message.data)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/push/CustomPushHcmIntentService.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.push
2 |
3 | import android.annotation.SuppressLint
4 | import android.os.Bundle
5 | import android.util.Base64
6 | import com.huawei.hms.push.HmsMessageService
7 | import com.huawei.hms.push.RemoteMessage
8 | import im.threads.ui.ChatCenterPushMessageHelper
9 | import org.json.JSONException
10 | import org.json.JSONObject
11 | import java.io.UnsupportedEncodingException
12 |
13 | class CustomPushHcmIntentService : HmsMessageService() {
14 | private val chatCenterPushMessageHelper = ChatCenterPushMessageHelper()
15 |
16 | override fun onNewToken(token: String) {
17 | super.onNewToken(token)
18 | chatCenterPushMessageHelper.setHcmToken(token)
19 | }
20 |
21 | @SuppressLint("RestrictedApi")
22 | override fun onMessageReceived(message: RemoteMessage) {
23 | super.onMessageReceived(message)
24 | chatCenterPushMessageHelper.process(base64JsonStringToBundle(message.data))
25 | }
26 |
27 | private fun base64JsonStringToBundle(base64Str: String): Bundle {
28 | return try {
29 | val data: ByteArray = Base64.decode(base64Str, 0)
30 | val decodedStr = String(data)
31 | jsonObjectToBundle(JSONObject(decodedStr))
32 | } catch (exception: JSONException) {
33 | Bundle()
34 | } catch (exception: UnsupportedEncodingException) {
35 | Bundle()
36 | }
37 | }
38 |
39 | @Throws(JSONException::class)
40 | private fun jsonObjectToBundle(jsonObject: JSONObject): Bundle {
41 | val bundle = Bundle()
42 | val iterator: Iterator<*> = jsonObject.keys()
43 | while (iterator.hasNext()) {
44 | val key = iterator.next() as String
45 | val value = jsonObject.getString(key)
46 | bundle.putString(key, value)
47 | }
48 | return bundle
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/push/HCMTokenRefresher.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.push
2 |
3 | import android.content.Context
4 | import com.huawei.agconnect.AGConnectOptionsBuilder
5 | import com.huawei.hms.aaid.HmsInstanceId
6 | import com.huawei.hms.common.ApiException
7 | import im.threads.ui.ChatCenterPushMessageHelper
8 | import java.io.IOException
9 |
10 | object HCMTokenRefresher {
11 | fun requestToken(context: Context) {
12 | val hcmAppId = AGConnectOptionsBuilder().build(context).getString("client/app_id")
13 | if (hcmAppId != null) {
14 | try {
15 | val hmsInstanceId = HmsInstanceId.getInstance(context)
16 | val token = hmsInstanceId.getToken(hcmAppId, "HCM")
17 | ChatCenterPushMessageHelper().setHcmToken(token)
18 | } catch (e: IOException) {
19 | } catch (e: ApiException) {
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/appCode/test/TestChatActivity.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.appCode.test
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import androidx.appcompat.app.AppCompatActivity
6 | import im.threads.business.annotation.OpenWay
7 | import im.threads.ui.fragments.ChatFragment
8 | import io.edna.threads.demo.R
9 |
10 | class TestChatActivity : AppCompatActivity() {
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | setContentView(R.layout.activity_test_chat)
14 |
15 | saveJsonMock(intent.extras?.getString(jsonMockExtraKey))
16 |
17 | supportFragmentManager.beginTransaction()
18 | .replace(R.id.chatFragmentContainer, ChatFragment.newInstance(OpenWay.DEFAULT))
19 | .commitNow()
20 | }
21 |
22 | override fun onStop() {
23 | saveJsonMock(null)
24 | super.onStop()
25 | }
26 |
27 | private fun saveJsonMock(jsonMock: String?) {
28 | applicationContext
29 | .getSharedPreferences(jsonMockPreferencesKey, Context.MODE_PRIVATE)
30 | .edit()
31 | .putString(jsonMockPreferencesValueKey, jsonMock)
32 | .commit()
33 | }
34 |
35 | companion object {
36 | const val jsonMockExtraKey = "jsonMockExtraKey"
37 | private const val jsonMockPreferencesKey = "ecc_demo_json_preference"
38 | private const val jsonMockPreferencesValueKey = "ecc_demo_json_preference_key"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/integrationCode/EdnaThreadsApplication.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.integrationCode
2 |
3 | import android.app.Application
4 | import android.util.Log
5 | import com.google.firebase.messaging.FirebaseMessaging
6 | import com.google.firebase.perf.FirebasePerformance
7 | import com.microsoft.appcenter.AppCenter
8 | import com.microsoft.appcenter.analytics.Analytics
9 | import com.microsoft.appcenter.crashes.Crashes
10 | import im.threads.business.core.ContextHolder
11 | import im.threads.business.models.enums.ApiVersionEnum
12 | import im.threads.ui.ChatCenterPushMessageHelper
13 | import io.edna.threads.demo.BuildConfig
14 | import io.edna.threads.demo.appCode.business.PreferencesProvider
15 | import io.edna.threads.demo.appCode.business.ServersProvider
16 | import io.edna.threads.demo.appCode.business.appModule
17 | import io.edna.threads.demo.appCode.models.ServerConfig
18 | import io.edna.threads.demo.appCode.push.HCMTokenRefresher
19 | import kotlinx.coroutines.CoroutineScope
20 | import kotlinx.coroutines.Dispatchers
21 | import org.koin.android.ext.android.inject
22 | import org.koin.android.ext.koin.androidContext
23 | import org.koin.core.context.startKoin
24 |
25 | class EdnaThreadsApplication : Application() {
26 | private val serversProvider: ServersProvider by inject()
27 | private val preferences: PreferencesProvider by inject()
28 | private val coroutineScope = CoroutineScope(Dispatchers.IO)
29 | private val asyncInit = false
30 |
31 | override fun onCreate() {
32 | super.onCreate()
33 |
34 | startAppCenter()
35 |
36 | startKoin {
37 | androidContext(this@EdnaThreadsApplication)
38 | modules(appModule)
39 | }
40 |
41 | val sdkInitializer = ThreadsLibInitializer()
42 | val apiVersion = ApiVersionEnum.createApiVersionEnum(preferences.getSelectedApiVersion())
43 | if (!BuildConfig.IS_MOCK_WEB_SERVER.get()) {
44 | // Инициализация сдк обычным способом
45 | serversProvider.getSelectedServer()?.let {
46 | sdkInitializer.initThreadsLib(this.applicationContext, apiVersion, it)
47 | } ?: Log.i("Init sdk", "No server")
48 | } else {
49 | // Инициализация сдк моком сервера для UI тестов
50 | val serverConfig = ServerConfig(
51 | "Mock Server",
52 | ednaMockThreadsGateProviderUid,
53 | ednaMockUrl,
54 | ednaMockUrl,
55 | ednaMockThreadsGateUrl,
56 | allowUntrustedSSLCertificate = ednaMockAllowUntrustedSSLCertificate
57 | )
58 | sdkInitializer.initThreadsLib(this.applicationContext, apiVersion, serverConfig)
59 | }
60 | checkAndUpdateTokens()
61 | }
62 |
63 | private fun checkAndUpdateTokens() {
64 | FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
65 | if (task.isSuccessful) {
66 | val token = task.result
67 | ChatCenterPushMessageHelper().setFcmToken(token)
68 | }
69 | }
70 | HCMTokenRefresher.requestToken(ContextHolder.context)
71 | }
72 |
73 | private fun startAppCenter() {
74 | if (BuildConfig.DEBUG.not()) {
75 | System.getenv("APP_CENTER_KEY")?.let { appCenterKey ->
76 | AppCenter.start(
77 | this,
78 | appCenterKey,
79 | Analytics::class.java,
80 | Crashes::class.java
81 | )
82 | }
83 | }
84 | }
85 | }
86 |
87 | private const val LATO_BOLD_FONT_PATH = "fonts/lato-bold.ttf"
88 | private const val LATO_LIGHT_FONT_PATH = "fonts/lato-light.ttf"
89 | private const val LATO_REGULAR_FONT_PATH = "fonts/lato-regular.ttf"
90 |
91 | const val ednaMockScheme = "http"
92 | const val ednaMockHost = "localhost"
93 | const val ednaMockPort = 8080
94 | const val ednaMockUrl = "$ednaMockScheme://$ednaMockHost:$ednaMockPort/"
95 | const val ednaMockThreadsGateUrl = "ws://$ednaMockHost:$ednaMockPort/gate/socket"
96 | const val ednaMockThreadsGateProviderUid = "TEST_93jLrtnipZsfbTddRfEfbyfEe5LKKhTl"
97 | const val ednaMockAllowUntrustedSSLCertificate = true
98 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/integrationCode/ThreadsLibInitializer.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.integrationCode
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import im.threads.business.core.UnreadMessagesCountListener
6 | import im.threads.business.logger.LoggerConfig
7 | import im.threads.business.logger.LoggerRetentionPolicy
8 | import im.threads.business.models.enums.ApiVersionEnum
9 | import im.threads.ui.config.ConfigBuilder
10 | import im.threads.ui.core.ThreadsLib
11 | import io.edna.threads.demo.appCode.models.ServerConfig
12 | import io.edna.threads.demo.appCode.themes.ChatThemes
13 | import io.edna.threads.demo.integrationCode.fragments.launch.LaunchFragment.Companion.APP_UNREAD_COUNT_BROADCAST
14 | import io.edna.threads.demo.integrationCode.fragments.launch.LaunchFragment.Companion.UNREAD_COUNT_KEY
15 | import java.io.File
16 |
17 | class ThreadsLibInitializer() {
18 |
19 | fun initThreadsLib(context: Context, apiVersionEnum: ApiVersionEnum, server: ServerConfig) {
20 | // Устанавливает конфиг для внутреннего логгера. Необязательный параметр
21 | val loggerConfig = LoggerConfig.Builder(context)
22 | .logToFile()
23 | .dir(File(context.filesDir, "logs"))
24 | .retentionPolicy(LoggerRetentionPolicy.TOTAL_SIZE)
25 | .maxTotalSize(5242880)
26 | .build()
27 |
28 | // Устанавливает общий конфиг для библиотеки. Обязательный параметр только context
29 | val configBuilder = ConfigBuilder(context)
30 | .unreadMessagesCountListener(object : UnreadMessagesCountListener {
31 | override fun onUnreadMessagesCountChanged(count: Int) {
32 | val intent = Intent(APP_UNREAD_COUNT_BROADCAST)
33 | intent.putExtra(UNREAD_COUNT_KEY, count)
34 | context.sendBroadcast(intent)
35 | }
36 | })
37 | .surveyCompletionDelay(2000)
38 | .historyLoadingCount(50)
39 | .isDebugLoggingEnabled(true)
40 | .showAttachmentsButton()
41 | .enableLogging(loggerConfig)
42 |
43 | // Устанавливаем параметры подключения к серверу
44 | configBuilder.apply {
45 | serverBaseUrl(server.serverBaseUrl)
46 | datastoreUrl(server.datastoreUrl)
47 | threadsGateUrl(server.threadsGateUrl)
48 | threadsGateProviderUid(server.threadsGateProviderUid)
49 | trustedSSLCertificates(server.trustedSSLCertificates)
50 | allowUntrustedSSLCertificates(server.allowUntrustedSSLCertificate)
51 | setNewChatCenterApi()
52 | setApiVersion(apiVersionEnum)
53 | }
54 |
55 | // Инициализация библиотеки. Только после данного вызова можно начинать работу с SDK
56 | ThreadsLib.init(configBuilder)
57 | ThreadsLib.getInstance().apply {
58 | // Кастомизация внешнего вида. Поддержка темной темы
59 | val themes = ChatThemes()
60 | applyLightTheme(themes.getLightChatTheme())
61 | applyDarkTheme(themes.getDarkChatTheme())
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/io/edna/threads/demo/integrationCode/fragments/chatFragment/ChatAppFragment.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo.integrationCode.fragments.chatFragment
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import im.threads.business.annotation.OpenWay
6 | import im.threads.ui.fragments.ChatFragment
7 | import io.edna.threads.demo.R
8 | import io.edna.threads.demo.appCode.fragments.BaseAppFragment
9 | import io.edna.threads.demo.databinding.FragmentChatBinding
10 | import java.lang.ref.WeakReference
11 |
12 | class ChatAppFragment : BaseAppFragment(FragmentChatBinding::inflate) {
13 |
14 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
15 | super.onViewCreated(view, savedInstanceState)
16 | subscribeToGlobalBackClick()
17 | ChatFragment.newInstance(OpenWay.DEFAULT).let {
18 | fragment = WeakReference(it)
19 | childFragmentManager
20 | .beginTransaction()
21 | .add(R.id.chatFragmentContainer, it)
22 | .commit()
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/alt_thread_incoming_bubble.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-hdpi/alt_thread_incoming_bubble.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/alt_thread_outgoing_bubble.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-hdpi/alt_thread_outgoing_bubble.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-hdpi/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/alt_thread_incoming_bubble.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-mdpi/alt_thread_incoming_bubble.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/alt_thread_outgoing_bubble.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-mdpi/alt_thread_outgoing_bubble.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-mdpi/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-night/splash_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | -
6 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
12 |
13 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/alt_thread_incoming_bubble.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-xhdpi/alt_thread_incoming_bubble.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/alt_thread_outgoing_bubble.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-xhdpi/alt_thread_outgoing_bubble.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/im_empty_users.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-xhdpi/im_empty_users.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-xhdpi/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/alt_thread_incoming_bubble.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-xxhdpi/alt_thread_incoming_bubble.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/alt_thread_outgoing_bubble.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-xxhdpi/alt_thread_outgoing_bubble.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable-xxhdpi/logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/alt_thread_incoming_image_mask.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable/alt_thread_incoming_image_mask.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/alt_thread_outgoing_image_mask.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable/alt_thread_outgoing_image_mask.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/alt_threads_scroll_down_icon_black.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/alt_threads_scroll_down_icon_light.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/app_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/drawable/app_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/buttons_bg_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
8 |
10 |
11 |
12 | -
13 |
14 |
16 |
18 |
19 |
20 | -
21 |
22 |
24 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/buttons_bg_selector_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
8 |
10 |
11 |
12 | -
13 |
14 |
16 |
18 |
19 |
20 | -
21 |
22 |
24 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/buttons_text_color_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/dark_theme.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_chevron_right.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cloud.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_edit.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_ok.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_ok_desable.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_ok_pressed.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_ok_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_plus.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_remove.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_user.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/light_theme.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/red_cyrcle.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
13 |
14 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/secondary_buttons_bg_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
8 |
10 |
11 |
12 | -
13 |
14 |
16 |
18 |
19 |
20 | -
21 |
22 |
24 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/secondary_buttons_text_color_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/splash_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | -
6 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/text_button_bg_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | -
5 |
6 |
8 |
10 |
11 |
12 | -
13 |
14 |
16 |
18 |
19 |
20 | -
21 |
22 |
24 |
26 |
27 |
28 | -
29 |
30 |
32 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/text_button_text_color_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/font/roboto_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/font/roboto_medium.ttf
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_test_chat.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_chat.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_samples_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
19 |
20 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_server_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
30 |
31 |
42 |
43 |
44 |
45 |
54 |
55 |
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_user_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
17 |
18 |
28 |
29 |
40 |
41 |
42 |
43 |
52 |
53 |
64 |
65 |
69 |
70 |
80 |
81 |
82 |
83 |
95 |
96 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/holder_demo_samples_text.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/holder_demo_samples_title.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/holder_horizontal_line.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/input_field.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
28 |
29 |
38 |
39 |
40 |
41 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/server_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
17 |
18 |
29 |
30 |
42 |
43 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/user_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
17 |
18 |
31 |
32 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/raw/snapshot_test_errors_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "type": "MESSAGE",
5 | "threadId": 184,
6 | "providerIds": [],
7 | "uuid": "b2eb39ef-b9f8-4f70-aaba-e89873ae1f25",
8 | "text": "Добрый день, возник вопрос",
9 | "receivedDate": "2023-04-06T08:06:57.870Z",
10 | "attachments": [],
11 | "quotes": [],
12 | "quickReplies": [],
13 | "read": true,
14 | "settings": {
15 | "blockInput": false,
16 | "masked": false
17 | },
18 | "authorized": true,
19 | "massPushMessage": false,
20 | "origin": "threads",
21 | "errorMock": true
22 | },
23 | {
24 | "type": "MESSAGE",
25 | "threadId": 184,
26 | "providerIds": [],
27 | "uuid": "75098c02-84f5-494a-8c9c-658f1487cc9e",
28 | "operator": {
29 | "id": 4,
30 | "name": "Оператор Елена",
31 | "alias": null,
32 | "status": null,
33 | "photoUrl": null,
34 | "gender": "FEMALE",
35 | "organizationUnit": "Skill Credit",
36 | "role": "OPERATOR"
37 | },
38 | "text": "",
39 | "receivedDate": "2023-04-06T08:10:06.944Z",
40 | "attachments": [
41 | {
42 | "id": 79,
43 | "result": "https://mobile4.dev.flex.mfms.ru/files/20230406-f46def28-5b72-41f9-864b-cf87e899ec28.pdf",
44 | "optional": {
45 | "size": 911839,
46 | "name": "89,93-.pdf",
47 | "type": "application/pdf"
48 | },
49 | "state": "ERROR",
50 | "name": "89,93-.pdf",
51 | "type": "application/pdf",
52 | "size": 911839,
53 | "wellDefined": true,
54 | "url": "https://mobile4.dev.flex.mfms.ru/files/20230406-f46def28-5b72-41f9-864b-cf87e899ec28.pdf"
55 | }
56 | ],
57 | "quotes": [],
58 | "quickReplies": [],
59 | "read": true,
60 | "settings": {
61 | "blockInput": false,
62 | "masked": false
63 | },
64 | "authorized": true,
65 | "massPushMessage": false,
66 | "origin": "threads"
67 | },
68 | {
69 | "type": "MESSAGE",
70 | "threadId": 184,
71 | "providerIds": [],
72 | "uuid": "c1ffdbcf-4ac9-49c9-b941-4b759a414a42",
73 | "text": "",
74 | "receivedDate": "2023-04-06T08:10:24.552Z",
75 | "attachments": [
76 | {
77 | "id": 80,
78 | "result": "https://mobile4.dev.flex.mfms.ru/files/20230406-fda68dc5-fff1-417d-a1b6-c301da1934c2.pdf",
79 | "optional": {
80 | "size": 61978,
81 | "name": "testpdf1.pdf",
82 | "type": "application/pdf"
83 | },
84 | "state": "ERROR",
85 | "name": "testpdf1.pdf",
86 | "type": "application/pdf",
87 | "size": 61978,
88 | "wellDefined": true,
89 | "url": "https://mobile4.dev.flex.mfms.ru/files/20230406-fda68dc5-fff1-417d-a1b6-c301da1934c2.pdf"
90 | }
91 | ],
92 | "quotes": [],
93 | "quickReplies": [],
94 | "read": true,
95 | "settings": {
96 | "blockInput": false,
97 | "masked": false
98 | },
99 | "authorized": true,
100 | "massPushMessage": false,
101 | "origin": "threads"
102 | }
103 | ],
104 | "agentInfo": {
105 | "action": "AGENT_JOINED",
106 | "actionDate": "2023-04-06T08:55:22.118Z",
107 | "thread": {
108 | "id": 184,
109 | "state": "IN_PROGRESS"
110 | },
111 | "agent": {
112 | "id": 4,
113 | "name": "Оператор Елена",
114 | "alias": null,
115 | "status": null,
116 | "photoUrl": null,
117 | "gender": "FEMALE",
118 | "organizationUnit": "Skill Credit",
119 | "role": "OPERATOR"
120 | }
121 | },
122 | "allowedToSendMessages": true
123 | }
--------------------------------------------------------------------------------
/app/src/main/res/raw/snapshot_test_history_bot_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "type": "MESSAGE",
5 | "threadId": 304,
6 | "providerIds": [],
7 | "uuid": "eda36c57-7286-4360-bb42-0cf3d7932113",
8 | "operator": {
9 | "id": 9,
10 | "name": "Бот Edna",
11 | "alias": null,
12 | "status": null,
13 | "photoUrl": null,
14 | "gender": "FEMALE",
15 | "organizationUnit": "Skill Debet",
16 | "role": "OPERATOR"
17 | },
18 | "text": "",
19 | "formattedText": "Добрый день! Я **Бот Edna**, и я готова Вам помочь! Вижу, у Вас проблемы с зачислением средств. Читали ли вы *наиболее частые причины* по [этой ссылке](https://edna.ru/)?",
20 | "receivedDate": "2023-03-22T08:42:44.275Z",
21 | "attachments": [],
22 | "quotes": [],
23 | "quickReplies": [],
24 | "read": true,
25 | "settings": {
26 | "blockInput": false,
27 | "masked": false
28 | },
29 | "authorized": true,
30 | "massPushMessage": false,
31 | "origin": "threads"
32 | },
33 | {
34 | "type": "MESSAGE",
35 | "clientId": "8766",
36 | "threadId": 482,
37 | "providerIds": [],
38 | "uuid": "a6b9dc67-c9f6-4971-94a5-a4c4904b15db",
39 | "operator": {
40 | "id": 13,
41 | "name": "Бот Edna",
42 | "alias": null,
43 | "status": null,
44 | "photoUrl": null,
45 | "gender": null,
46 | "organizationUnit": null,
47 | "role": "EXTERNAL_BOT"
48 | },
49 | "text": "Когда вы оформили карту? Давайте выберем один из вариантов",
50 | "receivedDate": "2023-03-22T08:44:19.497Z",
51 | "attachments": [],
52 | "quotes": [],
53 | "quickReplies": [
54 | {
55 | "id": 4858,
56 | "type": "TEXT",
57 | "text": "У меня нет карты банка",
58 | "imageUrl": null,
59 | "url": null,
60 | "shown_text": null,
61 | "callback_data": null,
62 | "payload": null
63 | },
64 | {
65 | "id": 4859,
66 | "type": "TEXT",
67 | "text": "Моя карта просрочена",
68 | "imageUrl": null,
69 | "url": null,
70 | "shown_text": null,
71 | "callback_data": null,
72 | "payload": null
73 | },
74 | {
75 | "id": 4860,
76 | "type": "TEXT",
77 | "text": "Моя карта оформлена в этом году",
78 | "imageUrl": null,
79 | "url": null,
80 | "shown_text": null,
81 | "callback_data": null,
82 | "payload": null
83 | },
84 | {
85 | "id": 4861,
86 | "type": "TEXT",
87 | "text": "Моя карта оформлена в прошлом году",
88 | "imageUrl": null,
89 | "url": null,
90 | "shown_text": null,
91 | "callback_data": null,
92 | "payload": null
93 | },
94 | {
95 | "id": 4862,
96 | "type": "TEXT",
97 | "text": "Нет нужного варианта",
98 | "imageUrl": null,
99 | "url": null,
100 | "shown_text": null,
101 | "callback_data": null,
102 | "payload": null
103 | }
104 | ],
105 | "read": false,
106 | "settings": {
107 | "blockInput": false,
108 | "masked": false
109 | },
110 | "authorized": true,
111 | "massPushMessage": false,
112 | "externalClientId": "8766",
113 | "origin": "threads"
114 | }
115 | ],
116 | "agentInfo": {
117 | "action": "AGENT_LOOKUP",
118 | "actionDate": "2023-03-22T08:51:43.124Z",
119 | "thread": {
120 | "id": 304,
121 | "state": "UNASSIGNED"
122 | },
123 | "agent": null
124 | },
125 | "allowedToSendMessages": true
126 | }
--------------------------------------------------------------------------------
/app/src/main/res/raw/snapshot_test_history_images_response_1.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "type": "MESSAGE",
5 | "threadId": 141,
6 | "providerIds": [],
7 | "uuid": "061f6c38-2ac6-4cf9-aa26-ead6b055bc12",
8 | "text": "",
9 | "receivedDate": "2023-03-27T10:05:25.953Z",
10 | "attachments": [
11 | {
12 | "id": 45,
13 | "result": "file:///android_asset/test_images/test_image6.jpg",
14 | "optional": {
15 | "size": 3457653,
16 | "name": "test_image6.jpg",
17 | "type": "image/jpeg"
18 | },
19 | "state": "READY",
20 | "name": "test_image6.jpg",
21 | "type": "image/jpeg",
22 | "size": 3457653,
23 | "wellDefined": true,
24 | "url": "file:///android_asset/test_images/test_image6.jpg"
25 | }
26 | ],
27 | "quotes": [],
28 | "quickReplies": [],
29 | "read": true,
30 | "settings": {
31 | "blockInput": false,
32 | "masked": false
33 | },
34 | "authorized": true,
35 | "massPushMessage": false,
36 | "origin": "threads"
37 | },
38 | {
39 | "type": "MESSAGE",
40 | "threadId": 141,
41 | "providerIds": [],
42 | "uuid": "65652fe7-b99e-4250-8328-4a8c3505eb0b",
43 | "operator": {
44 | "id": 4,
45 | "name": "Оператор Елена",
46 | "alias": null,
47 | "status": null,
48 | "photoUrl": null,
49 | "gender": "FEMALE",
50 | "organizationUnit": "Skill Credit",
51 | "role": "OPERATOR"
52 | },
53 | "text": "Добрый день!",
54 | "receivedDate": "2023-03-27T10:06:13.698Z",
55 | "attachments": [],
56 | "quotes": [
57 | {
58 | "type": "MESSAGE",
59 | "threadId": 141,
60 | "providerIds": [],
61 | "uuid": "061f6c38-2ac6-4cf9-aa26-ead6b055bc12",
62 | "text": "",
63 | "receivedDate": "2023-03-27T10:05:25.953Z",
64 | "attachments": [
65 | {
66 | "id": 45,
67 | "result": "file:///android_asset/test_images/test_image4.jpg",
68 | "optional": {
69 | "size": 3457653,
70 | "name": "test_image4.jpg",
71 | "type": "image/jpeg"
72 | },
73 | "state": "READY",
74 | "name": "test_image4.jpg",
75 | "type": "image/jpeg",
76 | "size": 3457653,
77 | "wellDefined": true,
78 | "url": "file:///android_asset/test_images/test_image4.jpg"
79 | }
80 | ],
81 | "quotes": [],
82 | "quickReplies": [],
83 | "read": true,
84 | "settings": {
85 | "blockInput": false,
86 | "masked": false
87 | },
88 | "authorized": true,
89 | "massPushMessage": false,
90 | "origin": "threads"
91 | }
92 | ],
93 | "quickReplies": [],
94 | "read": true,
95 | "settings": {
96 | "blockInput": false,
97 | "masked": false
98 | },
99 | "authorized": true,
100 | "massPushMessage": false,
101 | "origin": "threads"
102 | }
103 | ],
104 | "agentInfo": {
105 | "action": "AGENT_JOINED",
106 | "actionDate": "2023-03-27T10:24:51.591Z",
107 | "thread": {
108 | "id": 142,
109 | "state": "WAITING"
110 | },
111 | "agent": {
112 | "id": 4,
113 | "name": "Оператор Елена",
114 | "alias": null,
115 | "status": null,
116 | "photoUrl": null,
117 | "gender": "FEMALE",
118 | "organizationUnit": "Skill Credit",
119 | "role": "OPERATOR"
120 | }
121 | },
122 | "allowedToSendMessages": true
123 | }
--------------------------------------------------------------------------------
/app/src/main/res/raw/snapshot_test_history_images_response_2.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "type": "MESSAGE",
5 | "threadId": 142,
6 | "providerIds": [],
7 | "uuid": "23b186c2-33e1-4667-b427-1bd2b531a121",
8 | "operator": {
9 | "id": 4,
10 | "name": "Оператор Елена",
11 | "alias": null,
12 | "status": null,
13 | "photoUrl": null,
14 | "gender": "FEMALE",
15 | "organizationUnit": "Skill Credit",
16 | "role": "OPERATOR"
17 | },
18 | "text": "",
19 | "receivedDate": "2023-03-27T10:18:34.611Z",
20 | "attachments": [
21 | {
22 | "id": 46,
23 | "result": "file:///android_asset/test_images/test_image3.jpg",
24 | "optional": {
25 | "size": 238119,
26 | "name": "test_image3.jpg",
27 | "type": "image/jpeg"
28 | },
29 | "state": "READY",
30 | "name": "test_image3.jpg",
31 | "type": "image/jpeg",
32 | "size": 238119,
33 | "wellDefined": true,
34 | "url": "file:///android_asset/test_images/test_image3.jpg"
35 | }
36 | ],
37 | "quotes": [],
38 | "quickReplies": [],
39 | "read": true,
40 | "settings": {
41 | "blockInput": false,
42 | "masked": false
43 | },
44 | "authorized": true,
45 | "massPushMessage": false,
46 | "origin": "threads"
47 | },
48 | {
49 | "type": "MESSAGE",
50 | "threadId": 142,
51 | "providerIds": [],
52 | "uuid": "ce9f4e95-e370-4bde-b6f1-ed11bc3becd5",
53 | "text": "Обожаю океан!",
54 | "receivedDate": "2023-03-27T10:19:09.272Z",
55 | "attachments": [],
56 | "quotes": [
57 | {
58 | "type": "MESSAGE",
59 | "threadId": 142,
60 | "providerIds": [],
61 | "uuid": "23b186c2-33e1-4667-b427-1bd2b531a121",
62 | "operator": {
63 | "id": 4,
64 | "name": "Оператор Елена",
65 | "alias": null,
66 | "status": null,
67 | "photoUrl": null,
68 | "gender": "FEMALE",
69 | "organizationUnit": "Skill Credit",
70 | "role": "OPERATOR"
71 | },
72 | "text": "",
73 | "receivedDate": "2023-03-27T10:18:34.611Z",
74 | "attachments": [
75 | {
76 | "id": 46,
77 | "result": "file:///android_asset/test_images/test_image1.jpg",
78 | "optional": {
79 | "size": 238119,
80 | "name": "test_image1.jpg",
81 | "type": "image/jpeg"
82 | },
83 | "state": "READY",
84 | "name": "test_image2.jpg",
85 | "type": "image/jpeg",
86 | "size": 238119,
87 | "wellDefined": true,
88 | "url": "file:///android_asset/test_images/test_image1.jpg"
89 | }
90 | ],
91 | "quotes": [],
92 | "quickReplies": [],
93 | "read": true,
94 | "settings": {
95 | "blockInput": false,
96 | "masked": false
97 | },
98 | "authorized": true,
99 | "massPushMessage": false,
100 | "origin": "threads"
101 | }
102 | ],
103 | "quickReplies": [],
104 | "read": true,
105 | "settings": {
106 | "blockInput": false,
107 | "masked": false
108 | },
109 | "authorized": true,
110 | "massPushMessage": false,
111 | "origin": "threads"
112 | }
113 | ],
114 | "agentInfo": {
115 | "action": "AGENT_JOINED",
116 | "actionDate": "2023-03-27T10:24:51.591Z",
117 | "thread": {
118 | "id": 142,
119 | "state": "WAITING"
120 | },
121 | "agent": {
122 | "id": 4,
123 | "name": "Оператор Елена",
124 | "alias": null,
125 | "status": null,
126 | "photoUrl": null,
127 | "gender": "FEMALE",
128 | "organizationUnit": "Skill Credit",
129 | "role": "OPERATOR"
130 | }
131 | },
132 | "allowedToSendMessages": true
133 | }
--------------------------------------------------------------------------------
/app/src/main/res/raw/snapshot_test_history_images_response_3.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "type": "MESSAGE",
5 | "threadId": 142,
6 | "providerIds": [],
7 | "uuid": "581fc219-71c6-4c7a-ad7d-429605454115",
8 | "text": "А как вам это?",
9 | "receivedDate": "2023-03-27T10:19:45.144Z",
10 | "attachments": [
11 | {
12 | "id": 47,
13 | "result": "file:///android_asset/test_images/test_image2.jpg",
14 | "optional": {
15 | "size": 5303953,
16 | "name": "test_image2.jpg",
17 | "type": "image/jpeg"
18 | },
19 | "state": "READY",
20 | "name": "test_image2.jpg",
21 | "type": "image/jpeg",
22 | "size": 5303953,
23 | "wellDefined": true,
24 | "url": "file:///android_asset/test_images/test_image2.jpg"
25 | }
26 | ],
27 | "quotes": [],
28 | "quickReplies": [],
29 | "read": true,
30 | "settings": {
31 | "blockInput": false,
32 | "masked": false
33 | },
34 | "authorized": true,
35 | "massPushMessage": false,
36 | "origin": "threads"
37 | }
38 | ],
39 | "agentInfo": {
40 | "action": "AGENT_JOINED",
41 | "actionDate": "2023-03-27T10:24:51.591Z",
42 | "thread": {
43 | "id": 142,
44 | "state": "WAITING"
45 | },
46 | "agent": {
47 | "id": 4,
48 | "name": "Оператор Елена",
49 | "alias": null,
50 | "status": null,
51 | "photoUrl": null,
52 | "gender": "FEMALE",
53 | "organizationUnit": "Skill Credit",
54 | "role": "OPERATOR"
55 | }
56 | },
57 | "allowedToSendMessages": true
58 | }
--------------------------------------------------------------------------------
/app/src/main/res/raw/snapshot_test_history_images_response_4.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "type": "MESSAGE",
5 | "threadId": 142,
6 | "providerIds": [],
7 | "uuid": "90987158-c75a-45d9-87a8-79bbdf27956e",
8 | "operator": {
9 | "id": 4,
10 | "name": "Оператор Елена",
11 | "alias": null,
12 | "status": null,
13 | "photoUrl": null,
14 | "gender": "FEMALE",
15 | "organizationUnit": "Skill Credit",
16 | "role": "OPERATOR"
17 | },
18 | "text": "Великолепно! Как и вот это.",
19 | "receivedDate": "2023-03-27T10:22:04.907Z",
20 | "attachments": [
21 | {
22 | "id": 48,
23 | "result": "file:///android_asset/test_images/test_image5.jpg",
24 | "optional": {
25 | "size": 258264,
26 | "name": "test_image5.jpg",
27 | "type": "image/jpeg"
28 | },
29 | "state": "READY",
30 | "name": "test_image5.jpg",
31 | "type": "image/jpeg",
32 | "size": 258264,
33 | "wellDefined": true,
34 | "url": "file:///android_asset/test_images/test_image5.jpg"
35 | }
36 | ],
37 | "quotes": [],
38 | "quickReplies": [],
39 | "read": false,
40 | "settings": {
41 | "blockInput": false,
42 | "masked": false
43 | },
44 | "authorized": true,
45 | "massPushMessage": false,
46 | "origin": "threads"
47 | }
48 | ],
49 | "agentInfo": {
50 | "action": "AGENT_JOINED",
51 | "actionDate": "2023-03-27T10:24:51.591Z",
52 | "thread": {
53 | "id": 142,
54 | "state": "WAITING"
55 | },
56 | "agent": {
57 | "id": 4,
58 | "name": "Оператор Елена",
59 | "alias": null,
60 | "status": null,
61 | "photoUrl": null,
62 | "gender": "FEMALE",
63 | "organizationUnit": "Skill Credit",
64 | "role": "OPERATOR"
65 | }
66 | },
67 | "allowedToSendMessages": true
68 | }
--------------------------------------------------------------------------------
/app/src/main/res/raw/snapshot_test_history_system_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "clientId": "987525",
5 | "display": false,
6 | "questionId": 1,
7 | "rate": 1,
8 | "read": false,
9 | "receivedDate": "2023-03-24T11:40:34.324Z",
10 | "scale": 1,
11 | "sendingId": 136,
12 | "simple": true,
13 | "text": "Оцените наше обслуживание",
14 | "threadId": 137,
15 | "type": "SURVEY_QUESTION_ANSWER",
16 | "uuid": "3a84a1c8-5f2e-4e31-abcb-6fc8559b2dc9"
17 | },
18 | {
19 | "clientId": "987525",
20 | "display": false,
21 | "questionId": 3,
22 | "rate": 3,
23 | "read": false,
24 | "receivedDate": "2023-03-24T11:40:36.218Z",
25 | "scale": 5,
26 | "sendingId": 136,
27 | "simple": false,
28 | "text": "Оцените насколько мы решили ваш вопрос",
29 | "threadId": 137,
30 | "type": "SURVEY_QUESTION_ANSWER",
31 | "uuid": "0ee9607d-e444-4a4a-8fec-a2d928c7e40f"
32 | },
33 | {
34 | "type": "SURVEY",
35 | "providerIds": [],
36 | "uuid": "7f95eb98-bc74-490a-9426-9888abb68947",
37 | "text": "{\"id\":1,\"sendingId\":139,\"uuid\":\"7f95eb98-bc74-490a-9426-9888abb68947\",\"questions\":[{\"id\":1,\"sendingId\":139,\"text\":\"Оцените наше обслуживание\",\"scale\":1,\"simple\":true,\"displayText\":\"Качество обслуживания\",\"kpi\":3.0,\"int\":true},{\"id\":3,\"sendingId\":139,\"text\":\"Оцените насколько мы решили ваш вопрос\",\"scale\":5,\"simple\":false,\"displayText\":\"Качество обслуживания\",\"minValue\":1,\"maxValue\":5,\"kpi\":3.0,\"int\":true},{\"id\":4,\"sendingId\":139,\"text\":\"Оцените насколько внимательным был наш сотрудник\",\"scale\":5,\"simple\":false,\"displayText\":\"Качество обслуживания\",\"minValue\":1,\"maxValue\":5,\"kpi\":3.0,\"int\":true}],\"created\":\"2016-10-15T00:00:00.000Z\",\"status\":\"CREATED\",\"sendStatus\":\"CLOSED\",\"hideAfter\":999999999999999}",
38 | "receivedDate": "2023-03-24T12:52:13.667Z",
39 | "read": true,
40 | "content": {
41 | "id": 1,
42 | "sendingId": 139,
43 | "uuid": "7f95eb98-bc74-490a-9426-9888abb68947",
44 | "questions": [
45 | {
46 | "id": 1,
47 | "sendingId": 139,
48 | "text": "Оцените наше обслуживание",
49 | "scale": 1,
50 | "simple": true,
51 | "displayText": "Качество обслуживания",
52 | "kpi": 3.0,
53 | "int": true
54 | },
55 | {
56 | "id": 3,
57 | "sendingId": 139,
58 | "text": "Оцените насколько мы решили ваш вопрос",
59 | "scale": 5,
60 | "simple": false,
61 | "displayText": "Качество обслуживания",
62 | "minValue": 1,
63 | "maxValue": 5,
64 | "kpi": 3.0,
65 | "int": true
66 | }
67 | ],
68 | "created": "2016-10-15T00:00:00.000Z",
69 | "status": "CREATED",
70 | "sendStatus": "CLOSED",
71 | "hideAfter": 9999999999999
72 | },
73 | "authorized": true,
74 | "massPushMessage": false,
75 | "aps/sound": "default",
76 | "origin": "threads"
77 | }
78 | ]
79 | }
--------------------------------------------------------------------------------
/app/src/main/res/raw/snapshot_test_history_text_response_1.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "type": "MESSAGE",
5 | "threadId": 304,
6 | "providerIds": [],
7 | "uuid": "ad279408-a236-4fac-823b-a65a460dcb77",
8 | "text": "Добрый день! Мы создаем экосистему бизнеса.",
9 | "receivedDate": "2023-03-22T08:42:02.061Z",
10 | "attachments": [],
11 | "quotes": [],
12 | "quickReplies": [],
13 | "read": true,
14 | "settings": {
15 | "blockInput": false,
16 | "masked": false
17 | },
18 | "authorized": true,
19 | "massPushMessage": false,
20 | "origin": "threads"
21 | },
22 | {
23 | "type": "AVERAGE_WAIT_TIME",
24 | "threadId": 304,
25 | "providerIds": [],
26 | "uuid": "f583f7b4-fd6d-41af-8d59-8fd39ecee3bd",
27 | "text": "Среднее время ожидания ответа составляет 2 минуты",
28 | "receivedDate": "2023-03-22T08:42:02.392Z",
29 | "display": true,
30 | "authorized": true,
31 | "massPushMessage": false,
32 | "aps/sound": "default",
33 | "origin": "threads"
34 | },
35 | {
36 | "type": "OPERATOR_JOINED",
37 | "threadId": 304,
38 | "providerIds": [],
39 | "uuid": "46c00e2e-3e65-4ea2-86d9-429c0726867e",
40 | "operator": {
41 | "id": 9,
42 | "name": "Оператор Елена",
43 | "alias": null,
44 | "status": null,
45 | "photoUrl": null,
46 | "gender": "FEMALE",
47 | "organizationUnit": "Skill Debet",
48 | "role": "OPERATOR"
49 | },
50 | "text": "Вам ответит Оператор Елена",
51 | "receivedDate": "2023-03-22T08:42:38.526Z",
52 | "display": true,
53 | "authorized": true,
54 | "massPushMessage": false,
55 | "aps/sound": "default",
56 | "origin": "threads"
57 | },
58 | {
59 | "type": "MESSAGE",
60 | "threadId": 304,
61 | "providerIds": [],
62 | "uuid": "eda36c57-7286-4360-bb42-0cf3d7932113",
63 | "operator": {
64 | "id": 9,
65 | "name": "Оператор Елена",
66 | "alias": null,
67 | "status": null,
68 | "photoUrl": null,
69 | "gender": "FEMALE",
70 | "organizationUnit": "Skill Debet",
71 | "role": "OPERATOR"
72 | },
73 | "text": "Добро пожаловать в наш чат! А кто такие Edna?",
74 | "receivedDate": "2023-03-22T08:42:44.275Z",
75 | "attachments": [],
76 | "quotes": [],
77 | "quickReplies": [],
78 | "read": true,
79 | "settings": {
80 | "blockInput": false,
81 | "masked": false
82 | },
83 | "authorized": true,
84 | "massPushMessage": false,
85 | "origin": "threads"
86 | }
87 | ],
88 | "agentInfo": {
89 | "action": "AGENT_LOOKUP",
90 | "actionDate": "2023-03-22T08:51:43.124Z",
91 | "thread": {
92 | "id": 304,
93 | "state": "UNASSIGNED"
94 | },
95 | "agent": null
96 | },
97 | "allowedToSendMessages": true
98 | }
--------------------------------------------------------------------------------
/app/src/main/res/raw/snapshot_test_history_text_response_2.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "type": "MESSAGE",
5 | "threadId": 304,
6 | "providerIds": [],
7 | "uuid": "f78114b1-65c3-483e-a2c1-691c3d519b7d",
8 | "operator": {
9 | "id": 9,
10 | "name": "Оператор Елена",
11 | "alias": null,
12 | "status": null,
13 | "photoUrl": null,
14 | "gender": "FEMALE",
15 | "organizationUnit": "Skill Debet",
16 | "role": "OPERATOR"
17 | },
18 | "text": "",
19 | "formattedText": "То есть это все про вас?\n- **Цифровая трансформация клиентов**. Использование мессенджеров в качестве основного канала связи стало нормой.",
20 | "receivedDate": "2023-03-22T08:44:01.005Z",
21 | "attachments": [],
22 | "quotes": [
23 | {
24 | "type": "MESSAGE",
25 | "threadId": 304,
26 | "providerIds": [],
27 | "uuid": "110c8a46-8c38-45df-9949-5f12b7922f01",
28 | "text": "Добро пожаловать в наш чат! А кто такие Edna?",
29 | "receivedDate": "2023-03-22T08:43:19.497Z",
30 | "attachments": [],
31 | "quotes": [
32 | {
33 | "type": "MESSAGE",
34 | "threadId": 304,
35 | "providerIds": [],
36 | "uuid": "eda36c57-7286-4360-bb42-0cf3d7932113",
37 | "operator": {
38 | "id": 9,
39 | "name": "Оператор Елена",
40 | "alias": null,
41 | "status": null,
42 | "photoUrl": null,
43 | "gender": "FEMALE",
44 | "organizationUnit": "Skill Debet",
45 | "role": "OPERATOR"
46 | },
47 | "text": "Прежде всего, постоянное информационно-пропагандистское обеспечение нашей деятельности предопределяет высокую востребованность форм воздействия!",
48 | "receivedDate": "2023-03-22T08:42:44.275Z",
49 | "attachments": [],
50 | "quotes": [],
51 | "quickReplies": [],
52 | "read": true,
53 | "settings": {
54 | "blockInput": false,
55 | "masked": false
56 | },
57 | "authorized": true,
58 | "massPushMessage": false,
59 | "origin": "threads"
60 | }
61 | ],
62 | "quickReplies": [],
63 | "read": true,
64 | "settings": {
65 | "blockInput": false,
66 | "masked": false
67 | },
68 | "authorized": true,
69 | "massPushMessage": false,
70 | "origin": "threads"
71 | }
72 | ],
73 | "quickReplies": [],
74 | "read": true,
75 | "settings": {
76 | "blockInput": false,
77 | "masked": false
78 | },
79 | "authorized": true,
80 | "massPushMessage": false,
81 | "origin": "threads"
82 | }
83 | ],
84 | "agentInfo": {
85 | "action": "AGENT_LOOKUP",
86 | "actionDate": "2023-03-22T08:51:43.124Z",
87 | "thread": {
88 | "id": 304,
89 | "state": "UNASSIGNED"
90 | },
91 | "agent": null
92 | },
93 | "allowedToSendMessages": true
94 | }
--------------------------------------------------------------------------------
/app/src/main/res/raw/snapshot_test_history_text_response_3.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "type": "MESSAGE",
5 | "threadId": 304,
6 | "providerIds": [],
7 | "uuid": "309153f8-d58e-4e8d-bdae-592670c93333",
8 | "text": "Именно! А еще у нас есть различные каналы коммуникации с клиентами! Подробнее: http://127.0.0.1:8080/channels",
9 | "receivedDate": "2023-03-22T08:44:21.741Z",
10 | "attachments": [],
11 | "quotes": [],
12 | "quickReplies": [],
13 | "read": true,
14 | "settings": {
15 | "blockInput": false,
16 | "masked": false
17 | },
18 | "authorized": true,
19 | "massPushMessage": false,
20 | "origin": "threads"
21 | },
22 | {
23 | "type": "MESSAGE",
24 | "threadId": 304,
25 | "providerIds": [],
26 | "uuid": "a30877eb-3b79-4203-bc14-a622be9acc90",
27 | "operator": {
28 | "id": 9,
29 | "name": "Оператор Елена",
30 | "alias": null,
31 | "status": null,
32 | "photoUrl": null,
33 | "gender": "FEMALE",
34 | "organizationUnit": "Skill Debet",
35 | "role": "OPERATOR"
36 | },
37 | "text": "Отлично! Давайте проверим ваши контакты. Ваш email: info@edna.ru, телефон: +7 (495) 609-60-80. Верно?",
38 | "receivedDate": "2023-03-22T08:45:08.649Z",
39 | "attachments": [],
40 | "quotes": [],
41 | "quickReplies": [],
42 | "read": true,
43 | "settings": {
44 | "blockInput": false,
45 | "masked": false
46 | },
47 | "authorized": true,
48 | "massPushMessage": false,
49 | "origin": "threads"
50 | },
51 | {
52 | "type": "MESSAGE",
53 | "threadId": 304,
54 | "providerIds": [],
55 | "uuid": "3aee0831-12b9-43ed-9e08-03a6dcd96843",
56 | "text": "Да, все верно!",
57 | "receivedDate": "2023-03-22T08:45:37.630Z",
58 | "attachments": [],
59 | "quotes": [],
60 | "quickReplies": [],
61 | "read": true,
62 | "settings": {
63 | "blockInput": false,
64 | "masked": false
65 | },
66 | "authorized": true,
67 | "massPushMessage": false,
68 | "origin": "threads"
69 | },
70 | {
71 | "type": "MESSAGE",
72 | "threadId": 304,
73 | "providerIds": [],
74 | "uuid": "20f8f1a3-6edb-4aa9-8d98-27e2dde324f0",
75 | "operator": {
76 | "id": 9,
77 | "name": "Оператор Елена",
78 | "alias": null,
79 | "status": null,
80 | "photoUrl": null,
81 | "gender": "FEMALE",
82 | "organizationUnit": "Skill Debet",
83 | "role": "OPERATOR"
84 | },
85 | "text": "",
86 | "formattedText": "Тогда ***до связи***!",
87 | "receivedDate": "2023-03-22T08:46:18.047Z",
88 | "attachments": [],
89 | "quotes": [],
90 | "quickReplies": [],
91 | "read": true,
92 | "settings": {
93 | "blockInput": false,
94 | "masked": false
95 | },
96 | "authorized": true,
97 | "massPushMessage": false,
98 | "origin": "threads"
99 | }
100 | ],
101 | "agentInfo": {
102 | "action": "AGENT_LOOKUP",
103 | "actionDate": "2023-03-22T08:51:43.124Z",
104 | "thread": {
105 | "id": 304,
106 | "state": "UNASSIGNED"
107 | },
108 | "agent": null
109 | },
110 | "allowedToSendMessages": true
111 | }
--------------------------------------------------------------------------------
/app/src/main/res/raw/snapshot_test_history_voice_response.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "type": "MESSAGE",
5 | "threadId": 182,
6 | "providerIds": [],
7 | "uuid": "8ea00dba-527d-4fd3-9321-01ce829304eb",
8 | "text": "",
9 | "receivedDate": "2023-04-05T10:29:43.666Z",
10 | "attachments": [
11 | {
12 | "id": 70,
13 | "result": "file:///android_asset/test_files/client_text1.ogg",
14 | "optional": {
15 | "size": 52095,
16 | "name": "client_text1.ogg",
17 | "type": "audio/ogg"
18 | },
19 | "state": "READY",
20 | "name": "client_text1.ogg",
21 | "type": "audio/ogg",
22 | "size": 52095,
23 | "wellDefined": true,
24 | "url": "file:///android_asset/test_files/client_text1.ogg"
25 | }
26 | ],
27 | "quotes": [],
28 | "quickReplies": [],
29 | "read": true,
30 | "settings": {
31 | "blockInput": false,
32 | "masked": false
33 | },
34 | "authorized": true,
35 | "massPushMessage": false,
36 | "origin": "threads"
37 | },
38 | {
39 | "type": "MESSAGE",
40 | "threadId": 182,
41 | "providerIds": [],
42 | "uuid": "1c1df1af-1a21-49be-9421-f2d846ae493c",
43 | "operator": {
44 | "id": 4,
45 | "name": "Оператор Елена",
46 | "alias": null,
47 | "status": null,
48 | "photoUrl": null,
49 | "gender": "FEMALE",
50 | "organizationUnit": "Skill Credit",
51 | "role": "OPERATOR"
52 | },
53 | "text": "",
54 | "receivedDate": "2023-04-05T10:36:12.443Z",
55 | "attachments": [
56 | {
57 | "id": 71,
58 | "result": "file:///android_asset/test_files/operator_text1.ogg",
59 | "optional": {
60 | "size": 31183,
61 | "name": "operator_text1.ogg",
62 | "type": "audio/ogg"
63 | },
64 | "state": "READY",
65 | "name": "operator_text1.ogg",
66 | "type": "audio/ogg",
67 | "size": 31183,
68 | "wellDefined": true,
69 | "url": "file:///android_asset/test_files/operator_text1.ogg"
70 | }
71 | ],
72 | "quotes": [],
73 | "quickReplies": [],
74 | "read": false,
75 | "settings": {
76 | "blockInput": false,
77 | "masked": false
78 | },
79 | "authorized": true,
80 | "massPushMessage": false,
81 | "origin": "threads"
82 | }
83 | ],
84 | "agentInfo": {
85 | "action": "AGENT_JOINED",
86 | "actionDate": "2023-04-05T10:39:21.522Z",
87 | "thread": {
88 | "id": 182,
89 | "state": "WAITING"
90 | },
91 | "agent": {
92 | "id": 4,
93 | "name": "Оператор Елена",
94 | "alias": null,
95 | "status": null,
96 | "photoUrl": null,
97 | "gender": "FEMALE",
98 | "organizationUnit": "Skill Credit",
99 | "role": "OPERATOR"
100 | }
101 | },
102 | "allowedToSendMessages": true
103 | }
--------------------------------------------------------------------------------
/app/src/main/res/values-hdpi/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | @dimen/height_42
3 | @dimen/margin_5
4 | @dimen/margin_8
5 | @dimen/margin_16
6 | @dimen/height_42
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 48dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w1240dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 200dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 48dp
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attr.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/bools.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 | false
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #121212
4 | #2d2d2d
5 | #79747E
6 | #8E8E93
7 |
8 | #2B8718
9 |
10 | #b5b5b5
11 | #b7b7b7
12 | #f2f2f7
13 | #f4f4f4
14 | #ececec
15 | #fafafa
16 | #ffffff
17 |
18 | #007AFF
19 | #0A84FF
20 | #004EA4
21 | #1C1B1F
22 | #FF3B30
23 |
24 | #883C3C43
25 | #505050
26 | #505050
27 | @color/white_color_ec
28 | @color/white_color_ec
29 | #000000
30 | #505050
31 | @color/white_color_ec
32 | #A9A9A9
33 |
34 |
35 | #BBF1D1
36 | #54DCA0
37 | #DFF3E7
38 | #2E7B59
39 | #18382A
40 | #D0D2D4
41 | #4D000000
42 | #0000FF
43 |
44 |
45 | #183D2C
46 | #2A6E50
47 | #628676
48 | #1C1B1F
49 | #000000
50 | #9fa5a9
51 | #4D000000
52 | #0000FF
53 | #505050
54 | #f2f2f7
55 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 2dp
3 | 3dp
4 | 5dp
5 | 8dp
6 | 12dp
7 | 14dp
8 | 16dp
9 | 19dp
10 | 20dp
11 | 21dp
12 | 24dp
13 | 26dp
14 | 32dp
15 | 40dp
16 | 52dp
17 |
18 | 48dp
19 |
20 | 25dp
21 | 36dp
22 | 42dp
23 | 50dp
24 | 56dp
25 |
26 | 11sp
27 | 12sp
28 | 14sp
29 | 16sp
30 | 22sp
31 | 28sp
32 |
33 | 64sp
34 | 56dp
35 | @dimen/height_56
36 |
37 | @dimen/margin_16
38 | @dimen/margin_24
39 | @dimen/margin_40
40 | @dimen/margin_52
41 | @dimen/height_56
42 |
43 | @dimen/margin_20
44 | @dimen/margin_16
45 |
46 |
47 | 23dp
48 | 8dp
49 | 8dp
50 | 8dp
51 | 22dp
52 | 12dp
53 | 12dp
54 | 12dp
55 | 12dp
56 | 12dp
57 | 18dp
58 | 12dp
59 |
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Edna ChatCenter
3 |
4 | Вход в аккаунт
5 | Сервер
6 | Пользователь
7 | Версия API
8 | Войти
9 | Logout
10 | Вход под пользователем:
11 | Демонстрационные примеры
12 | Функционал не поддерживается в текущей версии приложения.
13 |
14 | Welcome screen
15 | Select server screen
16 | Демонстрации
17 | Чат
18 | Add server screen
19 | Select user screen
20 | Add user screen
21 |
22 | Текстовые сообщения
23 | Сообщения с ошибками
24 | Голосовые сообщения
25 | Изображения
26 | Файлы
27 | Системные сообщения
28 | Чат с ботом
29 | Удаленные и измененные сообщения
30 |
31 | Серверы
32 | Пользователи
33 | Name
34 | * Name
35 | Имя пользователя
36 | * Имя пользователя
37 | ID пользователя
38 | * ID пользователя
39 | Данные пользователя
40 | appMarker
41 | signature
42 | Authorization header
43 | X-Auth-Schema header
44 | Datastore URL
45 | Threads Gate URL
46 | Server Base URL
47 | Threads Gate Provider Uid
48 | * Datastore URL
49 | * Threads Gate URL
50 | * Server Base URL
51 | * Threads Gate Provider Uid
52 | Поле обязательное для заполнения
53 | Добавьте пользователя\nдля входа в чат
54 |
55 | Кнопка назад
56 | Кнопка сохранить
57 | Кнопка добавить
58 | Иконка элемента списка серверов
59 | Кнопка редактировать
60 | Кнопка удалить
61 | Иконка элемента списка пользователей
62 |
63 | Демонстрация сообщений
64 | Оператор Елена
65 |
66 | Выберите тему
67 | По умолчанию
68 | Темная
69 | Светлая
70 | OK
71 | Удалить
72 | Изменить
73 | Предварительная регистрация
74 | Необходимо установить или заново переустановить пользователя
75 | Приложение будет перезапущено
76 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/test/java/io/edna/threads/demo/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package io.edna.threads.demo
2 |
3 | import org.junit.Test
4 |
5 | /**
6 | * Example local unit test, which will execute on the development machine (host).
7 | *
8 | * See [testing documentation](http://d.android.com/tools/testing).
9 | */
10 | class ExampleUnitTest {
11 | @Test
12 | fun addition_isCorrect() {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = '1.8.0'
4 | dependencies {
5 | classpath 'com.android.tools.build:gradle:7.2.1'
6 | classpath 'com.google.gms:google-services:4.3.15'
7 | classpath 'net.researchgate:gradle-release:2.8.1'
8 | classpath 'com.huawei.agconnect:agcp:1.6.4.300'
9 | classpath "org.jlleitschuh.gradle:ktlint-gradle:11.5.1"
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
12 | classpath "dev.testify:plugin:2.0.0-alpha02"
13 | classpath 'com.google.firebase:perf-plugin:1.4.2'
14 | }
15 | }
16 |
17 | plugins {
18 | id 'com.android.application' version '7.2.1' apply false
19 | id 'com.android.library' version '7.2.1' apply false
20 | id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
21 | id 'org.jlleitschuh.gradle.ktlint' version "10.3.0"
22 | }
23 |
24 | allprojects {
25 | //Support @JvmDefault
26 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
27 | kotlinOptions {
28 | freeCompilerArgs = ['-Xjvm-default=enable'] //enable or compatibility
29 | jvmTarget = '11'
30 | }
31 | }
32 | }
33 |
34 | subprojects {
35 | apply plugin: "org.jlleitschuh.gradle.ktlint"
36 | }
37 |
38 | task clean(type: Delete) {
39 | delete rootProject.buildDir
40 | }
41 |
42 | ext {
43 | compileSdkVersion = 34
44 | minSdkVersion = 21
45 | targetSdkVersion = 31
46 |
47 | androidXCoreVersion = '1.9.0'
48 | androidXPreferenceVersion = '1.1.1'
49 | androidXSwiperefreshlayout = '1.1.0'
50 | materialComponentsVersion = '1.8.0'
51 | appCompatVersion = '1.6.1'
52 | kotlinReflect = '1.7.10'
53 |
54 | constraintlayoutVersion = '2.1.4'
55 | navigationVersion = '2.5.3'
56 |
57 | testExpressoVersion = '3.5.1'
58 | testJunitVersion = '4.13.2'
59 | testJunitAndroidVersion = '1.1.5'
60 | lifecycleViewmodelVersion = '2.4.0'
61 | calligraphy3Version = '3.1.1'
62 | viewpumpVersion = '2.0.3'
63 |
64 | viewmodelVersion = '2.5.1'
65 | koin_version = '3.2.0'
66 | okhttp_webserver_version = '4.11.0'
67 |
68 | pushVersion = '3.5.2'
69 | okhttpVersion = '4.9.3'
70 | retrofitVersion = '2.11.0'
71 | rxjava2Version = '2.2.21'
72 | rxAndroidVersion = '2.1.1'
73 | streamVersion = '1.2.1'
74 | gsonVersion = '2.11.0'
75 | picasso_version = '2.8'
76 | ffmpeg = '0.3.2'
77 | fcmVersion = '23.0.6'
78 | work_version = "2.7.1"
79 | sqlite_version = "2.0.1"
80 | crypto_tink = '1.7.0'
81 | markwonVersion = '4.6.2'
82 | robolectricVersion = '4.11'
83 | androidXJunitVersion = '1.1.3'
84 | androidXTestVersion = '1.5.0'
85 | espressoVersion = '3.4.0'
86 | mockitoVersion = '3.12.4'
87 | mockitoInlineVersion = '2.21.0'
88 | webserver_version = '2.35.0'
89 | test_ext = '1.1.5'
90 | kaspresso_version = '1.5.3'
91 | retrofitVersion = '2.9.0'
92 | parcelerVersion = '1.1.12'
93 | parcelerVersion = '1.1.12'
94 | firebaseMessagingVersion = '23.4.0'
95 | hmsMessagingVersion = '6.11.0.300'
96 | appCenterSdkVersion = '4.4.5'
97 | }
98 |
--------------------------------------------------------------------------------
/docs/image1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/docs/image1.jpg
--------------------------------------------------------------------------------
/docs/image2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/docs/image2.jpg
--------------------------------------------------------------------------------
/docs/image3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/docs/image3.jpg
--------------------------------------------------------------------------------
/docs/image4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/docs/image4.png
--------------------------------------------------------------------------------
/docs/image5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/docs/image5.png
--------------------------------------------------------------------------------
/docs/image6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/docs/image6.png
--------------------------------------------------------------------------------
/docs/image7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/docs/image7.png
--------------------------------------------------------------------------------
/docs/image8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/docs/image8.png
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | # When configured, Gradle will run in incubating parallel mode.
10 | # This option should only be used with decoupled projects. More details, visit
11 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
12 | # org.gradle.parallel=true
13 | # AndroidX package structure to make it clearer which packages are bundled with the
14 | # Android operating system, and which are packaged with your app"s APK
15 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
16 | # Kotlin code style for this project: "official" or "obsolete":
17 | # Enables namespacing of each library's R class so that its R class includes only the
18 | # resources declared in the library itself and none from the library's dependencies,
19 | # thereby reducing the size of the R class for that library
20 | version=4.42.0
21 | android.enableJetifier=true
22 | android.useAndroidX=true
23 | org.gradle.configureondemand=true
24 | org.gradle.daemon=true
25 | org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
26 | org.gradle.parallel=true
27 | android.nonTransitiveRClass=true
28 | kotlin.code.style=official
29 | org.gradle.unsafe.configuration-cache=false
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Mar 06 12:42:14 EET 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/push-lib/Android_SDK_autodraw_3.3.0.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/push-lib/Android_SDK_autodraw_3.3.0.docx
--------------------------------------------------------------------------------
/push-lib/MFMSPushLite.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/push-lib/MFMSPushLite.pdf
--------------------------------------------------------------------------------
/push-lib/edna-PushService-MobileSDK-Android-Lite_3.3.0.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThreadsMobileLib/edna-sdk-android/a95049023ec0b62ff91021b48069f385a8ab3011/push-lib/edna-PushService-MobileSDK-Android-Lite_3.3.0.docx
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | maven { url "https://jitpack.io" }
7 | maven { url 'https://plugins.gradle.org/m2/' }
8 | maven { url 'https://maven-pub.edna.ru/repository/maven-public/' }
9 | maven { url 'https://developer.huawei.com/repo/' }
10 | }
11 | }
12 | dependencyResolutionManagement {
13 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
14 | repositories {
15 | google()
16 | mavenCentral()
17 | maven { url "https://jitpack.io" }
18 | maven { url 'https://plugins.gradle.org/m2/' }
19 | maven { url 'https://maven-pub.edna.ru/repository/maven-public/' }
20 | maven { url 'https://developer.huawei.com/repo/' }
21 | }
22 | }
23 | rootProject.name = "Edna ChatCenter"
24 | include ':app'
--------------------------------------------------------------------------------