Fix search slow, last added slow

This commit is contained in:
h4h13 2019-10-25 01:38:09 +05:30
parent 27190d5b74
commit e75246ff46
36 changed files with 732 additions and 501 deletions

61
.github/stale.yml vendored Normal file
View file

@ -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

View file

@ -83,6 +83,7 @@ android {
kapt { kapt {
generateStubs = true generateStubs = true
} }
} }
def getProperties(String fileName) { def getProperties(String fileName) {
@ -107,9 +108,9 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation project(':appthemehelper') implementation project(':appthemehelper')
implementation 'androidx.multidex:multidex:2.0.1' 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.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.gridlayout:gridlayout:1.0.0"
implementation "androidx.cardview:cardview:1.0.0" implementation "androidx.cardview:cardview:1.0.0"
implementation "androidx.palette:palette: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.palette:palette-ktx:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 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.google.android.play:core:1.6.3'
implementation 'com.squareup.retrofit2:retrofit:2.6.1' implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1' implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.1' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.2'
implementation 'com.afollestad.material-dialogs:core:3.1.1' implementation 'com.afollestad.material-dialogs:core:3.1.1'
implementation 'com.afollestad.material-dialogs:input: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.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 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:3.4.0.201406110918-r'
implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0' implementation 'com.github.ksoichiro:android-observablescrollview:1.6.0'
@ -163,4 +168,3 @@ dependencies {
} }

View file

@ -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
)

View file

@ -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<out T : Any> {
class Success<out T : Any>(val data: T) : Result<T>()
class Error(val exception: Throwable) : Result<Nothing>()
}

View file

@ -129,7 +129,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedP
val uri = intent.data val uri = intent.data
val mimeType = intent.type val mimeType = intent.type
var handled = false var handled = false
println("uri -> $uri")
if (intent.action != null && intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH) { if (intent.action != null && intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH) {
val songs = SearchQueryHelper.getSongs(this, intent.extras!!) val songs = SearchQueryHelper.getSongs(this, intent.extras!!)
if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) { if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) {

View file

@ -25,6 +25,7 @@ import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsPresenter import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsPresenter
import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsView 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.PlaylistsUtil
import code.name.monkey.retromusic.util.RetroColorUtil import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.ViewUtil import code.name.monkey.retromusic.util.ViewUtil
@ -50,6 +51,9 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar() setDrawUnderStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
App.musicComponent.inject(this)
playlistSongsPresenter.attachView(this)
setStatusbarColor(Color.TRANSPARENT) setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto() setNavigationbarColorAuto()
@ -65,10 +69,6 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli
finish() finish()
} }
App.musicComponent.inject(this)
playlistSongsPresenter.attachView(this)
setUpToolBar() setUpToolBar()
setUpRecyclerView() setUpRecyclerView()
} }
@ -160,14 +160,12 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli
override fun onMediaStoreChanged() { override fun onMediaStoreChanged() {
super.onMediaStoreChanged() super.onMediaStoreChanged()
if (playlist !is AbsCustomPlaylist) { if (playlist !is AbsCustomPlaylist) {
// Playlist deleted // Playlist deleted
if (!PlaylistsUtil.doesPlaylistExist(this, playlist.id)) { if (!PlaylistsUtil.doesPlaylistExist(this, playlist.id)) {
finish() finish()
return return
} }
// Playlist renamed // Playlist renamed
val playlistName = PlaylistsUtil.getNameForPlaylist(this, playlist.id.toLong()) val playlistName = PlaylistsUtil.getNameForPlaylist(this, playlist.id.toLong())
if (playlistName != playlist.name) { if (playlistName != playlist.name) {
@ -182,8 +180,13 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli
supportActionBar!!.title = title 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 empty.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
emptyText.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE emptyText.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
} }

View file

@ -1,10 +1,8 @@
package code.name.monkey.retromusic.activities package code.name.monkey.retromusic.activities
import android.app.Activity import android.app.Activity
import android.app.SearchManager
import android.app.Service import android.app.Service
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.os.Bundle import android.os.Bundle
@ -77,6 +75,10 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch
keyboardPopup.setTextColor(this) keyboardPopup.setTextColor(this)
keyboardPopup.iconTint = this keyboardPopup.iconTint = this
} }
if (savedInstanceState != null) {
query = savedInstanceState.getString(QUERY);
}
} }
private fun setupRecyclerView() { private fun setupRecyclerView() {
@ -104,15 +106,9 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch
} }
private fun setupSearchView() { private fun setupSearchView() {
getSystemService(Context.SEARCH_SERVICE) as SearchManager
searchView.addTextChangedListener(this) searchView.addTextChangedListener(this)
} }
override fun onResume() {
super.onResume()
searchPresenter.search(query)
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
searchPresenter.detachView() searchPresenter.detachView()
@ -123,11 +119,6 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch
outState.putString(QUERY, query) outState.putString(QUERY, query)
} }
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
searchPresenter.search(savedInstanceState.getString(QUERY, ""))
}
private fun setUpToolBar() { private fun setUpToolBar() {
title = null title = null
appBarLayout.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary)) appBarLayout.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
@ -135,14 +126,14 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch
private fun search(query: String) { private fun search(query: String) {
this.query = query.trim { it <= ' ' } this.query = query
voiceSearch.visibility = if (query.isNotEmpty()) View.GONE else View.VISIBLE voiceSearch.visibility = if (query.isNotEmpty()) View.GONE else View.VISIBLE
searchPresenter.search(query) searchPresenter.search(query)
} }
override fun onMediaStoreChanged() { override fun onMediaStoreChanged() {
super.onMediaStoreChanged() super.onMediaStoreChanged()
searchPresenter.search(query!!) query?.let { search(it) }
} }
override fun onQueryTextSubmit(query: String): Boolean { override fun onQueryTextSubmit(query: String): Boolean {

View file

@ -16,27 +16,21 @@ import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist 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.model.Playlist
import code.name.monkey.retromusic.providers.interfaces.Repository
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import com.google.android.material.textview.MaterialTextView import com.google.android.material.textview.MaterialTextView
class HomeAdapter( class HomeAdapter(
private val activity: AppCompatActivity, private val activity: AppCompatActivity,
private val displayMetrics: DisplayMetrics, private val displayMetrics: DisplayMetrics
private val repository: Repository
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { ) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var list = ArrayList<Home>()
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return when (position) { return list[position].homeSection
0 -> TOP_ARTISTS
1 -> TOP_ALBUMS
2 -> RECENT_ARTISTS
3 -> RECENT_ALBUMS
4 -> PLAYLISTS
else -> -1
}
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
@ -51,35 +45,39 @@ class HomeAdapter(
} }
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
println(getItemViewType(position)) println("ViewType ${getItemViewType(position)}")
when (getItemViewType(position)) { when (getItemViewType(position)) {
RECENT_ALBUMS -> { RECENT_ALBUMS -> {
val viewHolder = holder as AlbumViewHolder 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 -> { TOP_ALBUMS -> {
val viewHolder = holder as AlbumViewHolder val viewHolder = holder as AlbumViewHolder
viewHolder.bindView(list[position].arrayList.toAlbums(), R.string.top_albums, R.string.most_played_albums)
viewHolder.bindView(repository.topAlbums(), R.string.top_albums, R.string.most_played_albums)
} }
RECENT_ARTISTS -> { RECENT_ARTISTS -> {
val viewHolder = holder as ArtistViewHolder 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 -> { TOP_ARTISTS -> {
val viewHolder = holder as ArtistViewHolder 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 -> { PLAYLISTS -> {
val viewHolder = holder as PlaylistViewHolder val viewHolder = holder as PlaylistViewHolder
viewHolder.bindView(repository.favoritePlaylist, R.string.favorites, R.string.favorites_songs) viewHolder.bindView(list[position].arrayList as ArrayList<Playlist>, R.string.favorites, R.string.favorites_songs)
} }
} }
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
return 5 return list.size
}
fun swapData(sections: ArrayList<Home>) {
list = sections
notifyDataSetChanged()
} }
companion object { companion object {
@ -103,11 +101,13 @@ class HomeAdapter(
show() show()
adapter = AlbumFullWidthAdapter(activity, list, displayMetrics) adapter = AlbumFullWidthAdapter(activity, list, displayMetrics)
} }
titleContainer . show () titleContainer.show()
title.text = activity.getString(titleRes) title.text = activity.getString(titleRes)
text.text = activity.getString(subtitleRes) text.text = activity.getString(subtitleRes)
} }
} }
} }
inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) { inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
@ -154,3 +154,20 @@ class HomeAdapter(
val text: MaterialTextView = itemView.findViewById(R.id.text) val text: MaterialTextView = itemView.findViewById(R.id.text)
} }
} }
private fun <E> ArrayList<E>.toAlbums(): ArrayList<Album> {
val arrayList = ArrayList<Album>()
for (x in this) {
arrayList.add(x as Album)
}
return arrayList;
}
private fun <E> ArrayList<E>.toArtists(): ArrayList<Artist> {
val arrayList = ArrayList<Artist>()
for (x in this) {
arrayList.add(x as Artist)
}
return arrayList;
}

View file

@ -19,7 +19,6 @@ import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.NavigationUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import java.util.*
import android.util.Pair as UtilPair import android.util.Pair as UtilPair
class SearchAdapter( class SearchAdapter(
@ -57,7 +56,7 @@ class SearchAdapter(
holder.title?.text = artist.name holder.title?.text = artist.name
holder.text?.text = MusicUtil.getArtistInfoString(activity, artist) holder.text?.text = MusicUtil.getArtistInfoString(activity, artist)
ArtistGlideRequest.Builder.from(Glide.with(activity), artist) ArtistGlideRequest.Builder.from(Glide.with(activity), artist)
.build().into(holder.image); .build().into(holder.image)
} }
SONG -> { SONG -> {
val song = dataSet?.get(position) as Song val song = dataSet?.get(position) as Song
@ -79,16 +78,14 @@ class SearchAdapter(
init { init {
itemView.setOnLongClickListener(null) itemView.setOnLongClickListener(null)
if (menu != null) { if (itemViewType == SONG) {
if (itemViewType == SONG) { menu?.visibility = View.VISIBLE
menu!!.visibility = View.VISIBLE menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
menu!!.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) { override val song: Song
override val song: Song get() = dataSet!![adapterPosition] as Song
get() = dataSet!![adapterPosition] as Song })
}) } else {
} else { menu?.visibility = View.GONE
menu!!.visibility = View.GONE
}
} }
when (itemViewType) { when (itemViewType) {
@ -126,7 +123,6 @@ class SearchAdapter(
} }
companion object { companion object {
private const val HEADER = 0 private const val HEADER = 0
private const val ALBUM = 1 private const val ALBUM = 1
private const val ARTIST = 2 private const val ARTIST = 2

View file

@ -215,9 +215,7 @@ class PlaylistAdapter(protected val activity: AppCompatActivity, dataSet: ArrayL
} }
companion object { companion object {
val TAG: String = PlaylistAdapter::class.java.simpleName val TAG: String = PlaylistAdapter::class.java.simpleName
private const val SMART_PLAYLIST = 0 private const val SMART_PLAYLIST = 0
private const val DEFAULT_PLAYLIST = 1 private const val DEFAULT_PLAYLIST = 1
} }

View file

@ -44,7 +44,7 @@ abstract class AbsLibraryPagerRecyclerViewFragment<A : RecyclerView.Adapter<*>,
private fun initAdapter() { private fun initAdapter() {
adapter = createAdapter() adapter = createAdapter()
adapter!!.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { adapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() { override fun onChanged() {
super.onChanged() super.onChanged()
checkIsEmpty() checkIsEmpty()

View file

@ -2,7 +2,6 @@ package code.name.monkey.retromusic.fragments.mainactivity.home
import android.app.ActivityOptions import android.app.ActivityOptions
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.* 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.R
import code.name.monkey.retromusic.adapter.HomeAdapter import code.name.monkey.retromusic.adapter.HomeAdapter
import code.name.monkey.retromusic.dialogs.OptionsSheetDialogFragment 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.extensions.show
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote 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.HistoryPlaylist
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist
import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist 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.mvp.presenter.HomeView
import code.name.monkey.retromusic.providers.interfaces.Repository
import code.name.monkey.retromusic.util.Compressor import code.name.monkey.retromusic.util.Compressor
import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
@ -49,19 +47,14 @@ import javax.inject.Inject
class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallbacks, HomeView { class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallbacks, HomeView {
private lateinit var homeAdapter: HomeAdapter private lateinit var homeAdapter: HomeAdapter
@Inject @Inject
lateinit var repository: Repository lateinit var homePresenter: HomePresenter
private var disposable: CompositeDisposable = CompositeDisposable() private var disposable: CompositeDisposable = CompositeDisposable()
private lateinit var toolbar: Toolbar private lateinit var toolbar: Toolbar
override fun sections(sections: ArrayList<Home>) { override fun sections(sections: ArrayList<Home>) {
val finalList = sections.sortedWith(compareBy { it.priority }) println(sections.size)
homeAdapter.swapData(sections)
if (sections.isEmpty()) {
showEmptyView()
} else {
emptyContainer.hide()
}
} }
override fun onCreateView(inflater: LayoutInflater, viewGroup: ViewGroup?, savedInstanceState: Bundle?): View? { 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) titleWelcome.text = String.format("%s", PreferenceUtil.getInstance(requireContext()).userName)
App.musicComponent.inject(this) App.musicComponent.inject(this)
homeAdapter = HomeAdapter(mainActivity, displayMetrics, repository) homeAdapter = HomeAdapter(mainActivity, displayMetrics)
recyclerView.apply { recyclerView.apply {
layoutManager = LinearLayoutManager(mainActivity) layoutManager = LinearLayoutManager(mainActivity)
adapter = homeAdapter adapter = homeAdapter
} }
homePresenter.attachView(this)
homePresenter.loadSections()
} }
private fun toolbarColor(): Int { private fun toolbarColor(): Int {
return if (PreferenceUtil.getInstance(requireContext()).isHomeBanner) { return if (PreferenceUtil.getInstance(requireContext()).isHomeBanner) {
toolbarContainer.setBackgroundColor(Color.TRANSPARENT)
ColorUtil.withAlpha(RetroColorUtil.toolbarColor(mainActivity), 0.85f) ColorUtil.withAlpha(RetroColorUtil.toolbarColor(mainActivity), 0.85f)
} else { } else {
RetroColorUtil.toolbarColor(mainActivity) RetroColorUtil.toolbarColor(mainActivity)
@ -176,6 +170,7 @@ class BannerHomeFragment : AbsMainActivityFragment(), MainActivityFragmentCallba
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
disposable.dispose() disposable.dispose()
homePresenter.detachView()
} }
override fun showEmptyView() { override fun showEmptyView() {

View file

@ -16,7 +16,6 @@ package code.name.monkey.retromusic.loaders
import android.content.Context import android.content.Context
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import io.reactivex.Observable
object SearchLoader { object SearchLoader {

View file

@ -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<List<Any>>(context) {
override fun loadInBackground(): List<Any>? {
val results = ArrayList<Any>()
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
}
}

View file

@ -14,13 +14,17 @@
package code.name.monkey.retromusic.mvp package code.name.monkey.retromusic.mvp
import androidx.annotation.CallSuper
/** /**
* Created by hemanths on 16/08/17. * Created by hemanths on 16/08/17.
*/ */
interface Presenter<T> { interface Presenter<T> {
@CallSuper
fun attachView(view: T) fun attachView(view: T)
@CallSuper
fun detachView() fun detachView()
} }

View file

@ -14,14 +14,16 @@
package code.name.monkey.retromusic.mvp.presenter 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.model.Album
import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import io.reactivex.disposables.Disposable import kotlinx.coroutines.*
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
/** /**
@ -37,22 +39,30 @@ interface AlbumsPresenter : Presenter<AlbumsView> {
class AlbumsPresenterImpl @Inject constructor( class AlbumsPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<AlbumsView>(), AlbumsPresenter { ) : PresenterImpl<AlbumsView>(), AlbumsPresenter, CoroutineScope {
private val job = Job()
private var disposable: Disposable? = null override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
private fun showList(albums: ArrayList<Album>) {
view?.albums(albums)
}
override fun detachView() { override fun detachView() {
super.detachView() super.detachView()
disposable?.dispose() job.cancel()
} }
override fun loadAlbums() { override fun loadAlbums() {
disposable = repository.allAlbumsFlowable launch {
.subscribe({ view?.albums(it) }, { t -> println(t) }) when (val result = repository.allAlbums()) {
is Result.Success -> {
withContext(Dispatchers.Main) {
view?.albums(result.data)
}
}
is Result.Error -> {
view?.showEmptyView()
}
}
}
} }
} }
} }

View file

@ -14,13 +14,15 @@
package code.name.monkey.retromusic.mvp.presenter 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.model.Artist
import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import io.reactivex.disposables.Disposable import kotlinx.coroutines.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
interface ArtistsView : BaseView { interface ArtistsView : BaseView {
fun artists(artists: ArrayList<Artist>) fun artists(artists: ArrayList<Artist>)
@ -32,18 +34,26 @@ interface ArtistsPresenter : Presenter<ArtistsView> {
class ArtistsPresenterImpl @Inject constructor( class ArtistsPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<ArtistsView>(), ArtistsPresenter { ) : PresenterImpl<ArtistsView>(), ArtistsPresenter, CoroutineScope {
private val job = Job()
private var disposable: Disposable? = null override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
override fun detachView() { override fun detachView() {
super.detachView() super.detachView()
disposable?.dispose() job.cancel()
} }
override fun loadArtists() { override fun loadArtists() {
disposable = repository.allArtistsFlowable launch {
.subscribe({ view?.artists(it) }, { t -> println(t) }) when (val result = repository.allArtists()) {
is Result.Success -> withContext(Dispatchers.Main) {
view?.artists(result.data)
}
is Result.Error -> withContext(Dispatchers.Main) { view?.showEmptyView() }
}
}
} }
} }
} }

View file

@ -14,14 +14,16 @@
package code.name.monkey.retromusic.mvp.presenter 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.model.Song
import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import io.reactivex.disposables.Disposable import kotlinx.coroutines.*
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
/** /**
@ -37,18 +39,29 @@ interface GenreDetailsPresenter : Presenter<GenreDetailsView> {
class GenreDetailsPresenterImpl @Inject constructor( class GenreDetailsPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<GenreDetailsView>(), GenreDetailsPresenter { ) : PresenterImpl<GenreDetailsView>(), GenreDetailsPresenter, CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
override fun detachView() { override fun detachView() {
super.detachView() super.detachView()
disposable?.dispose() job.cancel()
} }
private var disposable: Disposable? = null
override fun loadGenreSongs(genreId: Int) { override fun loadGenreSongs(genreId: Int) {
disposable = repository.getGenreFlowable(genreId) launch {
.subscribe({ view?.songs(it) }, { t -> println(t) }) when (val result = repository.getGenre(genreId)) {
is Result.Success -> withContext(Dispatchers.Main) {
view?.songs(result.data)
}
is Result.Error -> withContext(Dispatchers.Main) {
view?.showEmptyView()
}
}
}
} }
} }
} }

View file

@ -14,14 +14,16 @@
package code.name.monkey.retromusic.mvp.presenter 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.model.Genre
import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import io.reactivex.disposables.Disposable import kotlinx.coroutines.*
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
/** /**
* @author Hemanth S (h4h13). * @author Hemanth S (h4h13).
@ -35,13 +37,26 @@ interface GenresPresenter : Presenter<GenresView> {
class GenresPresenterImpl @Inject constructor( class GenresPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<GenresView>(), GenresPresenter { ) : PresenterImpl<GenresView>(), 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() { override fun loadGenres() {
disposable = repository.allGenresFlowable launch {
.subscribe({ view.genres(it) }, { t -> println(t) }) when (val result = repository.allGenres()) {
is Result.Success -> withContext(Dispatchers.Main) {
view?.genres(result.data)
}
is Result.Error -> withContext(Dispatchers.Main) { view?.showEmptyView() }
}
}
} }
} }
} }

View file

@ -14,12 +14,7 @@
package code.name.monkey.retromusic.mvp.presenter package code.name.monkey.retromusic.mvp.presenter
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.Result
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.model.Home import code.name.monkey.retromusic.model.Home
import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter 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 code.name.monkey.retromusic.providers.interfaces.Repository
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import kotlinx.coroutines.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
operator fun CompositeDisposable.plusAssign(disposable: Disposable) { operator fun CompositeDisposable.plusAssign(disposable: Disposable) {
add(disposable) add(disposable)
@ -40,238 +37,38 @@ interface HomeView : BaseView {
interface HomePresenter : Presenter<HomeView> { interface HomePresenter : Presenter<HomeView> {
fun loadSections() fun loadSections()
class HomePresenterImpl @Inject constructor( class HomePresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<HomeView>(), HomePresenter { ) : PresenterImpl<HomeView>(), HomePresenter, CoroutineScope {
private val job = Job()
private val hashSet: HashSet<Home> = HashSet() override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
override fun detachView() {
super.detachView()
job.cancel()
}
override fun loadSections() { override fun loadSections() {
loadRecentArtists() launch {
loadRecentAlbums() val list = ArrayList<Home>()
loadTopArtists() val recentArtistResult = listOf(
loadATopAlbums() repository.topArtists(),
loadFavorite() repository.topAlbums(),
//loadHomeSection() repository.recentArtists(),
} repository.recentAlbums(),
repository.favoritePlaylist()
private var disposable: CompositeDisposable = CompositeDisposable() )
for (r in recentArtistResult) {
private fun showData(sections: ArrayList<Home>) { when (r) {
if (sections.isEmpty()) { is Result.Success -> list.add(r.data)
view.showEmptyView() }
} else { }
view.sections(sections) 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<Home> = HashSet()
val recentArtist = it[0] as ArrayList<Artist>
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<Album>
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<Artist>
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<Album>
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<Playlist>
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<Home> = 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()
})
}
}*/

View file

@ -14,13 +14,15 @@
package code.name.monkey.retromusic.mvp.presenter 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.Playlist
import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import io.reactivex.disposables.Disposable import kotlinx.coroutines.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
/** /**
@ -37,13 +39,29 @@ interface PlaylistsPresenter : Presenter<PlaylistView> {
class PlaylistsPresenterImpl @Inject constructor( class PlaylistsPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<PlaylistView>(), PlaylistsPresenter { ) : PresenterImpl<PlaylistView>(), 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() { override fun playlists() {
disposable = repository.allPlaylistsFlowable launch {
.subscribe({ view?.playlists(it) }, { t -> println(t) }) when (val result = repository.allPlaylists()) {
is Result.Success -> withContext(Dispatchers.Main) {
view?.playlists(result.data)
}
is Result.Error -> withContext(Dispatchers.Main) {
view?.showEmptyView()
}
}
}
} }
} }
} }

View file

@ -14,14 +14,16 @@
package code.name.monkey.retromusic.mvp.presenter 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.Playlist
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.mvp.BaseView import code.name.monkey.retromusic.mvp.BaseView
import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import io.reactivex.disposables.Disposable import kotlinx.coroutines.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
/** /**
* Created by hemanths on 20/08/17. * Created by hemanths on 20/08/17.
@ -35,18 +37,29 @@ interface PlaylistSongsPresenter : Presenter<PlaylistSongsView> {
class PlaylistSongsPresenterImpl @Inject constructor( class PlaylistSongsPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<PlaylistSongsView>(), PlaylistSongsPresenter { ) : PresenterImpl<PlaylistSongsView>(), 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) { override fun loadPlaylistSongs(playlist: Playlist) {
disposable = repository.getPlaylistSongsFlowable(playlist) launch {
.subscribe({ view?.songs(it) }, { t -> println(t) }) 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() { override fun detachView() {
super.detachView() super.detachView()
disposable?.dispose() job.cancel()
} }
} }
} }

View file

@ -14,19 +14,22 @@
package code.name.monkey.retromusic.mvp.presenter 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.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import kotlinx.coroutines.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
/** /**
* Created by hemanths on 20/08/17. * Created by hemanths on 20/08/17.
*/ */
interface SearchView { interface SearchView : BaseView {
fun showData(data: MutableList<Any>) fun showData(data: MutableList<Any>)
fun showEmptyView()
} }
interface SearchPresenter : Presenter<SearchView> { interface SearchPresenter : Presenter<SearchView> {
@ -35,18 +38,27 @@ interface SearchPresenter : Presenter<SearchView> {
class SearchPresenterImpl @Inject constructor( class SearchPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<SearchView>(), SearchPresenter { ) : PresenterImpl<SearchView>(), SearchPresenter, CoroutineScope {
override fun attachView(view: SearchView) { override val coroutineContext: CoroutineContext
super.attachView(view) get() = Dispatchers.IO + job
}
private var job: Job = Job()
override fun detachView() { override fun detachView() {
super.detachView() super.detachView()
job.cancel()
} }
override fun search(query: String?) { 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() }
}
}
} }
} }
} }

View file

@ -14,13 +14,15 @@
package code.name.monkey.retromusic.mvp.presenter 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.model.Song
import code.name.monkey.retromusic.mvp.Presenter import code.name.monkey.retromusic.mvp.Presenter
import code.name.monkey.retromusic.mvp.PresenterImpl import code.name.monkey.retromusic.mvp.PresenterImpl
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
import io.reactivex.disposables.Disposable import kotlinx.coroutines.*
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
/** /**
* Created by hemanths on 10/08/17. * Created by hemanths on 10/08/17.
@ -33,21 +35,27 @@ interface SongView {
interface SongPresenter : Presenter<SongView> { interface SongPresenter : Presenter<SongView> {
fun loadSongs() fun loadSongs()
class SongPresenterImpl @Inject constructor( class SongPresenterImpl @Inject constructor(
private val repository: Repository private val repository: Repository
) : PresenterImpl<SongView>(), SongPresenter { ) : PresenterImpl<SongView>(), SongPresenter, CoroutineScope {
private var disposable: Disposable? = null private var job: Job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
override fun loadSongs() { override fun loadSongs() {
disposable = repository.allSongsFlowable launch {
.subscribe({ view?.songs(it) }, { t -> print(t) }) when (val songs = repository.allSongs()) {
is Result.Success -> withContext(Dispatchers.Main) { view?.songs(songs.data) }
is Result.Error -> view?.showEmptyView()
}
}
} }
override fun detachView() { override fun detachView() {
super.detachView() super.detachView()
disposable?.dispose() job.cancel();
} }
} }
} }

View file

@ -15,7 +15,11 @@
package code.name.monkey.retromusic.providers package code.name.monkey.retromusic.providers
import android.content.Context 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.loaders.*
import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.providers.interfaces.Repository import code.name.monkey.retromusic.providers.interfaces.Repository
@ -27,6 +31,205 @@ import io.reactivex.schedulers.Schedulers
class RepositoryImpl(private val context: Context) : Repository { class RepositoryImpl(private val context: Context) : Repository {
override suspend fun allAlbums(): Result<ArrayList<Album>> {
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<ArrayList<Artist>> {
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<ArrayList<Playlist>> {
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<ArrayList<Genre>> {
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<MutableList<Any>> {
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<ArrayList<Song>> {
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<ArrayList<Song>> {
return try {
val songs: ArrayList<Song> = 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<ArrayList<Song>> {
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<Home> {
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<Home> {
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<Home> {
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<Home> {
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<Home> {
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( override fun artistInfoFloable(
name: String, name: String,
lang: String?, lang: String?,
@ -37,41 +240,6 @@ class RepositoryImpl(private val context: Context) : Repository {
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
} }
override fun search(query: String?): MutableList<Any> {
return SearchLoader.searchAll(context, query)
}
override fun allAlbums(): ArrayList<Album> {
return AlbumLoader.getAllAlbums(context)
}
override fun recentAlbums(): ArrayList<Album> {
return LastAddedSongsLoader.getLastAddedAlbums(context)
}
override fun topAlbums(): ArrayList<Album> {
return TopAndRecentlyPlayedTracksLoader.getTopAlbums(context)
}
override fun allArtists(): ArrayList<Artist> {
return ArtistLoader.getAllArtists(context)
}
override fun recentArtists(): ArrayList<Artist> {
return LastAddedSongsLoader.getLastAddedArtists(context)
}
override fun topArtists(): ArrayList<Artist> {
return TopAndRecentlyPlayedTracksLoader.getTopArtists(context)
}
override fun allPlaylists(): ArrayList<Playlist> {
return PlaylistLoader.getAllPlaylists(context)
}
override fun allGenres(): ArrayList<Genre> {
return GenreLoader.getAllGenres(context)
}
override fun getSongFlowable(id: Int): Observable<Song> { override fun getSongFlowable(id: Int): Observable<Song> {
return SongLoader.getSongFlowable(context, id) return SongLoader.getSongFlowable(context, id)
@ -91,10 +259,9 @@ class RepositoryImpl(private val context: Context) : Repository {
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
} }
override fun getPlaylistSongsFlowable(playlist: Playlist): Observable<ArrayList<Song>> { override fun getPlaylistSongsFlowable(playlist: Playlist): Observable<ArrayList<Song>> {
return PlaylistSongsLoader.getPlaylistSongListFlowable(context, playlist) return PlaylistSongsLoader.getPlaylistSongListFlowable(context, playlist)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
} }
@ -104,12 +271,6 @@ class RepositoryImpl(private val context: Context) : Repository {
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
} }
override val favoritePlaylist: ArrayList<Playlist>
get() = PlaylistLoader.getFavoritePlaylist(context)
override fun allSongs(): ArrayList<Song> {
return SongLoader.getAllSongs(context)
}
override val favoritePlaylistFlowable: Observable<ArrayList<Playlist>> override val favoritePlaylistFlowable: Observable<ArrayList<Playlist>>
get() = PlaylistLoader.getFavoritePlaylistFlowable(context) get() = PlaylistLoader.getFavoritePlaylistFlowable(context)
@ -180,13 +341,5 @@ class RepositoryImpl(private val context: Context) : Repository {
return ArtistLoader.getArtist(context, artistId.toInt()) return ArtistLoader.getArtist(context, artistId.toInt())
} }
override fun getPlaylistSongs(playlist: Playlist): ArrayList<Song> {
return PlaylistSongsLoader.getPlaylistSongList(context, playlist)
}
override fun getGenre(genreId: Int): ArrayList<Song> {
return GenreLoader.getSongs(context, genreId)
}
} }

View file

@ -14,6 +14,7 @@
package code.name.monkey.retromusic.providers.interfaces package code.name.monkey.retromusic.providers.interfaces
import code.name.monkey.retromusic.Result
import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.rest.model.LastFmArtist import code.name.monkey.retromusic.rest.model.LastFmArtist
import io.reactivex.Observable import io.reactivex.Observable
@ -24,44 +25,57 @@ import io.reactivex.Observable
interface Repository { interface Repository {
val allSongsFlowable: Observable<ArrayList<Song>> suspend fun allAlbums(): Result<ArrayList<Album>>
fun allSongs(): ArrayList<Song> suspend fun allSongs(): Result<ArrayList<Song>>
suspend fun allArtists(): Result<ArrayList<Artist>>
suspend fun allPlaylists(): Result<ArrayList<Playlist>>
suspend fun allGenres(): Result<ArrayList<Genre>>
suspend fun search(query: String?): Result<MutableList<Any>>
suspend fun getPlaylistSongs(playlist: Playlist): Result<ArrayList<Song>>
suspend fun getGenre(genreId: Int): Result<ArrayList<Song>>
suspend fun recentArtists(): Result<Home>
suspend fun topArtists(): Result<Home>
suspend fun topAlbums(): Result<Home>
suspend fun recentAlbums(): Result<Home>
suspend fun favoritePlaylist(): Result<Home>
val allSongsFlowable: Observable<ArrayList<Song>>
val suggestionSongsFlowable: Observable<ArrayList<Song>> val suggestionSongsFlowable: Observable<ArrayList<Song>>
val allAlbumsFlowable: Observable<ArrayList<Album>> val allAlbumsFlowable: Observable<ArrayList<Album>>
fun allAlbums(): ArrayList<Album>
val recentAlbumsFlowable: Observable<ArrayList<Album>> val recentAlbumsFlowable: Observable<ArrayList<Album>>
fun recentAlbums(): ArrayList<Album>
val topAlbumsFlowable: Observable<ArrayList<Album>> val topAlbumsFlowable: Observable<ArrayList<Album>>
fun topAlbums(): ArrayList<Album>
val allArtistsFlowable: Observable<ArrayList<Artist>> val allArtistsFlowable: Observable<ArrayList<Artist>>
fun allArtists(): ArrayList<Artist>
val recentArtistsFlowable: Observable<ArrayList<Artist>> val recentArtistsFlowable: Observable<ArrayList<Artist>>
fun recentArtists(): ArrayList<Artist>
val topArtistsFlowable: Observable<ArrayList<Artist>> val topArtistsFlowable: Observable<ArrayList<Artist>>
fun topArtists(): ArrayList<Artist>
val allPlaylistsFlowable: Observable<ArrayList<Playlist>> val allPlaylistsFlowable: Observable<ArrayList<Playlist>>
fun allPlaylists(): ArrayList<Playlist>
val allGenresFlowable: Observable<ArrayList<Genre>> val allGenresFlowable: Observable<ArrayList<Genre>>
fun allGenres(): ArrayList<Genre>
fun getSongFlowable(id: Int): Observable<Song> fun getSongFlowable(id: Int): Observable<Song>
fun getSong(id: Int): Song fun getSong(id: Int): Song
@ -74,19 +88,13 @@ interface Repository {
fun getArtistById(artistId: Long): Artist fun getArtistById(artistId: Long): Artist
fun search(query: String?): MutableList<Any>
fun getPlaylistSongsFlowable(playlist: Playlist): Observable<ArrayList<Song>> fun getPlaylistSongsFlowable(playlist: Playlist): Observable<ArrayList<Song>>
fun getPlaylistSongs(playlist: Playlist): ArrayList<Song>
fun getGenreFlowable(genreId: Int): Observable<ArrayList<Song>> fun getGenreFlowable(genreId: Int): Observable<ArrayList<Song>>
fun getGenre(genreId: Int): ArrayList<Song>
val favoritePlaylistFlowable: Observable<ArrayList<Playlist>> val favoritePlaylistFlowable: Observable<ArrayList<Playlist>>
val favoritePlaylist: ArrayList<Playlist>
fun artistInfoFloable(name: String, fun artistInfoFloable(name: String,
lang: String?, lang: String?,

View file

@ -54,8 +54,16 @@
tools:background="@color/md_red_400" tools:background="@color/md_red_400"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:srcCompat="@tools:sample/backgrounds/scenic[9]" /> tools:srcCompat="@tools:sample/backgrounds/scenic[9]" />
<View
android:layout_width="match_parent"
android:layout_height="24dp"
android:layout_gravity="bottom"
android:background="@drawable/shadow_up_full_theme"
android:backgroundTint="?colorPrimary" />
</FrameLayout> </FrameLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -78,6 +86,7 @@
android:layout_marginTop="@dimen/toolbar_margin_vertical" android:layout_marginTop="@dimen/toolbar_margin_vertical"
android:layout_marginEnd="@dimen/toolbar_margin_horizontal" android:layout_marginEnd="@dimen/toolbar_margin_horizontal"
android:layout_marginBottom="@dimen/toolbar_margin_vertical" android:layout_marginBottom="@dimen/toolbar_margin_vertical"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="8dp" app:cardCornerRadius="8dp"
app:cardElevation="6dp" app:cardElevation="6dp"
app:cardUseCompatPadding="true" app:cardUseCompatPadding="true"
@ -114,8 +123,8 @@
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:cardElevation="8dp"
app:cardBackgroundColor="?colorPrimary" app:cardBackgroundColor="?colorPrimary"
app:cardElevation="8dp"
app:shapeAppearanceOverlay="@style/TopCornerCardView"> app:shapeAppearanceOverlay="@style/TopCornerCardView">
<include layout="@layout/home_content" /> <include layout="@layout/home_content" />

View file

@ -53,8 +53,16 @@
tools:background="@color/md_red_400" tools:background="@color/md_red_400"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:srcCompat="@tools:sample/backgrounds/scenic[9]" /> tools:srcCompat="@tools:sample/backgrounds/scenic[9]" />
<View
android:layout_width="match_parent"
android:layout_height="24dp"
android:layout_gravity="bottom"
android:background="@drawable/shadow_up_full_theme"
android:backgroundTint="?colorPrimary" />
</FrameLayout> </FrameLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -77,6 +85,7 @@
android:layout_marginTop="@dimen/toolbar_margin_vertical" android:layout_marginTop="@dimen/toolbar_margin_vertical"
android:layout_marginEnd="@dimen/toolbar_margin_horizontal" android:layout_marginEnd="@dimen/toolbar_margin_horizontal"
android:layout_marginBottom="@dimen/toolbar_margin_vertical" android:layout_marginBottom="@dimen/toolbar_margin_vertical"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="8dp" app:cardCornerRadius="8dp"
app:cardElevation="6dp" app:cardElevation="6dp"
app:cardUseCompatPadding="true" app:cardUseCompatPadding="true"

View file

@ -53,6 +53,13 @@
tools:background="@color/md_red_400" tools:background="@color/md_red_400"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:srcCompat="@tools:sample/backgrounds/scenic[9]" /> tools:srcCompat="@tools:sample/backgrounds/scenic[9]" />
<View
android:layout_width="match_parent"
android:layout_height="24dp"
android:layout_gravity="bottom"
android:background="@drawable/shadow_up_full_theme"
android:backgroundTint="?colorPrimary" />
</FrameLayout> </FrameLayout>
<LinearLayout <LinearLayout
@ -77,6 +84,7 @@
android:layout_marginTop="@dimen/toolbar_margin_vertical" android:layout_marginTop="@dimen/toolbar_margin_vertical"
android:layout_marginEnd="@dimen/toolbar_margin_horizontal" android:layout_marginEnd="@dimen/toolbar_margin_horizontal"
android:layout_marginBottom="@dimen/toolbar_margin_vertical" android:layout_marginBottom="@dimen/toolbar_margin_vertical"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="8dp" app:cardCornerRadius="8dp"
app:cardElevation="6dp" app:cardElevation="6dp"
app:cardUseCompatPadding="true" app:cardUseCompatPadding="true"
@ -111,8 +119,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/toolbar_margin_horizontal" android:layout_marginStart="@dimen/toolbar_margin_horizontal"
android:layout_marginEnd="@dimen/toolbar_margin_horizontal" android:layout_marginEnd="@dimen/toolbar_margin_horizontal"
app:cardElevation="8dp"
app:cardBackgroundColor="?colorPrimary" app:cardBackgroundColor="?colorPrimary"
app:cardElevation="8dp"
app:shapeAppearanceOverlay="@style/TopCornerCardView"> app:shapeAppearanceOverlay="@style/TopCornerCardView">
<include layout="@layout/home_content" /> <include layout="@layout/home_content" />

View file

@ -29,43 +29,27 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"> app:layout_scrollFlags="scroll|enterAlways">
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="48dp" />
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
style="@style/Toolbar" style="@style/Toolbar"
app:navigationIcon="@drawable/ic_keyboard_backspace_black_24dp" app:navigationIcon="@drawable/ic_keyboard_backspace_black_24dp"
app:titleTextAppearance="@style/ToolbarTextAppearanceNormal" /> app:titleTextAppearance="@style/ToolbarTextAppearanceNormal" />
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="48dp" />
</FrameLayout> </FrameLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView <com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> android:clipToPadding="false"
android:scrollbars="none"
<LinearLayout app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:scrollbars="none" />
<Space
android:layout_width="match_parent"
android:layout_height="52dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<LinearLayout <LinearLayout
android:id="@android:id/empty" android:id="@android:id/empty"
@ -73,7 +57,9 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:gravity="center" android:gravity="center"
android:orientation="vertical"> android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:layout_width="96dp" android:layout_width="96dp"

View file

@ -69,36 +69,25 @@
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView <com.google.android.material.textview.MaterialTextView
android:id="@android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="@string/no_results"
android:textAppearance="@style/TextViewHeadline6"
android:visibility="gone"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> android:clipToPadding="false"
android:scrollbarStyle="outsideOverlay"
<FrameLayout android:scrollbars="vertical"
android:layout_width="match_parent" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
android:layout_height="wrap_content">
<com.google.android.material.textview.MaterialTextView
android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="48dp"
android:paddingBottom="48dp"
android:text="@string/no_results"
android:textAppearance="@style/TextViewHeadline6"
android:visibility="gone"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:scrollbarStyle="outsideOverlay"
android:scrollbars="vertical" />
</FrameLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/keyboardPopup" android:id="@+id/keyboardPopup"

View file

@ -66,7 +66,7 @@
</FrameLayout> </FrameLayout>
<FrameLayout <com.google.android.material.card.MaterialCardView
android:id="@+id/toolbarContainer" android:id="@+id/toolbarContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -74,6 +74,9 @@
android:layout_marginTop="@dimen/toolbar_margin_vertical" android:layout_marginTop="@dimen/toolbar_margin_vertical"
android:layout_marginEnd="@dimen/toolbar_margin_horizontal" android:layout_marginEnd="@dimen/toolbar_margin_horizontal"
android:layout_marginBottom="@dimen/toolbar_margin_vertical" android:layout_marginBottom="@dimen/toolbar_margin_vertical"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="8dp"
app:cardUseCompatPadding="true"
app:layout_scrollFlags="scroll|enterAlways" app:layout_scrollFlags="scroll|enterAlways"
app:shapeAppearance="@style/ToolbarCornerCardView"> app:shapeAppearance="@style/ToolbarCornerCardView">
@ -89,7 +92,7 @@
app:titleMarginStart="0dp" app:titleMarginStart="0dp"
app:titleTextAppearance="@style/ToolbarTextAppearanceSearch" app:titleTextAppearance="@style/ToolbarTextAppearanceSearch"
tools:ignore="UnusedAttribute" /> tools:ignore="UnusedAttribute" />
</FrameLayout> </com.google.android.material.card.MaterialCardView>
</LinearLayout> </LinearLayout>
</com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
@ -103,8 +106,8 @@
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:cardElevation="8dp"
app:cardBackgroundColor="?colorPrimary" app:cardBackgroundColor="?colorPrimary"
app:cardElevation="8dp"
app:shapeAppearanceOverlay="@style/TopCornerCardView"> app:shapeAppearanceOverlay="@style/TopCornerCardView">
<include layout="@layout/home_content" /> <include layout="@layout/home_content" />

View file

@ -42,6 +42,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="@style/TextViewCaption" android:textAppearance="@style/TextViewCaption"
android:visibility="gone"
tools:text="@tools:sample/full_names" /> tools:text="@tools:sample/full_names" />
</LinearLayout> </LinearLayout>

View file

@ -39,6 +39,7 @@
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/text" android:id="@+id/text"
android:visibility="gone"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="@style/TextViewCaption" android:textAppearance="@style/TextViewCaption"

View file

@ -620,7 +620,7 @@
<string name="grid_style_label"><![CDATA[Grids & Style]]></string> <string name="grid_style_label"><![CDATA[Grids & Style]]></string>
<string name="welcome">Welcome,</string> <string name="welcome">Welcome,</string>
<string name="premium">Get Premium</string> <string name="premium">Get Premium</string>
<string name="pro_summary">Now playing themes, Carousel effect, Color theme and more..</string> <string name="pro_summary">Now playing themes, Carousel effect and more..</string>
<string name="action_play_all">Play all</string> <string name="action_play_all">Play all</string>
<string name="start_play_music">Start playing music.</string> <string name="start_play_music">Start playing music.</string>
<string name="keyboard">Keyboard</string> <string name="keyboard">Keyboard</string>

View file

@ -27,7 +27,7 @@ android {
dependencies { dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.1.0' 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.preference:preference:1.1.0'
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
// Used for the list preference classes // Used for the list preference classes