Android Kotlin Pusher Chatkit not loading all rooms in recycler view - android

I'm trying to view all already joined rooms in pusher chatkit recycler view however it doesn't seem to be working. It only loads one room after I scroll. When I open the activity, it shows blank. Also, when I click on the room, the intent isn't started, it just stays on the recycler view. It should be going to the selected chat room.
Through Debug, I'm able to see that I am connecting to the accessible rooms(there's 7 of them) however it only seems like one of them is being added to the adapter/recyclerview however I can't find where it is falling short. I am relatively new to kotlin which probably adds to the issue.
Here is the tutorial I am following which I thought would be relatively good to go out of the box but it seems there are some snags.
any and all help is appreciated.
ChatRoomsListActivity
class ChatRoomsListActivity : AppCompatActivity() {
val adapter = ChatRoomsListAdapter();
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat_room_list)
initRecyclerView()
initChatManager()
}
private fun initRecyclerView() {
recycler_view.layoutManager = LinearLayoutManager(this#ChatRoomsListActivity)
recycler_view.adapter = adapter
/*
recycler_view.apply {
val topSpacingDecorator = TopSpacingItemDecoration(30)
addItemDecoration(topSpacingDecorator)
recycler_view.layoutManager = LinearLayoutManager(this#ChatRoomsListActivity)
recycler_view.adapter = adapter
adapter = ChatRoomsListAdapter();
adapter = adapter
}
*/
}
private fun initChatManager() {
val chatManager = ChatManager(
instanceLocator = "xxxxxxxxxxxxxx",
userId = "username1-PCKid",
dependencies = AndroidChatkitDependencies(
tokenProvider = ChatkitTokenProvider(
endpoint = "yyyyyyyyyyyyyyyyyyy",
// endpoint = "http://10.0.2.2:3000/auth",
userId = "username1-PCKid"
)
)
)
chatManager.connect(listeners = ChatListeners(
onErrorOccurred = { },
onAddedToRoom = { },
onRemovedFromRoom = { },
onCurrentUserReceived = { },
onNewReadCursor = { },
onRoomDeleted = { },
onRoomUpdated = { },
onPresenceChanged = { u, n, p -> },
onUserJoinedRoom = { u, r -> },
onUserLeftRoom = { u, r -> },
onUserStartedTyping = { u, r -> },
onUserStoppedTyping = { u, r -> }
)) { result ->
when (result) {
is Result.Success -> {
// We have connected!
val currentUser = result.value
AppController.currentUser = currentUser
val userJoinedRooms = ArrayList<Room>(currentUser.rooms)
for (i in 0 until userJoinedRooms.size) {
adapter.addRoom(userJoinedRooms[i]) // reads users rooms
}
currentUser.getJoinableRooms { result ->
when (result) {
is Result.Success -> {
// Do something with List<Room>
val rooms = result.value
runOnUiThread {
for (i in 0 until rooms.size) {
adapter.addRoom(rooms[i])
}
}
}
}
}
adapter.setInterface(object : ChatRoomsListAdapter.RoomClickedInterface {
override fun roomSelected(room: Room) {
if (room.memberUserIds.contains(currentUser.id)) {
// user already belongs to this room
roomJoined(room)
Log.d("roomSelected", "user already belongs to this room: " + roomJoined(room))
} else {
currentUser.joinRoom(
roomId = room.id,
callback = { result ->
when (result) {
is Result.Success -> {
// Joined the room!
roomJoined(result.value)
}
is Result.Failure -> {
Log.d("TAG", result.error.toString())
}
}
}
)
}
}
})
}
is Result.Failure -> {
// Failure
Log.d("TAG", result.error.toString())
}
}
}
}
private fun roomJoined(room: Room) {
val intent = Intent(this#ChatRoomsListActivity, ChatRoomActivity::class.java)
intent.putExtra("room_id", room.id)
intent.putExtra("room_name", room.name)
startActivity(intent)
}
}
ChatRoomsListAdapter
class ChatRoomsListAdapter: RecyclerView.Adapter<ChatRoomsListAdapter.ViewHolder>() {
private var list = ArrayList<Room>()
private var roomClickedInterface: RoomClickedInterface? = null
// lateinit var roomClickedInterface:RoomClickedInterface
fun addRoom(room:Room){
list.add(room)
notifyDataSetChanged()
// Log.d("Rooms", room.toString())
}
fun setInterface(roomClickedInterface:RoomClickedInterface){
this.roomClickedInterface = roomClickedInterface
// roomClickedInterface = roomClickedInterface
}
override fun getItemCount(): Int {
return list.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(
// R.layout.chat_list_row,
android.R.layout.simple_list_item_1,
parent,
false
)
return ViewHolder(view)
}
/*
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent!!.context)
.inflate(
android.R.layout.simple_list_item_1,
parent,
false
)
return ViewHolder(view)
}
*/
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.roomName.text = list[position].name
}
/*
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
holder!!.roomName.text = list[position].name
}
*/
inner class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView), View.OnClickListener {
override fun onClick(p0: View?) {
roomClickedInterface?.roomSelected(list[adapterPosition])
Toast.makeText(itemView.context, "hello test", Toast.LENGTH_LONG).show();
Log.d("test", "testing console log")
}
var roomName: TextView = itemView.findViewById(android.R.id.text1)
init {
itemView.setOnClickListener(this)
}
}
interface RoomClickedInterface{
fun roomSelected(room:Room)
}
}
Rooms that should be shown in Recyclerview
1)
2)
this is what it looks like after i scroll any direction
3)

You need to ensure you are calling adapter.notifyDataSetChanged(). So change
currentUser.getJoinableRooms { result ->
when (result) {
is Result.Success -> {
// Do something with List<Room>
val rooms = result.value
runOnUiThread {
for (i in 0 until rooms.size) {
adapter.addRoom(rooms[i])
}
}
}
}
to
currentUser.getJoinableRooms { result ->
when (result) {
is Result.Success -> {
// Do something with List<Room>
val rooms = result.value
runOnUiThread {
for (i in 0 until rooms.size) {
adapter.addRoom(rooms[i])
}
adapter.notifyDataSetChanged()
}
}
}

Related

Search Query in android studio(kotlin)

I'm currently following a news app tutorial and I have a problem. When I type in a keyword in the edit text widget, articles related to that keyword shows up in the recycler view but when I erase that keyword to type in another keyword, the articles (in the recycler view) from the previous search query doesn't update and even when I exit the search fragment and open it again,The recycler view remains stagnant instead of disappearing. Can anyone please take a look at my code and let me know what I've done wrong. Thanks in advance.
Here is my code:
Search Fragment
`class SearchNewsFragment : Fragment(R.layout.fragment_search_news) {
lateinit var viewModel: NewsViewModel
lateinit var newsAdapter: NewsAdapter
val TAG = "SearchNewsFragment"
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = (activity as NewsActivity).viewModel
setupRecyclerView()
newsAdapter.setOnItemClickListener {
val bundle = Bundle().apply {
putSerializable("article", it)
}
findNavController().navigate(
R.id.action_searchNewsFragment_to_articleFragment,
bundle
)
}
var job: Job? = null
etSearch.addTextChangedListener { editable ->
job?.cancel()
job = MainScope().launch {
delay(SEARCH_NEWS_TIME_DELAY)
editable?.let {
if(editable.toString().isNotEmpty()) {
viewModel.searchNews(editable.toString())
}
}
}
}
viewModel.searchNews.observe(viewLifecycleOwner, Observer { response ->
when(response) {
is Resource.Success -> {
hideProgressBar()
hideErrorMessage()
response.data?.let { newsResponse ->
newsAdapter.differ.submitList(newsResponse.articles.toList())
val totalPages = newsResponse.totalResults / Constants.QUERY_PAGE_SIZE + 2
isLastPage = viewModel.searchNewsPage == totalPages
if(isLastPage) {
rvSearchNews.setPadding(0, 0, 0, 0)
}
}
}
is Resource.Error -> {
hideProgressBar()
response.message?.let { message ->
Toast.makeText(activity, "An error occured: $message", Toast.LENGTH_LONG).show()
showErrorMessage(message)
}
}
is Resource.Loading -> {
showProgressBar()
}
}
})
btnRetry.setOnClickListener {
if (etSearch.text.toString().isNotEmpty()) {
viewModel.searchNews(etSearch.text.toString())
} else {
hideErrorMessage()
}
}
}
private fun hideProgressBar() {
paginationProgressBar.visibility = View.INVISIBLE
isLoading = false
}
private fun showProgressBar() {
paginationProgressBar.visibility = View.VISIBLE
isLoading = true
}
private fun hideErrorMessage() {
itemErrorMessage.visibility = View.INVISIBLE
isError = false
}
private fun showErrorMessage(message: String) {
itemErrorMessage.visibility = View.VISIBLE
tvErrorMessage.text = message
isError = true
}
var isError = false
var isLoading = false
var isLastPage = false
var isScrolling = false
val scrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
val visibleItemCount = layoutManager.childCount
val totalItemCount = layoutManager.itemCount
val isNoErrors = !isError
val isNotLoadingAndNotLastPage = !isLoading && !isLastPage
val isAtLastItem = firstVisibleItemPosition + visibleItemCount >= totalItemCount
val isNotAtBeginning = firstVisibleItemPosition >= 0
val isTotalMoreThanVisible = totalItemCount >= Constants.QUERY_PAGE_SIZE
val shouldPaginate = isNoErrors && isNotLoadingAndNotLastPage && isAtLastItem && isNotAtBeginning &&
isTotalMoreThanVisible && isScrolling
if(shouldPaginate) {
viewModel.searchNews(etSearch.text.toString())
isScrolling = false
}
}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if(newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
isScrolling = true
}
}
}
private fun setupRecyclerView() {
newsAdapter = NewsAdapter()
rvSearchNews.apply {
adapter = newsAdapter
layoutManager = LinearLayoutManager(activity)
addOnScrollListener(this#SearchNewsFragment.scrollListener)
}
}
}`
SearchNewsAdapter
`class SearchNewsAdapter : RecyclerView.Adapter<SearchNewsAdapter.ArticleViewHolder>() {
// Inner class for viewHolder
inner class ArticleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
private val differCallback = object : DiffUtil.ItemCallback<Article>(){
override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem.url== newItem.url
}
override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, differCallback)
//recyclerViewFunction
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
return ArticleViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.search_article_preview,parent, false)
)
}
override fun getItemCount(): Int {
return differ.currentList.size
}
override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
val article = differ.currentList[position]
holder.itemView.apply{
// Glide.with(this).load(article.urlToImage).into(ivArticleImage)
searchTitle.text = article.title
setOnClickListener{
onItemClickListener?.let{
it(article)
}
}
}
}
//item click listener to single article so that article fragment opens up the webview that shows our items
private var onItemClickListener: ((Article) -> Unit)? = null
fun setOnItemClickListener(listener:(Article) -> Unit){
onItemClickListener = listener
}
}`
NewsViewModel
`class NewsViewModel(
app: Application,
val newsRepository: NewsRepository
) : AndroidViewModel(app) {
val breakingNews: MutableLiveData<Resource<NewsResponse>> = MutableLiveData()
var breakingNewsPage = 1
var breakingNewsResponse: NewsResponse? = null
val searchNews: MutableLiveData<Resource<NewsResponse>> = MutableLiveData()
var searchNewsPage = 1
var searchNewsResponse: NewsResponse? = null
var newSearchQuery:String? = null
var oldSearchQuery:String? = null
init {
getBreakingNews("us")
}
fun getBreakingNews(countryCode: String) = viewModelScope.launch {
safeBreakingNewsCall(countryCode)
}
fun searchNews(searchQuery: String) = viewModelScope.launch {
safeSearchNewsCall(searchQuery)
}
private fun handleBreakingNewsResponse(response: Response<NewsResponse>) : Resource<NewsResponse> {
if(response.isSuccessful) {
response.body()?.let { resultResponse ->
breakingNewsPage++
if(breakingNewsResponse == null) {
breakingNewsResponse = resultResponse
} else {
val oldArticles = breakingNewsResponse?.articles
val newArticles = resultResponse.articles
oldArticles?.addAll(newArticles)
}
return Resource.Success(breakingNewsResponse ?: resultResponse)
}
}
return Resource.Error(response.message())
}
private fun handleSearchNewsResponse(response: Response<NewsResponse>) : Resource<NewsResponse> {
if(response.isSuccessful) {
response.body()?.let { resultResponse ->
if(searchNewsResponse == null || newSearchQuery != oldSearchQuery) {
searchNewsPage = 1
oldSearchQuery = newSearchQuery
searchNewsResponse = resultResponse
} else {
searchNewsPage++
val oldArticles = searchNewsResponse?.articles
val newArticles = resultResponse.articles
oldArticles?.addAll(newArticles)
}
return Resource.Success(searchNewsResponse ?: resultResponse)
}
}
return Resource.Error(response.message())
}
fun saveArticle(article: Article) = viewModelScope.launch {
newsRepository.upsert(article)
}
fun getSavedNews() = newsRepository.getSavedNews()
fun deleteArticle(article: Article) = viewModelScope.launch {
newsRepository.deleteArticle(article)
}
private suspend fun safeSearchNewsCall(searchQuery: String) {
newSearchQuery = searchQuery
searchNews.postValue(Resource.Loading())
try {
if(hasInternetConnection()) {
val response = newsRepository.searchNews(searchQuery, searchNewsPage)
searchNews.postValue(handleSearchNewsResponse(response))
} else {
searchNews.postValue(Resource.Error("No internet connection"))
}
} catch(t: Throwable) {
when(t) {
is IOException -> searchNews.postValue(Resource.Error("Network Failure"))
else -> searchNews.postValue(Resource.Error("Conversion Error"))
}
}
}
private suspend fun safeBreakingNewsCall(countryCode: String) {
breakingNews.postValue(Resource.Loading())
try {
if(hasInternetConnection()) {
val response = newsRepository.getBreakingNews(countryCode, breakingNewsPage)
breakingNews.postValue(handleBreakingNewsResponse(response))
} else {
breakingNews.postValue(Resource.Error("No internet connection"))
}
} catch(t: Throwable) {
when(t) {
is IOException -> breakingNews.postValue(Resource.Error("Network Failure"))
else -> breakingNews.postValue(Resource.Error("Conversion Error"))
}
}
}
private fun hasInternetConnection(): Boolean {
val connectivityManager = getApplication<NewsApplication>().getSystemService(
Context.CONNECTIVITY_SERVICE
) as ConnectivityManager
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val activeNetwork = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false
return when {
capabilities.hasTransport(TRANSPORT_WIFI) -> true
capabilities.hasTransport(TRANSPORT_CELLULAR) -> true
capabilities.hasTransport(TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
connectivityManager.activeNetworkInfo?.run {
return when(type) {
TYPE_WIFI -> true
TYPE_MOBILE -> true
TYPE_ETHERNET -> true
else -> false
}
}
}
return false
}
}
`
if(editable.toString().isNotEmpty()) { viewModel.searchNews(editable.toString()) }
this line of code prevent the empty query to be processed. So, when you delete everything from the edit text, it will do nothing, hence the result still the same.
even when I exit the search fragment and open it again,The recycler view remains stagnant instead of disappearing.
The search result is strored on NewsViewModel and because the ViewModel is initialized on the NewsActivity, it tied to the activity lifecycle. Even if you destroy the fragment, the search result (the whole ViewModel) will be kept because the activity is still alive. So, when you open back the search Fragment, the LiveData will give you the latest value.

Android Kotlin load only one more element to recyclerview problem

I want to load just one element with one scroll gesture. Now it is like one scroll gesture loads 1 or few new elements (depends on time of scroll gesture). As a solution I could do this gesture in shorter time than 500ms or make this postDelayed's delay longer but I guess there are better solutions for that. Do you have any ideas how to do that?
This app is written in MVP pattern. Here is my code:
CurrencyFragmentList.kt
private fun addScrollerListener() {
rvItem.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(_rvItem: RecyclerView, newState: Int) {
super.onScrollStateChanged(_rvItem, newState)
Log.e("scroll", isLoading.toString())
if (!isLoading) {
if (!_rvItem.canScrollVertically(1)) {
loadMore()
isLoading = true
}
}
}
})
}
private fun loadMore() {
showProgressDialog()
var numberOfDays = mainPresenter.getNumberOfMinusDays()
numberOfDays++
mainPresenter.saveNumberOfMinusDaysIntoSp(numberOfDays)
var dateMinusXDays = mainPresenter.currentDateMinusXDaysToStr(numberOfDays)
val nextLimit = listSize + 1
for (i in listSize until nextLimit) {
if (mainPresenter.checkIfSuchDateExistsinSp(dateMinusXDays)) {
Log.d("such date already exists in shared prefs", dateMinusXDays)
handler.postDelayed({
mainPresenter.processDateWithoutMakingACall(dateMinusXDays)
}, 500)
} else {
mainPresenter.makeACall(dateMinusXDays)
Log.d("retrofit call made", dateMinusXDays)
}
}
itemAdapter.notifyDataSetChanged()
}
override fun hideProgressDialog() {
if (apiResponseList.size > 1) {
apiResponseList.removeAt(apiResponseList.size - 1)
listSize = apiResponseList.size
itemAdapter.notifyItemRemoved(listSize)
} else progress_bar.visibility = View.GONE
isLoading = false
}
override fun assignResponseToRecyclerview(apiResponse: ApiResponse?) {
rvItem.apply {
layoutManager = _layoutManager
apiResponseList.add(apiResponse!!)
itemAdapter = activity?.let { ItemAdapter(apiResponseList, it) }!!
adapter = itemAdapter
}
Log.e("assign", isLoading.toString())
}
MainPresenter.kt
override fun makeACall(date: String?) {
//view.showProgressDialog()
date?.let { restModel.fetchApiResponse(this, it) }
}
fun processDateWithoutMakingACall(date: String) {
val apiResponse = processRawJson(sp.getString(date, "").toString())
passResponseToView(apiResponse)
}
override fun processRawJson(rawJson: String): ApiResponse {
val parser = JsonParser()
val rootObj = parser.parse(rawJson).asJsonObject
var ratesObj = JsonObject()
var ratesKeys: Set<String> = HashSet()
val ratesArrayList: ArrayList<Currency> = ArrayList()
val rootKeys = rootObj.keySet();
var baseValue = ""
var dateValue = ""
for (key in rootKeys) {
if (key == "base")
baseValue = rootObj.get(key).asString
if (key == "date")
dateValue = rootObj.get(key).asString
if (key == "rates") {
ratesObj = rootObj.get(key).asJsonObject
ratesKeys = ratesObj.keySet()
}
}
for (key2 in ratesKeys) {
Log.e("ratesKey", key2)
Log.e("ratesValue", ratesObj.get(key2).asFloat.toString())
ratesArrayList.add(Currency(key2, ratesObj.get(key2).asFloat))
}
saveRawJsonIntoSp(rawJson, dateValue)
return ApiResponse(baseValue, dateValue, ratesArrayList, false)
}
override fun passResponseToView(apiResponse: ApiResponse?) {
view.hideProgressDialog()
view.assignResponseToRecyclerview(apiResponse)
}
RestModel.kt
override fun fetchApiResponse(presenter: MainPresenter, date: String) {
job = CoroutineScope(Dispatchers.IO).launch {
val response = userService.getCurrenciesForDate(date)
withContext(Dispatchers.Main) {
if (response.isSuccessful) {
val rawJson = response.body()
val apiResponse = presenter.processRawJson(rawJson)
presenter.passResponseToView(apiResponse)
}
}
}
}
Any help will be really appreciated. Thank you in advance!
Try out the SnapHelper, it might slow layout manager to make more callbacks and stop overloading

Android Kotlin Pusher Chatkit - error - Room membership required

I'm trying to integrate chatkit into my Android app grabbing portions of code from this getting started tutorial and this android-public-demo-app project on github and I am getting this error:
D/ChatRoomsActivity: on subscripetoRoomMultipart reason:: Room membership required.
The user is already a member of the room which is producing is an error according to the dashboard/console snippets which are shown at the bottom of this post. Currently the currentUser is: user id=username2-PCKid
Error occurs in ChatRoomAcitivity.kt at currentUser.subscribeToRoomMultipart. I included the ChatRoomListActivity and adapters for context.
Any and all help is appreciated. Please let me know if more context is required.
here is my ChatRoomListActivity.kt
class ChatRoomsListActivity : AppCompatActivity() {
val adapter = ChatRoomsListAdapter();
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat_room_list)
initRecyclerView()
initChatManager()
}
private fun initRecyclerView() {
recycler_view.layoutManager = LinearLayoutManager(this#ChatRoomsListActivity)
recycler_view.adapter = adapter
}
private fun initChatManager() {
val chatManager = ChatManager(
instanceLocator = "************",
userId = "username2-PCKid",
dependencies = AndroidChatkitDependencies(
tokenProvider = ChatkitTokenProvider(
endpoint = "******************",
userId = "username2-PCKid"
)
)
)
chatManager.connect(listeners = ChatListeners(
)
, callback = { result ->
when (result) {
is Result.Success -> {
// We have connected!
Log.d(AppActivityTags.chatRoomsListActivityTAG, "chatManager connected!")
val currentUser = result.value
AppController.currentUser = currentUser
Log.d(AppActivityTags.chatRoomsListActivityTAG, "user: " + currentUser + " is logged in to chatkit")
val userJoinedRooms = ArrayList<Room>()
for (x in currentUser.rooms) {
adapter.addRoom(x)
recycler_view.smoothScrollToPosition(0)
}
adapter.notifyDataSetChanged()
Log.d(AppActivityTags.chatRoomsListActivityTAG, "joined rooms.size: " + userJoinedRooms.size.toString());
adapter.setInterface(object : ChatRoomsListAdapter.RoomClickedInterface {
override fun roomSelected(room: Room) {
Log.d(AppActivityTags.chatRoomsListActivityTAG, "Room clicked!")
if (room.memberUserIds.contains("username2-PCKid")) {
// if (room.memberUserIds.contains(currentUser.id)) { <-- OG code
// user already belongs to this room
roomJoined(room)
Log.d("roomSelected", "user already belongs to this room: " + roomJoined(room))
} else {
currentUser.joinRoom(
roomId = room.id,
callback = { result ->
when (result) {
is Result.Success -> {
// Joined the room!
roomJoined(result.value)
}
is Result.Failure -> {
Log.d(AppActivityTags.chatRoomsListActivityTAG, result.error.toString())
}
}
}
)
}
}
})
}
is Result.Failure -> {
// Failure
Log.d(AppActivityTags.chatRoomsListActivityTAG, "ChatManager connection failed"
+ result.error.toString())
}
}
})
}
private fun roomJoined(room: Room) {
val intent = Intent(this#ChatRoomsListActivity, ChatRoomActivity::class.java)
Log.d(AppActivityTags.chatRoomsListActivityTAG, "function roomJoined activated")
intent.putExtra("room_id", room.id)
intent.putExtra("room_name", room.name)
startActivity(intent)
}
}
here is my ChatRoomListAdapter.kt
class ChatRoomsListAdapter: RecyclerView.Adapter<ChatRoomsListAdapter.ViewHolder>() {
private var list = ArrayList<Room>()
private var roomClickedInterface: RoomClickedInterface? = null
fun addRoom(room:Room){
list.add(room);
Log.d(AppActivityTags.chatRoomsListAdapterTAG, "Room name: " + room.name)
Log.d(AppActivityTags.chatRoomsListAdapterTAG, "Room id: " + room.id)
Log.d(AppActivityTags.chatRoomsListAdapterTAG, "Room memberUserIds: " + room.memberUserIds)
Log.d(AppActivityTags.chatRoomsListAdapterTAG, "Room isPrivate: " + room.isPrivate)
}
fun setInterface(roomClickedInterface:RoomClickedInterface){
this.roomClickedInterface = roomClickedInterface
}
override fun getItemCount(): Int {
return list.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(
android.R.layout.simple_list_item_1,
parent,
false
)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.roomName.text = list[position].name
val context = holder.itemView.context
holder.itemView.setOnClickListener {
room = list[position]
val intent = Intent(context, ChatRoomActivity::class.java)
Log.d(AppActivityTags.chatRoomsListActivityTAG, "function roomJoined activated")
intent.putExtra("room_id", room.id)
intent.putExtra("room_name", room.name)
context.startActivity(intent)
}
}
inner class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView), View.OnClickListener {
override fun onClick(p0: View?) {
roomClickedInterface?.roomSelected(list[adapterPosition])
Toast.makeText(itemView.context, "item was clicked", Toast.LENGTH_LONG).show()
val mContext = itemView.context
Log.d(AppActivityTags.chatRoomsListAdapterTAG, "Size of adapter: " + list.size.toString())
Log.d(AppActivityTags.chatRoomsListAdapterTAG, roomName.toString() + " roomName clicked")
}
var roomName: TextView = itemView.findViewById(android.R.id.text1)
init {
itemView.setOnClickListener(this)
}
}
interface RoomClickedInterface{
fun roomSelected(room:Room)
}
}
here is my ChatRoomActivity.kt
class ChatRoomActivity : AppCompatActivity() {
lateinit var adapter:ChatRoomAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat_room)
supportActionBar!!.title = intent.getStringExtra("room_name")
adapter = ChatRoomAdapter()
setUpRecyclerView()
val currentUser = AppController.currentUser
val roomId = intent.getStringExtra("room_id")
currentUser.subscribeToRoomMultipart(
roomId = roomId,
listeners = RoomListeners(
onMultipartMessage = { message ->
Log.d("TAG",message.toString())
// com.pusher.chatkit.messages.multipart.Message
runOnUiThread(Runnable{
adapter.addMessage(message)
recycler_view.layoutManager?.scrollToPosition(adapter.itemCount -1)
})
},
onErrorOccurred = { error ->
Log.d(AppActivityTags.chatRoomActivityTAG, "error.reason: " + error.reason)
Log.d(AppActivityTags.chatRoomActivityTAG, "currentuser.rooms: " + currentUser.rooms)
}
),
messageLimit = 100, // Optional
callback = { subscription ->
// Called when the subscription has started.
// You should terminate the subscription with subscription.unsubscribe()
// when it is no longer needed
}
)
button_send.setOnClickListener {
if (edit_text.text.isNotEmpty()){
currentUser.sendSimpleMessage(
roomId = roomId,
messageText = edit_text.text.toString(),
callback = { result -> //Result<Int, Error>
when (result) {
is Result.Success -> {
runOnUiThread {
edit_text.text.clear()
hideKeyboard()
}
}
is Result.Failure -> {
Log.d(AppActivityTags.chatRoomActivityTAG, "error # button_send.setOnclick: " + result.error.toString())
}
}
}
)
}
}
}
private fun hideKeyboard() {
val imm = this.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
var view = this.currentFocus
if (view == null) {
view = View(this)
}
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
private fun setUpRecyclerView() {
recycler_view.layoutManager= LinearLayoutManager(this#ChatRoomActivity)
recycler_view.adapter = adapter
}
}
here is my ChatRoomAdapter.kt
class ChatRoomAdapter: RecyclerView.Adapter<ChatRoomAdapter.ViewHolder>() {
private var list = ArrayList<Message>()
fun addMessage(message: Message){
list.add(message)
notifyDataSetChanged()
}
override fun getItemCount(): Int {
return list.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.custom_chat_row,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val inlineMessage: Payload.Inline = list[position].parts[0].payload as Payload.Inline
holder.userName.text = list[position].sender.name
holder.message.text = inlineMessage.content
}
inner class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
var userName: TextView = itemView.findViewById(R.id.text_user_name)
var message: TextView = itemView.findViewById(R.id.chat_message)
}
}
I think I know what happened.
I think what happened was I created a room from the pusher-chat kit dashboard and then tried to sign in as them. and then enter the room as them. I was able to see my chatroomlists that they were affiliated with however I think that since I created the chatroom from the dashboard, it thought I was someone else.
Long story short, it works if I create the room from my android emulator and then go to the room. if I create the room from the dashboard and try to join, it doesn't seem to work.

Implement Load More Pagination with GSON Data from AsyncTask

Hello everyone I've created a RecyclerView and get the data with AsyncTask. In the first step I want is to display 10 first data and load more 10 data until it reach the last data.
After that I want to implement a progressbar as a footer to load data.
here is my code for my MutationRecyclerViewAdapter
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_mutation, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.mItem = mValues[position]
holder.itemView.text_transaction_type.text = getTransactionTypeString(mValues[position].transactionType)
holder.itemView.text_transaction_number.text = mValues[position].transactionID
holder.itemView.text_transaction_date.text = AppUtil.getDefaultDateFormat(mValues[position].transactionDate)
holder.itemView.text_balance.text = mValues[position].balance
holder.itemView.text_amount.text = mValues[position].amount
holder.itemView.text_merchant_name.text = mValues[position].merchant
if(mValues[position].transactionType != null) {
when (mValues[position].transactionType) {
"PR", "ST" -> {
holder.itemView.image_transaction_icon.setImageResource(R.drawable.ic_action_purchase)
holder.itemView.image_transaction_icon.background = ContextCompat.getDrawable(mContext!!, R.drawable.bg_circle)
holder.itemView.text_transaction_type.setTextColor(ContextCompat.getColor(mContext!!, R.color.orange))
holder.itemView.text_product_name.text = holder.mItem!!.merchant
holder.itemView.text_amount.setTextColor(ContextCompat.getColor(mContext!!, R.color.orange))
//holder.itemView.text_product_name.visibility = View.VISIBLE
holder.itemView.image_balance.setImageResource(R.drawable.ic_min_orange)
}
"RD" -> {
holder.itemView.image_transaction_icon.setImageResource(R.drawable.ic_action_withdraw_rotated)
holder.itemView.image_transaction_icon.background = ContextCompat.getDrawable(mContext!!, R.drawable.bg_circle)
holder.itemView.text_transaction_type.setTextColor(ContextCompat.getColor(mContext!!, R.color.orange))
holder.itemView.image_balance.setImageResource(R.drawable.ic_plus)
holder.itemView.text_amount.setTextColor(ContextCompat.getColor(mContext!!, R.color.orange))
}
"CI" -> {
holder.itemView.text_transaction_type.setTextColor(ContextCompat.getColor(mContext!!, R.color.green_grass_dark))
holder.itemView.image_transaction_icon.background = ContextCompat.getDrawable(mContext, R.drawable.bg_circle_green)
holder.itemView.image_transaction_icon.setImageResource(R.drawable.ic_action_cash_in)
holder.itemView.image_balance.setImageResource(R.drawable.ic_plus_green)
holder.itemView.text_amount.setTextColor(ContextCompat.getColor(mContext, R.color.green_grass_dark))
}
"CO", "FCO", "XX" -> {
holder.itemView.image_transaction_icon.background = ContextCompat.getDrawable(mContext!!, R.drawable.bg_circle)
holder.itemView.image_transaction_icon.setImageResource(R.drawable.ic_action_withdraw_rotated)
holder.itemView.text_transaction_type.setTextColor(ContextCompat.getColor(mContext, R.color.orange))
holder.itemView.image_balance.setImageResource(R.drawable.ic_min_orange)
holder.itemView.text_amount.setTextColor(ContextCompat.getColor(mContext, R.color.orange))
}
"AD" -> {
holder.itemView.image_transaction_icon.setImageResource(R.drawable.ic_action_adjustment)
holder.itemView.image_transaction_icon.background = ContextCompat.getDrawable(mContext!!, R.drawable.bg_circle_gray)
holder.itemView.text_transaction_type.setTextColor(ContextCompat.getColor(mContext, R.color.gray_dark))
holder.itemView.image_balance.setImageResource(R.drawable.ic_plus)
holder.itemView.text_amount.setTextColor(ContextCompat.getColor(mContext, R.color.gray_dark))
}
"RBY"->{
holder.itemView.image_transaction_icon.setImageResource(R.drawable.ic_action_adjustment)
holder.itemView.image_transaction_icon.background = ContextCompat.getDrawable(mContext!!, R.drawable.bg_circle_gray)
holder.itemView.text_transaction_type.setTextColor(ContextCompat.getColor(mContext, R.color.gray_dark))
holder.itemView.image_balance.setImageResource(R.drawable.ic_plus)
holder.itemView.text_amount.setTextColor(ContextCompat.getColor(mContext, R.color.gray_dark))
}
"TO" -> {
holder.itemView.image_transaction_icon.background = ContextCompat.getDrawable(mContext!!, R.drawable.bg_circle_blue)
holder.itemView.image_transaction_icon.setImageResource(R.drawable.ic_action_transfer)
holder.itemView.text_transaction_type.setTextColor(ContextCompat.getColor(mContext!!, R.color.blue_foreground))
holder.itemView.image_balance.setImageResource(R.drawable.ic_minus_blue)
holder.itemView.text_amount.setTextColor(ContextCompat.getColor(mContext, R.color.blue_foreground))
}
"TI", "BY" -> {
holder.itemView.image_transaction_icon.background = ContextCompat.getDrawable(mContext!!, R.drawable.bg_circle_green)
holder.itemView.image_transaction_icon.setImageResource(R.drawable.ic_action_transfer_in)
holder.itemView.text_transaction_type.setTextColor(ContextCompat.getColor(mContext!!, R.color.green_grass_dark))
holder.itemView.image_balance.setImageResource(R.drawable.ic_plus_green)
holder.itemView.text_amount.setTextColor(ContextCompat.getColor(mContext, R.color.green_grass_dark))
}
else -> {
holder.itemView.image_transaction_icon.setImageResource(R.drawable.ic_action_adjustment)
holder.itemView.image_transaction_icon.background = ContextCompat.getDrawable(mContext!!, R.drawable.bg_circle_gray)
holder.itemView.text_transaction_type.setTextColor(ContextCompat.getColor(mContext, R.color.gray_dark))
holder.itemView.image_balance.visibility = View.INVISIBLE
holder.itemView.text_amount.setTextColor(ContextCompat.getColor(mContext, R.color.gray_dark))
}
}
} else {
holder.itemView.image_transaction_icon.setImageResource(R.drawable.ic_action_adjustment)
holder.itemView.image_transaction_icon.background = ContextCompat.getDrawable(mContext!!, R.drawable.bg_circle_gray)
holder.itemView.text_transaction_type.setTextColor(ContextCompat.getColor(mContext, R.color.gray_dark))
holder.itemView.image_balance.visibility = View.INVISIBLE
holder.itemView.text_amount.setTextColor(ContextCompat.getColor(mContext, R.color.gray_dark))
}
holder.mView.setOnClickListener {
mListener?.onMutationFragmentInteraction(holder.mItem!!)
}
holder.mView.setOnLongClickListener {
mListener?.onLongMutationFragmentInteraction(holder.mItem!!)
false
}
}
private fun getTransactionTypeString(type: String): String {
return when(type) {
"PR" -> mContext!!.getString(R.string.purchase)
"CI" -> mContext!!.getString(R.string.cash_in)
"CO" -> mContext!!.getString(R.string.cash_out)
"RD" -> mContext!!.getString(R.string.redeem)
"TI" -> mContext!!.getString(R.string.transfer_in)
"TO" -> mContext!!.getString(R.string.transfer_out)
"FCO" -> mContext!!.getString(R.string.cash_out)
"XX" -> mContext!!.getString(R.string.cash_out)
"BY" -> mContext!!.getString(R.string.purchase)
"ST" -> mContext!!.getString(R.string.settlement)
"AD" -> mContext!!.getString(R.string.adjustment)
"RBY" ->mContext!!.getString(R.string.rby)
else -> return type
}
}
override fun getItemCount(): Int {
return mValues.size
}
inner class ViewHolder(val mView: View) : RecyclerView.ViewHolder(mView) {
var mItem: MutationItem? = null
}
and this my MutationFragment
private var maxItemSize = -1
private var mListener: OnMutationFragmentInteractionListener? = null
lateinit var adapter : MutationRecyclerViewAdapter
lateinit var refreshButton : ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (arguments != null) {
maxItemSize = arguments?.getInt(MAX_ITEMS_SIZE, -1)!!
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_mutation, container, false)
(activity as AppCompatActivity).supportActionBar?.title = "MutationFragment"
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
MutationContent.ITEMS.clear()
GetTransactionTask(context!!, this).execute()
mutation_list.layoutManager = LinearLayoutManager(context)
adapter = MutationRecyclerViewAdapter(MutationContent.getSavedTransactions(context, maxItemSize), mListener, context)
refreshLayout.apply {
scrollUpChild = mutation_list
setOnRefreshListener {
isRefreshing = false
GetTransactionTask(context!!, this#MutationFragment).execute()
}
}
}
fun toggleView(isEmpty : Boolean){
if(isEmpty){
progress_bar?.visibility = View.GONE
mutation_list?.visibility = View.GONE
//refreshButton.visibility = View.GONE
text_no_mutation?.visibility = View.VISIBLE
}
else{
progress_bar?.visibility = View.GONE
mutation_list?.visibility = View.VISIBLE
//refreshButton?.visibility = View.GONE
text_no_mutation?.visibility = View.GONE
}
activity?.invalidateOptionsMenu()
}
override fun onGetTransactionSuccess(response: ResponseRequestMutasiSaldo) {
MutationContent.import(context, response, maxItemSize)
adapter = MutationRecyclerViewAdapter(MutationContent.getSavedTransactions(context, maxItemSize),
mListener, context)
mutation_list?.adapter = adapter
if(adapter.mValues.isEmpty()) {
text_no_mutation?.setText(getString(R.string.no_mutation))
} else {
text_no_mutation?.setText(getString(R.string.load_mutation))
}
toggleView(adapter.mValues.isEmpty())
}
override fun onAttach(context: Context?) {
super.onAttach(context)
if (context is OnMutationFragmentInteractionListener) {
mListener = context
} else {
throw RuntimeException(context!!.toString() + " must implement OnSettingFragmentInteractionListener")
}
}
override fun onDetach() {
super.onDetach()
mListener = null
}
override fun onTransactionFailed(response: ResponseRequestMutasiSaldo) {
adapter = MutationRecyclerViewAdapter(
MutationContent.getSavedTransactions(context, maxItemSize),
mListener, context)
mutation_list?.adapter = adapter
toggleView(adapter.mValues.isEmpty())
/*if(activity != null)
Toasty.error(activity!!,response.errorMessage).show()*/
}
interface OnMutationFragmentInteractionListener {
fun onMutationFragmentInteraction(item: MutationItem)
fun onLongMutationFragmentInteraction(item: MutationItem)
}
companion object {
val MAX_ITEMS_SIZE = "MAX_ITEM_SIZE"
}
and this my Asynctask Class
override fun doInBackground(vararg p0: Void?): ResponseRequestMutasiSaldo? {
return ResourceService(context).requestMutasiSaldo()
}
override fun onPostExecute(result: ResponseRequestMutasiSaldo?) {
if(result != null && (result.error.equals(AppUtil.RESPONSE_ERROR_CODE_EXPIRY) || result.success.equals(AppUtil.RESPONSE_SUCCESS_CODE_EXPIRY))){
EventBus.getDefault().post(SessionExpiry(result.message?:""))
return
}
if(result != null && result.success.equals("1")) {
listener.onGetTransactionSuccess(result)
}
if(result != null && result.error.equals("1")){
listener.onTransactionFailed(result)
return
}
}
I have successfully got all the data from web service and now I've tried, using EndlessRecyclerViewListener like in this documentation and using several references to achive my task. But the function AddOnScroll didn't work properly and I didn't understand well how this work. How do I do if I want to use EndlessRecyclerViewListener? Or is there any other way to achive this without using EndlessRecyclerViewListener class?
Use addOnScrollListener to do this.
val pageLimit: Int = 10//row returned each time on scroll
var noMoreItems: Boolean = false
use addOnScrollListener in your recyclerview like this.
dataRecyclerView.addOnScrollListener(object : androidx.recyclerview.widget.RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: androidx.recyclerview.widget.RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (!recyclerView.canScrollVertically(1)) {
if (!utility.isConnected(mContext)) {
Toast.makeText(mContext, "No internet", Toast.LENGTH_SHORT).show()
return
}
if (noMoreItems)
return
val lastPage: String
val nextPage: Int
if (dataArrayList.size > 0) {
lastPage = ((dataArrayList.size - 1) / pageLimit).toInt().toString()
nextPage = Integer.parseInt(lastPage) + 1
} else {
nextPage = 1;
}
loadRecords(nextPage.toString())
}
}
})
here in loadRecords() you should call your asynctask with page number.
set noMOreItems=true when number of rows returned is less than pageLimit.

Update view adapter recyclerView mvvm (play sound and update view)

I have a list of user record sound
The user can click on the list and play the audio file
  How can I handle the MediaPlayer and the RecyclerView item in the Seekbar as well in the MVVM correctly?
That is, when the user clicks, the visitor changes the item and updates itself, and when it is clicked on an item again, it updates itself.
I did it now, but unfortunately, to the dirtiest possible form
activity code :
class SoundListActivity : BaseActivity(), Observer<List<VoiceEntity>>, VoiceAdapter.OnClickItemListener,
OnMultiSelectVoiceListener {
private lateinit var viewModel: VoiceViewModel
private val adapter = VoiceAdapter()
private val player = MediaPlayer()
private var positionPlayItem = -1
companion object {
fun start(context: Context) {
context.startActivity(Intent(context, SoundListActivity::class.java))
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sound_list)
viewModel = ViewModelProviders.of(this).get(VoiceViewModel::class.java)
viewModel.mutableList!!.observe(this, this)
adapter.onItemClickListener = this
adapter.listenerMultiSelect = this
recycler.layoutManager = LinearLayoutManager(this)
recycler.adapter = adapter
fabAdd.setOnClickListener {
stopPlay()
RecordSoundActivity.start(this)
}
toolbar.setIconLeftListener(View.OnClickListener {
stopPlay()
finish()
})
}
override fun onChanged(list: List<VoiceEntity>?) {
this.progressBar.visibility = View.GONE
this.layoutEmptyState.visibility = View.INVISIBLE
this.adapter.removeAll()
if (list == null || list.isEmpty()) {
layoutEmptyState.visibility = View.VISIBLE
return
}
adapter.addItems(ArrayList(list))
}
override fun onClickItem(item: VoiceEntity, position: Int) {
if (player.isPlaying) {
player.reset()
}
if (item.isPlaying) {
item.isPlaying = false
player.reset()
adapter.notifyDataSetChanged()
return
}
this.positionPlayItem = position
adapter.items!!.forEach {
if (it != item) {
it.isPlaying = false
}
}
player.setDataSource(item.path)
player.prepare()
player.start()
item.isPlaying = true
adapter.notifyDataSetChanged()
player.setOnCompletionListener {
player.reset()
adapter.notifyItemChanged(position)
item.isPlaying = false
}
}
private fun stopPlay() {
if (positionPlayItem == -1) {
return
}
player.reset()
adapter.items!![positionPlayItem].isPlaying = false
adapter.notifyItemChanged(positionPlayItem)
}
override fun onMultiSelectVoice(items: ArrayList<VoiceEntity>) {
stopPlay()
if (items.size == 0) {
layoutSelectItem.visibility = View.GONE
return
}
txtCounterSelect.text = String.format(getString(R.string.selected_number), items.size.toString())
setStatusBarColor(R.color.black)
if (layoutSelectItem.visibility == View.GONE) {
layoutSelectItem.visibility = View.VISIBLE
}
if (items.size > 1) {
imgShare.visibility = View.GONE
imgEdit.visibility = View.GONE
} else {
imgShare.visibility = View.VISIBLE
imgEdit.visibility = View.VISIBLE
}
imgCancelSelect.setOnClickListener {
resetData()
}
imgEdit.setOnClickListener {
edit(items.first())
}
imgShare.setOnClickListener {
if (items.isEmpty()) {
return#setOnClickListener
}
shareVoice(this, items[0].path)
}
imgDelete.setOnClickListener {
val alertDialog = AlertDialog.Builder(
supportFragmentManager,
getString(R.string.note), getString(R.string.do_you_sure_delete)
)
alertDialog.setBtnNegative(getString(R.string.no), View.OnClickListener {
alertDialog.dialog!!.dismiss()
})
alertDialog.setBtnPositive(getString(R.string.yes), View.OnClickListener {
val ex = Executors.newSingleThreadExecutor()
items.forEach { item ->
viewModel.remove(item)
ex.execute { File(item.path).deleteOnExit() }
}
items.clear()
layoutSelectItem.visibility = View.GONE
setStatusBarColor(R.color.colorPrimaryDark)
alertDialog.dialog!!.dismissAllowingStateLoss()
})
alertDialog.build().show()
}
}
private fun resetData() {
adapter.itemsSelected.clear()
adapter.items?.forEach { item ->
item.statusSelect = false
}
adapter.notifyDataSetChanged()
layoutSelectItem.visibility = View.GONE
setStatusBarColor(R.color.colorPrimaryDark)
}
private fun edit(item: VoiceEntity) {
val bottomSheet = NameBottomSheet(supportFragmentManager)
bottomSheet.listener = object : NameBottomSheet.OnTitleListener {
override fun onTitle(title: String) {
item.title = title
viewModel.update(item)
resetData()
}
}
bottomSheet.item = item
bottomSheet.show()
}
override fun onBackPressed() {
if (layoutSelectItem.visibility == View.VISIBLE) {
resetData()
return
}
stopPlay()
super.onBackPressed()
}
}
adapter class code :
class VoiceAdapter : AdapterRecyclerView<VoiceEntity>() {
var onItemClickListener: OnClickItemListener? = null
var itemsSelected: ArrayList<VoiceEntity> = ArrayList()
var listenerMultiSelect: OnMultiSelectVoiceListener? = null
override fun getItemLayout(viewType: Int): Int {
return R.layout.item_voice
}
override fun onBindView(
viewDataBinding: ViewDataBinding,
viewHolder: ItemViewHolder,
position: Int,
viewType: Int,
element: VoiceEntity
) {
val binding = viewDataBinding as ItemVoiceBinding
binding.txtTitle.text = element.title
binding.txtDate.text = element.date.toAgoTime(context!!)
binding.icPlay.setImageResource(if (element.isPlaying) R.drawable.ic_pause else R.drawable.ic_play)
binding.seekBar.max = element.duration / 60
val colorSelectItem =
ContextCompat.getColor(binding.rootLayout.context, R.color.color_background_select_item_recycler_view)
val color = if (element.statusSelect) colorSelectItem else Color.TRANSPARENT
binding.rootLayout.setBackgroundColor(color)
if (element.statusSelect) {
changeColorLight(binding)
} else {
changeColorDarker(binding)
}
if (element.isPlaying) {
binding.layoutPlaying.visibility = View.VISIBLE
binding.lottieLayer.playAnimation()
//TODO : change handled voice progressBar show
val t = object : Thread() {
override fun run() {
super.run()
for (i in 0..element.duration) {
Thread.sleep(60)
binding.seekBar.progress = i
if (!element.isPlaying) break
}
}
}
t.start()
} else {
binding.layoutPlaying.visibility = View.GONE
binding.lottieLayer.cancelAnimation()
}
binding.rootLayout.setOnClickListener {
if (itemsSelected.size > 0) {
val item = items!![viewHolder.adapterPosition]
if (itemsSelected.contains(item)) {
item.statusSelect = false
itemsSelected.remove(item)
binding.rootLayout.animatedColorBackgroundSelected(false)
listenerMultiSelect?.onMultiSelectVoice(itemsSelected)
changeColorDarker(binding)
return#setOnClickListener
}
item.statusSelect = true
itemsSelected.add(item)
binding.rootLayout.animatedColorBackgroundSelected()
listenerMultiSelect?.onMultiSelectVoice(itemsSelected)
changeColorLight(binding)
return#setOnClickListener
}
onItemClickListener?.onClickItem(element, position)!!
}
binding.rootLayout.setOnLongClickListener {
val item = items!![viewHolder.adapterPosition]
if (itemsSelected.contains(item)) {
item.statusSelect = false
itemsSelected.remove(item)
binding.rootLayout.animatedColorBackgroundSelected(false)
changeColorDarker(binding)
listenerMultiSelect?.onMultiSelectVoice(itemsSelected)
}
item.statusSelect = true
itemsSelected.add(item)
binding.rootLayout.animatedColorBackgroundSelected()
changeColorLight(binding)
listenerMultiSelect?.onMultiSelectVoice(itemsSelected)
true
}
}
private fun changeColorLight(binding: ItemVoiceBinding) {
binding.txtDate.setTextColor(ContextCompat.getColor(binding.root.context, R.color.color_subtitle_light))
binding.txtTitle.setTextColor(ContextCompat.getColor(binding.root.context, R.color.color_title_light))
}
private fun changeColorDarker(binding: ItemVoiceBinding) {
binding.txtDate.setTextColor(ContextCompat.getColor(binding.root.context, R.color.color_subtitle))
binding.txtTitle.setTextColor(ContextCompat.getColor(binding.root.context, R.color.color_title))
}
interface OnClickItemListener {
fun onClickItem(item: VoiceEntity, position: Int)
}
}
github repository (open source project)

Categories

Resources