diff --git a/.gitignore b/.gitignore index f8d94768..03b224d9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ # built application files *.apk *.ap_ -*.jar # files for the dex VM *.dex @@ -38,4 +37,4 @@ android/proguard/ *.iws .idea/ build/ -.gradle \ No newline at end of file +.gradle diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..de57238b --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 stfalcon.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 8260eae7..011249cf 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -[ ![Download](https://api.bintray.com/packages/troy379/maven/ChatKit/images/download.svg) ](https://bintray.com/troy379/maven/ChatKit/_latestVersion) - # ChatKit for Android +[![](https://jitpack.io/v/stfalcon-studio/Chatkit.svg)](https://jitpack.io/#stfalcon-studio/Chatkit) + ChatKit is a library designed to simplify the development of UI for such a trivial task as chat. It has flexible possibilities for styling, customizing and data management

@@ -41,19 +41,50 @@ To implement all of the features above you can use the following components: ### Download -Download via Gradle: -```gradle -compile 'com.github.stfalcon:chatkit:0.2.0' +1. Add jitpack to the root build.gradle file of your project at the end of repositories. +``` +allprojects { + repositories { + ... + maven { url 'https://jitpack.io' } + } +} +``` +2. Add the dependency +[![](https://jitpack.io/v/stfalcon-studio/Chatkit.svg)](https://jitpack.io/#stfalcon-studio/Chatkit) +``` +dependencies { + ... + implementation 'com.github.stfalcon-studio:Chatkit:[last_version]' +} ``` -or Maven: -```xml - - com.github.stfalcon - chatkit - 0.2.0 - pom - +### AndroidX +To use with AndroidX you have to set targetSdkVersion for your project to 28 and add following 2 lines in ```gradle.properties``` file. +``` +android.useAndroidX=true +android.enableJetifier=true +``` + +### Proguard +If you are using ProGuard you might need to add rules: +``` +-keep class * extends com.stfalcon.chatkit.messages.MessageHolders$OutcomingTextMessageViewHolder { + public (android.view.View, java.lang.Object); + public (android.view.View); + } +-keep class * extends com.stfalcon.chatkit.messages.MessageHolders$IncomingTextMessageViewHolder { + public (android.view.View, java.lang.Object); + public (android.view.View); + } +-keep class * extends com.stfalcon.chatkit.messages.MessageHolders$IncomingImageMessageViewHolder { + public (android.view.View, java.lang.Object); + public (android.view.View); + } +-keep class * extends com.stfalcon.chatkit.messages.MessageHolders$OutcomingImageMessageViewHolder { + public (android.view.View, java.lang.Object); + public (android.view.View); + } ``` ### Try it @@ -79,7 +110,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at -http://www.apache.org/licenses/LICENSE-2.0 +https://github.com/stfalcon-studio/ChatKit/blob/master/LICENSE Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/build.gradle b/build.gradle index 3c9f496e..9c349992 100644 --- a/build.gradle +++ b/build.gradle @@ -3,19 +3,22 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.1' - classpath 'com.novoda:bintray-release:0.4.0' - - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files + classpath 'com.android.tools.build:gradle:4.1.2' } } +plugins { + id 'maven-publish' +} + allprojects { repositories { jcenter() + google() + maven { url "https://jitpack.io" } } } diff --git a/chatkit/build.gradle b/chatkit/build.gradle index a7b3e3f7..ad99aae0 100644 --- a/chatkit/build.gradle +++ b/chatkit/build.gradle @@ -1,16 +1,14 @@ apply plugin: 'com.android.library' -apply plugin: 'com.novoda.bintray-release' +apply plugin: 'maven-publish' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion 29 + buildToolsVersion '29.0.2' defaultConfig { minSdkVersion 14 - targetSdkVersion 25 versionCode 1 - versionName "0.2.1" - + versionName '0.4.1' consumerProguardFiles 'proguard.txt' } android { @@ -18,27 +16,35 @@ android { abortOnError false } } -} -publish { - groupId = 'com.github.stfalcon' - artifactId = 'chatkit' - publishVersion = '0.2.1' - desc = 'ChatKit - is a library designed to simplify the development of UI for such a trivial task as chat. It have flexible possibilities for styling, customizing and data management' - licences = ['Apache-2.0'] - uploadName = 'ChatKit' - website = 'https://github.com/stfalcon-studio/ChatKit.git' -} + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } -ext { - supportVersion = '25.3.1' - flexboxVersion = '0.2.5' + afterEvaluate { + publishing { + publications { + // Creates a Maven publication called "release". + release(MavenPublication) { + // Applies the component for the release build variant. + from components.release + + // You can then customize attributes of the publication as shown below. + groupId = 'com.github.stfalcon' + artifactId = 'chatkit' + version = '0.4.1' + } + } + } + } } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) + implementation fileTree(dir: 'libs', include: ['*.jar']) - compile "com.android.support:appcompat-v7:$supportVersion" - compile "com.android.support:design:$supportVersion" - compile "com.google.android:flexbox:$flexboxVersion" + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.google.android.material:material:1.2.1' + implementation "com.google.android:flexbox:1.0.0" + implementation 'androidx.recyclerview:recyclerview:1.1.0' } diff --git a/chatkit/src/main/AndroidManifest.xml b/chatkit/src/main/AndroidManifest.xml index 9f22fb31..e3238ed8 100644 --- a/chatkit/src/main/AndroidManifest.xml +++ b/chatkit/src/main/AndroidManifest.xml @@ -1,8 +1,3 @@ - - - + diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/commons/ImageLoader.java b/chatkit/src/main/java/com/stfalcon/chatkit/commons/ImageLoader.java index 4d795854..bfcfeb78 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/commons/ImageLoader.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/commons/ImageLoader.java @@ -18,11 +18,13 @@ import android.widget.ImageView; +import androidx.annotation.Nullable; + /** * Callback for implementing images loading in message list */ public interface ImageLoader { - void loadImage(ImageView imageView, String url); + void loadImage(ImageView imageView, @Nullable String url, @Nullable Object payload); } diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/commons/Style.java b/chatkit/src/main/java/com/stfalcon/chatkit/commons/Style.java index fcbd8a77..c69511a3 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/commons/Style.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/commons/Style.java @@ -20,14 +20,15 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; -import android.support.annotation.AttrRes; -import android.support.annotation.ColorRes; -import android.support.annotation.DimenRes; -import android.support.annotation.DrawableRes; -import android.support.v4.content.ContextCompat; import android.util.AttributeSet; import android.util.TypedValue; +import androidx.annotation.AttrRes; +import androidx.annotation.ColorRes; +import androidx.annotation.DimenRes; +import androidx.annotation.DrawableRes; +import androidx.core.content.ContextCompat; + import com.stfalcon.chatkit.R; /** diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/commons/ViewHolder.java b/chatkit/src/main/java/com/stfalcon/chatkit/commons/ViewHolder.java index dff3193c..c92d5213 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/commons/ViewHolder.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/commons/ViewHolder.java @@ -16,9 +16,10 @@ package com.stfalcon.chatkit.commons; -import android.support.v7.widget.RecyclerView; import android.view.View; +import androidx.recyclerview.widget.RecyclerView; + /** * Base ViewHolder */ diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/commons/models/IUser.java b/chatkit/src/main/java/com/stfalcon/chatkit/commons/models/IUser.java index d51c2081..d4c621a0 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/commons/models/IUser.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/commons/models/IUser.java @@ -25,20 +25,20 @@ public interface IUser { * Returns the user's id * * @return the user's id - * */ + */ String getId(); /** * Returns the user's name * * @return the user's name - * */ + */ String getName(); /** * Returns the user's avatar image url * * @return the user's avatar image url - * */ + */ String getAvatar(); } diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/commons/models/MessageContentType.java b/chatkit/src/main/java/com/stfalcon/chatkit/commons/models/MessageContentType.java index 943623c1..cb33dd6c 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/commons/models/MessageContentType.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/commons/models/MessageContentType.java @@ -1,5 +1,23 @@ +/******************************************************************************* + * Copyright 2016 stfalcon.com + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ + package com.stfalcon.chatkit.commons.models; +import androidx.annotation.Nullable; + import com.stfalcon.chatkit.messages.MessageHolders; /* @@ -16,6 +34,7 @@ public interface MessageContentType extends IMessage { * Default media type for image message. */ interface Image extends IMessage { + @Nullable String getImageUrl(); } diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogListStyle.java b/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogListStyle.java index 539d3227..b8ea3eca 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogListStyle.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogListStyle.java @@ -27,7 +27,7 @@ /** * Style for DialogList customization by xml attributes */ - +@SuppressWarnings("WeakerAccess") class DialogListStyle extends Style { private int dialogTitleTextColor; @@ -75,75 +75,79 @@ static DialogListStyle parse(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.DialogsList); //Item background - style.setDialogItemBackground(typedArray.getColor(R.styleable.DialogsList_dialogItemBackground, - style.getColor(R.color.transparent))); - style.setDialogUnreadItemBackground(typedArray.getColor(R.styleable.DialogsList_dialogUnreadItemBackground, - style.getColor(R.color.transparent))); + style.dialogItemBackground = typedArray.getColor(R.styleable.DialogsList_dialogItemBackground, + style.getColor(R.color.transparent)); + style.dialogUnreadItemBackground = typedArray.getColor(R.styleable.DialogsList_dialogUnreadItemBackground, + style.getColor(R.color.transparent)); + //Title text - style.setDialogTitleTextColor(typedArray.getColor(R.styleable.DialogsList_dialogTitleTextColor, - style.getColor(R.color.dialog_title_text))); - style.setDialogTitleTextSize(typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogTitleTextSize, - context.getResources().getDimensionPixelSize(R.dimen.dialog_title_text_size))); - style.setDialogTitleTextStyle(typedArray.getInt(R.styleable.DialogsList_dialogTitleTextStyle, Typeface.NORMAL)); + style.dialogTitleTextColor = typedArray.getColor(R.styleable.DialogsList_dialogTitleTextColor, + style.getColor(R.color.dialog_title_text)); + style.dialogTitleTextSize = typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogTitleTextSize, + context.getResources().getDimensionPixelSize(R.dimen.dialog_title_text_size)); + style.dialogTitleTextStyle = typedArray.getInt(R.styleable.DialogsList_dialogTitleTextStyle, Typeface.NORMAL); + //Title unread text - style.setDialogUnreadTitleTextColor(typedArray.getColor(R.styleable.DialogsList_dialogUnreadTitleTextColor, - style.getColor(R.color.dialog_title_text))); - style.setDialogUnreadTitleTextStyle(typedArray.getInt(R.styleable.DialogsList_dialogUnreadTitleTextStyle, Typeface.NORMAL)); + style.dialogUnreadTitleTextColor = typedArray.getColor(R.styleable.DialogsList_dialogUnreadTitleTextColor, + style.getColor(R.color.dialog_title_text)); + style.dialogUnreadTitleTextStyle = typedArray.getInt(R.styleable.DialogsList_dialogUnreadTitleTextStyle, Typeface.NORMAL); //Message text - style.setDialogMessageTextColor(typedArray.getColor(R.styleable.DialogsList_dialogMessageTextColor, - style.getColor(R.color.dialog_message_text))); - style.setDialogMessageTextSize(typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogMessageTextSize, - context.getResources().getDimensionPixelSize(R.dimen.dialog_message_text_size))); - style.setDialogMessageTextStyle(typedArray.getInt(R.styleable.DialogsList_dialogMessageTextStyle, Typeface.NORMAL)); + style.dialogMessageTextColor = typedArray.getColor(R.styleable.DialogsList_dialogMessageTextColor, + style.getColor(R.color.dialog_message_text)); + style.dialogMessageTextSize = typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogMessageTextSize, + context.getResources().getDimensionPixelSize(R.dimen.dialog_message_text_size)); + style.dialogMessageTextStyle = typedArray.getInt(R.styleable.DialogsList_dialogMessageTextStyle, Typeface.NORMAL); + //Message unread text - style.setDialogUnreadMessageTextColor(typedArray.getColor(R.styleable.DialogsList_dialogUnreadMessageTextColor, - style.getColor(R.color.dialog_message_text))); - style.setDialogUnreadMessageTextStyle(typedArray.getInt(R.styleable.DialogsList_dialogUnreadMessageTextStyle, Typeface.NORMAL)); + style.dialogUnreadMessageTextColor = typedArray.getColor(R.styleable.DialogsList_dialogUnreadMessageTextColor, + style.getColor(R.color.dialog_message_text)); + style.dialogUnreadMessageTextStyle = typedArray.getInt(R.styleable.DialogsList_dialogUnreadMessageTextStyle, Typeface.NORMAL); //Date text - style.setDialogDateColor(typedArray.getColor(R.styleable.DialogsList_dialogDateColor, - style.getColor(R.color.dialog_date_text))); - style.setDialogDateSize(typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogDateSize, - context.getResources().getDimensionPixelSize(R.dimen.dialog_date_text_size))); - style.setDialogDateStyle(typedArray.getInt(R.styleable.DialogsList_dialogDateStyle, Typeface.NORMAL)); + style.dialogDateColor = typedArray.getColor(R.styleable.DialogsList_dialogDateColor, + style.getColor(R.color.dialog_date_text)); + style.dialogDateSize = typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogDateSize, + context.getResources().getDimensionPixelSize(R.dimen.dialog_date_text_size)); + style.dialogDateStyle = typedArray.getInt(R.styleable.DialogsList_dialogDateStyle, Typeface.NORMAL); + //Date unread text - style.setDialogUnreadDateColor(typedArray.getColor(R.styleable.DialogsList_dialogUnreadDateColor, - style.getColor(R.color.dialog_date_text))); - style.setDialogUnreadDateStyle(typedArray.getInt(R.styleable.DialogsList_dialogUnreadDateStyle, Typeface.NORMAL)); + style.dialogUnreadDateColor = typedArray.getColor(R.styleable.DialogsList_dialogUnreadDateColor, + style.getColor(R.color.dialog_date_text)); + style.dialogUnreadDateStyle = typedArray.getInt(R.styleable.DialogsList_dialogUnreadDateStyle, Typeface.NORMAL); //Unread bubble - style.setDialogUnreadBubbleEnabled(typedArray.getBoolean(R.styleable.DialogsList_dialogUnreadBubbleEnabled, true)); - style.setDialogUnreadBubbleBackgroundColor(typedArray.getColor(R.styleable.DialogsList_dialogUnreadBubbleBackgroundColor, - style.getColor(R.color.dialog_unread_bubble))); + style.dialogUnreadBubbleEnabled = typedArray.getBoolean(R.styleable.DialogsList_dialogUnreadBubbleEnabled, true); + style.dialogUnreadBubbleBackgroundColor = typedArray.getColor(R.styleable.DialogsList_dialogUnreadBubbleBackgroundColor, + style.getColor(R.color.dialog_unread_bubble)); //Unread bubble text - style.setDialogUnreadBubbleTextColor(typedArray.getColor(R.styleable.DialogsList_dialogUnreadBubbleTextColor, - style.getColor(R.color.dialog_unread_text))); - style.setDialogUnreadBubbleTextSize(typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogUnreadBubbleTextSize, - context.getResources().getDimensionPixelSize(R.dimen.dialog_unread_bubble_text_size))); - style.setDialogUnreadBubbleTextStyle(typedArray.getInt(R.styleable.DialogsList_dialogUnreadBubbleTextStyle, Typeface.NORMAL)); + style.dialogUnreadBubbleTextColor = typedArray.getColor(R.styleable.DialogsList_dialogUnreadBubbleTextColor, + style.getColor(R.color.dialog_unread_text)); + style.dialogUnreadBubbleTextSize = typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogUnreadBubbleTextSize, + context.getResources().getDimensionPixelSize(R.dimen.dialog_unread_bubble_text_size)); + style.dialogUnreadBubbleTextStyle = typedArray.getInt(R.styleable.DialogsList_dialogUnreadBubbleTextStyle, Typeface.NORMAL); //Avatar - style.setDialogAvatarWidth(typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogAvatarWidth, - context.getResources().getDimensionPixelSize(R.dimen.dialog_avatar_width))); - style.setDialogAvatarHeight(typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogAvatarHeight, - context.getResources().getDimensionPixelSize(R.dimen.dialog_avatar_height))); + style.dialogAvatarWidth = typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogAvatarWidth, + context.getResources().getDimensionPixelSize(R.dimen.dialog_avatar_width)); + style.dialogAvatarHeight = typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogAvatarHeight, + context.getResources().getDimensionPixelSize(R.dimen.dialog_avatar_height)); //Last message avatar - style.setDialogMessageAvatarEnabled(typedArray.getBoolean(R.styleable.DialogsList_dialogMessageAvatarEnabled, true)); - style.setDialogMessageAvatarWidth(typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogMessageAvatarWidth, - context.getResources().getDimensionPixelSize(R.dimen.dialog_last_message_avatar_width))); - style.setDialogMessageAvatarHeight(typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogMessageAvatarHeight, - context.getResources().getDimensionPixelSize(R.dimen.dialog_last_message_avatar_height))); + style.dialogMessageAvatarEnabled = typedArray.getBoolean(R.styleable.DialogsList_dialogMessageAvatarEnabled, true); + style.dialogMessageAvatarWidth = typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogMessageAvatarWidth, + context.getResources().getDimensionPixelSize(R.dimen.dialog_last_message_avatar_width)); + style.dialogMessageAvatarHeight = typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogMessageAvatarHeight, + context.getResources().getDimensionPixelSize(R.dimen.dialog_last_message_avatar_height)); //Divider - style.setDialogDividerEnabled(typedArray.getBoolean(R.styleable.DialogsList_dialogDividerEnabled, true)); - style.setDialogDividerColor(typedArray.getColor(R.styleable.DialogsList_dialogDividerColor, style.getColor(R.color.dialog_divider))); - style.setDialogDividerLeftPadding(typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogDividerLeftPadding, - context.getResources().getDimensionPixelSize(R.dimen.dialog_divider_margin_left))); - style.setDialogDividerRightPadding(typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogDividerRightPadding, - context.getResources().getDimensionPixelSize(R.dimen.dialog_divider_margin_right))); + style.dialogDividerEnabled = typedArray.getBoolean(R.styleable.DialogsList_dialogDividerEnabled, true); + style.dialogDividerColor = typedArray.getColor(R.styleable.DialogsList_dialogDividerColor, style.getColor(R.color.dialog_divider)); + style.dialogDividerLeftPadding = typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogDividerLeftPadding, + context.getResources().getDimensionPixelSize(R.dimen.dialog_divider_margin_left)); + style.dialogDividerRightPadding = typedArray.getDimensionPixelSize(R.styleable.DialogsList_dialogDividerRightPadding, + context.getResources().getDimensionPixelSize(R.dimen.dialog_divider_margin_right)); typedArray.recycle(); @@ -154,251 +158,127 @@ private DialogListStyle(Context context, AttributeSet attrs) { super(context, attrs); } - int getDialogTitleTextColor() { + protected int getDialogTitleTextColor() { return dialogTitleTextColor; } - void setDialogTitleTextColor(int dialogTitleTextColor) { - this.dialogTitleTextColor = dialogTitleTextColor; - } - - int getDialogTitleTextSize() { + protected int getDialogTitleTextSize() { return dialogTitleTextSize; } - void setDialogTitleTextSize(int dialogTitleTextSize) { - this.dialogTitleTextSize = dialogTitleTextSize; - } - - int getDialogTitleTextStyle() { + protected int getDialogTitleTextStyle() { return dialogTitleTextStyle; } - void setDialogTitleTextStyle(int dialogTitleTextStyle) { - this.dialogTitleTextStyle = dialogTitleTextStyle; - } - - int getDialogUnreadTitleTextColor() { + protected int getDialogUnreadTitleTextColor() { return dialogUnreadTitleTextColor; } - void setDialogUnreadTitleTextColor(int dialogUnreadTitleTextColor) { - this.dialogUnreadTitleTextColor = dialogUnreadTitleTextColor; - } - - int getDialogUnreadTitleTextStyle() { + protected int getDialogUnreadTitleTextStyle() { return dialogUnreadTitleTextStyle; } - void setDialogUnreadTitleTextStyle(int dialogUnreadTitleTextStyle) { - this.dialogUnreadTitleTextStyle = dialogUnreadTitleTextStyle; - } - - int getDialogMessageTextColor() { + protected int getDialogMessageTextColor() { return dialogMessageTextColor; } - void setDialogMessageTextColor(int dialogMessageTextColor) { - this.dialogMessageTextColor = dialogMessageTextColor; - } - - int getDialogMessageTextSize() { + protected int getDialogMessageTextSize() { return dialogMessageTextSize; } - void setDialogMessageTextSize(int dialogMessageTextSize) { - this.dialogMessageTextSize = dialogMessageTextSize; - } - - int getDialogMessageTextStyle() { + protected int getDialogMessageTextStyle() { return dialogMessageTextStyle; } - void setDialogMessageTextStyle(int dialogMessageTextStyle) { - this.dialogMessageTextStyle = dialogMessageTextStyle; - } - - int getDialogUnreadMessageTextColor() { + protected int getDialogUnreadMessageTextColor() { return dialogUnreadMessageTextColor; } - void setDialogUnreadMessageTextColor(int dialogUnreadMessageTextColor) { - this.dialogUnreadMessageTextColor = dialogUnreadMessageTextColor; - } - - int getDialogUnreadMessageTextStyle() { + protected int getDialogUnreadMessageTextStyle() { return dialogUnreadMessageTextStyle; } - void setDialogUnreadMessageTextStyle(int dialogUnreadMessageTextStyle) { - this.dialogUnreadMessageTextStyle = dialogUnreadMessageTextStyle; - } - - int getDialogDateColor() { + protected int getDialogDateColor() { return dialogDateColor; } - void setDialogDateColor(int dialogDateColor) { - this.dialogDateColor = dialogDateColor; - } - - int getDialogDateSize() { + protected int getDialogDateSize() { return dialogDateSize; } - void setDialogDateSize(int dialogDateSize) { - this.dialogDateSize = dialogDateSize; - } - - int getDialogDateStyle() { + protected int getDialogDateStyle() { return dialogDateStyle; } - void setDialogDateStyle(int dialogDateStyle) { - this.dialogDateStyle = dialogDateStyle; - } - - int getDialogUnreadDateColor() { + protected int getDialogUnreadDateColor() { return dialogUnreadDateColor; } - void setDialogUnreadDateColor(int dialogUnreadDateColor) { - this.dialogUnreadDateColor = dialogUnreadDateColor; - } - - int getDialogUnreadDateStyle() { + protected int getDialogUnreadDateStyle() { return dialogUnreadDateStyle; } - void setDialogUnreadDateStyle(int dialogUnreadDateStyle) { - this.dialogUnreadDateStyle = dialogUnreadDateStyle; - } - - boolean isDialogUnreadBubbleEnabled() { + protected boolean isDialogUnreadBubbleEnabled() { return dialogUnreadBubbleEnabled; } - void setDialogUnreadBubbleEnabled(boolean dialogUnreadBubbleEnabled) { - this.dialogUnreadBubbleEnabled = dialogUnreadBubbleEnabled; - } - - int getDialogUnreadBubbleTextColor() { + protected int getDialogUnreadBubbleTextColor() { return dialogUnreadBubbleTextColor; } - void setDialogUnreadBubbleTextColor(int dialogUnreadBubbleTextColor) { - this.dialogUnreadBubbleTextColor = dialogUnreadBubbleTextColor; - } - - int getDialogUnreadBubbleTextSize() { + protected int getDialogUnreadBubbleTextSize() { return dialogUnreadBubbleTextSize; } - void setDialogUnreadBubbleTextSize(int dialogUnreadBubbleTextSize) { - this.dialogUnreadBubbleTextSize = dialogUnreadBubbleTextSize; - } - - int getDialogUnreadBubbleTextStyle() { + protected int getDialogUnreadBubbleTextStyle() { return dialogUnreadBubbleTextStyle; } - void setDialogUnreadBubbleTextStyle(int dialogUnreadBubbleTextStyle) { - this.dialogUnreadBubbleTextStyle = dialogUnreadBubbleTextStyle; - } - - int getDialogUnreadBubbleBackgroundColor() { + protected int getDialogUnreadBubbleBackgroundColor() { return dialogUnreadBubbleBackgroundColor; } - void setDialogUnreadBubbleBackgroundColor(int dialogUnreadBubbleBackgroundColor) { - this.dialogUnreadBubbleBackgroundColor = dialogUnreadBubbleBackgroundColor; - } - - int getDialogAvatarWidth() { + protected int getDialogAvatarWidth() { return dialogAvatarWidth; } - void setDialogAvatarWidth(int dialogAvatarWidth) { - this.dialogAvatarWidth = dialogAvatarWidth; - } - - int getDialogAvatarHeight() { + protected int getDialogAvatarHeight() { return dialogAvatarHeight; } - void setDialogAvatarHeight(int dialogAvatarHeight) { - this.dialogAvatarHeight = dialogAvatarHeight; - } - - boolean isDialogDividerEnabled() { + protected boolean isDialogDividerEnabled() { return dialogDividerEnabled; } - void setDialogDividerEnabled(boolean dialogDividerEnabled) { - this.dialogDividerEnabled = dialogDividerEnabled; - } - - int getDialogDividerColor() { + protected int getDialogDividerColor() { return dialogDividerColor; } - void setDialogDividerColor(int dialogDividerColor) { - this.dialogDividerColor = dialogDividerColor; - } - - int getDialogDividerLeftPadding() { + protected int getDialogDividerLeftPadding() { return dialogDividerLeftPadding; } - void setDialogDividerLeftPadding(int dialogDividerLeftMargin) { - this.dialogDividerLeftPadding = dialogDividerLeftMargin; - } - - int getDialogDividerRightPadding() { + protected int getDialogDividerRightPadding() { return dialogDividerRightPadding; } - void setDialogDividerRightPadding(int dialogDividerRightMargin) { - this.dialogDividerRightPadding = dialogDividerRightMargin; - } - - int getDialogItemBackground() { + protected int getDialogItemBackground() { return dialogItemBackground; } - void setDialogItemBackground(int dialogItemBackground) { - this.dialogItemBackground = dialogItemBackground; - } - - int getDialogUnreadItemBackground() { + protected int getDialogUnreadItemBackground() { return dialogUnreadItemBackground; } - void setDialogUnreadItemBackground(int dialogUnreadItemBackground) { - this.dialogUnreadItemBackground = dialogUnreadItemBackground; - } - - void setDialogMessageAvatarEnabled(boolean dialogMessageAvatarEnabled) { - this.dialogMessageAvatarEnabled = dialogMessageAvatarEnabled; - } - - boolean isDialogMessageAvatarEnabled() { + protected boolean isDialogMessageAvatarEnabled() { return dialogMessageAvatarEnabled; } - int getDialogMessageAvatarWidth() { + protected int getDialogMessageAvatarWidth() { return dialogMessageAvatarWidth; } - void setDialogMessageAvatarWidth(int dialogMessageAvatarWidth) { - this.dialogMessageAvatarWidth = dialogMessageAvatarWidth; - } - - int getDialogMessageAvatarHeight() { + protected int getDialogMessageAvatarHeight() { return dialogMessageAvatarHeight; } - - void setDialogMessageAvatarHeight(int dialogMessageAvatarHeight) { - this.dialogMessageAvatarHeight = dialogMessageAvatarHeight; - } } diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogsList.java b/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogsList.java index 55f531af..cf2448cb 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogsList.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogsList.java @@ -17,13 +17,14 @@ package com.stfalcon.chatkit.dialogs; import android.content.Context; -import android.support.annotation.Nullable; -import android.support.v7.widget.DefaultItemAnimator; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.SimpleItemAnimator; import android.util.AttributeSet; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SimpleItemAnimator; + import com.stfalcon.chatkit.commons.models.IDialog; /** @@ -73,9 +74,9 @@ public void setAdapter(Adapter adapter) { * @param adapter Adapter. Must extend DialogsListAdapter * @param

Dialog model class */ - public + public > void setAdapter(DialogsListAdapter adapter) { - setAdapter(adapter, true); + setAdapter(adapter, false); } /** @@ -85,7 +86,7 @@ void setAdapter(DialogsListAdapter adapter) { * @param reverseLayout weather to use reverse layout for layout manager. * @param Dialog model class */ - public + public > void setAdapter(DialogsListAdapter adapter, boolean reverseLayout) { SimpleItemAnimator itemAnimator = new DefaultItemAnimator(); itemAnimator.setSupportsChangeAnimations(false); diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogsListAdapter.java b/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogsListAdapter.java index 444ef76a..147fda0e 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogsListAdapter.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/dialogs/DialogsListAdapter.java @@ -16,9 +16,8 @@ package com.stfalcon.chatkit.dialogs; +import android.graphics.Typeface; import android.graphics.drawable.GradientDrawable; -import android.support.annotation.LayoutRes; -import android.support.v7.widget.RecyclerView; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; @@ -26,6 +25,10 @@ import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.LayoutRes; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + import com.stfalcon.chatkit.R; import com.stfalcon.chatkit.commons.ImageLoader; import com.stfalcon.chatkit.commons.ViewHolder; @@ -46,10 +49,11 @@ /** * Adapter for {@link DialogsList} */ +@SuppressWarnings("WeakerAccess") public class DialogsListAdapter extends RecyclerView.Adapter { - private List items = new ArrayList<>(); + protected List items = new ArrayList<>(); private int itemLayoutId; private Class holderClass; private ImageLoader imageLoader; @@ -197,20 +201,32 @@ public void addItems(List newItems) { */ public void addItem(DIALOG dialog) { items.add(dialog); - notifyItemInserted(0); + notifyItemInserted(items.size() - 1); } /** * Add dialog to dialogs list * * @param dialog dialog item - * @param position position in dialogs lost + * @param position position in dialogs list */ public void addItem(int position, DIALOG dialog) { items.add(position, dialog); notifyItemInserted(position); } + /** + * Move an item + * + * @param fromPosition the actual position of the item + * @param toPosition the new position of the item + */ + public void moveItem(int fromPosition, int toPosition) { + DIALOG dialog = items.remove(fromPosition); + items.add(toPosition, dialog); + notifyItemMoved(fromPosition, toPosition); + } + /** * Update dialog by position in dialogs list * @@ -243,6 +259,47 @@ public void updateItemById(DIALOG item) { } } + /** + * Upsert dialog in dialogs list or add it to then end of dialogs list + * + * @param item dialog item + */ + public void upsertItem(DIALOG item) { + boolean updated = false; + for (int i = 0; i < items.size(); i++) { + if (items.get(i).getId().equals(item.getId())) { + items.set(i, item); + notifyItemChanged(i); + updated = true; + break; + } + } + if (!updated) { + addItem(item); + } + } + + /** + * Find an item by its id + * + * @param id the wanted item's id + * @return the found item, or null + */ + @Nullable + public DIALOG getItemById(String id) { + if (items == null) { + items = new ArrayList<>(); + } + for (DIALOG item : items) { + if (item.getId() == null && id == null) { + return item; + } else if (item.getId() != null && item.getId().equals(id)) { + return item; + } + } + return null; + } + /** * Update last message in dialog and swap item to top of list. * @@ -272,15 +329,12 @@ public boolean updateDialogWithMessage(String dialogId, IMessage message) { * Sort dialog by last message date */ public void sortByLastMessageDate() { - Collections.sort(items, new Comparator() { - @Override - public int compare(DIALOG o1, DIALOG o2) { - if (o1.getLastMessage().getCreatedAt().after(o2.getLastMessage().getCreatedAt())) { - return -1; - } else if (o1.getLastMessage().getCreatedAt().before(o2.getLastMessage().getCreatedAt())) { - return 1; - } else return 0; - } + Collections.sort(items, (o1, o2) -> { + if (o1.getLastMessage().getCreatedAt().after(o2.getLastMessage().getCreatedAt())) { + return -1; + } else if (o1.getLastMessage().getCreatedAt().before(o2.getLastMessage().getCreatedAt())) { + return 1; + } else return 0; }); notifyDataSetChanged(); } @@ -295,6 +349,13 @@ public void sort(Comparator comparator) { notifyDataSetChanged(); } + /** + * @return registered image loader + */ + public ImageLoader getImageLoader() { + return imageLoader; + } + /** * Register a callback to be invoked when image need to load. * @@ -304,13 +365,6 @@ public void setImageLoader(ImageLoader imageLoader) { this.imageLoader = imageLoader; } - /** - * @return registered image loader - */ - public ImageLoader getImageLoader() { - return imageLoader; - } - /** * @return the item click callback. */ @@ -387,9 +441,16 @@ void setStyle(DialogListStyle dialogStyle) { this.dialogStyle = dialogStyle; } + /** + * @return the position of a dialog in the dialogs list. + */ + public int getDialogPosition(DIALOG dialog) { + return this.items.indexOf(dialog); + } + /* - * LISTENERS - * */ + * LISTENERS + * */ public interface OnDialogClickListener { void onDialogClick(DIALOG dialog); } @@ -407,8 +468,8 @@ public interface OnDialogViewLongClickListener { } /* - * HOLDERS - * */ + * HOLDERS + * */ public abstract static class BaseDialogViewHolder extends ViewHolder { @@ -427,19 +488,19 @@ void setImageLoader(ImageLoader imageLoader) { this.imageLoader = imageLoader; } - void setOnDialogClickListener(OnDialogClickListener onDialogClickListener) { + protected void setOnDialogClickListener(OnDialogClickListener onDialogClickListener) { this.onDialogClickListener = onDialogClickListener; } - void setOnDialogViewClickListener(OnDialogViewClickListener onDialogViewClickListener) { + protected void setOnDialogViewClickListener(OnDialogViewClickListener onDialogViewClickListener) { this.onDialogViewClickListener = onDialogViewClickListener; } - void setOnLongItemClickListener(OnDialogLongClickListener onLongItemClickListener) { + protected void setOnLongItemClickListener(OnDialogLongClickListener onLongItemClickListener) { this.onLongItemClickListener = onLongItemClickListener; } - void setOnDialogViewLongClickListener(OnDialogViewLongClickListener onDialogViewLongClickListener) { + protected void setOnDialogViewLongClickListener(OnDialogViewLongClickListener onDialogViewLongClickListener) { this.onDialogViewLongClickListener = onDialogViewLongClickListener; } @@ -463,15 +524,15 @@ public static class DialogViewHolder extends BaseDialogV public DialogViewHolder(View itemView) { super(itemView); - root = (ViewGroup) itemView.findViewById(R.id.dialogRootLayout); - container = (ViewGroup) itemView.findViewById(R.id.dialogContainer); - tvName = (TextView) itemView.findViewById(R.id.dialogName); - tvDate = (TextView) itemView.findViewById(R.id.dialogDate); - tvLastMessage = (TextView) itemView.findViewById(R.id.dialogLastMessage); - tvBubble = (TextView) itemView.findViewById(R.id.dialogUnreadBubble); - ivLastMessageUser = (ImageView) itemView.findViewById(R.id.dialogLastMessageUserAvatar); - ivAvatar = (ImageView) itemView.findViewById(R.id.dialogAvatar); - dividerContainer = (ViewGroup) itemView.findViewById(R.id.dialogDividerContainer); + root = itemView.findViewById(R.id.dialogRootLayout); + container = itemView.findViewById(R.id.dialogContainer); + tvName = itemView.findViewById(R.id.dialogName); + tvDate = itemView.findViewById(R.id.dialogDate); + tvLastMessage = itemView.findViewById(R.id.dialogLastMessage); + tvBubble = itemView.findViewById(R.id.dialogUnreadBubble); + ivLastMessageUser = itemView.findViewById(R.id.dialogLastMessageUserAvatar); + ivAvatar = itemView.findViewById(R.id.dialogAvatar); + dividerContainer = itemView.findViewById(R.id.dialogDividerContainer); divider = itemView.findViewById(R.id.dialogDivider); } @@ -530,17 +591,17 @@ private void applyDefaultStyle() { if (tvName != null) { tvName.setTextColor(dialogStyle.getDialogTitleTextColor()); - tvName.setTypeface(tvName.getTypeface(), dialogStyle.getDialogTitleTextStyle()); + tvName.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogTitleTextStyle()); } if (tvDate != null) { tvDate.setTextColor(dialogStyle.getDialogDateColor()); - tvDate.setTypeface(tvDate.getTypeface(), dialogStyle.getDialogDateStyle()); + tvDate.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogDateStyle()); } if (tvLastMessage != null) { tvLastMessage.setTextColor(dialogStyle.getDialogMessageTextColor()); - tvLastMessage.setTypeface(tvLastMessage.getTypeface(), dialogStyle.getDialogMessageTextStyle()); + tvLastMessage.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogMessageTextStyle()); } } } @@ -553,17 +614,17 @@ private void applyUnreadStyle() { if (tvName != null) { tvName.setTextColor(dialogStyle.getDialogUnreadTitleTextColor()); - tvName.setTypeface(tvName.getTypeface(), dialogStyle.getDialogUnreadTitleTextStyle()); + tvName.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogUnreadTitleTextStyle()); } if (tvDate != null) { tvDate.setTextColor(dialogStyle.getDialogUnreadDateColor()); - tvDate.setTypeface(tvDate.getTypeface(), dialogStyle.getDialogUnreadDateStyle()); + tvDate.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogUnreadDateStyle()); } if (tvLastMessage != null) { tvLastMessage.setTextColor(dialogStyle.getDialogUnreadMessageTextColor()); - tvLastMessage.setTypeface(tvLastMessage.getTypeface(), dialogStyle.getDialogUnreadMessageTextStyle()); + tvLastMessage.setTypeface(Typeface.DEFAULT, dialogStyle.getDialogUnreadMessageTextStyle()); } } } @@ -582,56 +643,60 @@ public void onBind(final DIALOG dialog) { //Set Date String formattedDate = null; - Date lastMessageDate = dialog.getLastMessage().getCreatedAt(); - if (datesFormatter != null) formattedDate = datesFormatter.format(lastMessageDate); - tvDate.setText(formattedDate == null - ? getDateString(lastMessageDate) - : formattedDate); + + if (dialog.getLastMessage() != null) { + Date lastMessageDate = dialog.getLastMessage().getCreatedAt(); + if (datesFormatter != null) formattedDate = datesFormatter.format(lastMessageDate); + tvDate.setText(formattedDate == null + ? getDateString(lastMessageDate) + : formattedDate); + } else { + tvDate.setText(null); + } //Set Dialog avatar if (imageLoader != null) { - imageLoader.loadImage(ivAvatar, dialog.getDialogPhoto()); + imageLoader.loadImage(ivAvatar, dialog.getDialogPhoto(), null); } - //Set Last message user avatar - if (imageLoader != null) { - imageLoader.loadImage(ivLastMessageUser, dialog.getLastMessage().getUser().getAvatar()); + //Set Last message user avatar with check if there is last message + if (imageLoader != null && dialog.getLastMessage() != null) { + imageLoader.loadImage(ivLastMessageUser, dialog.getLastMessage().getUser().getAvatar(), null); } ivLastMessageUser.setVisibility(dialogStyle.isDialogMessageAvatarEnabled() - && dialog.getUsers().size() > 1 ? VISIBLE : GONE); + && dialog.getUsers().size() > 1 + && dialog.getLastMessage() != null ? VISIBLE : GONE); //Set Last message text - tvLastMessage.setText(dialog.getLastMessage().getText()); + if (dialog.getLastMessage() != null) { + tvLastMessage.setText(dialog.getLastMessage().getText()); + } else { + tvLastMessage.setText(null); + } //Set Unread message count bubble tvBubble.setText(String.valueOf(dialog.getUnreadCount())); tvBubble.setVisibility(dialogStyle.isDialogUnreadBubbleEnabled() && dialog.getUnreadCount() > 0 ? VISIBLE : GONE); - container.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (onDialogClickListener != null) { - onDialogClickListener.onDialogClick(dialog); - } - if (onDialogViewClickListener != null) { - onDialogViewClickListener.onDialogViewClick(view, dialog); - } + container.setOnClickListener(view -> { + if (onDialogClickListener != null) { + onDialogClickListener.onDialogClick(dialog); + } + if (onDialogViewClickListener != null) { + onDialogViewClickListener.onDialogViewClick(view, dialog); } }); - container.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View view) { - if (onLongItemClickListener != null) { - onLongItemClickListener.onDialogLongClick(dialog); - } - if (onDialogViewLongClickListener != null) { - onDialogViewLongClickListener.onDialogViewLongClick(view, dialog); - } - return onLongItemClickListener != null || onDialogViewLongClickListener != null; + container.setOnLongClickListener(view -> { + if (onLongItemClickListener != null) { + onLongItemClickListener.onDialogLongClick(dialog); + } + if (onDialogViewLongClickListener != null) { + onDialogViewLongClickListener.onDialogViewLongClick(view, dialog); } + return onLongItemClickListener != null || onDialogViewLongClickListener != null; }); } diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageHolders.java b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageHolders.java index bfe459ac..2c09b016 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageHolders.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageHolders.java @@ -1,10 +1,8 @@ package com.stfalcon.chatkit.messages; -import android.support.annotation.LayoutRes; -import android.support.annotation.NonNull; -import android.support.v4.view.ViewCompat; import android.text.Spannable; import android.text.method.LinkMovementMethod; +import android.util.SparseArray; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -13,6 +11,10 @@ import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.core.view.ViewCompat; + import com.stfalcon.chatkit.R; import com.stfalcon.chatkit.commons.ImageLoader; import com.stfalcon.chatkit.commons.ViewHolder; @@ -29,6 +31,7 @@ /* * Created by troy379 on 31.03.17. */ +@SuppressWarnings("WeakerAccess") public class MessageHolders { private static final short VIEW_TYPE_DATE_HEADER = 130; @@ -71,6 +74,24 @@ public MessageHolders setIncomingTextConfig( return this; } + /** + * Sets both of custom view holder class and layout resource for incoming text message. + * + * @param holder holder class. + * @param layout layout resource. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setIncomingTextConfig( + @NonNull Class> holder, + @LayoutRes int layout, + Object payload) { + this.incomingTextConfig.holder = holder; + this.incomingTextConfig.layout = layout; + this.incomingTextConfig.payload = payload; + return this; + } + /** * Sets custom view holder class for incoming text message. * @@ -83,6 +104,21 @@ public MessageHolders setIncomingTextHolder( return this; } + /** + * Sets custom view holder class for incoming text message. + * + * @param holder holder class. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setIncomingTextHolder( + @NonNull Class> holder, + Object payload) { + this.incomingTextConfig.holder = holder; + this.incomingTextConfig.payload = payload; + return this; + } + /** * Sets custom layout resource for incoming text message. * @@ -94,6 +130,19 @@ public MessageHolders setIncomingTextLayout(@LayoutRes int layout) { return this; } + /** + * Sets custom layout resource for incoming text message. + * + * @param layout layout resource. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setIncomingTextLayout(@LayoutRes int layout, Object payload) { + this.incomingTextConfig.layout = layout; + this.incomingTextConfig.payload = payload; + return this; + } + /** * Sets both of custom view holder class and layout resource for outcoming text message. * @@ -109,6 +158,24 @@ public MessageHolders setOutcomingTextConfig( return this; } + /** + * Sets both of custom view holder class and layout resource for outcoming text message. + * + * @param holder holder class. + * @param layout layout resource. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setOutcomingTextConfig( + @NonNull Class> holder, + @LayoutRes int layout, + Object payload) { + this.outcomingTextConfig.holder = holder; + this.outcomingTextConfig.layout = layout; + this.outcomingTextConfig.payload = payload; + return this; + } + /** * Sets custom view holder class for outcoming text message. * @@ -121,6 +188,21 @@ public MessageHolders setOutcomingTextHolder( return this; } + /** + * Sets custom view holder class for outcoming text message. + * + * @param holder holder class. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setOutcomingTextHolder( + @NonNull Class> holder, + Object payload) { + this.outcomingTextConfig.holder = holder; + this.outcomingTextConfig.payload = payload; + return this; + } + /** * Sets custom layout resource for outcoming text message. * @@ -132,6 +214,19 @@ public MessageHolders setOutcomingTextLayout(@LayoutRes int layout) { return this; } + /** + * Sets custom layout resource for outcoming text message. + * + * @param layout layout resource. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setOutcomingTextLayout(@LayoutRes int layout, Object payload) { + this.outcomingTextConfig.layout = layout; + this.outcomingTextConfig.payload = payload; + return this; + } + /** * Sets both of custom view holder class and layout resource for incoming image message. * @@ -147,6 +242,24 @@ public MessageHolders setIncomingImageConfig( return this; } + /** + * Sets both of custom view holder class and layout resource for incoming image message. + * + * @param holder holder class. + * @param layout layout resource. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setIncomingImageConfig( + @NonNull Class> holder, + @LayoutRes int layout, + Object payload) { + this.incomingImageConfig.holder = holder; + this.incomingImageConfig.layout = layout; + this.incomingImageConfig.payload = payload; + return this; + } + /** * Sets custom view holder class for incoming image message. * @@ -159,6 +272,21 @@ public MessageHolders setIncomingImageHolder( return this; } + /** + * Sets custom view holder class for incoming image message. + * + * @param holder holder class. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setIncomingImageHolder( + @NonNull Class> holder, + Object payload) { + this.incomingImageConfig.holder = holder; + this.incomingImageConfig.payload = payload; + return this; + } + /** * Sets custom layout resource for incoming image message. * @@ -170,6 +298,19 @@ public MessageHolders setIncomingImageLayout(@LayoutRes int layout) { return this; } + /** + * Sets custom layout resource for incoming image message. + * + * @param layout layout resource. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setIncomingImageLayout(@LayoutRes int layout, Object payload) { + this.incomingImageConfig.layout = layout; + this.incomingImageConfig.payload = payload; + return this; + } + /** * Sets both of custom view holder class and layout resource for outcoming image message. * @@ -185,6 +326,24 @@ public MessageHolders setOutcomingImageConfig( return this; } + /** + * Sets both of custom view holder class and layout resource for outcoming image message. + * + * @param holder holder class. + * @param layout layout resource. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setOutcomingImageConfig( + @NonNull Class> holder, + @LayoutRes int layout, + Object payload) { + this.outcomingImageConfig.holder = holder; + this.outcomingImageConfig.layout = layout; + this.outcomingImageConfig.payload = payload; + return this; + } + /** * Sets custom view holder class for outcoming image message. * @@ -197,6 +356,21 @@ public MessageHolders setOutcomingImageHolder( return this; } + /** + * Sets custom view holder class for outcoming image message. + * + * @param holder holder class. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setOutcomingImageHolder( + @NonNull Class> holder, + Object payload) { + this.outcomingImageConfig.holder = holder; + this.outcomingImageConfig.payload = payload; + return this; + } + /** * Sets custom layout resource for outcoming image message. * @@ -208,6 +382,19 @@ public MessageHolders setOutcomingImageLayout(@LayoutRes int layout) { return this; } + /** + * Sets custom layout resource for outcoming image message. + * + * @param layout layout resource. + * @param payload custom data. + * @return {@link MessageHolders} for subsequent configuration. + */ + public MessageHolders setOutcomingImageLayout(@LayoutRes int layout, Object payload) { + this.outcomingImageConfig.layout = layout; + this.outcomingImageConfig.payload = payload; + return this; + } + /** * Sets both of custom view holder class and layout resource for date header. * @@ -297,9 +484,40 @@ MessageHolders registerContentType( return this; } + /** + * Registers custom content type (e.g. multimedia, events etc.) + * + * @param type unique id for content type + * @param incomingHolder holder class for incoming message + * @param outcomingHolder holder class for outcoming message + * @param incomingPayload payload for incoming message + * @param outcomingPayload payload for outcoming message + * @param incomingLayout layout resource for incoming message + * @param outcomingLayout layout resource for outcoming message + * @param contentChecker {@link MessageHolders.ContentChecker} for registered type + * @return {@link MessageHolders} for subsequent configuration. + */ + public + MessageHolders registerContentType( + byte type, + @NonNull Class> incomingHolder, Object incomingPayload, @LayoutRes int incomingLayout, + @NonNull Class> outcomingHolder, Object outcomingPayload, @LayoutRes int outcomingLayout, + @NonNull MessageHolders.ContentChecker contentChecker) { + + if (type == 0) + throw new IllegalArgumentException("content type must be greater or less than '0'!"); + + customContentTypes.add( + new MessageHolders.ContentTypeConfig<>(type, + new HolderConfig<>(incomingHolder, incomingLayout, incomingPayload), + new HolderConfig<>(outcomingHolder, outcomingLayout, outcomingPayload))); + this.contentChecker = contentChecker; + return this; + } + /* - * INTERFACES - * */ + * INTERFACES + * */ /** * The interface, which contains logic for checking the availability of content. @@ -317,13 +535,13 @@ public interface ContentChecker { } /* - * PRIVATE METHODS - * */ + * PRIVATE METHODS + * */ - ViewHolder getHolder(ViewGroup parent, int viewType, MessagesListStyle messagesListStyle) { + protected ViewHolder getHolder(ViewGroup parent, int viewType, MessagesListStyle messagesListStyle) { switch (viewType) { case VIEW_TYPE_DATE_HEADER: - return getHolder(parent, dateHeaderLayout, dateHeaderHolder, messagesListStyle); + return getHolder(parent, dateHeaderLayout, dateHeaderHolder, messagesListStyle, null); case VIEW_TYPE_TEXT_MESSAGE: return getHolder(parent, incomingTextConfig, messagesListStyle); case -VIEW_TYPE_TEXT_MESSAGE: @@ -346,16 +564,26 @@ ViewHolder getHolder(ViewGroup parent, int viewType, MessagesListStyle messagesL } @SuppressWarnings("unchecked") - void bind(ViewHolder holder, Object item, boolean isSelected, ImageLoader imageLoader, - View.OnClickListener onMessageClickListener, - View.OnLongClickListener onMessageLongClickListener, - DateFormatter.Formatter dateHeadersFormatter) { + protected void bind(final ViewHolder holder, final Object item, boolean isSelected, + final ImageLoader imageLoader, + final View.OnClickListener onMessageClickListener, + final View.OnLongClickListener onMessageLongClickListener, + final DateFormatter.Formatter dateHeadersFormatter, + final SparseArray clickListenersArray) { if (item instanceof IMessage) { ((MessageHolders.BaseMessageViewHolder) holder).isSelected = isSelected; ((MessageHolders.BaseMessageViewHolder) holder).imageLoader = imageLoader; holder.itemView.setOnLongClickListener(onMessageLongClickListener); holder.itemView.setOnClickListener(onMessageClickListener); + + for (int i = 0; i < clickListenersArray.size(); i++) { + final int key = clickListenersArray.keyAt(i); + final View view = holder.itemView.findViewById(key); + if (view != null) { + view.setOnClickListener(v -> clickListenersArray.get(key).onMessageViewClick(view, (IMessage) item)); + } + } } else if (item instanceof Date) { ((MessageHolders.DefaultDateHeaderViewHolder) holder).dateHeadersFormatter = dateHeadersFormatter; } @@ -364,7 +592,7 @@ void bind(ViewHolder holder, Object item, boolean isSelected, ImageLoader imageL } - int getViewType(Object item, String senderId) { + protected int getViewType(Object item, String senderId) { boolean isOutcoming = false; int viewType; @@ -378,24 +606,34 @@ int getViewType(Object item, String senderId) { return isOutcoming ? viewType * -1 : viewType; } - private ViewHolder getHolder(ViewGroup parent, HolderConfig holderConfig, MessagesListStyle style) { - return getHolder(parent, holderConfig.layout, holderConfig.holder, style); + private ViewHolder getHolder(ViewGroup parent, HolderConfig holderConfig, + MessagesListStyle style) { + return getHolder(parent, holderConfig.layout, holderConfig.holder, style, holderConfig.payload); } private - ViewHolder getHolder(ViewGroup parent, @LayoutRes int layout, Class holderClass, MessagesListStyle style) { + ViewHolder getHolder(ViewGroup parent, @LayoutRes int layout, Class holderClass, + MessagesListStyle style, Object payload) { View v = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false); try { - Constructor constructor = holderClass.getDeclaredConstructor(View.class); - constructor.setAccessible(true); - HOLDER holder = constructor.newInstance(v); + Constructor constructor = null; + HOLDER holder; + try { + constructor = holderClass.getDeclaredConstructor(View.class, Object.class); + constructor.setAccessible(true); + holder = constructor.newInstance(v, payload); + } catch (NoSuchMethodException e) { + constructor = holderClass.getDeclaredConstructor(View.class); + constructor.setAccessible(true); + holder = constructor.newInstance(v); + } if (holder instanceof DefaultMessageViewHolder && style != null) { ((DefaultMessageViewHolder) holder).applyStyle(style); } return holder; } catch (Exception e) { - throw new RuntimeException("Somehow we couldn't create the ViewHolder for message. Please, report this issue on GitHub with full stacktrace in description.", e); + throw new UnsupportedOperationException("Somehow we couldn't create the ViewHolder for message. Please, report this issue on GitHub with full stacktrace in description.", e); } } @@ -423,8 +661,8 @@ private short getContentViewType(IMessage message) { } /* - * HOLDERS - * */ + * HOLDERS + * */ /** * The base class for view holders for incoming and outcoming message. @@ -434,15 +672,26 @@ public static abstract class BaseMessageViewHolder ext boolean isSelected; + /** + * For setting custom data to ViewHolder + */ + protected Object payload; + /** * Callback for implementing images loading in message list */ - ImageLoader imageLoader; + protected ImageLoader imageLoader; + @Deprecated public BaseMessageViewHolder(View itemView) { super(itemView); } + public BaseMessageViewHolder(View itemView, Object payload) { + super(itemView); + this.payload = payload; + } + /** * Returns whether is item selected * @@ -484,7 +733,6 @@ public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event } }); } - } /** @@ -496,10 +744,15 @@ public static class IncomingTextMessageViewHolder protected ViewGroup bubble; protected TextView text; + @Deprecated public IncomingTextMessageViewHolder(View itemView) { super(itemView); - bubble = (ViewGroup) itemView.findViewById(R.id.bubble); - text = (TextView) itemView.findViewById(R.id.messageText); + init(itemView); + } + + public IncomingTextMessageViewHolder(View itemView, Object payload) { + super(itemView, payload); + init(itemView); } @Override @@ -534,6 +787,11 @@ public void applyStyle(MessagesListStyle style) { configureLinksBehavior(text); } } + + private void init(View itemView) { + bubble = itemView.findViewById(R.id.bubble); + text = itemView.findViewById(R.id.messageText); + } } /** @@ -545,10 +803,15 @@ public static class OutcomingTextMessageViewHolder protected ViewGroup bubble; protected TextView text; + @Deprecated public OutcomingTextMessageViewHolder(View itemView) { super(itemView); - bubble = (ViewGroup) itemView.findViewById(R.id.bubble); - text = (TextView) itemView.findViewById(R.id.messageText); + init(itemView); + } + + public OutcomingTextMessageViewHolder(View itemView, Object payload) { + super(itemView, payload); + init(itemView); } @Override @@ -583,6 +846,11 @@ public final void applyStyle(MessagesListStyle style) { configureLinksBehavior(text); } } + + private void init(View itemView) { + bubble = itemView.findViewById(R.id.bubble); + text = itemView.findViewById(R.id.messageText); + } } /** @@ -594,26 +862,22 @@ public static class IncomingImageMessageViewHolder public DefaultDateHeaderViewHolder(View itemView) { super(itemView); - text = (TextView) itemView.findViewById(R.id.messageText); + text = itemView.findViewById(R.id.messageText); } @Override @@ -734,10 +1040,15 @@ public abstract static class BaseIncomingMessageViewHolder { public DefaultIncomingTextMessageViewHolder(View itemView) { - super(itemView); + super(itemView, null); } } @@ -824,7 +1150,7 @@ private static class DefaultOutcomingTextMessageViewHolder extends OutcomingTextMessageViewHolder { public DefaultOutcomingTextMessageViewHolder(View itemView) { - super(itemView); + super(itemView, null); } } @@ -832,7 +1158,7 @@ private static class DefaultIncomingImageMessageViewHolder extends IncomingImageMessageViewHolder { public DefaultIncomingImageMessageViewHolder(View itemView) { - super(itemView); + super(itemView, null); } } @@ -840,7 +1166,7 @@ private static class DefaultOutcomingImageMessageViewHolder extends OutcomingImageMessageViewHolder { public DefaultOutcomingImageMessageViewHolder(View itemView) { - super(itemView); + super(itemView, null); } } @@ -859,14 +1185,21 @@ private ContentTypeConfig( } } - private class HolderConfig { + private static class HolderConfig { - Class> holder; - int layout; + protected Class> holder; + protected int layout; + protected Object payload; HolderConfig(Class> holder, int layout) { this.holder = holder; this.layout = layout; } + + HolderConfig(Class> holder, int layout, Object payload) { + this.holder = holder; + this.layout = layout; + this.payload = payload; + } } } diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageInput.java b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageInput.java index 310fafad..665f0503 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageInput.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageInput.java @@ -19,8 +19,6 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.v4.view.ViewCompat; -import android.support.v4.widget.Space; import android.text.Editable; import android.text.TextWatcher; import android.util.AttributeSet; @@ -29,8 +27,11 @@ import android.widget.EditText; import android.widget.ImageButton; import android.widget.RelativeLayout; +import android.widget.Space; import android.widget.TextView; +import androidx.core.view.ViewCompat; + import com.stfalcon.chatkit.R; import java.lang.reflect.Field; @@ -38,8 +39,9 @@ /** * Component for input outcoming messages */ +@SuppressWarnings({"WeakerAccess", "unused"}) public class MessageInput extends RelativeLayout - implements View.OnClickListener, TextWatcher { + implements View.OnClickListener, TextWatcher, View.OnFocusChangeListener { protected EditText messageInput; protected ImageButton messageSendButton; @@ -49,6 +51,19 @@ public class MessageInput extends RelativeLayout private CharSequence input; private InputListener inputListener; private AttachmentsListener attachmentsListener; + private boolean isTyping; + private TypingListener typingListener; + private int delayTypingStatusMillis; + private Runnable typingTimerRunnable = new Runnable() { + @Override + public void run() { + if (isTyping) { + isTyping = false; + if (typingListener != null) typingListener.onStopTyping(); + } + } + }; + private boolean lastFocus; public MessageInput(Context context) { super(context); @@ -109,6 +124,8 @@ public void onClick(View view) { if (isSubmitted) { messageInput.setText(""); } + removeCallbacks(typingTimerRunnable); + post(typingTimerRunnable); } else if (id == R.id.attachmentButton) { onAddAttachments(); } @@ -122,6 +139,14 @@ public void onClick(View view) { public void onTextChanged(CharSequence s, int start, int count, int after) { input = s; messageSendButton.setEnabled(input.length() > 0); + if (s.length() > 0) { + if (!isTyping) { + isTyping = true; + if (typingListener != null) typingListener.onStartTyping(); + } + removeCallbacks(typingTimerRunnable); + postDelayed(typingTimerRunnable, delayTypingStatusMillis); + } } /** @@ -130,7 +155,7 @@ public void onTextChanged(CharSequence s, int start, int count, int after) { */ @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { - + //do nothing } /** @@ -138,7 +163,15 @@ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) */ @Override public void afterTextChanged(Editable editable) { + //do nothing + } + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (lastFocus && !hasFocus && typingListener != null) { + typingListener.onStopTyping(); + } + lastFocus = hasFocus; } private boolean onSubmit() { @@ -188,21 +221,23 @@ && getPaddingBottom() == 0) { style.getInputDefaultPaddingBottom() ); } + this.delayTypingStatusMillis = style.getDelayTypingStatus(); } private void init(Context context) { inflate(context, R.layout.view_message_input, this); - messageInput = (EditText) findViewById(R.id.messageInput); - messageSendButton = (ImageButton) findViewById(R.id.messageSendButton); - attachmentButton = (ImageButton) findViewById(R.id.attachmentButton); - sendButtonSpace = (Space) findViewById(R.id.sendButtonSpace); - attachmentButtonSpace = (Space) findViewById(R.id.attachmentButtonSpace); + messageInput = findViewById(R.id.messageInput); + messageSendButton = findViewById(R.id.messageSendButton); + attachmentButton = findViewById(R.id.attachmentButton); + sendButtonSpace = findViewById(R.id.sendButtonSpace); + attachmentButtonSpace = findViewById(R.id.attachmentButtonSpace); messageSendButton.setOnClickListener(this); attachmentButton.setOnClickListener(this); messageInput.addTextChangedListener(this); messageInput.setText(""); + messageInput.setOnFocusChangeListener(this); } private void setCursor(Drawable drawable) { @@ -230,6 +265,10 @@ private void setCursor(Drawable drawable) { } } + public void setTypingListener(TypingListener typingListener) { + this.typingListener = typingListener; + } + /** * Interface definition for a callback to be invoked when user pressed 'submit' button */ @@ -254,4 +293,21 @@ public interface AttachmentsListener { */ void onAddAttachments(); } + + /** + * Interface definition for a callback to be invoked when user typing + */ + public interface TypingListener { + + /** + * Fires when user presses start typing + */ + void onStartTyping(); + + /** + * Fires when user presses stop typing + */ + void onStopTyping(); + + } } diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageInputStyle.java b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageInputStyle.java index 0c6d3248..ddac1859 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageInputStyle.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessageInputStyle.java @@ -20,20 +20,23 @@ import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; -import android.support.annotation.ColorInt; -import android.support.annotation.DrawableRes; -import android.support.v4.graphics.drawable.DrawableCompat; import android.util.AttributeSet; +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; +import androidx.core.graphics.drawable.DrawableCompat; + import com.stfalcon.chatkit.R; import com.stfalcon.chatkit.commons.Style; /** * Style for MessageInputStyle customization by xml attributes */ +@SuppressWarnings("WeakerAccess") class MessageInputStyle extends Style { private static final int DEFAULT_MAX_LINES = 5; + private static final int DEFAULT_DELAY_TYPING_STATUS = 1500; private boolean showAttachmentButton; @@ -81,6 +84,8 @@ class MessageInputStyle extends Style { private int inputDefaultPaddingTop; private int inputDefaultPaddingBottom; + private int delayTypingStatus; + static MessageInputStyle parse(Context context, AttributeSet attrs) { MessageInputStyle style = new MessageInputStyle(context, attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MessageInput); @@ -138,6 +143,8 @@ static MessageInputStyle parse(Context context, AttributeSet attrs) { style.inputBackground = typedArray.getDrawable(R.styleable.MessageInput_inputBackground); style.inputCursorDrawable = typedArray.getDrawable(R.styleable.MessageInput_inputCursorDrawable); + style.delayTypingStatus = typedArray.getInt(R.styleable.MessageInput_delayTypingStatus, DEFAULT_DELAY_TYPING_STATUS); + typedArray.recycle(); style.inputDefaultPaddingLeft = style.getDimension(R.dimen.input_padding_left); @@ -169,11 +176,11 @@ private Drawable getSelector(@ColorInt int normalColor, @ColorInt int pressedCol return drawable; } - boolean showAttachmentButton() { + protected boolean showAttachmentButton() { return showAttachmentButton; } - Drawable getAttachmentButtonBackground() { + protected Drawable getAttachmentButtonBackground() { if (attachmentButtonBackground == -1) { return getSelector(attachmentButtonDefaultBgColor, attachmentButtonDefaultBgPressedColor, attachmentButtonDefaultBgDisabledColor, R.drawable.mask); @@ -182,7 +189,7 @@ Drawable getAttachmentButtonBackground() { } } - Drawable getAttachmentButtonIcon() { + protected Drawable getAttachmentButtonIcon() { if (attachmentButtonIcon == -1) { return getSelector(attachmentButtonDefaultIconColor, attachmentButtonDefaultIconPressedColor, attachmentButtonDefaultIconDisabledColor, R.drawable.ic_add_attachment); @@ -191,19 +198,19 @@ Drawable getAttachmentButtonIcon() { } } - int getAttachmentButtonWidth() { + protected int getAttachmentButtonWidth() { return attachmentButtonWidth; } - int getAttachmentButtonHeight() { + protected int getAttachmentButtonHeight() { return attachmentButtonHeight; } - int getAttachmentButtonMargin() { + protected int getAttachmentButtonMargin() { return attachmentButtonMargin; } - Drawable getInputButtonBackground() { + protected Drawable getInputButtonBackground() { if (inputButtonBackground == -1) { return getSelector(inputButtonDefaultBgColor, inputButtonDefaultBgPressedColor, inputButtonDefaultBgDisabledColor, R.drawable.mask); @@ -212,7 +219,7 @@ Drawable getInputButtonBackground() { } } - Drawable getInputButtonIcon() { + protected Drawable getInputButtonIcon() { if (inputButtonIcon == -1) { return getSelector(inputButtonDefaultIconColor, inputButtonDefaultIconPressedColor, inputButtonDefaultIconDisabledColor, R.drawable.ic_send); @@ -221,64 +228,68 @@ Drawable getInputButtonIcon() { } } - int getInputButtonMargin() { + protected int getInputButtonMargin() { return inputButtonMargin; } - int getInputButtonWidth() { + protected int getInputButtonWidth() { return inputButtonWidth; } - int getInputButtonHeight() { + protected int getInputButtonHeight() { return inputButtonHeight; } - int getInputMaxLines() { + protected int getInputMaxLines() { return inputMaxLines; } - String getInputHint() { + protected String getInputHint() { return inputHint; } - String getInputText() { + protected String getInputText() { return inputText; } - int getInputTextSize() { + protected int getInputTextSize() { return inputTextSize; } - int getInputTextColor() { + protected int getInputTextColor() { return inputTextColor; } - int getInputHintColor() { + protected int getInputHintColor() { return inputHintColor; } - Drawable getInputBackground() { + protected Drawable getInputBackground() { return inputBackground; } - Drawable getInputCursorDrawable() { + protected Drawable getInputCursorDrawable() { return inputCursorDrawable; } - int getInputDefaultPaddingLeft() { + protected int getInputDefaultPaddingLeft() { return inputDefaultPaddingLeft; } - int getInputDefaultPaddingRight() { + protected int getInputDefaultPaddingRight() { return inputDefaultPaddingRight; } - int getInputDefaultPaddingTop() { + protected int getInputDefaultPaddingTop() { return inputDefaultPaddingTop; } - int getInputDefaultPaddingBottom() { + protected int getInputDefaultPaddingBottom() { return inputDefaultPaddingBottom; } + int getDelayTypingStatus() { + return delayTypingStatus; + } + } diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesList.java b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesList.java index 17b3f8ed..901b6eeb 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesList.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesList.java @@ -17,13 +17,14 @@ package com.stfalcon.chatkit.messages; import android.content.Context; -import android.support.annotation.Nullable; -import android.support.v7.widget.DefaultItemAnimator; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.SimpleItemAnimator; import android.util.AttributeSet; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SimpleItemAnimator; + import com.stfalcon.chatkit.commons.models.IMessage; /** diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesListAdapter.java b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesListAdapter.java index aedcf4eb..74ed2760 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesListAdapter.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesListAdapter.java @@ -19,16 +19,18 @@ import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; -import android.support.annotation.LayoutRes; -import android.support.v7.widget.RecyclerView; import android.text.Spannable; import android.text.method.LinkMovementMethod; +import android.util.SparseArray; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import androidx.annotation.LayoutRes; +import androidx.recyclerview.widget.RecyclerView; + import com.stfalcon.chatkit.R; import com.stfalcon.chatkit.commons.ImageLoader; import com.stfalcon.chatkit.commons.ViewHolder; @@ -43,19 +45,20 @@ /** * Adapter for {@link MessagesList}. */ +@SuppressWarnings("WeakerAccess") public class MessagesListAdapter extends RecyclerView.Adapter implements RecyclerScrollMoreListener.OnLoadMoreListener { + protected static boolean isSelectionModeEnabled; + + protected List items; private MessageHolders holders; private String senderId; - private List items; private int selectedItemsCount; private SelectionListener selectionListener; - static boolean isSelectionModeEnabled; - private OnLoadMoreListener loadMoreListener; private OnMessageClickListener onMessageClickListener; private OnMessageViewClickListener onMessageViewClickListener; @@ -65,6 +68,7 @@ public class MessagesListAdapter private RecyclerView.LayoutManager layoutManager; private MessagesListStyle messagesListStyle; private DateFormatter.Formatter dateHeadersFormatter; + private SparseArray viewClickListenersArray = new SparseArray<>(); /** * For default list item layout and view holder. @@ -103,7 +107,8 @@ public void onBindViewHolder(ViewHolder holder, int position) { holders.bind(holder, wrapper.item, wrapper.isSelected, imageLoader, getMessageClickListener(wrapper), getMessageLongClickListener(wrapper), - dateHeadersFormatter); + dateHeadersFormatter, + viewClickListenersArray); } @Override @@ -123,9 +128,20 @@ public void onLoadMore(int page, int total) { } } + @Override + public int getMessagesCount() { + int count = 0; + for (Wrapper item : items) { + if (item.item instanceof IMessage) { + count++; + } + } + return count; + } + /* - * PUBLIC METHODS - * */ + * PUBLIC METHODS + * */ /** * Adds message to bottom of list and scroll if needed. @@ -153,6 +169,8 @@ public void addToStart(MESSAGE message, boolean scroll) { * @param reverse {@code true} if need to reverse messages before adding. */ public void addToEnd(List messages, boolean reverse) { + if (messages.isEmpty()) return; + if (reverse) Collections.reverse(messages); if (!items.isEmpty()) { @@ -174,8 +192,8 @@ public void addToEnd(List messages, boolean reverse) { * * @param message updated message object. */ - public void update(MESSAGE message) { - update(message.getId(), message); + public boolean update(MESSAGE message) { + return update(message.getId(), message); } /** @@ -184,12 +202,60 @@ public void update(MESSAGE message) { * @param oldId an identifier of message to update. * @param newMessage new message object. */ - public void update(String oldId, MESSAGE newMessage) { + public boolean update(String oldId, MESSAGE newMessage) { int position = getMessagePositionById(oldId); if (position >= 0) { Wrapper element = new Wrapper<>(newMessage); items.set(position, element); notifyItemChanged(position); + return true; + } else { + return false; + } + } + + /** + * Moves the elements position from current to start + * + * @param newMessage new message object. + */ + public void updateAndMoveToStart(MESSAGE newMessage) { + int position = getMessagePositionById(newMessage.getId()); + if (position >= 0) { + Wrapper element = new Wrapper<>(newMessage); + items.remove(position); + items.add(0, element); + notifyItemMoved(position, 0); + notifyItemChanged(0); + } + } + + /** + * Updates message by its id if it exists, add to start if not + * + * @param message message object to insert or update. + */ + public void upsert(MESSAGE message) { + if (!update(message)) { + addToStart(message, false); + } + } + + /** + * Updates and moves to start if message by its id exists and if specified move to start, if not + * specified the item stays at current position and updated + * + * @param message message object to insert or update. + */ + public void upsert(MESSAGE message, boolean moveToStartIfUpdate) { + if (moveToStartIfUpdate) { + if (getMessagePositionById(message.getId()) > 0) { + updateAndMoveToStart(message); + } else { + upsert(message); + } + } else { + upsert(message); } } @@ -208,12 +274,18 @@ public void delete(MESSAGE message) { * @param messages messages list to delete. */ public void delete(List messages) { + boolean result = false; for (MESSAGE message : messages) { int index = getMessagePositionById(message.getId()); - items.remove(index); - notifyItemRemoved(index); + if (index >= 0) { + items.remove(index); + notifyItemRemoved(index); + result = true; + } + } + if (result) { + recountDateHeaders(); } - recountDateHeaders(); } /** @@ -236,12 +308,18 @@ public void deleteById(String id) { * @param ids array of identifiers of messages to delete. */ public void deleteByIds(String[] ids) { + boolean result = false; for (String id : ids) { int index = getMessagePositionById(id); - items.remove(index); - notifyItemRemoved(index); + if (index >= 0) { + items.remove(index); + notifyItemRemoved(index); + result = true; + } + } + if (result) { + recountDateHeaders(); } - recountDateHeaders(); } /** @@ -254,10 +332,22 @@ public boolean isEmpty() { } /** - * Clears the messages list. + * Clears the messages list. With notifyDataSetChanged */ public void clear() { - items.clear(); + clear(true); + } + + /** + * Clears the messages list. + */ + public void clear(boolean notifyDataSetChanged) { + if (items != null) { + items.clear(); + if (notifyDataSetChanged) { + notifyDataSetChanged(); + } + } } /** @@ -369,6 +459,16 @@ public void setOnMessageViewClickListener(OnMessageViewClickListener on this.onMessageViewClickListener = onMessageViewClickListener; } + /** + * Registers click listener for view by id + * + * @param viewId view + * @param onMessageViewClickListener click listener. + */ + public void registerViewClickListener(int viewId, OnMessageViewClickListener onMessageViewClickListener) { + this.viewClickListenersArray.append(viewId, onMessageViewClickListener); + } + /** * Sets long click listener for item. Fires only if selection mode is disabled. * @@ -404,8 +504,8 @@ public void setDateHeadersFormatter(DateFormatter.Formatter dateHeadersFormatter } /* - * PRIVATE METHODS - * */ + * PRIVATE METHODS + * */ private void recountDateHeaders() { List indicesToDelete = new ArrayList<>(); @@ -429,7 +529,7 @@ private void recountDateHeaders() { } } - private void generateDateHeaders(List messages) { + protected void generateDateHeaders(List messages) { for (int i = 0; i < messages.size(); i++) { MESSAGE message = messages.get(i); this.items.add(new Wrapper<>(message)); @@ -518,39 +618,32 @@ private void notifyMessageViewLongClicked(View view, MESSAGE message) { } private View.OnClickListener getMessageClickListener(final Wrapper wrapper) { - return new View.OnClickListener() { - @Override - public void onClick(View view) { - if (selectionListener != null && isSelectionModeEnabled) { - wrapper.isSelected = !wrapper.isSelected; + return view -> { + if (selectionListener != null && isSelectionModeEnabled) { + wrapper.isSelected = !wrapper.isSelected; - if (wrapper.isSelected) incrementSelectedItemsCount(); - else decrementSelectedItemsCount(); + if (wrapper.isSelected) incrementSelectedItemsCount(); + else decrementSelectedItemsCount(); - MESSAGE message = (wrapper.item); - notifyItemChanged(getMessagePositionById(message.getId())); - } else { - notifyMessageClicked(wrapper.item); - notifyMessageViewClicked(view, wrapper.item); - } + MESSAGE message = (wrapper.item); + notifyItemChanged(getMessagePositionById(message.getId())); + } else { + notifyMessageClicked(wrapper.item); + notifyMessageViewClicked(view, wrapper.item); } }; } private View.OnLongClickListener getMessageLongClickListener(final Wrapper wrapper) { - return new View.OnLongClickListener() { - @Override - public boolean onLongClick(View view) { - if (selectionListener == null) { - notifyMessageLongClicked(wrapper.item); - notifyMessageViewLongClicked(view, wrapper.item); - return true; - } else { - isSelectionModeEnabled = true; - view.performClick(); - return true; - } + return view -> { + if (selectionListener == null) { + notifyMessageLongClicked(wrapper.item); + notifyMessageViewLongClicked(view, wrapper.item); + } else { + isSelectionModeEnabled = true; + view.performClick(); } + return true; }; } @@ -586,11 +679,11 @@ void setStyle(MessagesListStyle style) { } /* - * WRAPPER - * */ - private class Wrapper { - DATA item; - boolean isSelected; + * WRAPPER + * */ + public static class Wrapper { + public DATA item; + public boolean isSelected; Wrapper(DATA item) { this.item = item; @@ -598,8 +691,8 @@ private class Wrapper { } /* - * LISTENERS - * */ + * LISTENERS + * */ /** * Interface definition for a callback to be invoked when next part of messages need to be loaded. @@ -849,7 +942,7 @@ public static class DefaultDateHeaderViewHolder extends ViewHolder public DefaultDateHeaderViewHolder(View itemView) { super(itemView); - text = (TextView) itemView.findViewById(R.id.messageText); + text = itemView.findViewById(R.id.messageText); } @Override diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesListStyle.java b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesListStyle.java index a1c06a59..4ea6ed10 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesListStyle.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/messages/MessagesListStyle.java @@ -22,17 +22,19 @@ import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Drawable; -import android.support.annotation.ColorInt; -import android.support.annotation.DrawableRes; -import android.support.v4.graphics.drawable.DrawableCompat; import android.util.AttributeSet; +import androidx.annotation.ColorInt; +import androidx.annotation.DrawableRes; +import androidx.core.graphics.drawable.DrawableCompat; + import com.stfalcon.chatkit.R; import com.stfalcon.chatkit.commons.Style; /** * Style for MessagesListStyle customization by xml attributes */ +@SuppressWarnings("WeakerAccess") class MessagesListStyle extends Style { private int textAutoLinkMask; @@ -230,55 +232,55 @@ private Drawable getMessageSelector(@ColorInt int normalColor, @ColorInt int sel return drawable; } - int getTextAutoLinkMask() { + protected int getTextAutoLinkMask() { return textAutoLinkMask; } - int getIncomingTextLinkColor() { + protected int getIncomingTextLinkColor() { return incomingTextLinkColor; } - int getOutcomingTextLinkColor() { + protected int getOutcomingTextLinkColor() { return outcomingTextLinkColor; } - int getIncomingAvatarWidth() { + protected int getIncomingAvatarWidth() { return incomingAvatarWidth; } - int getIncomingAvatarHeight() { + protected int getIncomingAvatarHeight() { return incomingAvatarHeight; } - int getIncomingDefaultBubblePaddingLeft() { + protected int getIncomingDefaultBubblePaddingLeft() { return incomingDefaultBubblePaddingLeft; } - int getIncomingDefaultBubblePaddingRight() { + protected int getIncomingDefaultBubblePaddingRight() { return incomingDefaultBubblePaddingRight; } - int getIncomingDefaultBubblePaddingTop() { + protected int getIncomingDefaultBubblePaddingTop() { return incomingDefaultBubblePaddingTop; } - int getIncomingDefaultBubblePaddingBottom() { + protected int getIncomingDefaultBubblePaddingBottom() { return incomingDefaultBubblePaddingBottom; } - int getIncomingTextColor() { + protected int getIncomingTextColor() { return incomingTextColor; } - int getIncomingTextSize() { + protected int getIncomingTextSize() { return incomingTextSize; } - int getIncomingTextStyle() { + protected int getIncomingTextStyle() { return incomingTextStyle; } - Drawable getOutcomingBubbleDrawable() { + protected Drawable getOutcomingBubbleDrawable() { if (outcomingBubbleDrawable == -1) { return getMessageSelector(outcomingDefaultBubbleColor, outcomingDefaultBubbleSelectedColor, outcomingDefaultBubblePressedColor, R.drawable.shape_outcoming_message); @@ -287,7 +289,7 @@ Drawable getOutcomingBubbleDrawable() { } } - Drawable getOutcomingImageOverlayDrawable() { + protected Drawable getOutcomingImageOverlayDrawable() { if (outcomingImageOverlayDrawable == -1) { return getMessageSelector(Color.TRANSPARENT, outcomingDefaultImageOverlaySelectedColor, outcomingDefaultImageOverlayPressedColor, R.drawable.shape_outcoming_message); @@ -296,103 +298,103 @@ Drawable getOutcomingImageOverlayDrawable() { } } - int getOutcomingDefaultBubblePaddingLeft() { + protected int getOutcomingDefaultBubblePaddingLeft() { return outcomingDefaultBubblePaddingLeft; } - int getOutcomingDefaultBubblePaddingRight() { + protected int getOutcomingDefaultBubblePaddingRight() { return outcomingDefaultBubblePaddingRight; } - int getOutcomingDefaultBubblePaddingTop() { + protected int getOutcomingDefaultBubblePaddingTop() { return outcomingDefaultBubblePaddingTop; } - int getOutcomingDefaultBubblePaddingBottom() { + protected int getOutcomingDefaultBubblePaddingBottom() { return outcomingDefaultBubblePaddingBottom; } - int getOutcomingTextColor() { + protected int getOutcomingTextColor() { return outcomingTextColor; } - int getOutcomingTextSize() { + protected int getOutcomingTextSize() { return outcomingTextSize; } - int getOutcomingTextStyle() { + protected int getOutcomingTextStyle() { return outcomingTextStyle; } - int getOutcomingTimeTextColor() { + protected int getOutcomingTimeTextColor() { return outcomingTimeTextColor; } - int getOutcomingTimeTextSize() { + protected int getOutcomingTimeTextSize() { return outcomingTimeTextSize; } - int getOutcomingTimeTextStyle() { + protected int getOutcomingTimeTextStyle() { return outcomingTimeTextStyle; } - int getOutcomingImageTimeTextColor() { + protected int getOutcomingImageTimeTextColor() { return outcomingImageTimeTextColor; } - int getOutcomingImageTimeTextSize() { + protected int getOutcomingImageTimeTextSize() { return outcomingImageTimeTextSize; } - int getOutcomingImageTimeTextStyle() { + protected int getOutcomingImageTimeTextStyle() { return outcomingImageTimeTextStyle; } - int getDateHeaderTextColor() { + protected int getDateHeaderTextColor() { return dateHeaderTextColor; } - int getDateHeaderTextSize() { + protected int getDateHeaderTextSize() { return dateHeaderTextSize; } - int getDateHeaderTextStyle() { + protected int getDateHeaderTextStyle() { return dateHeaderTextStyle; } - int getDateHeaderPadding() { + protected int getDateHeaderPadding() { return dateHeaderPadding; } - String getDateHeaderFormat() { + protected String getDateHeaderFormat() { return dateHeaderFormat; } - int getIncomingTimeTextSize() { + protected int getIncomingTimeTextSize() { return incomingTimeTextSize; } - int getIncomingTimeTextStyle() { + protected int getIncomingTimeTextStyle() { return incomingTimeTextStyle; } - int getIncomingTimeTextColor() { + protected int getIncomingTimeTextColor() { return incomingTimeTextColor; } - int getIncomingImageTimeTextColor() { + protected int getIncomingImageTimeTextColor() { return incomingImageTimeTextColor; } - int getIncomingImageTimeTextSize() { + protected int getIncomingImageTimeTextSize() { return incomingImageTimeTextSize; } - int getIncomingImageTimeTextStyle() { + protected int getIncomingImageTimeTextStyle() { return incomingImageTimeTextStyle; } - Drawable getIncomingBubbleDrawable() { + protected Drawable getIncomingBubbleDrawable() { if (incomingBubbleDrawable == -1) { return getMessageSelector(incomingDefaultBubbleColor, incomingDefaultBubbleSelectedColor, incomingDefaultBubblePressedColor, R.drawable.shape_incoming_message); @@ -401,7 +403,7 @@ Drawable getIncomingBubbleDrawable() { } } - Drawable getIncomingImageOverlayDrawable() { + protected Drawable getIncomingImageOverlayDrawable() { if (incomingImageOverlayDrawable == -1) { return getMessageSelector(Color.TRANSPARENT, incomingDefaultImageOverlaySelectedColor, incomingDefaultImageOverlayPressedColor, R.drawable.shape_incoming_message); diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/messages/RecyclerScrollMoreListener.java b/chatkit/src/main/java/com/stfalcon/chatkit/messages/RecyclerScrollMoreListener.java index 92cffc38..f6e61998 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/messages/RecyclerScrollMoreListener.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/messages/RecyclerScrollMoreListener.java @@ -16,10 +16,10 @@ package com.stfalcon.chatkit.messages; -import android.support.v7.widget.GridLayoutManager; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.StaggeredGridLayoutManager; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.StaggeredGridLayoutManager; class RecyclerScrollMoreListener extends RecyclerView.OnScrollListener { @@ -79,7 +79,7 @@ public void onScrolled(RecyclerView view, int dx, int dy) { int visibleThreshold = 5; if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) { currentPage++; - loadMoreListener.onLoadMore(currentPage, totalItemCount); + loadMoreListener.onLoadMore(loadMoreListener.getMessagesCount(), totalItemCount); loading = true; } } @@ -87,5 +87,7 @@ public void onScrolled(RecyclerView view, int dx, int dy) { interface OnLoadMoreListener { void onLoadMore(int page, int total); + + int getMessagesCount(); } } diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/utils/RoundedImageView.java b/chatkit/src/main/java/com/stfalcon/chatkit/utils/RoundedImageView.java index 91e85142..d53c6f0d 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/utils/RoundedImageView.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/utils/RoundedImageView.java @@ -18,17 +18,18 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.net.Uri; -import android.support.annotation.DimenRes; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; import android.util.AttributeSet; -import android.widget.ImageView; + +import androidx.annotation.DimenRes; +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.content.ContextCompat; /** * Thanks to Joonho Kim (https://github.com/pungrue26) for his lightweight SelectableRoundedImageView, * that was used as default image message representation */ -public class RoundedImageView extends ImageView { +public class RoundedImageView extends AppCompatImageView { private int mResource = 0; private Drawable mDrawable; @@ -124,7 +125,7 @@ private void updateDrawable() { ((RoundedCornerDrawable) mDrawable).setCornerRadii(mRadii); } - static class RoundedCornerDrawable extends Drawable { + private static class RoundedCornerDrawable extends Drawable { private RectF mBounds = new RectF(); private final RectF mBitmapRect = new RectF(); @@ -133,17 +134,15 @@ static class RoundedCornerDrawable extends Drawable { private final Paint mBitmapPaint; - private BitmapShader mBitmapShader; - private float[] mRadii = new float[]{0, 0, 0, 0, 0, 0, 0, 0}; private Path mPath = new Path(); private Bitmap mBitmap; private boolean mBoundsConfigured = false; - RoundedCornerDrawable(Bitmap bitmap, Resources r) { + private RoundedCornerDrawable(Bitmap bitmap, Resources r) { mBitmap = bitmap; - mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + BitmapShader mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mBitmapWidth = bitmap.getScaledWidth(r.getDisplayMetrics()); mBitmapHeight = bitmap.getScaledHeight(r.getDisplayMetrics()); @@ -155,12 +154,12 @@ static class RoundedCornerDrawable extends Drawable { mBitmapPaint.setShader(mBitmapShader); } - static RoundedCornerDrawable fromBitmap(Bitmap bitmap, Resources r) { + private static RoundedCornerDrawable fromBitmap(Bitmap bitmap, Resources r) { if (bitmap != null) return new RoundedCornerDrawable(bitmap, r); else return null; } - static Drawable fromDrawable(Drawable drawable, Resources r) { + private static Drawable fromDrawable(Drawable drawable, Resources r) { if (drawable != null) { if (drawable instanceof RoundedCornerDrawable) { return drawable; @@ -180,7 +179,7 @@ static Drawable fromDrawable(Drawable drawable, Resources r) { return drawable; } - static Bitmap drawableToBitmap(Drawable drawable) { + private static Bitmap drawableToBitmap(Drawable drawable) { if (drawable == null) return null; if (drawable instanceof BitmapDrawable) { diff --git a/chatkit/src/main/java/com/stfalcon/chatkit/utils/ShapeImageView.java b/chatkit/src/main/java/com/stfalcon/chatkit/utils/ShapeImageView.java index d9717f64..f212468a 100644 --- a/chatkit/src/main/java/com/stfalcon/chatkit/utils/ShapeImageView.java +++ b/chatkit/src/main/java/com/stfalcon/chatkit/utils/ShapeImageView.java @@ -20,21 +20,23 @@ import android.graphics.Canvas; import android.graphics.Path; import android.util.AttributeSet; -import android.widget.ImageView; +import android.view.View; /** * ImageView with mask what described with Bézier Curves */ -public class ShapeImageView extends ImageView { +public class ShapeImageView extends androidx.appcompat.widget.AppCompatImageView { private Path path; public ShapeImageView(Context context) { super(context); + setLayerType(View.LAYER_TYPE_SOFTWARE, null); } public ShapeImageView(Context context, AttributeSet attrs) { super(context, attrs); + setLayerType(View.LAYER_TYPE_SOFTWARE, null); } @Override @@ -56,9 +58,14 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) { @Override protected void onDraw(Canvas canvas) { - if (canvas != null) { - canvas.clipPath(path); + if (path.isEmpty()) { super.onDraw(canvas); + return; } + + int saveCount = canvas.save(); + canvas.clipPath(path); + super.onDraw(canvas); + canvas.restoreToCount(saveCount); } } diff --git a/chatkit/src/main/res/layout/item_date_header.xml b/chatkit/src/main/res/layout/item_date_header.xml index 3564394c..356aef27 100644 --- a/chatkit/src/main/res/layout/item_date_header.xml +++ b/chatkit/src/main/res/layout/item_date_header.xml @@ -1,6 +1,6 @@ \ No newline at end of file + android:id="@id/messageText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:padding="16dp" /> \ No newline at end of file diff --git a/chatkit/src/main/res/layout/item_dialog.xml b/chatkit/src/main/res/layout/item_dialog.xml index 9820dec2..3e3f8b55 100644 --- a/chatkit/src/main/res/layout/item_dialog.xml +++ b/chatkit/src/main/res/layout/item_dialog.xml @@ -1,7 +1,7 @@ + android:id="@id/dialogRootLayout" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + android:layout_margin="16dp" /> + android:maxLines="1" /> + android:maxLines="1" /> + android:layout_marginRight="7dp" /> + android:maxLines="1" /> @@ -88,7 +88,7 @@ android:ellipsize="end" android:fontFamily="@string/font_fontFamily_medium" android:gravity="center" - android:lines="1"/> + android:lines="1" /> + android:background="@color/dialog_divider" /> diff --git a/chatkit/src/main/res/layout/item_incoming_image_message.xml b/chatkit/src/main/res/layout/item_incoming_image_message.xml index 2685e398..73d614d4 100644 --- a/chatkit/src/main/res/layout/item_incoming_image_message.xml +++ b/chatkit/src/main/res/layout/item_incoming_image_message.xml @@ -1,5 +1,4 @@ - + android:layout_marginRight="8dp" /> + android:layout_toRightOf="@id/messageUserAvatar" /> + android:layout_alignTop="@id/image" /> + android:layout_below="@id/image" /> \ No newline at end of file diff --git a/chatkit/src/main/res/layout/item_incoming_text_message.xml b/chatkit/src/main/res/layout/item_incoming_text_message.xml index 3c35437d..f7ba34b0 100644 --- a/chatkit/src/main/res/layout/item_incoming_text_message.xml +++ b/chatkit/src/main/res/layout/item_incoming_text_message.xml @@ -1,5 +1,4 @@ - + android:layout_marginRight="8dp" /> + android:layout_height="wrap_content" /> + app:layout_alignSelf="center" /> diff --git a/chatkit/src/main/res/layout/item_outcoming_image_message.xml b/chatkit/src/main/res/layout/item_outcoming_image_message.xml index 21712d4f..0149b461 100644 --- a/chatkit/src/main/res/layout/item_outcoming_image_message.xml +++ b/chatkit/src/main/res/layout/item_outcoming_image_message.xml @@ -1,5 +1,4 @@ - + android:layout_marginStart="@dimen/message_outcoming_bubble_margin_left" /> + android:layout_alignTop="@id/image" /> + android:layout_below="@id/image" /> \ No newline at end of file diff --git a/chatkit/src/main/res/layout/item_outcoming_text_message.xml b/chatkit/src/main/res/layout/item_outcoming_text_message.xml index 51e5aeaa..58e58351 100644 --- a/chatkit/src/main/res/layout/item_outcoming_text_message.xml +++ b/chatkit/src/main/res/layout/item_outcoming_text_message.xml @@ -1,5 +1,4 @@ - + android:layout_alignWithParentIfMissing="true" /> + app:layout_order="1" /> diff --git a/chatkit/src/main/res/layout/view_message_input.xml b/chatkit/src/main/res/layout/view_message_input.xml index aaed1f5f..9ab1b4d9 100644 --- a/chatkit/src/main/res/layout/view_message_input.xml +++ b/chatkit/src/main/res/layout/view_message_input.xml @@ -1,5 +1,4 @@ - @@ -8,14 +7,14 @@ android:id="@id/attachmentButton" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_centerVertical="true"/> + android:layout_centerVertical="true" /> - + android:layout_toRightOf="@id/attachmentButton" /> + android:inputType="textAutoCorrect|textAutoComplete|textMultiLine|textCapSentences" /> - + android:layout_toStartOf="@id/messageSendButton" /> + android:layout_centerVertical="true" /> \ No newline at end of file diff --git a/chatkit/src/main/res/values/attrs.xml b/chatkit/src/main/res/values/attrs.xml index dca85be2..4e996630 100644 --- a/chatkit/src/main/res/values/attrs.xml +++ b/chatkit/src/main/res/values/attrs.xml @@ -1,225 +1,227 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - + + + + + + - - + + - - + + - - - - + + + + - - - + + + - - - - + + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - - - + + + + - - - + + + - - - - + + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - - - + + + + - - - + + + - + - - + + - - - + + + - + - - - + + + - - + + - - - + + + - + - - - + + + - - + + - - - + + + - + - - - + + + - - - + + + - - - + + + - + - - + + - - - + + + - - - - + + + + - - + + diff --git a/chatkit/src/main/res/values/strings.xml b/chatkit/src/main/res/values/strings.xml index ea100eae..2c5844dd 100644 --- a/chatkit/src/main/res/values/strings.xml +++ b/chatkit/src/main/res/values/strings.xml @@ -1 +1 @@ - + diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 0c0bb994..32e427f5 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,3 +1,37 @@ +## Version 0.3.3 (2018/10/12) +* Merged: Added upsert method to move a specific item to the start. [#209](https://github.com/stfalcon-studio/ChatKit/pull/209) + +## Version 0.3.2 (2018/09/28) +* [Passing custom data to ImageLoader](https://github.com/stfalcon-studio/ChatKit/issues/183) +* Fixed [#198](https://github.com/stfalcon-studio/ChatKit/issues/198) +* Protected `items` field in `MessagesListAdapter` and `DialogsListAdapte` [#188](https://github.com/stfalcon-studio/ChatKit/issues/188) +* Fixed `delete` and `deleteByIds` methods in MessagesListAdapter +* Merged: Clear last message if null in dialog list (Fix issue #189) [#190](https://github.com/stfalcon-studio/ChatKit/pull/190) +* Merged: Add upsert method to dialogs list [#191](https://github.com/stfalcon-studio/ChatKit/pull/191) +* Merged: Update documentation to add upsertItem method [#208](https://github.com/stfalcon-studio/ChatKit/pull/208) + +## Version 0.3.1 (2018/08/16) +* [Passing custom data to your ViewHolder](https://github.com/stfalcon-studio/ChatKit/blob/master/docs/COMPONENT_MESSAGES_LIST.md#passing-custom-data-to-your-viewholder) [#180](https://github.com/stfalcon-studio/ChatKit/issues/180) +* Added Proguard rules to [Readme](https://github.com/stfalcon-studio/ChatKit#proguard) and [sample project](https://github.com/stfalcon-studio/ChatKit/blob/master/sample/proguard-rules.pro). [#122](https://github.com/stfalcon-studio/ChatKit/issues/122) +* Fixed [#174](https://github.com/stfalcon-studio/ChatKit/issues/174) + +## Version 0.3.0 (2018/07/12) +* [Added Typing Listener to MessageInput](https://github.com/stfalcon-studio/ChatKit/blob/master/docs/COMPONENT_MESSAGE_INPUT.MD#typing-listener). Thanks to [toanpv](https://github.com/toanpv); +* Fixed artifacts with bubble background in message list; +* Added separate method MessagesListAdapter.clear(notifyDataSetChanged). Method MessagesListAdapter.clear() does notifyDataSetChanged by default. [#89](https://github.com/stfalcon-studio/ChatKit/issues/86); +* Fixed "The totalItemsCount parameter in OnLoadMore callback contains date header." [#86](https://github.com/stfalcon-studio/ChatKit/issues/86); +* Merged pull requests: + * Avoid Crash on empty list in addToEnd [#146](https://github.com/stfalcon-studio/ChatKit/pull/146); + * Fix link typo in docs [#134](https://github.com/stfalcon-studio/ChatKit/pull/134); + * Add nullable for getImageUrl() [#119](https://github.com/stfalcon-studio/ChatKit/pull/119); + * Made correction to DialogList documentation [#112](https://github.com/stfalcon-studio/ChatKit/pull/112); + * Allow moving Dialog item and get Dialog by id [#70](https://github.com/stfalcon-studio/ChatKit/pull/70); + * Allow the user to get the current position of a DIALOG [#32](https://github.com/stfalcon-studio/ChatKit/pull/32); + * Added upsert(Message) method to add or update message to adapter as appropriate [#61](https://github.com/stfalcon-studio/ChatKit/pull/61); + * Create LICENSE [#167](https://github.com/stfalcon-studio/ChatKit/pull/167); + * NPE check in DialofsListAdapter.java when there is no last message (is null) [#75](https://github.com/stfalcon-studio/ChatKit/pull/75); +* Sample: Fixed artifacts on some devices in ShapeImageView. Changed fixture message image. + ## Version 0.2.0 (2017/04/07) * [Default image type](COMPONENT_MESSAGES_LIST.md#adding-image-message); diff --git a/docs/COMPONENT_DIALOGS_LIST.MD b/docs/COMPONENT_DIALOGS_LIST.MD index 9b4f72ce..21763d0b 100644 --- a/docs/COMPONENT_DIALOGS_LIST.MD +++ b/docs/COMPONENT_DIALOGS_LIST.MD @@ -36,7 +36,7 @@ dialogsListView.setAdapter(dialogsListAdapter); #### Prepare your model -To be able to add dialog, you must implement the `IDealog` interface to your existing model and override its methods: +To be able to add dialog, you must implement the `IDialog` interface to your existing model and override its methods: ```java public class DefaultDialog implements IDialog { @@ -113,8 +113,9 @@ When your models are ready to be used by adapter, you can simply add them to the * adapter.setItems(List items) - replaces existing list with a new dialog list; * adapter.addItems(List items) - adds a new dialog list to the end of the list; -* adapter.addItem(DIALOG dialog) - adds a new dialog to the specified position; -* adapter.addItem(int position, DIALOG dialog) - adds one dialog to the end of the list. +* adapter.addItem(DIALOG dialog) - adds one dialog to the end of the list +* adapter.addItem(int position, DIALOG dialog) - adds a new dialog to the specified position. +* adapter.upsertItem(DIALOG dialog) - adds one dialog to the end of the list if not exists, otherwise updates the existing dialog. #### Updating dialogs If dialog has changed, you can update it by position in list by calling `adapter.updateItem(int position, DIALOG item)` or update it by dialog id by calling `adapter.updateItemById(DIALOG item)` @@ -220,7 +221,7 @@ But what if changing appearance is not enough? Not a problem, create your own la * `@id/dialogDividerContainer` (ViewGroup) * `@id/dialogDivider` (View) -For better understanding see how [custom layout looks like](https://github.com/stfalcon-studio/ChatKit/blob/master/sample/src/main/res/layout/item_dialog_custom.xml). +For better understanding see how [custom layout looks like](https://github.com/stfalcon-studio/ChatKit/blob/master/sample/src/main/res/layout/item_custom_dialog.xml). After creating layout you need to transfer it to the adapter’s constructor. ```java diff --git a/docs/COMPONENT_MESSAGES_LIST.md b/docs/COMPONENT_MESSAGES_LIST.md index 707a9d5e..cff2a03e 100644 --- a/docs/COMPONENT_MESSAGES_LIST.md +++ b/docs/COMPONENT_MESSAGES_LIST.md @@ -147,7 +147,7 @@ If message has changed, you can update it by calling `adapter.update(IMessage me #### Click listeners -Of course, the adapter have listeners for such important actions as short and long clicks. They just returns a message object that has been pressed, with a type that is specified as the generic type of adapter: +Of course, the adapter has listeners for such important actions as short and long clicks. They just returns a message object that has been pressed, with a type that is specified as the generic type of adapter: ```java public interface OnMessageClickListener { @@ -157,6 +157,12 @@ public interface OnMessageLongClickListener { void onMessageLongClick(MESSAGE message); } ``` + +Also here is an ability to set listeners on separate Views in message item: +``` +public void registerViewClickListener(int viewId, OnMessageViewClickListener onMessageViewClickListener) +``` + #### Links highlighting In 99% of cases the user is confused, when he can not follow the link or call the phone, indicated in the message. If you think the same way, just include `textAutoLink="all"`, like in the ordinary `TextView`. Similarly, you can specify highlighting for certain types, for example, `email|phone|web`:

@@ -276,7 +282,7 @@ But what if you need not only to change the appearance of the elements, but also * `@id/messageTime` (TextView) * `@id/messageUserAvatar` (ImageView) -For better understanding see how [custom layout looks like](https://github.com/stfalcon-studio/ChatKit/blob/master/sample/src/main/res/layout/item_custom_incoming_message.xml) +For better understanding see how [custom layout looks like](https://github.com/stfalcon-studio/ChatKit/blob/master/sample/src/main/res/layout/item_custom_incoming_text_message.xml) After a layout was created, you need to put it into `HoldersConfig` object, which has appropriate methods for each layout files: `setIncomingLayout(int layoutRes)`, `setOutcomingLayout(int layoutRes)` `setDateHeaderLayout(int layoutRes)`. To hook up a config object, you need to transfer it to adapter through a constructor: @@ -315,8 +321,8 @@ For example, you can add status for outgoing messages with only few lines: public class CustomOutcomingMessageViewHolder extends MessagesListAdapter.OutcomingMessageViewHolder { - public CustomOutcomingMessageViewHolder(View itemView) { - super(itemView); + public CustomOutcomingMessageViewHolder(View itemView, Object payload) { + super(itemView, payload); } @Override @@ -332,6 +338,58 @@ public class CustomOutcomingMessageViewHolder

Pay attention to outgoing message’ status and online indicator.

+#### Passing custom data to your ViewHolder +You can pass any data to your custom ViewHolder. To do this, firstly you need override the constructor `super(View itemView, Object payload)` (the constructor `super(View itemView)` is deprecated and will be deleted in one of the new version of library). After that you can pass data as third parameter in method `MessageHolders().setXXXConfig`. +For example, let's add click listener in incoming text message on avatar click. +Create interface for click callback and payload class to store it: +```java +public interface OnAvatarClickListener { + void onAvatarClick(); +} + +public class Payload { + public OnAvatarClickListener avatarClickListener; +} +``` +Then in our custom ViewHolder in method `onBind`: +```java +@Override + public void onBind(Message message) { + super.onBind(message); + ... + //We can set click listener on view from payload + final Payload payload = (Payload) this.payload; + userAvatar.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (payload != null && payload.avatarClickListener != null) { + payload.avatarClickListener.onAvatarClick(); + } + } + }); + } +``` +Then create Payload and set it and our ViewHolder class to MessageHolders config. +```java +//We can pass any data to ViewHolder with payload +CustomIncomingTextMessageViewHolder.Payload payload = new CustomIncomingTextMessageViewHolder.Payload(); +//For example click listener +payload.avatarClickListener = new CustomIncomingTextMessageViewHolder.OnAvatarClickListener() { + @Override + public void onAvatarClick() { + Toast.makeText(CustomHolderMessagesActivity.this, + "Text message avatar clicked", Toast.LENGTH_SHORT).show(); + } +}; + +MessageHolders holdersConfig = new MessageHolders() + .setIncomingTextConfig( + CustomIncomingTextMessageViewHolder.class, + R.layout.item_custom_incoming_text_message, + payload) + ... +``` + #### Custom content types We understand that ony images as media messages are often not enough. Therefore, we implemented the ability to add custom content types for displaying different types of content (geopoints, video, voice messages etc.). @@ -369,4 +427,4 @@ If the `hasContentFor` method returns `true` for the selected type, the correspo As the result, well get the following:

-

\ No newline at end of file +

diff --git a/docs/COMPONENT_MESSAGE_INPUT.MD b/docs/COMPONENT_MESSAGE_INPUT.MD index 6c49542e..72165205 100644 --- a/docs/COMPONENT_MESSAGE_INPUT.MD +++ b/docs/COMPONENT_MESSAGE_INPUT.MD @@ -47,6 +47,24 @@ messageInput.setAttachmentsListener(new MessageInput.AttachmentsListener() { }); ``` +#### Typing Listener + +If you want to track typing event: +```java +messageInput.setTypingListener(new MessageInput.TypingListener() { + @Override + public void onStartTyping() { + + } + + @Override + public void onStopTyping() { + + } + }); +``` +Default delay typing is 1500, you can change it with only one line `delayTypingStatus="delayInMilis"` + #### Make it look the way you want By using available widget attribute you can change color and size of text and input hint, maximum number of permitted lines, size and indents “submit” button, and its icon and background. diff --git a/docs/STYLES_ATTR.md b/docs/STYLES_ATTR.md index df2075e4..7c04e9c9 100644 --- a/docs/STYLES_ATTR.md +++ b/docs/STYLES_ATTR.md @@ -37,7 +37,7 @@ | `dialogItemBackground` | Sets background of dialogs items| | `dialogItemBackground` | Sets background of dialogs items when has unread messages | -## [MessagesList]](COMPONENT_MESSAGES_LIST.md) xml attributes: +## [MessagesList](COMPONENT_MESSAGES_LIST.md) xml attributes: | Attribute | Description| | ------------- |-------------| @@ -126,4 +126,5 @@ | `inputTextColor` | Sets input message text color| | `inputHintColor` | Sets text color of hint in message input field| | `inputBackground` | Sets background for input message view | -| `inputCursorDrawable` | Sets cursor drawable for input message EditText | \ No newline at end of file +| `inputCursorDrawable` | Sets cursor drawable for input message EditText | +| `delayTypingStatus` | Sets delay typing for TypingListener| diff --git a/gradle.properties b/gradle.properties index aac7c9b4..de89bf94 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,17 +1,16 @@ # Project-wide Gradle settings. - # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. - # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html - # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx1536m - # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..13372aef Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fb4882dc..b12ede36 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Apr 06 11:02:19 EEST 2017 +#Tue Feb 09 17:12:38 EET 2021 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip diff --git a/gradlew b/gradlew index 27309d92..dc2f857e 100755 --- a/gradlew +++ b/gradlew @@ -10,22 +10,22 @@ # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +while [ -h "$PRG" ]; do + ls=$(ls -ld "$PRG") + link=$(expr "$ls" : '.*-> \(.*\)$') + if expr "$link" : '/.*' >/dev/null; then + PRG="$link" + else + PRG=$(dirname "$PRG")"/$link" + fi done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" +SAVED="$(pwd)" +cd "$(dirname \"$PRG\")/" >/dev/null +APP_HOME="$(pwd -P)" cd "$SAVED" >/dev/null APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=$(basename "$0") # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" @@ -33,15 +33,15 @@ DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { - echo "$*" +warn() { + echo "$*" } -die ( ) { - echo - echo "$*" - echo - exit 1 +die() { + echo + echo "$*" + echo + exit 1 } # OS specific support (must be 'true' or 'false'). @@ -49,114 +49,114 @@ cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$(uname)" in +CYGWIN*) + cygwin=true + ;; +Darwin*) + darwin=true + ;; +MINGW*) + msys=true + ;; +NONSTOP*) + nonstop=true + ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME +if [ -n "$JAVA_HOME" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ]; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." - fi + fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ]; then + MAX_FD_LIMIT=$(ulimit -H -n) + if [ $? -eq 0 ]; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ]; then + MAX_FD="$MAX_FD_LIMIT" fi + ulimit -n $MAX_FD + if [ $? -ne 0 ]; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" +if $cygwin; then + APP_HOME=$(cygpath --path --mixed "$APP_HOME") + CLASSPATH=$(cygpath --path --mixed "$CLASSPATH") + JAVACMD=$(cygpath --unix "$JAVACMD") + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=$(find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null) + SEP="" + for dir in $ROOTDIRSRAW; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ]; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@"; do + CHECK=$(echo "$arg" | egrep -c "$OURCYGPATTERN" -) + CHECK2=$(echo "$arg" | egrep -c "^-") ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ]; then ### Added a condition + eval $(echo args$i)=$(cygpath --path --ignore --mixed "$arg") + else + eval $(echo args$i)="\"$arg\"" fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac + i=$((i + 1)) + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { - JVM_OPTS=("$@") + JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" diff --git a/sample/build.gradle b/sample/build.gradle index 13d52cae..ec6c1258 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,15 +1,14 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion 29 + buildToolsVersion '29.0.2' defaultConfig { applicationId "com.stfalcon.chatkit.sample" minSdkVersion 14 - targetSdkVersion 25 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } buildTypes { release { @@ -22,36 +21,34 @@ android { abortOnError false } } -} -ext { - supportVersion = '25.3.1' - picassoVersion = '2.5.2' - circleImageViewVersion = '2.1.0' - shapeImageViewVersion = '0.9.3' - circleindicatorVersion = '1.2.2@aar' + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { - compile project(':chatkit') + implementation project(':chatkit') - compile fileTree(dir: 'libs', include: ['*.jar']) - androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + implementation fileTree(dir: 'libs', include: ['*.jar']) + androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { exclude group: 'com.android.support', module: 'support-annotations' }) - testCompile 'junit:junit:4.12' + testImplementation 'junit:junit:4.13' - compile "com.android.support:appcompat-v7:$supportVersion" - compile "com.android.support:cardview-v7:$supportVersion" - compile "com.android.support:design:$supportVersion" + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'com.google.android.material:material:1.2.1' //Picasso - compile "com.squareup.picasso:picasso:$picassoVersion" + implementation "com.squareup.picasso:picasso:2.71828" //ImageViews - compile "de.hdodenhof:circleimageview:$circleImageViewVersion" - compile "com.github.siyamed:android-shape-imageview:$shapeImageViewVersion" + implementation "de.hdodenhof:circleimageview:2.2.0" + implementation "com.github.siyamed:android-shape-imageview:0.9.3" //Utils - compile "me.relex:circleindicator:$circleindicatorVersion" + implementation "me.relex:circleindicator:1.2.2@aar" + } diff --git a/sample/proguard-rules.pro b/sample/proguard-rules.pro index 7e694d20..2995e8d9 100644 --- a/sample/proguard-rules.pro +++ b/sample/proguard-rules.pro @@ -15,3 +15,99 @@ #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} +# JSR 305 annotations are for embedding nullability information. +-dontwarn javax.annotation.** + +# A resource is loaded with a relative path so the package of this class must be preserved. +-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase + +# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. +-dontwarn org.codehaus.mojo.animal_sniffer.* + +# OkHttp platform used only on JVM and when Conscrypt dependency is available. +-dontwarn okhttp3.internal.platform.ConscryptPlatform + + +-dontwarn okio.** +-dontwarn com.squareup.okhttp.** +-dontwarn okhttp3.** +-dontwarn javax.annotation.** + +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgent +-keep public class * extends android.preference.Preference +-keep public class * extends android.support.v4.app.Fragment +-keep public class * extends android.support.v4.app.DialogFragment +-keep public class * extends android.app.Fragment +-keep public class com.android.vending.licensing.ILicensingService + +# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native +-keepclasseswithmembernames class * { + native ; +} + +-keep public class * extends android.view.View { + public (android.content.Context); + public (android.content.Context, android.util.AttributeSet); + public (android.content.Context, android.util.AttributeSet, int); + public void set*(...); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembers class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclassmembers class * extends android.app.Activity { + public void *(android.view.View); +} + +# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + +-keepclassmembers class **.R$* { + public static ; +} +-keep class android.support.v7.internal.** { *; } +-keep interface android.support.v7.internal.** { *; } +-keep class android.support.v7.** { *; } +-keep interface android.support.v7.** { *; } +# The support library contains references to newer platform versions. +# Don't warn about those in case this app is linking against an older +# platform version. We know about them, and they are safe. +-dontwarn android.support.** + + + +#FOR CHATKIT + +-keep class * extends com.stfalcon.chatkit.messages.MessageHolders$OutcomingTextMessageViewHolder { + public (android.view.View, java.lang.Object); + public (android.view.View); + } +-keep class * extends com.stfalcon.chatkit.messages.MessageHolders$IncomingTextMessageViewHolder { + public (android.view.View, java.lang.Object); + public (android.view.View); + } +-keep class * extends com.stfalcon.chatkit.messages.MessageHolders$IncomingImageMessageViewHolder { + public (android.view.View, java.lang.Object); + public (android.view.View); + } +-keep class * extends com.stfalcon.chatkit.messages.MessageHolders$OutcomingImageMessageViewHolder { + public (android.view.View, java.lang.Object); + public (android.view.View); + } diff --git a/sample/src/androidTest/java/com/stfalcon/chatkit/sample/ExampleInstrumentedTest.java b/sample/src/androidTest/java/com/stfalcon/chatkit/sample/ExampleInstrumentedTest.java index 9ba761a3..ff85a942 100644 --- a/sample/src/androidTest/java/com/stfalcon/chatkit/sample/ExampleInstrumentedTest.java +++ b/sample/src/androidTest/java/com/stfalcon/chatkit/sample/ExampleInstrumentedTest.java @@ -1,13 +1,14 @@ package com.stfalcon.chatkit.sample; import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; /** * Instrumentation test, which will execute on an Android device. diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index e95c5cbb..6526cb56 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ + package="com.stfalcon.chatkit.sample"> - + - - + + + android:theme="@style/BlueTheme" /> - - - - - - + android:theme="@style/BlueTheme" /> + + + + + + + android:theme="@style/BlueTheme" /> diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/common/data/fixtures/FixturesData.java b/sample/src/main/java/com/stfalcon/chatkit/sample/common/data/fixtures/FixturesData.java index 6f7d35bc..ead984e3 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/common/data/fixtures/FixturesData.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/common/data/fixtures/FixturesData.java @@ -71,7 +71,7 @@ abstract class FixturesData { static final ArrayList images = new ArrayList() { { add("https://habrastorage.org/getpro/habr/post_images/e4b/067/b17/e4b067b17a3e414083f7420351db272b.jpg"); - add("http://www.designboom.com/wp-content/uploads/2015/11/stefano-boeri-architetti-vertical-forest-residential-tower-lausanne-switzerland-designboom-01.jpg"); + add("https://cdn.pixabay.com/photo/2017/12/25/17/48/waters-3038803_1280.jpg"); } }; diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/common/data/model/Dialog.java b/sample/src/main/java/com/stfalcon/chatkit/sample/common/data/model/Dialog.java index 36584756..7f239df6 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/common/data/model/Dialog.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/common/data/model/Dialog.java @@ -62,4 +62,8 @@ public void setLastMessage(Message lastMessage) { public int getUnreadCount() { return unreadCount; } + + public void setUnreadCount(int unreadCount) { + this.unreadCount = unreadCount; + } } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/DemoDialogsActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/DemoDialogsActivity.java index f2848ba8..51d649c3 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/DemoDialogsActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/DemoDialogsActivity.java @@ -1,9 +1,9 @@ package com.stfalcon.chatkit.sample.features.demo; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; -import android.widget.ImageView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import com.squareup.picasso.Picasso; import com.stfalcon.chatkit.commons.ImageLoader; @@ -25,12 +25,7 @@ public abstract class DemoDialogsActivity extends AppCompatActivity protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - imageLoader = new ImageLoader() { - @Override - public void loadImage(ImageView imageView, String url) { - Picasso.with(DemoDialogsActivity.this).load(url).into(imageView); - } - }; + imageLoader = (imageView, url, payload) -> Picasso.get().load(url).into(imageView); } @Override diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/DemoMessagesActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/DemoMessagesActivity.java index 0fedc8cf..5566a519 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/DemoMessagesActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/DemoMessagesActivity.java @@ -2,11 +2,12 @@ import android.os.Bundle; import android.os.Handler; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; -import android.widget.ImageView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; import com.squareup.picasso.Picasso; import com.stfalcon.chatkit.commons.ImageLoader; @@ -42,12 +43,7 @@ public abstract class DemoMessagesActivity extends AppCompatActivity protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - imageLoader = new ImageLoader() { - @Override - public void loadImage(ImageView imageView, String url) { - Picasso.with(DemoMessagesActivity.this).load(url).into(imageView); - } - }; + imageLoader = (imageView, url, payload) -> Picasso.get().load(url).into(imageView); } @Override @@ -89,6 +85,7 @@ public void onBackPressed() { @Override public void onLoadMore(int page, int totalItemsCount) { + Log.i("TAG", "onLoadMore: " + page + " " + totalItemsCount); if (totalItemsCount < TOTAL_MESSAGES_COUNT) { loadMessages(); } @@ -102,29 +99,24 @@ public void onSelectionChanged(int count) { } protected void loadMessages() { - new Handler().postDelayed(new Runnable() { //imitation of internet connection - @Override - public void run() { - ArrayList messages = MessagesFixtures.getMessages(lastLoadedDate); - lastLoadedDate = messages.get(messages.size() - 1).getCreatedAt(); - messagesAdapter.addToEnd(messages, false); - } + //imitation of internet connection + new Handler().postDelayed(() -> { + ArrayList messages = MessagesFixtures.getMessages(lastLoadedDate); + lastLoadedDate = messages.get(messages.size() - 1).getCreatedAt(); + messagesAdapter.addToEnd(messages, false); }, 1000); } private MessagesListAdapter.Formatter getMessageStringFormatter() { - return new MessagesListAdapter.Formatter() { - @Override - public String format(Message message) { - String createdAt = new SimpleDateFormat("MMM d, EEE 'at' h:mm a", Locale.getDefault()) - .format(message.getCreatedAt()); - - String text = message.getText(); - if (text == null) text = "[attachment]"; - - return String.format(Locale.getDefault(), "%s: %s (%s)", - message.getUser().getName(), text, createdAt); - } + return message -> { + String createdAt = new SimpleDateFormat("MMM d, EEE 'at' h:mm a", Locale.getDefault()) + .format(message.getCreatedAt()); + + String text = message.getText(); + if (text == null) text = "[attachment]"; + + return String.format(Locale.getDefault(), "%s: %s (%s)", + message.getUser().getName(), text, createdAt); }; } } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/CustomHolderDialogsActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/CustomHolderDialogsActivity.java index c08df41d..188aa038 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/CustomHolderDialogsActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/CustomHolderDialogsActivity.java @@ -25,7 +25,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_holder_dialogs); - dialogsList = (DialogsList) findViewById(R.id.dialogsList); + dialogsList = findViewById(R.id.dialogsList); initAdapter(); } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/CustomHolderMessagesActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/CustomHolderMessagesActivity.java index 6ec42903..0a59d16f 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/CustomHolderMessagesActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/CustomHolderMessagesActivity.java @@ -3,6 +3,7 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.widget.Toast; import com.stfalcon.chatkit.messages.MessageHolders; import com.stfalcon.chatkit.messages.MessageInput; @@ -34,10 +35,10 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_holder_messages); - messagesList = (MessagesList) findViewById(R.id.messagesList); + messagesList = findViewById(R.id.messagesList); initAdapter(); - MessageInput input = (MessageInput) findViewById(R.id.input); + MessageInput input = findViewById(R.id.input); input.setInputListener(this); input.setAttachmentsListener(this); } @@ -60,10 +61,18 @@ public void onMessageLongClick(Message message) { } private void initAdapter() { + + //We can pass any data to ViewHolder with payload + CustomIncomingTextMessageViewHolder.Payload payload = new CustomIncomingTextMessageViewHolder.Payload(); + //For example click listener + payload.avatarClickListener = () -> Toast.makeText(CustomHolderMessagesActivity.this, + "Text message avatar clicked", Toast.LENGTH_SHORT).show(); + MessageHolders holdersConfig = new MessageHolders() .setIncomingTextConfig( CustomIncomingTextMessageViewHolder.class, - R.layout.item_custom_incoming_text_message) + R.layout.item_custom_incoming_text_message, + payload) .setOutcomingTextConfig( CustomOutcomingTextMessageViewHolder.class, R.layout.item_custom_outcoming_text_message) diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomIncomingImageMessageViewHolder.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomIncomingImageMessageViewHolder.java index 47e9282a..124b4cc4 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomIncomingImageMessageViewHolder.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomIncomingImageMessageViewHolder.java @@ -14,8 +14,8 @@ public class CustomIncomingImageMessageViewHolder private View onlineIndicator; - public CustomIncomingImageMessageViewHolder(View itemView) { - super(itemView); + public CustomIncomingImageMessageViewHolder(View itemView, Object payload) { + super(itemView, payload); onlineIndicator = itemView.findViewById(R.id.onlineIndicator); } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomIncomingTextMessageViewHolder.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomIncomingTextMessageViewHolder.java index c4df3e95..fee813c1 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomIncomingTextMessageViewHolder.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomIncomingTextMessageViewHolder.java @@ -11,8 +11,8 @@ public class CustomIncomingTextMessageViewHolder private View onlineIndicator; - public CustomIncomingTextMessageViewHolder(View itemView) { - super(itemView); + public CustomIncomingTextMessageViewHolder(View itemView, Object payload) { + super(itemView, payload); onlineIndicator = itemView.findViewById(R.id.onlineIndicator); } @@ -26,5 +26,21 @@ public void onBind(Message message) { } else { onlineIndicator.setBackgroundResource(R.drawable.shape_bubble_offline); } + + //We can set click listener on view from payload + final Payload payload = (Payload) this.payload; + userAvatar.setOnClickListener(view -> { + if (payload != null && payload.avatarClickListener != null) { + payload.avatarClickListener.onAvatarClick(); + } + }); + } + + public static class Payload { + public OnAvatarClickListener avatarClickListener; + } + + public interface OnAvatarClickListener { + void onAvatarClick(); } } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomOutcomingImageMessageViewHolder.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomOutcomingImageMessageViewHolder.java index 36a22359..484ce026 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomOutcomingImageMessageViewHolder.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomOutcomingImageMessageViewHolder.java @@ -1,5 +1,6 @@ package com.stfalcon.chatkit.sample.features.demo.custom.holder.holders.messages; +import android.util.Pair; import android.view.View; import com.stfalcon.chatkit.messages.MessageHolders; @@ -11,8 +12,8 @@ public class CustomOutcomingImageMessageViewHolder extends MessageHolders.OutcomingImageMessageViewHolder { - public CustomOutcomingImageMessageViewHolder(View itemView) { - super(itemView); + public CustomOutcomingImageMessageViewHolder(View itemView, Object payload) { + super(itemView, payload); } @Override @@ -21,4 +22,11 @@ public void onBind(Message message) { time.setText(message.getStatus() + " " + time.getText()); } + + //Override this method to have ability to pass custom data in ImageLoader for loading image(not avatar). + @Override + protected Object getPayloadForImageLoader(Message message) { + //For example you can pass size of placeholder before loading + return new Pair<>(100, 100); + } } \ No newline at end of file diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomOutcomingTextMessageViewHolder.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomOutcomingTextMessageViewHolder.java index 81c319d2..aa3a445b 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomOutcomingTextMessageViewHolder.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/holder/holders/messages/CustomOutcomingTextMessageViewHolder.java @@ -8,8 +8,8 @@ public class CustomOutcomingTextMessageViewHolder extends MessageHolders.OutcomingTextMessageViewHolder { - public CustomOutcomingTextMessageViewHolder(View itemView) { - super(itemView); + public CustomOutcomingTextMessageViewHolder(View itemView, Object payload) { + super(itemView, payload); } @Override diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/layout/CustomLayoutDialogsActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/layout/CustomLayoutDialogsActivity.java index b8bddf84..faaea0b3 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/layout/CustomLayoutDialogsActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/layout/CustomLayoutDialogsActivity.java @@ -24,7 +24,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_layout_dialogs); - dialogsList = (DialogsList) findViewById(R.id.dialogsList); + dialogsList = findViewById(R.id.dialogsList); initAdapter(); } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/layout/CustomLayoutMessagesActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/layout/CustomLayoutMessagesActivity.java index d7d7c14f..12e7749b 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/layout/CustomLayoutMessagesActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/layout/CustomLayoutMessagesActivity.java @@ -30,10 +30,10 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_layout_messages); - messagesList = (MessagesList) findViewById(R.id.messagesList); + messagesList = findViewById(R.id.messagesList); initAdapter(); - MessageInput input = (MessageInput) findViewById(R.id.input); + MessageInput input = findViewById(R.id.input); input.setInputListener(this); input.setAttachmentsListener(this); } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/CustomMediaMessagesActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/CustomMediaMessagesActivity.java index 7f3ae57f..caf47d13 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/CustomMediaMessagesActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/CustomMediaMessagesActivity.java @@ -36,10 +36,10 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_media_messages); - this.messagesList = (MessagesList) findViewById(R.id.messagesList); + this.messagesList = findViewById(R.id.messagesList); initAdapter(); - MessageInput input = (MessageInput) findViewById(R.id.input); + MessageInput input = findViewById(R.id.input); input.setInputListener(this); input.setAttachmentsListener(this); } @@ -60,11 +60,10 @@ public void onAddAttachments() { @Override public boolean hasContentFor(Message message, byte type) { - switch (type) { - case CONTENT_TYPE_VOICE: - return message.getVoice() != null - && message.getVoice().getUrl() != null - && !message.getVoice().getUrl().isEmpty(); + if (type == CONTENT_TYPE_VOICE) { + return message.getVoice() != null + && message.getVoice().getUrl() != null + && !message.getVoice().getUrl().isEmpty(); } return false; } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/holders/IncomingVoiceMessageViewHolder.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/holders/IncomingVoiceMessageViewHolder.java index c87e395f..bdacb34a 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/holders/IncomingVoiceMessageViewHolder.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/holders/IncomingVoiceMessageViewHolder.java @@ -18,10 +18,10 @@ public class IncomingVoiceMessageViewHolder private TextView tvDuration; private TextView tvTime; - public IncomingVoiceMessageViewHolder(View itemView) { - super(itemView); - tvDuration = (TextView) itemView.findViewById(R.id.duration); - tvTime = (TextView) itemView.findViewById(R.id.time); + public IncomingVoiceMessageViewHolder(View itemView, Object payload) { + super(itemView, payload); + tvDuration = itemView.findViewById(R.id.duration); + tvTime = itemView.findViewById(R.id.time); } @Override diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/holders/OutcomingVoiceMessageViewHolder.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/holders/OutcomingVoiceMessageViewHolder.java index 556e1fcf..b21db7d7 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/holders/OutcomingVoiceMessageViewHolder.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/custom/media/holders/OutcomingVoiceMessageViewHolder.java @@ -18,10 +18,10 @@ public class OutcomingVoiceMessageViewHolder private TextView tvDuration; private TextView tvTime; - public OutcomingVoiceMessageViewHolder(View itemView) { - super(itemView); - tvDuration = (TextView) itemView.findViewById(R.id.duration); - tvTime = (TextView) itemView.findViewById(R.id.time); + public OutcomingVoiceMessageViewHolder(View itemView, Object payload) { + super(itemView, payload); + tvDuration = itemView.findViewById(R.id.duration); + tvTime = itemView.findViewById(R.id.time); } @Override diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/def/DefaultDialogsActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/def/DefaultDialogsActivity.java index b9cf7444..c88a3771 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/def/DefaultDialogsActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/def/DefaultDialogsActivity.java @@ -12,12 +12,8 @@ import com.stfalcon.chatkit.sample.common.data.model.Message; import com.stfalcon.chatkit.sample.features.demo.DemoDialogsActivity; -import java.util.ArrayList; - public class DefaultDialogsActivity extends DemoDialogsActivity { - private ArrayList dialogs; - public static void open(Context context) { context.startActivity(new Intent(context, DefaultDialogsActivity.class)); } @@ -29,7 +25,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_default_dialogs); - dialogsList = (DialogsList) findViewById(R.id.dialogsList); + dialogsList = findViewById(R.id.dialogsList); initAdapter(); } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/def/DefaultMessagesActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/def/DefaultMessagesActivity.java index 0dcb32f7..a74bca89 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/def/DefaultMessagesActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/def/DefaultMessagesActivity.java @@ -3,6 +3,7 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.util.Log; import com.stfalcon.chatkit.messages.MessageInput; import com.stfalcon.chatkit.messages.MessagesList; @@ -10,10 +11,12 @@ import com.stfalcon.chatkit.sample.R; import com.stfalcon.chatkit.sample.common.data.fixtures.MessagesFixtures; import com.stfalcon.chatkit.sample.features.demo.DemoMessagesActivity; +import com.stfalcon.chatkit.sample.utils.AppUtils; public class DefaultMessagesActivity extends DemoMessagesActivity implements MessageInput.InputListener, - MessageInput.AttachmentsListener { + MessageInput.AttachmentsListener, + MessageInput.TypingListener { public static void open(Context context) { context.startActivity(new Intent(context, DefaultMessagesActivity.class)); @@ -26,11 +29,13 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_default_messages); - this.messagesList = (MessagesList) findViewById(R.id.messagesList); + this.messagesList = findViewById(R.id.messagesList); initAdapter(); - MessageInput input = (MessageInput) findViewById(R.id.input); + MessageInput input = findViewById(R.id.input); input.setInputListener(this); + input.setTypingListener(this); + input.setAttachmentsListener(this); } @Override @@ -50,6 +55,20 @@ private void initAdapter() { super.messagesAdapter = new MessagesListAdapter<>(super.senderId, super.imageLoader); super.messagesAdapter.enableSelectionMode(this); super.messagesAdapter.setLoadMoreListener(this); + super.messagesAdapter.registerViewClickListener(R.id.messageUserAvatar, + (view, message) -> AppUtils.showToast(DefaultMessagesActivity.this, + message.getUser().getName() + " avatar click", + false)); this.messagesList.setAdapter(super.messagesAdapter); } + + @Override + public void onStartTyping() { + Log.v("Typing listener", getString(R.string.start_typing_status)); + } + + @Override + public void onStopTyping() { + Log.v("Typing listener", getString(R.string.stop_typing_status)); + } } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/styled/StyledDialogsActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/styled/StyledDialogsActivity.java index 1d8d2865..eb0acc9d 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/styled/StyledDialogsActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/styled/StyledDialogsActivity.java @@ -28,7 +28,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_styled_dialogs); - dialogsList = (DialogsList) findViewById(R.id.dialogsList); + dialogsList = findViewById(R.id.dialogsList); initAdapter(); } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/styled/StyledMessagesActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/styled/StyledMessagesActivity.java index ba01566a..e97ecec0 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/styled/StyledMessagesActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/demo/styled/StyledMessagesActivity.java @@ -30,10 +30,10 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_styled_messages); - messagesList = (MessagesList) findViewById(R.id.messagesList); + messagesList = findViewById(R.id.messagesList); initAdapter(); - MessageInput input = (MessageInput) findViewById(R.id.input); + MessageInput input = findViewById(R.id.input); input.setInputListener(this); input.setAttachmentsListener(this); } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/MainActivity.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/MainActivity.java index 8a49e160..b05896ce 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/MainActivity.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/MainActivity.java @@ -1,8 +1,9 @@ package com.stfalcon.chatkit.sample.features.main; import android.os.Bundle; -import android.support.v4.view.ViewPager; -import android.support.v7.app.AppCompatActivity; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.viewpager.widget.ViewPager; import com.stfalcon.chatkit.sample.R; import com.stfalcon.chatkit.sample.features.demo.custom.holder.CustomHolderDialogsActivity; @@ -26,12 +27,12 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - ViewPager pager = (ViewPager) findViewById(R.id.pager); + ViewPager pager = findViewById(R.id.pager); pager.setAdapter(new MainActivityPagerAdapter(this, getSupportFragmentManager())); pager.setPageMargin((int) getResources().getDimension(R.dimen.card_padding) / 4); pager.setOffscreenPageLimit(3); - CircleIndicator indicator = (CircleIndicator) findViewById(R.id.indicator); + CircleIndicator indicator = findViewById(R.id.indicator); indicator.setViewPager(pager); } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/adapter/DemoCardFragment.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/adapter/DemoCardFragment.java index 8d4054fd..c8779198 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/adapter/DemoCardFragment.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/adapter/DemoCardFragment.java @@ -2,13 +2,14 @@ import android.content.Context; import android.os.Bundle; -import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; +import androidx.fragment.app.Fragment; + import com.stfalcon.chatkit.sample.R; /* @@ -54,9 +55,9 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_demo_card, container, false); - TextView tvTitle = (TextView) v.findViewById(R.id.tvTitle); - TextView tvDescription = (TextView) v.findViewById(R.id.tvDescription); - Button button = (Button) v.findViewById(R.id.button); + TextView tvTitle = v.findViewById(R.id.tvTitle); + TextView tvDescription = v.findViewById(R.id.tvDescription); + Button button = v.findViewById(R.id.button); tvTitle.setText(title); tvDescription.setText(description); @@ -67,10 +68,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, @Override public void onClick(View view) { - switch (view.getId()) { - case R.id.button: - onAction(); - break; + if (view.getId() == R.id.button) { + onAction(); } } diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/adapter/MainActivityPagerAdapter.java b/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/adapter/MainActivityPagerAdapter.java index bfab5867..09f9d842 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/adapter/MainActivityPagerAdapter.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/features/main/adapter/MainActivityPagerAdapter.java @@ -1,9 +1,10 @@ package com.stfalcon.chatkit.sample.features.main.adapter; import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentStatePagerAdapter; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentStatePagerAdapter; import com.stfalcon.chatkit.sample.R; @@ -18,10 +19,10 @@ public class MainActivityPagerAdapter extends FragmentStatePagerAdapter { public static final int ID_CUSTOM_VIEW_HOLDER = 3; public static final int ID_CUSTOM_CONTENT = 4; - private Context context; + private final Context context; public MainActivityPagerAdapter(Context context, FragmentManager fm) { - super(fm); + super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); this.context = context; } @@ -58,4 +59,4 @@ public Fragment getItem(int position) { public int getCount() { return 5; } -} \ No newline at end of file +} diff --git a/sample/src/main/java/com/stfalcon/chatkit/sample/utils/AppUtils.java b/sample/src/main/java/com/stfalcon/chatkit/sample/utils/AppUtils.java index 8c914dfd..ca49edef 100644 --- a/sample/src/main/java/com/stfalcon/chatkit/sample/utils/AppUtils.java +++ b/sample/src/main/java/com/stfalcon/chatkit/sample/utils/AppUtils.java @@ -1,9 +1,10 @@ package com.stfalcon.chatkit.sample.utils; import android.content.Context; -import android.support.annotation.StringRes; import android.widget.Toast; +import androidx.annotation.StringRes; + /* * Created by troy379 on 04.04.17. */ diff --git a/sample/src/main/res/drawable/dark_blue_top_gradient.xml b/sample/src/main/res/drawable/dark_blue_top_gradient.xml index fbfded4c..06162093 100644 --- a/sample/src/main/res/drawable/dark_blue_top_gradient.xml +++ b/sample/src/main/res/drawable/dark_blue_top_gradient.xml @@ -1,9 +1,9 @@ + android:shape="rectangle"> + android:startColor="@color/cornflower_blue_darkest" /> \ No newline at end of file diff --git a/sample/src/main/res/drawable/ic_play_black.xml b/sample/src/main/res/drawable/ic_play_black.xml index fd5de4d8..1a348327 100644 --- a/sample/src/main/res/drawable/ic_play_black.xml +++ b/sample/src/main/res/drawable/ic_play_black.xml @@ -1,5 +1,4 @@ - + android:pathData="M3,1.5v14l11,-7z" /> diff --git a/sample/src/main/res/drawable/ic_play_white.xml b/sample/src/main/res/drawable/ic_play_white.xml index cf96f070..4196f11a 100644 --- a/sample/src/main/res/drawable/ic_play_white.xml +++ b/sample/src/main/res/drawable/ic_play_white.xml @@ -1,5 +1,4 @@ - + android:pathData="M3,1.5v14l11,-7z" /> diff --git a/sample/src/main/res/drawable/shape_bubble_offline.xml b/sample/src/main/res/drawable/shape_bubble_offline.xml index d1cc3c34..219d82d1 100644 --- a/sample/src/main/res/drawable/shape_bubble_offline.xml +++ b/sample/src/main/res/drawable/shape_bubble_offline.xml @@ -1,13 +1,13 @@ + android:shape="oval"> - + + android:color="@color/white" /> + android:height="20dp" /> \ No newline at end of file diff --git a/sample/src/main/res/drawable/shape_bubble_online.xml b/sample/src/main/res/drawable/shape_bubble_online.xml index 9b1bbe94..2b5f2386 100644 --- a/sample/src/main/res/drawable/shape_bubble_online.xml +++ b/sample/src/main/res/drawable/shape_bubble_online.xml @@ -1,13 +1,13 @@ + android:shape="oval"> - + + android:color="@color/white" /> + android:height="20dp" /> \ No newline at end of file diff --git a/sample/src/main/res/drawable/shape_custom_cursor.xml b/sample/src/main/res/drawable/shape_custom_cursor.xml index c60888f9..ece0b260 100644 --- a/sample/src/main/res/drawable/shape_custom_cursor.xml +++ b/sample/src/main/res/drawable/shape_custom_cursor.xml @@ -1,8 +1,8 @@ + android:shape="rectangle"> - + - + \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_custom_holder_dialogs.xml b/sample/src/main/res/layout/activity_custom_holder_dialogs.xml index 81eb8ecd..0359eb85 100644 --- a/sample/src/main/res/layout/activity_custom_holder_dialogs.xml +++ b/sample/src/main/res/layout/activity_custom_holder_dialogs.xml @@ -1,5 +1,4 @@ - + app:dialogUnreadTitleTextStyle="bold" /> diff --git a/sample/src/main/res/layout/activity_custom_holder_messages.xml b/sample/src/main/res/layout/activity_custom_holder_messages.xml index 88c6d1cc..723bca6c 100644 --- a/sample/src/main/res/layout/activity_custom_holder_messages.xml +++ b/sample/src/main/res/layout/activity_custom_holder_messages.xml @@ -1,5 +1,4 @@ - + app:outcomingTimeTextColor="@color/gray_dark_transparent" /> + android:background="@color/gray_light" /> + app:showAttachmentButton="true" /> \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_custom_layout_dialogs.xml b/sample/src/main/res/layout/activity_custom_layout_dialogs.xml index 81eb8ecd..0359eb85 100644 --- a/sample/src/main/res/layout/activity_custom_layout_dialogs.xml +++ b/sample/src/main/res/layout/activity_custom_layout_dialogs.xml @@ -1,5 +1,4 @@ - + app:dialogUnreadTitleTextStyle="bold" /> diff --git a/sample/src/main/res/layout/activity_custom_layout_messages.xml b/sample/src/main/res/layout/activity_custom_layout_messages.xml index 88c6d1cc..723bca6c 100644 --- a/sample/src/main/res/layout/activity_custom_layout_messages.xml +++ b/sample/src/main/res/layout/activity_custom_layout_messages.xml @@ -1,5 +1,4 @@ - + app:outcomingTimeTextColor="@color/gray_dark_transparent" /> + android:background="@color/gray_light" /> + app:showAttachmentButton="true" /> \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_custom_media_messages.xml b/sample/src/main/res/layout/activity_custom_media_messages.xml index 9ce4da57..85e7db97 100644 --- a/sample/src/main/res/layout/activity_custom_media_messages.xml +++ b/sample/src/main/res/layout/activity_custom_media_messages.xml @@ -1,5 +1,4 @@ - + android:layout_above="@+id/input" /> + android:background="@color/gray_light" /> + app:showAttachmentButton="true" /> \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_default_dialogs.xml b/sample/src/main/res/layout/activity_default_dialogs.xml index bb5e9436..a14ac43c 100644 --- a/sample/src/main/res/layout/activity_default_dialogs.xml +++ b/sample/src/main/res/layout/activity_default_dialogs.xml @@ -1,5 +1,4 @@ - @@ -7,6 +6,6 @@ + android:layout_height="match_parent" /> diff --git a/sample/src/main/res/layout/activity_default_messages.xml b/sample/src/main/res/layout/activity_default_messages.xml index 9ce4da57..85e7db97 100644 --- a/sample/src/main/res/layout/activity_default_messages.xml +++ b/sample/src/main/res/layout/activity_default_messages.xml @@ -1,5 +1,4 @@ - + android:layout_above="@+id/input" /> + android:background="@color/gray_light" /> + app:showAttachmentButton="true" /> \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index a831f0b8..a84a40bf 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -1,5 +1,4 @@ - @@ -8,7 +7,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/dark_blue_top_gradient" - android:fitsSystemWindows="true"/> + android:fitsSystemWindows="true" /> + android:textSize="28sp" /> - + android:paddingRight="@dimen/card_padding" + android:paddingBottom="20dp" /> + android:layout_alignParentBottom="true" /> - \ No newline at end of file + \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_styled_dialogs.xml b/sample/src/main/res/layout/activity_styled_dialogs.xml index 81eb8ecd..0359eb85 100644 --- a/sample/src/main/res/layout/activity_styled_dialogs.xml +++ b/sample/src/main/res/layout/activity_styled_dialogs.xml @@ -1,5 +1,4 @@ - + app:dialogUnreadTitleTextStyle="bold" /> diff --git a/sample/src/main/res/layout/activity_styled_messages.xml b/sample/src/main/res/layout/activity_styled_messages.xml index 62e217d3..9e2111d2 100644 --- a/sample/src/main/res/layout/activity_styled_messages.xml +++ b/sample/src/main/res/layout/activity_styled_messages.xml @@ -1,5 +1,4 @@ - + app:textAutoLink="all" /> + android:background="@color/gray_light" /> + app:showAttachmentButton="true" /> \ No newline at end of file diff --git a/sample/src/main/res/layout/fragment_demo_card.xml b/sample/src/main/res/layout/fragment_demo_card.xml index 87290af0..11841c1a 100644 --- a/sample/src/main/res/layout/fragment_demo_card.xml +++ b/sample/src/main/res/layout/fragment_demo_card.xml @@ -1,5 +1,4 @@ - + android:textSize="22sp" /> + android:textSize="15sp" />