From e75246ff46f7faa00af6d1fd4de63ea5deba5bc8 Mon Sep 17 00:00:00 2001 From: h4h13 Date: Fri, 25 Oct 2019 01:38:09 +0530 Subject: [PATCH] Fix search slow, last added slow --- .github/stale.yml | 61 ++++ app/build.gradle | 20 +- .../name/monkey/retromusic/AppExecutors.kt | 27 ++ .../code/name/monkey/retromusic/Result.kt | 24 ++ .../retromusic/activities/MainActivity.kt | 1 - .../activities/PlaylistDetailActivity.kt | 17 +- .../retromusic/activities/SearchActivity.kt | 21 +- .../monkey/retromusic/adapter/HomeAdapter.kt | 59 ++-- .../retromusic/adapter/SearchAdapter.kt | 22 +- .../adapter/playlist/PlaylistAdapter.kt | 2 - .../AbsLibraryPagerRecyclerViewFragment.kt | 2 +- .../mainactivity/home/BannerHomeFragment.kt | 21 +- .../monkey/retromusic/loaders/SearchLoader.kt | 1 - .../misc/AsyncSearchResultLoader.kt | 50 ++++ .../name/monkey/retromusic/mvp/Presenter.kt | 4 + .../mvp/presenter/AlbumPresenter.kt | 30 +- .../mvp/presenter/ArtistPresenter.kt | 22 +- .../mvp/presenter/GenreDetailsPresenter.kt | 25 +- .../mvp/presenter/GenrePresenter.kt | 25 +- .../retromusic/mvp/presenter/HomePresenter.kt | 263 ++---------------- .../mvp/presenter/PlaylistPresenter.kt | 28 +- .../mvp/presenter/PlaylistSongsPresenter.kt | 25 +- .../mvp/presenter/SearchPresenter.kt | 28 +- .../retromusic/mvp/presenter/SongPresenter.kt | 22 +- .../retromusic/providers/RepositoryImpl.kt | 257 +++++++++++++---- .../providers/interfaces/Repository.kt | 46 +-- .../res/layout-land/fragment_banner_home.xml | 11 +- .../fragment_banner_home.xml | 9 + .../layout-xlarge/fragment_banner_home.xml | 10 +- .../res/layout/activity_playlist_detail.xml | 40 +-- app/src/main/res/layout/activity_search.xml | 45 ++- .../main/res/layout/fragment_banner_home.xml | 9 +- .../layout/metal_section_recycler_view.xml | 1 + .../main/res/layout/section_recycler_view.xml | 1 + app/src/main/res/values/strings.xml | 2 +- appthemehelper/build.gradle | 2 +- 36 files changed, 732 insertions(+), 501 deletions(-) create mode 100644 .github/stale.yml create mode 100644 app/src/main/java/code/name/monkey/retromusic/AppExecutors.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/Result.kt create mode 100644 app/src/main/java/code/name/monkey/retromusic/misc/AsyncSearchResultLoader.kt diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000..3603948a --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,61 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 60 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 7 + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - pinned + - security + - "[Status] Maybe Later" + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: false + +# Label to use when marking as stale +staleLabel: wontfix + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +# closeComment: > +# Your comment here. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +# only: issues + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +# pulls: +# daysUntilStale: 30 +# markComment: > +# This pull request has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. + +# issues: +# exemptLabels: +# - confirmed \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 918d6b78..81403928 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -83,6 +83,7 @@ android { kapt { generateStubs = true } + } def getProperties(String fileName) { @@ -107,9 +108,9 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation project(':appthemehelper') implementation 'androidx.multidex:multidex:2.0.1' - implementation 'androidx.fragment:fragment:1.2.0-alpha04' + implementation 'androidx.fragment:fragment:1.2.0-beta02' implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.recyclerview:recyclerview:1.1.0-beta04' + implementation 'androidx.recyclerview:recyclerview:1.1.0-beta05' implementation "androidx.gridlayout:gridlayout:1.0.0" implementation "androidx.cardview:cardview:1.0.0" implementation "androidx.palette:palette:1.0.0" @@ -118,12 +119,12 @@ dependencies { implementation 'androidx.palette:palette-ktx:1.0.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'com.google.android.material:material:1.1.0-beta01' + implementation 'com.google.android.material:material:1.2.0-alpha01' implementation 'com.google.android.play:core:1.6.3' - implementation 'com.squareup.retrofit2:retrofit:2.6.1' - implementation 'com.squareup.retrofit2:converter-gson:2.6.1' - implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.1' + implementation 'com.squareup.retrofit2:retrofit:2.6.2' + implementation 'com.squareup.retrofit2:converter-gson:2.6.2' + implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.2' implementation 'com.afollestad.material-dialogs:core:3.1.1' implementation 'com.afollestad.material-dialogs:input:3.1.1' @@ -147,6 +148,10 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1" + + implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:3.4.0.201406110918-r' implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0' @@ -162,5 +167,4 @@ dependencies { kapt 'com.google.dagger:dagger-compiler:2.23.1' -} - +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/AppExecutors.kt b/app/src/main/java/code/name/monkey/retromusic/AppExecutors.kt new file mode 100644 index 00000000..7d8c5aaf --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/AppExecutors.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ + +package code.name.monkey.retromusic + +import kotlinx.coroutines.Dispatchers +import kotlin.coroutines.CoroutineContext + +/** + * Created by hemanths on 2019-10-23. + */ + +class AppExecutors constructor( + val ioContext: CoroutineContext = Dispatchers.IO, + val uiContext: CoroutineContext = Dispatchers.Main +) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/Result.kt b/app/src/main/java/code/name/monkey/retromusic/Result.kt new file mode 100644 index 00000000..f2f00f8b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/Result.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ + +package code.name.monkey.retromusic + +/** + * Created by hemanths on 2019-10-23. + */ + +sealed class Result { + class Success(val data: T) : Result() + class Error(val exception: Throwable) : Result() +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt index eb740960..e21e597c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt @@ -129,7 +129,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP val uri = intent.data val mimeType = intent.type var handled = false - println("uri -> $uri") if (intent.action != null && intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH) { val songs = SearchQueryHelper.getSongs(this, intent.extras!!) if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) { diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt index be59d515..19930a4a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt @@ -25,6 +25,7 @@ import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsPresenter import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsView +import code.name.monkey.retromusic.util.DensityUtil import code.name.monkey.retromusic.util.PlaylistsUtil import code.name.monkey.retromusic.util.RetroColorUtil import code.name.monkey.retromusic.util.ViewUtil @@ -50,6 +51,9 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli override fun onCreate(savedInstanceState: Bundle?) { setDrawUnderStatusBar() super.onCreate(savedInstanceState) + App.musicComponent.inject(this) + + playlistSongsPresenter.attachView(this) setStatusbarColor(Color.TRANSPARENT) setNavigationbarColorAuto() @@ -65,10 +69,6 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli finish() } - App.musicComponent.inject(this) - - playlistSongsPresenter.attachView(this) - setUpToolBar() setUpRecyclerView() } @@ -160,14 +160,12 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli override fun onMediaStoreChanged() { super.onMediaStoreChanged() - if (playlist !is AbsCustomPlaylist) { // Playlist deleted if (!PlaylistsUtil.doesPlaylistExist(this, playlist.id)) { finish() return } - // Playlist renamed val playlistName = PlaylistsUtil.getNameForPlaylist(this, playlist.id.toLong()) if (playlistName != playlist.name) { @@ -182,8 +180,13 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli supportActionBar!!.title = title } - private fun checkIsEmpty() { + private fun checkForPadding() { + val height = DensityUtil.dip2px(this, 52f) + recyclerView.setPadding(0, 0, 0, (height )) + } + private fun checkIsEmpty() { + checkForPadding() empty.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE emptyText.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/SearchActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/SearchActivity.kt index 0fb0e5bc..e9bcbab4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/SearchActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/SearchActivity.kt @@ -1,10 +1,8 @@ package code.name.monkey.retromusic.activities import android.app.Activity -import android.app.SearchManager import android.app.Service import android.content.ActivityNotFoundException -import android.content.Context import android.content.Intent import android.content.res.ColorStateList import android.os.Bundle @@ -77,6 +75,10 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch keyboardPopup.setTextColor(this) keyboardPopup.iconTint = this } + if (savedInstanceState != null) { + query = savedInstanceState.getString(QUERY); + } + } private fun setupRecyclerView() { @@ -104,15 +106,9 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch } private fun setupSearchView() { - getSystemService(Context.SEARCH_SERVICE) as SearchManager searchView.addTextChangedListener(this) } - override fun onResume() { - super.onResume() - searchPresenter.search(query) - } - override fun onDestroy() { super.onDestroy() searchPresenter.detachView() @@ -123,11 +119,6 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch outState.putString(QUERY, query) } - override fun onRestoreInstanceState(savedInstanceState: Bundle) { - super.onRestoreInstanceState(savedInstanceState) - searchPresenter.search(savedInstanceState.getString(QUERY, "")) - } - private fun setUpToolBar() { title = null appBarLayout.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary)) @@ -135,14 +126,14 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch private fun search(query: String) { - this.query = query.trim { it <= ' ' } + this.query = query voiceSearch.visibility = if (query.isNotEmpty()) View.GONE else View.VISIBLE searchPresenter.search(query) } override fun onMediaStoreChanged() { super.onMediaStoreChanged() - searchPresenter.search(query!!) + query?.let { search(it) } } override fun onQueryTextSubmit(query: String): Boolean { diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt index b9c3c8a2..3a0c9510 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt @@ -16,27 +16,21 @@ import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.loaders.PlaylistSongsLoader import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Artist +import code.name.monkey.retromusic.model.Home import code.name.monkey.retromusic.model.Playlist -import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.util.PreferenceUtil import com.google.android.material.textview.MaterialTextView class HomeAdapter( private val activity: AppCompatActivity, - private val displayMetrics: DisplayMetrics, - private val repository: Repository + private val displayMetrics: DisplayMetrics ) : RecyclerView.Adapter() { + private var list = ArrayList() + override fun getItemViewType(position: Int): Int { - return when (position) { - 0 -> TOP_ARTISTS - 1 -> TOP_ALBUMS - 2 -> RECENT_ARTISTS - 3 -> RECENT_ALBUMS - 4 -> PLAYLISTS - else -> -1 - } + return list[position].homeSection } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { @@ -51,35 +45,39 @@ class HomeAdapter( } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - println(getItemViewType(position)) + println("ViewType ${getItemViewType(position)}") when (getItemViewType(position)) { RECENT_ALBUMS -> { val viewHolder = holder as AlbumViewHolder - viewHolder.bindView(repository.recentAlbums(), R.string.recent_albums, R.string.recent_added_albums) + viewHolder.bindView(list[position].arrayList.toAlbums(), R.string.recent_albums, R.string.recent_added_albums) } TOP_ALBUMS -> { val viewHolder = holder as AlbumViewHolder - - viewHolder.bindView(repository.topAlbums(), R.string.top_albums, R.string.most_played_albums) + viewHolder.bindView(list[position].arrayList.toAlbums(), R.string.top_albums, R.string.most_played_albums) } RECENT_ARTISTS -> { val viewHolder = holder as ArtistViewHolder - viewHolder.bindView(repository.recentArtists(), R.string.recent_artists, R.string.recent_added_artists) + viewHolder.bindView(list[position].arrayList.toArtists(), R.string.recent_artists, R.string.recent_added_artists) } TOP_ARTISTS -> { val viewHolder = holder as ArtistViewHolder - viewHolder.bindView(repository.recentArtists(), R.string.top_artists, R.string.most_played_artists) + viewHolder.bindView(list[position].arrayList.toArtists(), R.string.top_artists, R.string.most_played_artists) } PLAYLISTS -> { val viewHolder = holder as PlaylistViewHolder - viewHolder.bindView(repository.favoritePlaylist, R.string.favorites, R.string.favorites_songs) + viewHolder.bindView(list[position].arrayList as ArrayList, R.string.favorites, R.string.favorites_songs) } } } override fun getItemCount(): Int { - return 5 + return list.size + } + + fun swapData(sections: ArrayList) { + list = sections + notifyDataSetChanged() } companion object { @@ -103,11 +101,13 @@ class HomeAdapter( show() adapter = AlbumFullWidthAdapter(activity, list, displayMetrics) } - titleContainer . show () + titleContainer.show() title.text = activity.getString(titleRes) text.text = activity.getString(subtitleRes) } } + + } inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) { @@ -153,4 +153,21 @@ class HomeAdapter( val title: MaterialTextView = itemView.findViewById(R.id.title) val text: MaterialTextView = itemView.findViewById(R.id.text) } -} \ No newline at end of file +} + +private fun ArrayList.toAlbums(): ArrayList { + val arrayList = ArrayList() + for (x in this) { + arrayList.add(x as Album) + } + return arrayList; +} + +private fun ArrayList.toArtists(): ArrayList { + val arrayList = ArrayList() + for (x in this) { + arrayList.add(x as Artist) + } + return arrayList; +} + diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt index 36f2fa4d..b7756540 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt @@ -19,7 +19,6 @@ import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.NavigationUtil import com.bumptech.glide.Glide -import java.util.* import android.util.Pair as UtilPair class SearchAdapter( @@ -57,7 +56,7 @@ class SearchAdapter( holder.title?.text = artist.name holder.text?.text = MusicUtil.getArtistInfoString(activity, artist) ArtistGlideRequest.Builder.from(Glide.with(activity), artist) - .build().into(holder.image); + .build().into(holder.image) } SONG -> { val song = dataSet?.get(position) as Song @@ -79,16 +78,14 @@ class SearchAdapter( init { itemView.setOnLongClickListener(null) - if (menu != null) { - if (itemViewType == SONG) { - menu!!.visibility = View.VISIBLE - menu!!.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) { - override val song: Song - get() = dataSet!![adapterPosition] as Song - }) - } else { - menu!!.visibility = View.GONE - } + if (itemViewType == SONG) { + menu?.visibility = View.VISIBLE + menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) { + override val song: Song + get() = dataSet!![adapterPosition] as Song + }) + } else { + menu?.visibility = View.GONE } when (itemViewType) { @@ -126,7 +123,6 @@ class SearchAdapter( } companion object { - private const val HEADER = 0 private const val ALBUM = 1 private const val ARTIST = 2 diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt index 885170c0..17d4f738 100755 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt @@ -215,9 +215,7 @@ class PlaylistAdapter(protected val activity: AppCompatActivity, dataSet: ArrayL } companion object { - val TAG: String = PlaylistAdapter::class.java.simpleName - private const val SMART_PLAYLIST = 0 private const val DEFAULT_PLAYLIST = 1 } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsLibraryPagerRecyclerViewFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsLibraryPagerRecyclerViewFragment.kt index 420d3620..5cab5db5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsLibraryPagerRecyclerViewFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsLibraryPagerRecyclerViewFragment.kt @@ -44,7 +44,7 @@ abstract class AbsLibraryPagerRecyclerViewFragment, private fun initAdapter() { adapter = createAdapter() - adapter!!.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { + adapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { override fun onChanged() { super.onChanged() checkIsEmpty() diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/home/BannerHomeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/home/BannerHomeFragment.kt index 667d5646..eb94a098 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/home/BannerHomeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/home/BannerHomeFragment.kt @@ -2,7 +2,6 @@ package code.name.monkey.retromusic.fragments.mainactivity.home import android.app.ActivityOptions import android.graphics.Bitmap -import android.graphics.Color import android.os.Bundle import android.util.DisplayMetrics import android.view.* @@ -18,7 +17,6 @@ import code.name.monkey.retromusic.Constants.USER_BANNER import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.HomeAdapter import code.name.monkey.retromusic.dialogs.OptionsSheetDialogFragment -import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.helper.MusicPlayerRemote @@ -28,8 +26,8 @@ import code.name.monkey.retromusic.model.Home import code.name.monkey.retromusic.model.smartplaylist.HistoryPlaylist import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist +import code.name.monkey.retromusic.mvp.presenter.HomePresenter import code.name.monkey.retromusic.mvp.presenter.HomeView -import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.util.Compressor import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.PreferenceUtil @@ -49,19 +47,14 @@ import javax.inject.Inject class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallbacks, HomeView { private lateinit var homeAdapter: HomeAdapter @Inject - lateinit var repository: Repository + lateinit var homePresenter: HomePresenter private var disposable: CompositeDisposable = CompositeDisposable() private lateinit var toolbar: Toolbar override fun sections(sections: ArrayList) { - val finalList = sections.sortedWith(compareBy { it.priority }) - - if (sections.isEmpty()) { - showEmptyView() - } else { - emptyContainer.hide() - } + println(sections.size) + homeAdapter.swapData(sections) } override fun onCreateView(inflater: LayoutInflater, viewGroup: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -133,17 +126,18 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba titleWelcome.text = String.format("%s", PreferenceUtil.getInstance(requireContext()).userName) App.musicComponent.inject(this) - homeAdapter = HomeAdapter(mainActivity, displayMetrics, repository) + homeAdapter = HomeAdapter(mainActivity, displayMetrics) recyclerView.apply { layoutManager = LinearLayoutManager(mainActivity) adapter = homeAdapter } + homePresenter.attachView(this) + homePresenter.loadSections() } private fun toolbarColor(): Int { return if (PreferenceUtil.getInstance(requireContext()).isHomeBanner) { - toolbarContainer.setBackgroundColor(Color.TRANSPARENT) ColorUtil.withAlpha(RetroColorUtil.toolbarColor(mainActivity), 0.85f) } else { RetroColorUtil.toolbarColor(mainActivity) @@ -176,6 +170,7 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba override fun onDestroyView() { super.onDestroyView() disposable.dispose() + homePresenter.detachView() } override fun showEmptyView() { diff --git a/app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.kt b/app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.kt index ef7395bf..80708e11 100644 --- a/app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.kt +++ b/app/src/main/java/code/name/monkey/retromusic/loaders/SearchLoader.kt @@ -16,7 +16,6 @@ package code.name.monkey.retromusic.loaders import android.content.Context import code.name.monkey.retromusic.R -import io.reactivex.Observable object SearchLoader { diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/AsyncSearchResultLoader.kt b/app/src/main/java/code/name/monkey/retromusic/misc/AsyncSearchResultLoader.kt new file mode 100644 index 00000000..a9c9486a --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/misc/AsyncSearchResultLoader.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ + +package code.name.monkey.retromusic.misc + +import android.content.Context +import android.text.TextUtils +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.loaders.AlbumLoader +import code.name.monkey.retromusic.loaders.ArtistLoader +import code.name.monkey.retromusic.loaders.SongLoader +import java.util.* + +internal class AsyncSearchResultLoader(context: Context, private val query: String) : WrappedAsyncTaskLoader>(context) { + + override fun loadInBackground(): List? { + val results = ArrayList() + if (!TextUtils.isEmpty(query)) { + val songs = SongLoader.getSongs(context, query.trim { it <= ' ' }) + if (!songs.isEmpty()) { + results.add(context.resources.getString(R.string.songs)) + results.addAll(songs) + } + + val artists = ArtistLoader.getArtists(context, query.trim { it <= ' ' }) + if (!artists.isEmpty()) { + results.add(context.resources.getString(R.string.artists)) + results.addAll(artists) + } + + val albums = AlbumLoader.getAlbums(context, query.trim { it <= ' ' }) + if (!albums.isEmpty()) { + results.add(context.resources.getString(R.string.albums)) + results.addAll(albums) + } + } + return results + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/Presenter.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/Presenter.kt index 1772b347..3e6889ad 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/Presenter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/Presenter.kt @@ -14,13 +14,17 @@ package code.name.monkey.retromusic.mvp +import androidx.annotation.CallSuper + /** * Created by hemanths on 16/08/17. */ interface Presenter { + @CallSuper fun attachView(view: T) + @CallSuper fun detachView() } diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumPresenter.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumPresenter.kt index 0ba96d25..e60898bd 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumPresenter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/AlbumPresenter.kt @@ -14,14 +14,16 @@ package code.name.monkey.retromusic.mvp.presenter +import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.providers.interfaces.Repository -import io.reactivex.disposables.Disposable +import kotlinx.coroutines.* import java.util.* import javax.inject.Inject +import kotlin.coroutines.CoroutineContext /** @@ -37,22 +39,30 @@ interface AlbumsPresenter : Presenter { class AlbumsPresenterImpl @Inject constructor( private val repository: Repository - ) : PresenterImpl(), AlbumsPresenter { + ) : PresenterImpl(), AlbumsPresenter, CoroutineScope { + private val job = Job() - private var disposable: Disposable? = null - - private fun showList(albums: ArrayList) { - view?.albums(albums) - } + override val coroutineContext: CoroutineContext + get() = Dispatchers.IO + job override fun detachView() { super.detachView() - disposable?.dispose() + job.cancel() } override fun loadAlbums() { - disposable = repository.allAlbumsFlowable - .subscribe({ view?.albums(it) }, { t -> println(t) }) + launch { + when (val result = repository.allAlbums()) { + is Result.Success -> { + withContext(Dispatchers.Main) { + view?.albums(result.data) + } + } + is Result.Error -> { + view?.showEmptyView() + } + } + } } } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistPresenter.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistPresenter.kt index c77f380d..6b0a0f96 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistPresenter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/ArtistPresenter.kt @@ -14,13 +14,15 @@ package code.name.monkey.retromusic.mvp.presenter +import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.providers.interfaces.Repository -import io.reactivex.disposables.Disposable +import kotlinx.coroutines.* import javax.inject.Inject +import kotlin.coroutines.CoroutineContext interface ArtistsView : BaseView { fun artists(artists: ArrayList) @@ -32,18 +34,26 @@ interface ArtistsPresenter : Presenter { class ArtistsPresenterImpl @Inject constructor( private val repository: Repository - ) : PresenterImpl(), ArtistsPresenter { + ) : PresenterImpl(), ArtistsPresenter, CoroutineScope { + private val job = Job() - private var disposable: Disposable? = null + override val coroutineContext: CoroutineContext + get() = Dispatchers.IO + job override fun detachView() { super.detachView() - disposable?.dispose() + job.cancel() } override fun loadArtists() { - disposable = repository.allArtistsFlowable - .subscribe({ view?.artists(it) }, { t -> println(t) }) + launch { + when (val result = repository.allArtists()) { + is Result.Success -> withContext(Dispatchers.Main) { + view?.artists(result.data) + } + is Result.Error -> withContext(Dispatchers.Main) { view?.showEmptyView() } + } + } } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenreDetailsPresenter.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenreDetailsPresenter.kt index d62ab123..4fe21bf7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenreDetailsPresenter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenreDetailsPresenter.kt @@ -14,14 +14,16 @@ package code.name.monkey.retromusic.mvp.presenter +import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.providers.interfaces.Repository -import io.reactivex.disposables.Disposable +import kotlinx.coroutines.* import java.util.* import javax.inject.Inject +import kotlin.coroutines.CoroutineContext /** @@ -37,18 +39,29 @@ interface GenreDetailsPresenter : Presenter { class GenreDetailsPresenterImpl @Inject constructor( private val repository: Repository - ) : PresenterImpl(), GenreDetailsPresenter { + ) : PresenterImpl(), GenreDetailsPresenter, CoroutineScope { + private val job = Job() + + override val coroutineContext: CoroutineContext + get() = Dispatchers.IO + job override fun detachView() { super.detachView() - disposable?.dispose() + job.cancel() } - private var disposable: Disposable? = null override fun loadGenreSongs(genreId: Int) { - disposable = repository.getGenreFlowable(genreId) - .subscribe({ view?.songs(it) }, { t -> println(t) }) + launch { + when (val result = repository.getGenre(genreId)) { + is Result.Success -> withContext(Dispatchers.Main) { + view?.songs(result.data) + } + is Result.Error -> withContext(Dispatchers.Main) { + view?.showEmptyView() + } + } + } } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenrePresenter.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenrePresenter.kt index 399a4a97..c929ab22 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenrePresenter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/GenrePresenter.kt @@ -14,14 +14,16 @@ package code.name.monkey.retromusic.mvp.presenter +import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.providers.interfaces.Repository -import io.reactivex.disposables.Disposable +import kotlinx.coroutines.* import java.util.* import javax.inject.Inject +import kotlin.coroutines.CoroutineContext /** * @author Hemanth S (h4h13). @@ -35,13 +37,26 @@ interface GenresPresenter : Presenter { class GenresPresenterImpl @Inject constructor( private val repository: Repository - ) : PresenterImpl(), GenresPresenter { + ) : PresenterImpl(), GenresPresenter, CoroutineScope { + private val job = Job() - private var disposable: Disposable? = null + override val coroutineContext: CoroutineContext + get() = Dispatchers.IO + job + + override fun detachView() { + super.detachView() + job.cancel() + } override fun loadGenres() { - disposable = repository.allGenresFlowable - .subscribe({ view.genres(it) }, { t -> println(t) }) + launch { + when (val result = repository.allGenres()) { + is Result.Success -> withContext(Dispatchers.Main) { + view?.genres(result.data) + } + is Result.Error -> withContext(Dispatchers.Main) { view?.showEmptyView() } + } + } } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/HomePresenter.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/HomePresenter.kt index c89ad868..ea2dca6a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/HomePresenter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/HomePresenter.kt @@ -14,12 +14,7 @@ package code.name.monkey.retromusic.mvp.presenter -import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.adapter.HomeAdapter.Companion.PLAYLISTS -import code.name.monkey.retromusic.adapter.HomeAdapter.Companion.RECENT_ALBUMS -import code.name.monkey.retromusic.adapter.HomeAdapter.Companion.RECENT_ARTISTS -import code.name.monkey.retromusic.adapter.HomeAdapter.Companion.TOP_ALBUMS -import code.name.monkey.retromusic.adapter.HomeAdapter.Companion.TOP_ARTISTS +import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.model.Home import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.Presenter @@ -27,7 +22,9 @@ import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.providers.interfaces.Repository import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable +import kotlinx.coroutines.* import javax.inject.Inject +import kotlin.coroutines.CoroutineContext operator fun CompositeDisposable.plusAssign(disposable: Disposable) { add(disposable) @@ -40,238 +37,38 @@ interface HomeView : BaseView { interface HomePresenter : Presenter { fun loadSections() - class HomePresenterImpl @Inject constructor( private val repository: Repository - ) : PresenterImpl(), HomePresenter { + ) : PresenterImpl(), HomePresenter, CoroutineScope { + private val job = Job() - private val hashSet: HashSet = HashSet() + override val coroutineContext: CoroutineContext + get() = Dispatchers.IO + job + + override fun detachView() { + super.detachView() + job.cancel() + } override fun loadSections() { - loadRecentArtists() - loadRecentAlbums() - loadTopArtists() - loadATopAlbums() - loadFavorite() - //loadHomeSection() - } - - private var disposable: CompositeDisposable = CompositeDisposable() - - private fun showData(sections: ArrayList) { - if (sections.isEmpty()) { - view.showEmptyView() - } else { - view.sections(sections) + launch { + val list = ArrayList() + val recentArtistResult = listOf( + repository.topArtists(), + repository.topAlbums(), + repository.recentArtists(), + repository.recentAlbums(), + repository.favoritePlaylist() + ) + for (r in recentArtistResult) { + when (r) { + is Result.Success -> list.add(r.data) + } + } + withContext(Dispatchers.Main) { + if (list.isNotEmpty()) view?.sections(list) else view?.showEmptyView() + } } } - - private fun loadRecentArtists() { - disposable += repository.recentArtistsFlowable - .subscribe { - if (it.isNotEmpty()) hashSet.add( - Home(0, - R.string.recent_artists, - R.string.recent_added_artists, - it, - RECENT_ARTISTS, - R.drawable.ic_artist_white_24dp - )) - showData(ArrayList(hashSet)) - } - } - - private fun loadRecentAlbums() { - disposable += repository.recentAlbumsFlowable - .subscribe { - if (it.isNotEmpty()) hashSet.add( - Home(1, - R.string.recent_albums, - R.string.recent_added_albums, - it, - RECENT_ALBUMS, - R.drawable.ic_album_white_24dp - )) - showData(ArrayList(hashSet)) - } - } - - private fun loadTopArtists() { - disposable += repository.topArtistsFlowable - .subscribe { - if (it.isNotEmpty()) hashSet.add( - Home(2, - R.string.top_artists, - R.string.most_played_artists, - it, - TOP_ARTISTS, - R.drawable.ic_artist_white_24dp - )) - showData(ArrayList(hashSet)) - } - } - - private fun loadATopAlbums() { - disposable += repository.topAlbumsFlowable - .subscribe { - if (it.isNotEmpty()) hashSet.add( - Home(3, - R.string.top_albums, - R.string.most_played_albums, - it, - TOP_ALBUMS, - R.drawable.ic_album_white_24dp - )) - showData(ArrayList(hashSet)) - } - } - - private fun loadFavorite() { - disposable += repository.favoritePlaylistFlowable - .subscribe { - if (it.isNotEmpty()) hashSet.add( - Home(4, - R.string.favorites, - R.string.favorites_songs, - it, - PLAYLISTS, - R.drawable.ic_favorite_white_24dp - )) - showData(ArrayList(hashSet)) - } - } - - /*private fun loadHomeSection() { - val ob = listOf(repository.recentArtistsFlowable, - repository.recentAlbumsFlowable, - repository.topArtistsFlowable, - repository.topAlbumsFlowable, - repository.favoritePlaylistFlowable) - - disposable += Observable.combineLatest(ob) { - val hashSet: HashSet = HashSet() - val recentArtist = it[0] as ArrayList - if (recentArtist.isNotEmpty()) hashSet.add( - Home(0, - R.string.recent_artists, - 0, - recentArtist, - RECENT_ARTISTS, - R.drawable.ic_artist_white_24dp - )) - val recentAlbums = it[1] as ArrayList - if (recentAlbums.isNotEmpty()) hashSet.add( - Home(1, - R.string.recent_albums, - 0, - recentAlbums, - RECENT_ALBUMS, - R.drawable.ic_album_white_24dp - )) - val topArtists = it[2] as ArrayList - if (topArtists.isNotEmpty()) hashSet.add( - Home(2, - R.string.top_artists, - 0, - topArtists, - TOP_ARTISTS, - R.drawable.ic_artist_white_24dp - )) - val topAlbums = it[3] as ArrayList - if (topAlbums.isNotEmpty()) hashSet.add( - Home(3, - R.string.top_albums, - 0, - topAlbums, - TOP_ALBUMS, - R.drawable.ic_album_white_24dp - )) - val playlists = it[4] as ArrayList - if (playlists.isNotEmpty()) hashSet.add( - Home(4, - R.string.favorites, - 0, - playlists, - PLAYLISTS, - R.drawable.ic_favorite_white_24dp - )) - return@combineLatest hashSet - }.subscribe { - view.sections(ArrayList(it)) - } - }*/ } -} - -/*class HomePresenter( - private val view: HomeContract.HomeView, - private val repositoryImpl: RepositoryImpl -) : Presenter(), HomeContract.HomePresenter { - private val hashSet: HashSet = HashSet() - - override fun homeSections() { - loadRecentArtists() - loadRecentAlbums() - loadTopArtists() - loadATopAlbums() - loadFavorite() - } - - override fun subscribe() { - homeSections() - } - - override fun unsubscribe() { - disposable.dispose() - } - - private fun loadRecentArtists() { - disposable += repositoryImpl.recentArtistsFlowable - .subscribe({ - if (it.isNotEmpty()) hashSet.add(Home(0, R.string.recent_artists, 0, it, RECENT_ARTISTS, R.drawable.ic_artist_white_24dp)) - view.showData(ArrayList(hashSet)) - }, { - view.showEmptyView() - }) - } - - private fun loadRecentAlbums() { - disposable += repositoryImpl.recentAlbumsFlowable - .subscribe({ - if (it.isNotEmpty()) hashSet.add(Home(1, R.string.recent_albums, 0, it, RECENT_ALBUMS, R.drawable.ic_album_white_24dp)) - view.showData(ArrayList(hashSet)) - }, { - view.showEmptyView() - }) - } - - private fun loadATopAlbums() { - disposable += repositoryImpl.topAlbumsFlowable - .subscribe({ - if (it.isNotEmpty()) hashSet.add(Home(3, R.string.top_albums, 0, it, TOP_ALBUMS, R.drawable.ic_album_white_24dp)) - view.showData(ArrayList(hashSet)) - }, { - view.showEmptyView() - }) - } - - private fun loadTopArtists() { - disposable += repositoryImpl.topArtistsFlowable - .subscribe({ - if (it.isNotEmpty()) hashSet.add(Home(2, R.string.top_artists, 0, it, TOP_ARTISTS, R.drawable.ic_artist_white_24dp)) - view.showData(ArrayList(hashSet)) - }, { - view.showEmptyView() - }) - } - - private fun loadFavorite() { - disposable += repositoryImpl.favoritePlaylistFlowable - .subscribe({ - if (it.isNotEmpty()) hashSet.add(Home(4, R.string.favorites, 0, it, PLAYLISTS, R.drawable.ic_favorite_white_24dp)) - view.showData(ArrayList(hashSet)) - }, { - view.showEmptyView() - }) - } -}*/ +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistPresenter.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistPresenter.kt index 022f5610..c5536b57 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistPresenter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistPresenter.kt @@ -14,13 +14,15 @@ package code.name.monkey.retromusic.mvp.presenter +import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.providers.interfaces.Repository -import io.reactivex.disposables.Disposable +import kotlinx.coroutines.* import javax.inject.Inject +import kotlin.coroutines.CoroutineContext /** @@ -37,13 +39,29 @@ interface PlaylistsPresenter : Presenter { class PlaylistsPresenterImpl @Inject constructor( private val repository: Repository - ) : PresenterImpl(), PlaylistsPresenter { + ) : PresenterImpl(), PlaylistsPresenter, CoroutineScope { - private var disposable: Disposable? = null + private val job = Job() + + override val coroutineContext: CoroutineContext + get() = Dispatchers.IO + job + + override fun detachView() { + super.detachView() + job.cancel() + } override fun playlists() { - disposable = repository.allPlaylistsFlowable - .subscribe({ view?.playlists(it) }, { t -> println(t) }) + launch { + when (val result = repository.allPlaylists()) { + is Result.Success -> withContext(Dispatchers.Main) { + view?.playlists(result.data) + } + is Result.Error -> withContext(Dispatchers.Main) { + view?.showEmptyView() + } + } + } } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistSongsPresenter.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistSongsPresenter.kt index 0a992894..0c832619 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistSongsPresenter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/PlaylistSongsPresenter.kt @@ -14,14 +14,16 @@ package code.name.monkey.retromusic.mvp.presenter +import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.providers.interfaces.Repository -import io.reactivex.disposables.Disposable +import kotlinx.coroutines.* import javax.inject.Inject +import kotlin.coroutines.CoroutineContext /** * Created by hemanths on 20/08/17. @@ -35,18 +37,29 @@ interface PlaylistSongsPresenter : Presenter { class PlaylistSongsPresenterImpl @Inject constructor( private val repository: Repository - ) : PresenterImpl(), PlaylistSongsPresenter { + ) : PresenterImpl(), PlaylistSongsPresenter, CoroutineScope { - private var disposable: Disposable? = null + private var job: Job = Job() + + override val coroutineContext: CoroutineContext + get() = Dispatchers.IO + job override fun loadPlaylistSongs(playlist: Playlist) { - disposable = repository.getPlaylistSongsFlowable(playlist) - .subscribe({ view?.songs(it) }, { t -> println(t) }) + launch { + when (val songs = repository.getPlaylistSongs(playlist)) { + is Result.Success -> withContext(Dispatchers.Main) { + view?.songs(songs.data) + } + is Result.Error -> withContext(Dispatchers.Main) { + view?.showEmptyView() + } + } + } } override fun detachView() { super.detachView() - disposable?.dispose() + job.cancel() } } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.kt index 53e1b925..1fd78208 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SearchPresenter.kt @@ -14,19 +14,22 @@ package code.name.monkey.retromusic.mvp.presenter +import code.name.monkey.retromusic.Result.Error +import code.name.monkey.retromusic.Result.Success +import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.providers.interfaces.Repository +import kotlinx.coroutines.* import javax.inject.Inject +import kotlin.coroutines.CoroutineContext /** * Created by hemanths on 20/08/17. */ -interface SearchView { +interface SearchView : BaseView { fun showData(data: MutableList) - - fun showEmptyView() } interface SearchPresenter : Presenter { @@ -35,18 +38,27 @@ interface SearchPresenter : Presenter { class SearchPresenterImpl @Inject constructor( private val repository: Repository - ) : PresenterImpl(), SearchPresenter { + ) : PresenterImpl(), SearchPresenter, CoroutineScope { - override fun attachView(view: SearchView) { - super.attachView(view) - } + override val coroutineContext: CoroutineContext + get() = Dispatchers.IO + job + + private var job: Job = Job() override fun detachView() { super.detachView() + job.cancel() } override fun search(query: String?) { - view?.showData(repository.search(query)) + launch { + when (val result = repository.search(query)) { + is Success -> withContext(Dispatchers.Main) { + view?.showData(result.data) + } + is Error -> withContext(Dispatchers.Main) { view?.showEmptyView() } + } + } } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SongPresenter.kt b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SongPresenter.kt index e8ec4f1e..ca75037c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SongPresenter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/mvp/presenter/SongPresenter.kt @@ -14,13 +14,15 @@ package code.name.monkey.retromusic.mvp.presenter +import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.providers.interfaces.Repository -import io.reactivex.disposables.Disposable +import kotlinx.coroutines.* import java.util.* import javax.inject.Inject +import kotlin.coroutines.CoroutineContext /** * Created by hemanths on 10/08/17. @@ -33,21 +35,27 @@ interface SongView { interface SongPresenter : Presenter { fun loadSongs() - class SongPresenterImpl @Inject constructor( private val repository: Repository - ) : PresenterImpl(), SongPresenter { + ) : PresenterImpl(), SongPresenter, CoroutineScope { - private var disposable: Disposable? = null + private var job: Job = Job() + + override val coroutineContext: CoroutineContext + get() = Dispatchers.IO + job override fun loadSongs() { - disposable = repository.allSongsFlowable - .subscribe({ view?.songs(it) }, { t -> print(t) }) + launch { + when (val songs = repository.allSongs()) { + is Result.Success -> withContext(Dispatchers.Main) { view?.songs(songs.data) } + is Result.Error -> view?.showEmptyView() + } + } } override fun detachView() { super.detachView() - disposable?.dispose() + job.cancel(); } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.kt b/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.kt index 8dc63688..6944e579 100644 --- a/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.kt +++ b/app/src/main/java/code/name/monkey/retromusic/providers/RepositoryImpl.kt @@ -15,7 +15,11 @@ package code.name.monkey.retromusic.providers import android.content.Context -import code.name.monkey.retromusic.App +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.Result +import code.name.monkey.retromusic.Result.Error +import code.name.monkey.retromusic.Result.Success +import code.name.monkey.retromusic.adapter.HomeAdapter import code.name.monkey.retromusic.loaders.* import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.providers.interfaces.Repository @@ -27,6 +31,205 @@ import io.reactivex.schedulers.Schedulers class RepositoryImpl(private val context: Context) : Repository { + override suspend fun allAlbums(): Result> { + return try { + val albums = AlbumLoader.getAllAlbums(context) + if (albums.isNotEmpty()) { + Success(albums) + } else { + Error(Throwable("No items found")) + } + } catch (e: Exception) { + Error(e) + } + } + + override suspend fun allArtists(): Result> { + return try { + val artists = ArtistLoader.getAllArtists(context) + if (artists.isNotEmpty()) { + Success(artists) + } else { + Error(Throwable("No items found")) + } + } catch (e: Exception) { + Error(e) + } + } + + override suspend fun allPlaylists(): Result> { + return try { + val playlists = PlaylistLoader.getAllPlaylists(context) + if (playlists.isNotEmpty()) { + Success(playlists) + } else { + Error(Throwable("No items found")) + } + } catch (e: Exception) { + Error(e) + } + } + + override suspend fun allGenres(): Result> { + return try { + val genres = GenreLoader.getAllGenres(context) + if (genres.isNotEmpty()) { + Success(genres) + } else { + Error(Throwable("No items found")) + } + } catch (e: Exception) { + Error(e) + } + } + + override suspend fun search(query: String?): Result> { + return try { + val result = SearchLoader.searchAll(context, query) + if (result.isNotEmpty()) { + Success(result) + } else { + Error(Throwable("No items found")) + } + } catch (e: Exception) { + Error(e) + } + } + + override suspend fun allSongs(): Result> { + return try { + val songs = SongLoader.getAllSongs(context); + if (songs.isEmpty()) { + Error(Throwable("No items found")) + } else { + Success(songs); + } + } catch (e: Exception) { + Error(e); + } + } + + override suspend fun getPlaylistSongs(playlist: Playlist): Result> { + return try { + val songs: ArrayList = if (playlist is AbsCustomPlaylist) { + playlist.getSongs(context) + } else { + PlaylistSongsLoader.getPlaylistSongList(context, playlist.id) + } + Success(songs); + } catch (e: Exception) { + Error(e) + } + } + + override suspend fun getGenre(genreId: Int): Result> { + return try { + val songs = GenreLoader.getSongs(context, genreId) + if (songs.isEmpty()) { + Error(Throwable("No items found")) + } else { + Success(songs); + } + } catch (e: Exception) { + Error(e) + } + } + + override suspend fun recentArtists(): Result { + return try { + val artists = LastAddedSongsLoader.getLastAddedArtists(context) + if (artists.isEmpty()) { + Error(Throwable("No items found")) + } else { + Success(Home(0, + R.string.recent_artists, + R.string.recent_added_artists, + artists, + HomeAdapter.RECENT_ARTISTS, + R.drawable.ic_artist_white_24dp)) + } + } catch (e: Exception) { + Error(e) + } + } + + override suspend fun recentAlbums(): Result { + return try { + val albums = LastAddedSongsLoader.getLastAddedAlbums(context) + if (albums.isEmpty()) { + Error(Throwable("No items found")) + } else { + Success(Home(1, + R.string.recent_albums, + R.string.recent_added_albums, + albums, + HomeAdapter.RECENT_ALBUMS, + R.drawable.ic_album_white_24dp + )); + } + } catch (e: Exception) { + Error(e) + } + } + + override suspend fun topAlbums(): Result { + return try { + val albums = TopAndRecentlyPlayedTracksLoader.getTopAlbums(context) + if (albums.isEmpty()) { + Error(Throwable("No items found")) + } else { + Success(Home(3, + R.string.top_albums, + R.string.most_played_albums, + albums, + HomeAdapter.TOP_ALBUMS, + R.drawable.ic_album_white_24dp + )); + } + } catch (e: Exception) { + Error(e) + } + } + + + override suspend fun topArtists(): Result { + return try { + val artists = TopAndRecentlyPlayedTracksLoader.getTopArtists(context) + if (artists.isEmpty()) { + Error(Throwable("No items found")) + } else { + Success(Home(2, + R.string.top_artists, + R.string.most_played_artists, + artists, + HomeAdapter.TOP_ARTISTS, + R.drawable.ic_artist_white_24dp + )); + } + } catch (e: Exception) { + Error(e) + } + } + + override suspend fun favoritePlaylist(): Result { + return try { + val playlists = PlaylistLoader.getFavoritePlaylist(context) + if (playlists.isEmpty()) { + Error(Throwable("No items found")) + } else { + Success(Home(4, + R.string.favorites, + R.string.favorites_songs, + playlists, + HomeAdapter.PLAYLISTS, + R.drawable.ic_favorite_white_24dp + )); + } + } catch (e: Exception) { + Error(e) + } + } + override fun artistInfoFloable( name: String, lang: String?, @@ -37,41 +240,6 @@ class RepositoryImpl(private val context: Context) : Repository { .observeOn(AndroidSchedulers.mainThread()) } - override fun search(query: String?): MutableList { - return SearchLoader.searchAll(context, query) - } - - override fun allAlbums(): ArrayList { - return AlbumLoader.getAllAlbums(context) - } - - override fun recentAlbums(): ArrayList { - return LastAddedSongsLoader.getLastAddedAlbums(context) - } - - override fun topAlbums(): ArrayList { - return TopAndRecentlyPlayedTracksLoader.getTopAlbums(context) - } - - override fun allArtists(): ArrayList { - return ArtistLoader.getAllArtists(context) - } - - override fun recentArtists(): ArrayList { - return LastAddedSongsLoader.getLastAddedArtists(context) - } - - override fun topArtists(): ArrayList { - return TopAndRecentlyPlayedTracksLoader.getTopArtists(context) - } - - override fun allPlaylists(): ArrayList { - return PlaylistLoader.getAllPlaylists(context) - } - - override fun allGenres(): ArrayList { - return GenreLoader.getAllGenres(context) - } override fun getSongFlowable(id: Int): Observable { return SongLoader.getSongFlowable(context, id) @@ -91,10 +259,9 @@ class RepositoryImpl(private val context: Context) : Repository { .observeOn(AndroidSchedulers.mainThread()) } - override fun getPlaylistSongsFlowable(playlist: Playlist): Observable> { return PlaylistSongsLoader.getPlaylistSongListFlowable(context, playlist) - .subscribeOn(Schedulers.io()) + .subscribeOn(Schedulers.computation()) .observeOn(AndroidSchedulers.mainThread()) } @@ -104,12 +271,6 @@ class RepositoryImpl(private val context: Context) : Repository { .observeOn(AndroidSchedulers.mainThread()) } - override val favoritePlaylist: ArrayList - get() = PlaylistLoader.getFavoritePlaylist(context) - - override fun allSongs(): ArrayList { - return SongLoader.getAllSongs(context) - } override val favoritePlaylistFlowable: Observable> get() = PlaylistLoader.getFavoritePlaylistFlowable(context) @@ -180,13 +341,5 @@ class RepositoryImpl(private val context: Context) : Repository { return ArtistLoader.getArtist(context, artistId.toInt()) } - override fun getPlaylistSongs(playlist: Playlist): ArrayList { - return PlaylistSongsLoader.getPlaylistSongList(context, playlist) - } - - override fun getGenre(genreId: Int): ArrayList { - return GenreLoader.getSongs(context, genreId) - - } } diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.kt b/app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.kt index 7ecf90a7..4ebeaa85 100644 --- a/app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/providers/interfaces/Repository.kt @@ -14,6 +14,7 @@ package code.name.monkey.retromusic.providers.interfaces +import code.name.monkey.retromusic.Result import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.rest.model.LastFmArtist import io.reactivex.Observable @@ -24,44 +25,57 @@ import io.reactivex.Observable interface Repository { - val allSongsFlowable: Observable> + suspend fun allAlbums(): Result> - fun allSongs(): ArrayList + suspend fun allSongs(): Result> + + suspend fun allArtists(): Result> + + suspend fun allPlaylists(): Result> + + suspend fun allGenres(): Result> + + suspend fun search(query: String?): Result> + + suspend fun getPlaylistSongs(playlist: Playlist): Result> + + suspend fun getGenre(genreId: Int): Result> + + suspend fun recentArtists(): Result + + suspend fun topArtists(): Result + + suspend fun topAlbums(): Result + + suspend fun recentAlbums(): Result + + suspend fun favoritePlaylist(): Result + + val allSongsFlowable: Observable> val suggestionSongsFlowable: Observable> val allAlbumsFlowable: Observable> - fun allAlbums(): ArrayList - val recentAlbumsFlowable: Observable> - fun recentAlbums(): ArrayList val topAlbumsFlowable: Observable> - fun topAlbums(): ArrayList val allArtistsFlowable: Observable> - fun allArtists(): ArrayList - val recentArtistsFlowable: Observable> - fun recentArtists(): ArrayList val topArtistsFlowable: Observable> - fun topArtists(): ArrayList val allPlaylistsFlowable: Observable> - fun allPlaylists(): ArrayList val allGenresFlowable: Observable> - fun allGenres(): ArrayList - fun getSongFlowable(id: Int): Observable fun getSong(id: Int): Song @@ -74,19 +88,13 @@ interface Repository { fun getArtistById(artistId: Long): Artist - fun search(query: String?): MutableList - fun getPlaylistSongsFlowable(playlist: Playlist): Observable> - fun getPlaylistSongs(playlist: Playlist): ArrayList - fun getGenreFlowable(genreId: Int): Observable> - fun getGenre(genreId: Int): ArrayList val favoritePlaylistFlowable: Observable> - val favoritePlaylist: ArrayList fun artistInfoFloable(name: String, lang: String?, diff --git a/app/src/main/res/layout-land/fragment_banner_home.xml b/app/src/main/res/layout-land/fragment_banner_home.xml index 8eadef8d..65700c99 100644 --- a/app/src/main/res/layout-land/fragment_banner_home.xml +++ b/app/src/main/res/layout-land/fragment_banner_home.xml @@ -54,8 +54,16 @@ tools:background="@color/md_red_400" tools:ignore="ContentDescription" tools:srcCompat="@tools:sample/backgrounds/scenic[9]" /> + + + diff --git a/app/src/main/res/layout-xlarge-land/fragment_banner_home.xml b/app/src/main/res/layout-xlarge-land/fragment_banner_home.xml index d283285d..199a838e 100644 --- a/app/src/main/res/layout-xlarge-land/fragment_banner_home.xml +++ b/app/src/main/res/layout-xlarge-land/fragment_banner_home.xml @@ -53,8 +53,16 @@ tools:background="@color/md_red_400" tools:ignore="ContentDescription" tools:srcCompat="@tools:sample/backgrounds/scenic[9]" /> + + + + + diff --git a/app/src/main/res/layout/activity_playlist_detail.xml b/app/src/main/res/layout/activity_playlist_detail.xml index a8933dab..76c13e22 100644 --- a/app/src/main/res/layout/activity_playlist_detail.xml +++ b/app/src/main/res/layout/activity_playlist_detail.xml @@ -29,43 +29,27 @@ android:layout_height="wrap_content" app:layout_scrollFlags="scroll|enterAlways"> - - + + - - - - - - - - - - + android:clipToPadding="false" + android:scrollbars="none" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> + android:orientation="vertical" + android:visibility="gone" + tools:visibility="visible"> - + + - - - - - - - - + android:clipToPadding="false" + android:scrollbarStyle="outsideOverlay" + android:scrollbars="vertical" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> - @@ -89,7 +92,7 @@ app:titleMarginStart="0dp" app:titleTextAppearance="@style/ToolbarTextAppearanceSearch" tools:ignore="UnusedAttribute" /> - + @@ -103,8 +106,8 @@ diff --git a/app/src/main/res/layout/metal_section_recycler_view.xml b/app/src/main/res/layout/metal_section_recycler_view.xml index 11db0507..67da7502 100644 --- a/app/src/main/res/layout/metal_section_recycler_view.xml +++ b/app/src/main/res/layout/metal_section_recycler_view.xml @@ -42,6 +42,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:textAppearance="@style/TextViewCaption" + android:visibility="gone" tools:text="@tools:sample/full_names" /> diff --git a/app/src/main/res/layout/section_recycler_view.xml b/app/src/main/res/layout/section_recycler_view.xml index 092108c5..d6bcdd55 100644 --- a/app/src/main/res/layout/section_recycler_view.xml +++ b/app/src/main/res/layout/section_recycler_view.xml @@ -39,6 +39,7 @@ Welcome, Get Premium - Now playing themes, Carousel effect, Color theme and more.. + Now playing themes, Carousel effect and more.. Play all Start playing music. Keyboard diff --git a/appthemehelper/build.gradle b/appthemehelper/build.gradle index 4753a30a..82756378 100644 --- a/appthemehelper/build.gradle +++ b/appthemehelper/build.gradle @@ -27,7 +27,7 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'com.google.android.material:material:1.1.0-alpha10' + implementation 'com.google.android.material:material:1.1.0-beta01' implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.cardview:cardview:1.0.0' // Used for the list preference classes