diff --git a/project/app/src/main/java/org/owntracks/android/support/ContactImageBindingAdapter.kt b/project/app/src/main/java/org/owntracks/android/support/ContactImageBindingAdapter.kt index 66915c2622..54ed990cb1 100644 --- a/project/app/src/main/java/org/owntracks/android/support/ContactImageBindingAdapter.kt +++ b/project/app/src/main/java/org/owntracks/android/support/ContactImageBindingAdapter.kt @@ -8,7 +8,10 @@ import android.util.Base64 import android.widget.ImageView import androidx.databinding.BindingAdapter import dagger.hilt.android.qualifiers.ApplicationContext -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.owntracks.android.model.FusedContact import org.owntracks.android.support.widgets.TextDrawable import timber.log.Timber @@ -18,11 +21,11 @@ class ContactImageBindingAdapter @Inject constructor( @ApplicationContext context: Context, private val memoryCache: ContactBitmapAndNameMemoryCache ) { - @BindingAdapter(value = ["contact"]) - fun ImageView.displayFaceInViewAsync(c: FusedContact?) { - c?.also { contact -> - GlobalScope.launch(Dispatchers.Main) { - setImageBitmap(getBitmapFromCache(contact)) + @BindingAdapter(value = ["contact", "coroutineScope"]) + fun ImageView.displayFaceInViewAsync(contact: FusedContact?, scope: CoroutineScope) { + contact?.also { + scope.launch(Dispatchers.Main) { + setImageBitmap(getBitmapFromCache(it)) } } } diff --git a/project/app/src/main/java/org/owntracks/android/ui/base/BaseActivity.java b/project/app/src/main/java/org/owntracks/android/ui/base/BaseActivity.java index 6065dd02c8..d8db27a6d0 100644 --- a/project/app/src/main/java/org/owntracks/android/ui/base/BaseActivity.java +++ b/project/app/src/main/java/org/owntracks/android/ui/base/BaseActivity.java @@ -58,7 +58,9 @@ protected final void bindAndAttachContentView(@LayoutRes int layoutResId, @Nulla binding.setLifecycleOwner(this); //noinspection unchecked - viewModel.attachView(savedInstanceState, (MvvmView) this); + if (MvvmView.class.isAssignableFrom(this.getClass())) { + viewModel.attachView(savedInstanceState, (MvvmView) this); + } } diff --git a/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsActivity.kt b/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsActivity.kt index 3b30a862f3..723c91e179 100644 --- a/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsActivity.kt +++ b/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsActivity.kt @@ -3,6 +3,7 @@ package org.owntracks.android.ui.contacts import android.content.Intent import android.os.Bundle import android.view.View +import androidx.activity.viewModels import androidx.recyclerview.widget.LinearLayoutManager import dagger.hilt.android.AndroidEntryPoint import org.owntracks.android.R @@ -10,27 +11,30 @@ import org.owntracks.android.databinding.UiContactsBinding import org.owntracks.android.model.FusedContact import org.owntracks.android.ui.base.BaseActivity import org.owntracks.android.ui.base.BaseAdapter +import org.owntracks.android.ui.base.viewmodel.NoOpViewModel import org.owntracks.android.ui.map.MapActivity @AndroidEntryPoint -class ContactsActivity : BaseActivity?>(), - ContactsMvvm.View, BaseAdapter.ClickListener { - +class ContactsActivity : BaseActivity(), + BaseAdapter.ClickListener { + private val vm: ContactsViewModel by viewModels() private lateinit var contactsAdapter: ContactsAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - contactsAdapter = ContactsAdapter(this) - setHasEventBus(false) + contactsAdapter = ContactsAdapter(this, vm.coroutineScope) bindAndAttachContentView(R.layout.ui_contacts, savedInstanceState) + setHasEventBus(false) setSupportToolbar(binding!!.appbar.toolbar) setDrawer(binding!!.appbar.toolbar) - binding!!.vm!!.contacts.observe({ this.lifecycle }, { contacts: Map -> + vm.contacts.observe({ this.lifecycle }, { contacts: Map -> contactsAdapter.setContactList(contacts.values) - binding!!.vm!!.refreshGeocodes() + vm.refreshGeocodes() }) - binding!!.recyclerView.layoutManager = LinearLayoutManager(this) - binding!!.recyclerView.adapter = contactsAdapter + binding?.recyclerView?.run { + layoutManager = LinearLayoutManager(this@ContactsActivity) + adapter = contactsAdapter + } } override fun onClick(fusedContact: FusedContact, view: View, longClick: Boolean) { diff --git a/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsActivityModule.kt b/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsActivityModule.kt deleted file mode 100644 index 403a4172b7..0000000000 --- a/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsActivityModule.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.owntracks.android.ui.contacts - -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityComponent - -@InstallIn(ActivityComponent::class) -@Module -abstract class ContactsActivityModule { - @Binds - abstract fun bindViewModel(viewModel: ContactsViewModel?): ContactsMvvm.ViewModel<*>? -} \ No newline at end of file diff --git a/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsAdapter.kt b/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsAdapter.kt index 0572364335..7e0a2b0b0e 100644 --- a/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsAdapter.kt +++ b/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsAdapter.kt @@ -5,14 +5,17 @@ import android.view.ViewGroup import androidx.databinding.DataBindingUtil import androidx.databinding.ViewDataBinding import androidx.recyclerview.widget.RecyclerView +import kotlinx.coroutines.CoroutineScope import org.owntracks.android.BR import org.owntracks.android.R import org.owntracks.android.model.FusedContact import org.owntracks.android.ui.base.BaseAdapter -import java.util.* -internal class ContactsAdapter(private val clickListener: BaseAdapter.ClickListener) : - RecyclerView.Adapter() { +internal class ContactsAdapter( + private val clickListener: BaseAdapter.ClickListener, + private val coroutineScope: CoroutineScope +) : + RecyclerView.Adapter() { private lateinit var contactList: List override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FusedContactViewHolder { val binding = DataBindingUtil.inflate( @@ -21,7 +24,7 @@ internal class ContactsAdapter(private val clickListener: BaseAdapter.ClickListe parent, false ) - return FusedContactViewHolder(binding) + return FusedContactViewHolder(binding, coroutineScope) } override fun onBindViewHolder(holder: FusedContactViewHolder, position: Int) { @@ -36,23 +39,30 @@ internal class ContactsAdapter(private val clickListener: BaseAdapter.ClickListe contactList = ArrayList(contacts) notifyDataSetChanged() } -} -internal class FusedContactViewHolder(private val binding: ViewDataBinding) : - RecyclerView.ViewHolder(binding.root) { - fun bind(fusedContact: FusedContact?, clickListener: BaseAdapter.ClickListener) { - fusedContact?.run { - binding.setVariable(BR.contact, this) - binding.root.setOnClickListener { - clickListener.onClick( - this, - binding.root, - false - ) - } + class FusedContactViewHolder( + private val binding: ViewDataBinding, + private val coroutineScope: CoroutineScope + ) : + RecyclerView.ViewHolder(binding.root) { + fun bind( + fusedContact: FusedContact?, + clickListener: BaseAdapter.ClickListener + ) { + fusedContact?.run { + binding.setVariable(BR.contact, this) + binding.setVariable(BR.coroutineScope, coroutineScope) + binding.root.setOnClickListener { + clickListener.onClick( + this, + binding.root, + false + ) + } + } + binding.executePendingBindings() } - - binding.executePendingBindings() } -} \ No newline at end of file +} + diff --git a/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsMvvm.kt b/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsMvvm.kt deleted file mode 100644 index d5cdc80213..0000000000 --- a/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsMvvm.kt +++ /dev/null @@ -1,26 +0,0 @@ -package org.owntracks.android.ui.contacts - -import androidx.lifecycle.LiveData -import org.owntracks.android.model.FusedContact -import org.owntracks.android.ui.base.view.MvvmView -import org.owntracks.android.ui.base.viewmodel.MvvmViewModel - -/* Copyright 2016 Patrick Löwenstein - * - * 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. */ -interface ContactsMvvm { - interface View : MvvmView - interface ViewModel : MvvmViewModel { - val contacts: LiveData> - } -} \ No newline at end of file diff --git a/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsViewModel.kt b/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsViewModel.kt index 0dd3431001..7bdd3ee84b 100644 --- a/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsViewModel.kt +++ b/project/app/src/main/java/org/owntracks/android/ui/contacts/ContactsViewModel.kt @@ -1,30 +1,25 @@ package org.owntracks.android.ui.contacts -import android.os.Bundle import androidx.lifecycle.LiveData -import dagger.hilt.android.scopes.ActivityScoped -import kotlinx.coroutines.MainScope +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.owntracks.android.data.repos.ContactsRepo import org.owntracks.android.geocoding.GeocoderProvider import org.owntracks.android.model.FusedContact -import org.owntracks.android.ui.base.viewmodel.BaseViewModel import timber.log.Timber import javax.inject.Inject -@ActivityScoped +@HiltViewModel class ContactsViewModel @Inject constructor( private val contactsRepo: ContactsRepo, private val geocoderProvider: GeocoderProvider -) : - BaseViewModel(), ContactsMvvm.ViewModel { - private val mainScope = MainScope() - override fun attachView(savedInstanceState: Bundle?, view: ContactsMvvm.View?) { - super.attachView(savedInstanceState, view!!) - } +) : ViewModel() { fun refreshGeocodes() { Timber.i("Refreshing contacts geocodes") - mainScope.launch { + viewModelScope.launch { contactsRepo.all.value?.run { map { it.value.messageLocation } .filterNotNull() @@ -34,6 +29,8 @@ class ContactsViewModel @Inject constructor( } } - override val contacts: LiveData> + val contacts: LiveData> get() = contactsRepo.all + val coroutineScope: CoroutineScope + get() = viewModelScope } \ No newline at end of file diff --git a/project/app/src/main/java/org/owntracks/android/ui/map/MapViewModel.kt b/project/app/src/main/java/org/owntracks/android/ui/map/MapViewModel.kt index 4c11a80090..46777e0061 100644 --- a/project/app/src/main/java/org/owntracks/android/ui/map/MapViewModel.kt +++ b/project/app/src/main/java/org/owntracks/android/ui/map/MapViewModel.kt @@ -12,6 +12,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.owntracks.android.data.repos.ContactsRepo import org.owntracks.android.data.repos.LocationRepo @@ -69,6 +70,9 @@ class MapViewModel @Inject constructor( val myLocationEnabled: LiveData get() = mutableMyLocationEnabled + val scope: CoroutineScope + get() = viewModelScope + val allContacts = contactsRepo.all val locationIdlingResource = SimpleIdlingResource("locationIdlingResource", false) diff --git a/project/app/src/main/res/layout/ui_map.xml b/project/app/src/main/res/layout/ui_map.xml index 2403e5bba1..b81f43a093 100644 --- a/project/app/src/main/res/layout/ui_map.xml +++ b/project/app/src/main/res/layout/ui_map.xml @@ -47,7 +47,8 @@ + app:contact="@{vm.currentContact}" + app:coroutineScope="@{vm.scope}" /> + @@ -30,6 +33,7 @@ android:layout_marginTop="16dp" android:contentDescription="@string/contact_image" app:contact="@{contact}" + app:coroutineScope="@{coroutineScope}" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />