From b265bc60d08d494f43ead2e9a810777fe7aa3d94 Mon Sep 17 00:00:00 2001 From: Luca Moroldo Date: Sun, 8 Sep 2019 12:15:37 +0200 Subject: [PATCH 1/8] basic implementation --- .idea/navEditor.xml | 13 ++++- .../com/esp/localjobs/data/models/User.kt | 5 +- .../esp/localjobs/fragments/JobsFragment.kt | 52 ++++++++++++++++++- .../fragments/UserProfileFragment.kt | 38 ++++++++++---- .../localjobs/viewModels/FilterViewModel.kt | 3 ++ app/src/main/res/layout/fragment_jobs.xml | 30 +++++++++++ .../main/res/layout/fragment_user_profile.xml | 13 ++++- app/src/main/res/navigation/nav_graph.xml | 12 +++++ app/src/main/res/values/strings.xml | 2 + 9 files changed, 150 insertions(+), 18 deletions(-) diff --git a/.idea/navEditor.xml b/.idea/navEditor.xml index 95e3f92..0f602e7 100644 --- a/.idea/navEditor.xml +++ b/.idea/navEditor.xml @@ -146,10 +146,19 @@ + diff --git a/app/src/main/java/com/esp/localjobs/data/models/User.kt b/app/src/main/java/com/esp/localjobs/data/models/User.kt index b16667b..47e942b 100644 --- a/app/src/main/java/com/esp/localjobs/data/models/User.kt +++ b/app/src/main/java/com/esp/localjobs/data/models/User.kt @@ -1,14 +1,17 @@ package com.esp.localjobs.data.models +import android.os.Parcelable import com.google.firebase.auth.FirebaseUser +import kotlinx.android.parcel.Parcelize +@Parcelize data class User( val uid: String = "", val displayName: String = "", val phoneNumber: String = "", val photoUrl: String = "", val mail: String = "" -) +) : Parcelable fun FirebaseUser.toUser() = User( uid = uid, diff --git a/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt b/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt index 25f1f2e..d785f21 100644 --- a/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt +++ b/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt @@ -8,15 +8,18 @@ import android.view.MenuInflater import android.view.View import android.view.ViewGroup import android.widget.SearchView +import androidx.core.view.forEach import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.Observer import androidx.navigation.fragment.FragmentNavigatorExtras import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.RecyclerView import com.esp.localjobs.R import com.esp.localjobs.adapters.JobItem import com.esp.localjobs.data.models.Location +import com.esp.localjobs.data.models.User import com.esp.localjobs.data.repository.JobsRepository import com.esp.localjobs.fragments.FiltersFragment.Companion.FILTER_FRAGMENT_TAG import com.esp.localjobs.fragments.map.LocationPickerFragment @@ -30,7 +33,8 @@ import kotlinx.android.synthetic.main.fragment_jobs.view.* import kotlinx.coroutines.InternalCoroutinesApi /** - * Fragment used to display a list of jobs + * Fragment used to display a list of jobs. If arguments include an User then the fragment + * shows the user's jobs/proposals */ @InternalCoroutinesApi class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener { @@ -38,6 +42,8 @@ class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener private val jobsViewModel: JobsViewModel by activityViewModels() private val filterViewModel: FilterViewModel by activityViewModels() + private val args: JobsFragmentArgs by navArgs() + val adapter = GroupAdapter() override fun onCreateView( @@ -56,7 +62,10 @@ class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener setupAdapter() observeChangesInJobList() - observeFilters() + + args.user?.let { + setupUserJobsView(it) + } ?: observeFilters() } private fun setupUI(view: View) = with(view) { @@ -137,6 +146,11 @@ class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + // hide menu actions if we are showing some user's jobs/proposals + args.user?.let { + menu.forEach { it.isVisible = false } + return + } inflater.inflate(R.menu.menu_search, menu) val searchView = menu.findItem(R.id.action_search_item).actionView as SearchView setupSearchView(searchView) @@ -181,6 +195,40 @@ class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener } } + private fun setupUserJobsView(user: User) { + activity?.title = getString(R.string.user_jobs_title, user.displayName) + val fromJobs = filterViewModel.filteringJobs ?: true + + val toCheck = if (fromJobs) + R.id.radio_job + else + R.id.radio_proposal + + jobs_type_radio_group.check(toCheck) + jobs_type_radio_group.setOnCheckedChangeListener { _, checkedId -> + if(checkedId == R.id.radio_job) { + loadJobs(JobsRepository.JobFilter( + uid = user.uid, + filteringJobs = true + )) + } else { + loadJobs(JobsRepository.JobFilter( + uid = user.uid, + filteringJobs = false + )) + } + } + + fabAdd.visibility = View.GONE + active_filters.visibility = View.GONE + jobs_type_radio_group.visibility = View.VISIBLE + + loadJobs(JobsRepository.JobFilter( + uid = user.uid, + filteringJobs = fromJobs + )) + } + override fun onLocationPicked(location: Location, distance: Int?) { Log.d(TAG, "location: $location") filterViewModel.setLocation(location) diff --git a/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt b/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt index b3fd2a5..1e5bcf4 100644 --- a/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt +++ b/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt @@ -6,6 +6,7 @@ import android.view.Menu import android.view.MenuInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.core.view.forEach import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment @@ -13,6 +14,7 @@ import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.esp.localjobs.R +import com.esp.localjobs.data.models.User import com.esp.localjobs.data.repository.userFirebaseRepository import com.esp.localjobs.databinding.FragmentUserProfileBinding import com.esp.localjobs.viewModels.LoginViewModel @@ -60,21 +62,23 @@ class UserProfileFragment : Fragment(), CoroutineScope { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val userId = args.userID - if (userId == null) - setupCurrentUserProfile() - else - setupUserDetails(userId) + args.userID?.let { + setupUserDetails(it) + } ?: setupCurrentUserProfile() } private fun setupCurrentUserProfile() { - name.text = getString(R.string.not_logged_in) - logout.visibility = View.GONE - login.visibility = View.VISIBLE + val user = loginViewModel.getCurrentUser() + + if (user == null) { + name.text = getString(R.string.not_logged_in) + logout.visibility = View.GONE + login.visibility = View.VISIBLE + } else { + binding.user = user + setupUserJobsButton(user) - loginViewModel.getCurrentUser()?.let { - binding.user = it logout.visibility = View.VISIBLE login.visibility = View.GONE } @@ -93,7 +97,19 @@ class UserProfileFragment : Fragment(), CoroutineScope { if (!isActive) return@launch - binding.user = user + user?.let { + binding.user = it + setupUserJobsButton(it) + } + } + + private fun setupUserJobsButton(user: User) { + user_jobs.visibility = View.VISIBLE + user_jobs.setOnClickListener { + val action = + UserProfileFragmentDirections.actionDestinationUserProfileToDestinationJobs(user) + findNavController().navigate(action) + } } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { diff --git a/app/src/main/java/com/esp/localjobs/viewModels/FilterViewModel.kt b/app/src/main/java/com/esp/localjobs/viewModels/FilterViewModel.kt index c1cfc36..ec7b9ae 100644 --- a/app/src/main/java/com/esp/localjobs/viewModels/FilterViewModel.kt +++ b/app/src/main/java/com/esp/localjobs/viewModels/FilterViewModel.kt @@ -39,6 +39,9 @@ class FilterViewModel : ViewModel() { val query: String? get() = activeFilters.value?.query + val filteringJobs: Boolean? + get() = activeFilters.value?.filteringJobs + init { val context = LocalJobsApplication.applicationContext() val filter = retrieveLastUsedFilter(context) diff --git a/app/src/main/res/layout/fragment_jobs.xml b/app/src/main/res/layout/fragment_jobs.xml index 198b07e..f887bf4 100644 --- a/app/src/main/res/layout/fragment_jobs.xml +++ b/app/src/main/res/layout/fragment_jobs.xml @@ -20,6 +20,36 @@ android:layout_height="50dp" android:id="@+id/active_filters"/> + + + + + + + + + + @@ -57,5 +57,14 @@ android:visibility="gone" android:text="@string/login"/> + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 153ed5c..9aaf201 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -29,6 +29,11 @@ android:name="job" app:argType="com.esp.localjobs.data.models.Job"/> + + Interested people: Author: In the past + %1$s\'s stuff + Jobs and proposals From 2065f2c55f5a4c66b3b50245ccfc4772926f8141 Mon Sep 17 00:00:00 2001 From: Luca Moroldo Date: Sun, 8 Sep 2019 12:20:09 +0200 Subject: [PATCH 2/8] ktlint --- app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt | 2 +- .../java/com/esp/localjobs/fragments/UserProfileFragment.kt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt b/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt index d785f21..4177794 100644 --- a/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt +++ b/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt @@ -206,7 +206,7 @@ class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener jobs_type_radio_group.check(toCheck) jobs_type_radio_group.setOnCheckedChangeListener { _, checkedId -> - if(checkedId == R.id.radio_job) { + if (checkedId == R.id.radio_job) { loadJobs(JobsRepository.JobFilter( uid = user.uid, filteringJobs = true diff --git a/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt b/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt index 1e5bcf4..264690e 100644 --- a/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt +++ b/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt @@ -6,7 +6,6 @@ import android.view.Menu import android.view.MenuInflater import android.view.View import android.view.ViewGroup -import android.widget.Toast import androidx.core.view.forEach import androidx.databinding.DataBindingUtil import androidx.fragment.app.Fragment From 6f0f6857d772187a5c50c3df054bc7ab30a15495 Mon Sep 17 00:00:00 2001 From: Luca Moroldo Date: Sun, 8 Sep 2019 17:01:27 +0200 Subject: [PATCH 3/8] add fav manager --- .../esp/localjobs/utils/IFavoritesManager.kt | 9 +++ .../esp/localjobs/utils/favoritesManager.kt | 56 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 app/src/main/java/com/esp/localjobs/utils/IFavoritesManager.kt create mode 100644 app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt diff --git a/app/src/main/java/com/esp/localjobs/utils/IFavoritesManager.kt b/app/src/main/java/com/esp/localjobs/utils/IFavoritesManager.kt new file mode 100644 index 0000000..5ec259a --- /dev/null +++ b/app/src/main/java/com/esp/localjobs/utils/IFavoritesManager.kt @@ -0,0 +1,9 @@ +package com.esp.localjobs.utils + +import com.esp.localjobs.data.models.Job + +interface IFavoritesManager { + fun add(job: Job) + fun remove(job: Job) + suspend fun get(): Set +} \ No newline at end of file diff --git a/app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt b/app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt new file mode 100644 index 0000000..ac001e8 --- /dev/null +++ b/app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt @@ -0,0 +1,56 @@ +package com.esp.localjobs.utils + +import android.content.Context +import android.content.SharedPreferences +import androidx.core.content.edit +import com.esp.localjobs.LocalJobsApplication +import com.esp.localjobs.data.base.BaseRepository +import com.esp.localjobs.data.models.Job +import com.esp.localjobs.data.repository.JobsRepository +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch + +object favoritesManager : IFavoritesManager { + private const val FAV_KEY = "favourites_ids" + + private val loader: BaseRepository by lazy { JobsRepository() } + private val sharedPreferences: SharedPreferences by lazy { + LocalJobsApplication.applicationContext() + .getSharedPreferences("favorites", Context.MODE_PRIVATE) + } + + private var favorites: MutableSet? = null + + override fun add(job: Job) { + val favKeys = sharedPreferences.getStringSet(FAV_KEY, mutableSetOf()) + ?: mutableSetOf() + favKeys.add(job.id) + sharedPreferences.edit(commit = true) { + putStringSet(FAV_KEY, favKeys) + } + favorites?.add(job) + } + + override fun remove(job: Job) { + val favKeys = sharedPreferences.getStringSet(FAV_KEY, null) ?: return + favKeys.remove(job.id) + sharedPreferences.edit(commit = true) { + putStringSet(FAV_KEY, favKeys) + } + favorites?.remove(job) + } + + override suspend fun get(): Set { + if (favorites == null) { + favorites = load() + } + return favorites as Set + } + + private suspend fun load(): MutableSet { + val favKeys = sharedPreferences.getStringSet(FAV_KEY, mutableSetOf()) + val favList = mutableSetOf() + favKeys?.forEach { key -> loader.get(key)?.let { favList.add(it) } } + return favList + } +} \ No newline at end of file From e57726262a2f0b1716ad54f0357e5e85868652c6 Mon Sep 17 00:00:00 2001 From: Luca Moroldo Date: Sun, 8 Sep 2019 18:06:30 +0200 Subject: [PATCH 4/8] add fav button --- .../com/esp/localjobs/adapters/JobItem.kt | 23 +++++++++++++++++++ app/src/main/res/layout/item_job.xml | 12 ++++++++++ 2 files changed, 35 insertions(+) diff --git a/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt b/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt index e58e1d4..de4314a 100644 --- a/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt +++ b/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt @@ -1,8 +1,10 @@ package com.esp.localjobs.adapters import android.text.format.DateUtils +import android.util.Log import android.view.View import android.widget.TextView +import androidx.annotation.UiThread import androidx.databinding.BindingAdapter import androidx.navigation.Navigation.findNavController import com.bumptech.glide.Glide @@ -13,6 +15,7 @@ import com.esp.localjobs.data.repository.userFirebaseRepository import com.esp.localjobs.databinding.ItemJobBinding import com.esp.localjobs.fragments.JobDetailsFragment import com.esp.localjobs.fragments.JobsFragmentDirections +import com.esp.localjobs.utils.favoritesManager import com.xwray.groupie.databinding.BindableItem import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope @@ -35,6 +38,26 @@ class JobItem(val job: Job) : BindableItem() { setAuthor(author) } + GlobalScope.launch(Dispatchers.IO) { + val favorites = favoritesManager.get() + Log.d("favorites", "List: $favorites") + if (favorites.contains(this@JobItem.job)) { + Log.d("favorites", "toggling: $this@JobItem.job") + launch(Dispatchers.Main) { favToggle.toggle() } + } + } + favToggle.setOnCheckedChangeListener { _, isChecked -> + if (!isChecked) { + Log.d("favorites", "removing: $this@JobItem.job") + favoritesManager.remove(this@JobItem.job) + } + else { + Log.d("favorites", "adding: $this@JobItem.job") + favoritesManager.add(this@JobItem.job) + } + } + + this@JobItem.job.imagesUri.firstOrNull()?.let { Glide.with(cardView.context).load(it).placeholder(R.drawable.placeholder).into(imageView) } ?: Glide.with(cardView.context).load("https://picsum.photos/400").placeholder(R.drawable.placeholder).into( diff --git a/app/src/main/res/layout/item_job.xml b/app/src/main/res/layout/item_job.xml index 30f3133..78df71a 100644 --- a/app/src/main/res/layout/item_job.xml +++ b/app/src/main/res/layout/item_job.xml @@ -72,6 +72,18 @@ android:background="@drawable/gradient_shape" app:layout_constraintBottom_toBottomOf="@+id/imageView"/> + + + Date: Sun, 8 Sep 2019 18:15:33 +0200 Subject: [PATCH 5/8] add cool fav button --- app/build.gradle | 3 +++ app/src/main/java/com/esp/localjobs/adapters/JobItem.kt | 4 ++-- app/src/main/res/layout/item_job.xml | 6 +++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 818f8ff..8cee1d4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -118,6 +118,9 @@ dependencies { // intro tutorial implementation 'com.github.AppIntro:AppIntro:5.1.0' + + // fav button + implementation 'com.github.ivbaranov:materialfavoritebutton:0.1.5' } // ktlint diff --git a/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt b/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt index de4314a..8e5322b 100644 --- a/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt +++ b/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt @@ -43,10 +43,10 @@ class JobItem(val job: Job) : BindableItem() { Log.d("favorites", "List: $favorites") if (favorites.contains(this@JobItem.job)) { Log.d("favorites", "toggling: $this@JobItem.job") - launch(Dispatchers.Main) { favToggle.toggle() } + launch(Dispatchers.Main) { favToggle.toggleFavorite() } } } - favToggle.setOnCheckedChangeListener { _, isChecked -> + favToggle.setOnFavoriteChangeListener { _, isChecked -> if (!isChecked) { Log.d("favorites", "removing: $this@JobItem.job") favoritesManager.remove(this@JobItem.job) diff --git a/app/src/main/res/layout/item_job.xml b/app/src/main/res/layout/item_job.xml index 78df71a..e6beb6b 100644 --- a/app/src/main/res/layout/item_job.xml +++ b/app/src/main/res/layout/item_job.xml @@ -73,12 +73,12 @@ app:layout_constraintBottom_toBottomOf="@+id/imageView"/> - Date: Sun, 8 Sep 2019 18:19:25 +0200 Subject: [PATCH 6/8] using companion object --- .../main/java/com/esp/localjobs/adapters/JobItem.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt b/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt index 8e5322b..b3b9f92 100644 --- a/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt +++ b/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt @@ -15,6 +15,7 @@ import com.esp.localjobs.data.repository.userFirebaseRepository import com.esp.localjobs.databinding.ItemJobBinding import com.esp.localjobs.fragments.JobDetailsFragment import com.esp.localjobs.fragments.JobsFragmentDirections +import com.esp.localjobs.utils.IFavoritesManager import com.esp.localjobs.utils.favoritesManager import com.xwray.groupie.databinding.BindableItem import kotlinx.coroutines.Dispatchers @@ -25,6 +26,10 @@ import kotlinx.coroutines.launch @InternalCoroutinesApi class JobItem(val job: Job) : BindableItem() { + companion object { + private val favManager: IFavoritesManager = favoritesManager + } + override fun getId() = job.uid.hashCode().toLong() @InternalCoroutinesApi @@ -39,7 +44,7 @@ class JobItem(val job: Job) : BindableItem() { } GlobalScope.launch(Dispatchers.IO) { - val favorites = favoritesManager.get() + val favorites = favManager.get() Log.d("favorites", "List: $favorites") if (favorites.contains(this@JobItem.job)) { Log.d("favorites", "toggling: $this@JobItem.job") @@ -49,11 +54,11 @@ class JobItem(val job: Job) : BindableItem() { favToggle.setOnFavoriteChangeListener { _, isChecked -> if (!isChecked) { Log.d("favorites", "removing: $this@JobItem.job") - favoritesManager.remove(this@JobItem.job) + favManager.remove(this@JobItem.job) } else { Log.d("favorites", "adding: $this@JobItem.job") - favoritesManager.add(this@JobItem.job) + favManager.add(this@JobItem.job) } } From 03cd28a8a72fe04b4f77affe0290133aa01ca1de Mon Sep 17 00:00:00 2001 From: Luca Moroldo Date: Sun, 8 Sep 2019 19:45:43 +0200 Subject: [PATCH 7/8] favorites button and interaction --- .../com/esp/localjobs/adapters/JobItem.kt | 20 ++++---- .../esp/localjobs/fragments/JobsFragment.kt | 46 ++++++++++++++++--- .../fragments/UserProfileFragment.kt | 14 ++++++ .../esp/localjobs/utils/favoritesManager.kt | 16 ++++++- app/src/main/res/layout/fragment_jobs.xml | 2 + .../main/res/layout/fragment_user_profile.xml | 9 ++++ app/src/main/res/navigation/nav_graph.xml | 4 ++ app/src/main/res/values/strings.xml | 3 ++ 8 files changed, 94 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt b/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt index b3b9f92..6439d46 100644 --- a/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt +++ b/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt @@ -21,6 +21,7 @@ import com.xwray.groupie.databinding.BindableItem import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.delay import kotlinx.coroutines.launch @InternalCoroutinesApi @@ -45,24 +46,19 @@ class JobItem(val job: Job) : BindableItem() { GlobalScope.launch(Dispatchers.IO) { val favorites = favManager.get() - Log.d("favorites", "List: $favorites") if (favorites.contains(this@JobItem.job)) { - Log.d("favorites", "toggling: $this@JobItem.job") - launch(Dispatchers.Main) { favToggle.toggleFavorite() } + favToggle.isFavorite = true } - } - favToggle.setOnFavoriteChangeListener { _, isChecked -> - if (!isChecked) { - Log.d("favorites", "removing: $this@JobItem.job") - favManager.remove(this@JobItem.job) - } - else { - Log.d("favorites", "adding: $this@JobItem.job") - favManager.add(this@JobItem.job) + favToggle.setOnFavoriteChangeListener { _, isChecked -> + if (!isChecked) + favManager.remove(this@JobItem.job) + else + favManager.add(this@JobItem.job) } } + this@JobItem.job.imagesUri.firstOrNull()?.let { Glide.with(cardView.context).load(it).placeholder(R.drawable.placeholder).into(imageView) } ?: Glide.with(cardView.context).load("https://picsum.photos/400").placeholder(R.drawable.placeholder).into( diff --git a/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt b/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt index 4177794..4b38dcc 100644 --- a/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt +++ b/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt @@ -23,6 +23,7 @@ import com.esp.localjobs.data.models.User import com.esp.localjobs.data.repository.JobsRepository import com.esp.localjobs.fragments.FiltersFragment.Companion.FILTER_FRAGMENT_TAG import com.esp.localjobs.fragments.map.LocationPickerFragment +import com.esp.localjobs.utils.favoritesManager import com.esp.localjobs.viewModels.FilterViewModel import com.esp.localjobs.viewModels.JobsViewModel import com.xwray.groupie.GroupAdapter @@ -30,14 +31,23 @@ import com.xwray.groupie.ViewHolder import kotlinx.android.synthetic.main.fragment_filter_status.* import kotlinx.android.synthetic.main.fragment_jobs.* import kotlinx.android.synthetic.main.fragment_jobs.view.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.InternalCoroutinesApi +import kotlinx.coroutines.async +import kotlinx.coroutines.launch +import kotlin.coroutines.CoroutineContext /** * Fragment used to display a list of jobs. If arguments include an User then the fragment * shows the user's jobs/proposals */ @InternalCoroutinesApi -class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener { +class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener, CoroutineScope { + private lateinit var mJob: kotlinx.coroutines.Job + override val coroutineContext: CoroutineContext + get() = mJob + Dispatchers.Main private val jobsViewModel: JobsViewModel by activityViewModels() private val filterViewModel: FilterViewModel by activityViewModels() @@ -63,9 +73,16 @@ class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener observeChangesInJobList() - args.user?.let { - setupUserJobsView(it) - } ?: observeFilters() + when { + args.user != null -> setupUserJobsView(args.user as User) + args.showFavorites -> showFavorites() + else -> observeFilters() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mJob = kotlinx.coroutines.Job() } private fun setupUI(view: View) = with(view) { @@ -146,8 +163,8 @@ class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - // hide menu actions if we are showing some user's jobs/proposals - args.user?.let { + // hide menu actions if we are showing some user's jobs/proposals or favorites + if (args.user != null || args.showFavorites) { menu.forEach { it.isVisible = false } return } @@ -229,6 +246,23 @@ class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener )) } + private fun showFavorites() = launch { + activity?.title = getString(R.string.favorites_title) + fabAdd.visibility = View.GONE + active_filters.visibility = View.GONE + + val deferredJobs = async(Dispatchers.IO) { favoritesManager.get() } + adapter.clear() + val jobs = deferredJobs.await() + if (jobs.isEmpty()) { + no_jobs_title.text = getString(R.string.empty_favorites_title) + no_jobs_message.text = "" + } + else + adapter.update(jobs.map { JobItem(it) } ) + + } + override fun onLocationPicked(location: Location, distance: Int?) { Log.d(TAG, "location: $location") filterViewModel.setLocation(location) diff --git a/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt b/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt index 264690e..d707c83 100644 --- a/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt +++ b/app/src/main/java/com/esp/localjobs/fragments/UserProfileFragment.kt @@ -77,8 +77,11 @@ class UserProfileFragment : Fragment(), CoroutineScope { } else { binding.user = user setupUserJobsButton(user) + setupFavoritesButton() logout.visibility = View.VISIBLE + favorites_button.visibility = View.VISIBLE + login.visibility = View.GONE } @@ -111,6 +114,17 @@ class UserProfileFragment : Fragment(), CoroutineScope { } } + private fun setupFavoritesButton() { + favorites_button.setOnClickListener { + val action = + UserProfileFragmentDirections.actionDestinationUserProfileToDestinationJobs( + null, + true + ) + findNavController().navigate(action) + } + } + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.menu_navigation, menu) menu.forEach { it.isVisible = false } diff --git a/app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt b/app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt index ac001e8..4d2a9ae 100644 --- a/app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt +++ b/app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt @@ -2,6 +2,7 @@ package com.esp.localjobs.utils import android.content.Context import android.content.SharedPreferences +import android.util.Log import androidx.core.content.edit import com.esp.localjobs.LocalJobsApplication import com.esp.localjobs.data.base.BaseRepository @@ -25,17 +26,27 @@ object favoritesManager : IFavoritesManager { val favKeys = sharedPreferences.getStringSet(FAV_KEY, mutableSetOf()) ?: mutableSetOf() favKeys.add(job.id) + Log.d("favorites", "adding: ${job.id}") sharedPreferences.edit(commit = true) { + // stringSet is bugged so i must do this :/ + remove(FAV_KEY) + apply() putStringSet(FAV_KEY, favKeys) + apply() } favorites?.add(job) } override fun remove(job: Job) { - val favKeys = sharedPreferences.getStringSet(FAV_KEY, null) ?: return + val favKeys = sharedPreferences.getStringSet(FAV_KEY, mutableSetOf()) ?: return favKeys.remove(job.id) + Log.d("favorites", "removing: ${job.id}") sharedPreferences.edit(commit = true) { + // stringSet is bugged so i must do this :/ + remove(FAV_KEY) + apply() putStringSet(FAV_KEY, favKeys) + apply() } favorites?.remove(job) } @@ -44,11 +55,12 @@ object favoritesManager : IFavoritesManager { if (favorites == null) { favorites = load() } - return favorites as Set + return (favorites as MutableSet).toSet() } private suspend fun load(): MutableSet { val favKeys = sharedPreferences.getStringSet(FAV_KEY, mutableSetOf()) + Log.d("favorites", "loading: $favKeys") val favList = mutableSetOf() favKeys?.forEach { key -> loader.get(key)?.let { favList.add(it) } } return favList diff --git a/app/src/main/res/layout/fragment_jobs.xml b/app/src/main/res/layout/fragment_jobs.xml index f887bf4..bd18727 100644 --- a/app/src/main/res/layout/fragment_jobs.xml +++ b/app/src/main/res/layout/fragment_jobs.xml @@ -68,6 +68,7 @@ android:padding="50dp"> + + \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 9aaf201..26b8412 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -34,6 +34,10 @@ app:argType="com.esp.localjobs.data.models.User" app:nullable="true" android:defaultValue="@null" /> + In the past %1$s\'s stuff Jobs and proposals + Favorites + Favorites + Empty favorites! From cf102fd3951fe50750af5664424bc6959e3bd325 Mon Sep 17 00:00:00 2001 From: Luca Moroldo Date: Sun, 8 Sep 2019 19:46:00 +0200 Subject: [PATCH 8/8] ktlint --- app/src/main/java/com/esp/localjobs/adapters/JobItem.kt | 5 ----- .../main/java/com/esp/localjobs/fragments/JobsFragment.kt | 7 ++----- .../main/java/com/esp/localjobs/utils/favoritesManager.kt | 2 -- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt b/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt index 6439d46..8771244 100644 --- a/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt +++ b/app/src/main/java/com/esp/localjobs/adapters/JobItem.kt @@ -1,10 +1,8 @@ package com.esp.localjobs.adapters import android.text.format.DateUtils -import android.util.Log import android.view.View import android.widget.TextView -import androidx.annotation.UiThread import androidx.databinding.BindingAdapter import androidx.navigation.Navigation.findNavController import com.bumptech.glide.Glide @@ -21,7 +19,6 @@ import com.xwray.groupie.databinding.BindableItem import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.InternalCoroutinesApi -import kotlinx.coroutines.delay import kotlinx.coroutines.launch @InternalCoroutinesApi @@ -57,8 +54,6 @@ class JobItem(val job: Job) : BindableItem() { } } - - this@JobItem.job.imagesUri.firstOrNull()?.let { Glide.with(cardView.context).load(it).placeholder(R.drawable.placeholder).into(imageView) } ?: Glide.with(cardView.context).load("https://picsum.photos/400").placeholder(R.drawable.placeholder).into( diff --git a/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt b/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt index 4b38dcc..bd7b80e 100644 --- a/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt +++ b/app/src/main/java/com/esp/localjobs/fragments/JobsFragment.kt @@ -33,7 +33,6 @@ import kotlinx.android.synthetic.main.fragment_jobs.* import kotlinx.android.synthetic.main.fragment_jobs.view.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.InternalCoroutinesApi import kotlinx.coroutines.async import kotlinx.coroutines.launch @@ -257,10 +256,8 @@ class JobsFragment : Fragment(), LocationPickerFragment.OnLocationPickedListener if (jobs.isEmpty()) { no_jobs_title.text = getString(R.string.empty_favorites_title) no_jobs_message.text = "" - } - else - adapter.update(jobs.map { JobItem(it) } ) - + } else + adapter.update(jobs.map { JobItem(it) }) } override fun onLocationPicked(location: Location, distance: Int?) { diff --git a/app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt b/app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt index 4d2a9ae..bad52f7 100644 --- a/app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt +++ b/app/src/main/java/com/esp/localjobs/utils/favoritesManager.kt @@ -8,8 +8,6 @@ import com.esp.localjobs.LocalJobsApplication import com.esp.localjobs.data.base.BaseRepository import com.esp.localjobs.data.models.Job import com.esp.localjobs.data.repository.JobsRepository -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch object favoritesManager : IFavoritesManager { private const val FAV_KEY = "favourites_ids"