Adde search genre

This commit is contained in:
h4h13 2019-12-06 22:43:09 +05:30
parent ee6af2a6d6
commit ff0fccae92
29 changed files with 460 additions and 589 deletions

View file

@ -13,8 +13,8 @@ android {
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
applicationId "code.name.monkey.retromusic" applicationId "code.name.monkey.retromusic"
versionCode 391 versionCode 392
versionName '3.4.700' versionName '3.4.800'
multiDexEnabled true multiDexEnabled true

File diff suppressed because one or more lines are too long

View file

@ -24,6 +24,7 @@ import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
import code.name.monkey.retromusic.extensions.ripAlpha
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.glide.ArtistGlideRequest import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
@ -57,7 +58,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
cab = MaterialCab(this, R.id.cab_stub) cab = MaterialCab(this, R.id.cab_stub)
.setMenu(menuRes) .setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close_white_24dp) .setCloseDrawableRes(R.drawable.ic_close_white_24dp)
.setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorPrimary))) .setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorSurface)))
.start(callback) .start(callback)
return cab as MaterialCab return cab as MaterialCab
} }
@ -187,16 +188,16 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C
} }
private fun setColors(color: Int) { private fun setColors(color: Int) {
val themeColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color val themeColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color.ripAlpha()
else ThemeStore.accentColor(this) else ThemeStore.accentColor(this)
songTitle.setTextColor(themeColor) songTitle.setTextColor(themeColor)
moreTitle.setTextColor(themeColor) moreTitle.setTextColor(themeColor)
val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor)
color color.ripAlpha()
else else
ATHUtil.resolveColor(this, R.attr.colorControlNormal) ATHUtil.resolveColor(this, R.attr.colorSurface)
MaterialUtil.setTint(button = shuffleAction, color = buttonColor) MaterialUtil.setTint(button = shuffleAction, color = buttonColor)
MaterialUtil.setTint(button = playAction, color = buttonColor) MaterialUtil.setTint(button = playAction, color = buttonColor)

View file

@ -24,6 +24,7 @@ import code.name.monkey.retromusic.adapter.album.AlbumAdapter
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.extensions.ripAlpha
import code.name.monkey.retromusic.glide.ArtistGlideRequest import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -50,7 +51,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
cab = MaterialCab(this, R.id.cab_stub) cab = MaterialCab(this, R.id.cab_stub)
.setMenu(menuRes) .setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close_white_24dp) .setCloseDrawableRes(R.drawable.ic_close_white_24dp)
.setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorPrimary))) .setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorSurface)))
.start(callback) .start(callback)
return cab as MaterialCab return cab as MaterialCab
} }
@ -224,21 +225,23 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
} }
private fun setColors(color: Int) { private fun setColors(color: Int) {
val textColor = if (PreferenceUtil.getInstance(this).adaptiveColor)
val textColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color color.ripAlpha()
else ThemeStore.accentColor(this) else
ThemeStore.accentColor(this)
albumTitle.setTextColor(textColor) albumTitle.setTextColor(textColor)
songTitle.setTextColor(textColor) songTitle.setTextColor(textColor)
biographyTitle.setTextColor(textColor) biographyTitle.setTextColor(textColor)
val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor)
else ATHUtil.resolveColor(this, R.attr.cardBackgroundColor) color.ripAlpha()
else
ATHUtil.resolveColor(this, R.attr.colorSurface)
MaterialUtil.setTint(button = shuffleAction, color = buttonColor) MaterialUtil.setTint(button = shuffleAction, color = buttonColor)
MaterialUtil.setTint(button = playAction, color = buttonColor) MaterialUtil.setTint(button = playAction, color = buttonColor)
val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface) val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
status_bar.setBackgroundColor(toolbarColor) status_bar.setBackgroundColor(toolbarColor)
toolbar.setBackgroundColor(toolbarColor) toolbar.setBackgroundColor(toolbarColor)
@ -272,21 +275,12 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView,
R.id.action_set_artist_image -> { R.id.action_set_artist_image -> {
val intent = Intent(Intent.ACTION_GET_CONTENT) val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*" intent.type = "image/*"
startActivityForResult( startActivityForResult(Intent.createChooser(intent, getString(R.string.pick_from_local_storage)), REQUEST_CODE_SELECT_IMAGE)
Intent.createChooser(
intent, getString(R.string.pick_from_local_storage)
), REQUEST_CODE_SELECT_IMAGE
)
return true return true
} }
R.id.action_reset_artist_image -> { R.id.action_reset_artist_image -> {
Toast.makeText( Toast.makeText(this@ArtistDetailActivity, resources.getString(R.string.updating), Toast.LENGTH_SHORT).show()
this@ArtistDetailActivity, CustomArtistImageUtil.getInstance(this@ArtistDetailActivity).resetCustomArtistImage(artist)
resources.getString(R.string.updating),
Toast.LENGTH_SHORT
).show()
CustomArtistImageUtil.getInstance(this@ArtistDetailActivity)
.resetCustomArtistImage(artist)
forceDownload = true forceDownload = true
return true return true
} }

View file

@ -39,7 +39,12 @@ class GenreDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder, GenreDet
private lateinit var songAdapter: ShuffleButtonSongAdapter private lateinit var songAdapter: ShuffleButtonSongAdapter
private var cab: MaterialCab? = null private var cab: MaterialCab? = null
private fun getEmojiByUnicode(unicode: Int): String {
return String(Character.toChars(unicode))
}
private fun checkIsEmpty() { private fun checkIsEmpty() {
emptyEmoji.text = getEmojiByUnicode(0x1F631)
empty?.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE empty?.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE
} }

View file

@ -12,263 +12,263 @@ import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.fragments.mainactivity.LibraryFragment import code.name.monkey.retromusic.fragments.mainactivity.LibraryFragment
import code.name.monkey.retromusic.fragments.mainactivity.folders.FoldersFragment import code.name.monkey.retromusic.fragments.mainactivity.folders.FoldersFragment
import code.name.monkey.retromusic.fragments.mainactivity.home.BannerHomeFragment import code.name.monkey.retromusic.fragments.mainactivity.home.BannerHomeFragment
import code.name.monkey.retromusic.helper.* import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SearchQueryHelper
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
import code.name.monkey.retromusic.loaders.* import code.name.monkey.retromusic.loaders.AlbumLoader
import code.name.monkey.retromusic.loaders.ArtistLoader
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.* import code.name.monkey.retromusic.util.AppRater
import code.name.monkey.retromusic.util.PreferenceUtil
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import java.util.* import java.util.*
class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedPreferenceChangeListener { class MainActivity : AbsSlidingMusicPanelActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
private lateinit var currentFragment: MainActivityFragmentCallbacks private lateinit var currentFragment: MainActivityFragmentCallbacks
private var blockRequestPermissions: Boolean = false private var blockRequestPermissions: Boolean = false
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private val broadcastReceiver = object : BroadcastReceiver() { private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
val action = intent.action val action = intent.action
if (action != null && action == Intent.ACTION_SCREEN_OFF) { if (action != null && action == Intent.ACTION_SCREEN_OFF) {
if (PreferenceUtil.getInstance(this@MainActivity).lockScreen && MusicPlayerRemote.isPlaying) { if (PreferenceUtil.getInstance(this@MainActivity).lockScreen && MusicPlayerRemote.isPlaying) {
val activity = Intent(context, LockScreenActivity::class.java) val activity = Intent(context, LockScreenActivity::class.java)
activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
ActivityCompat.startActivity(context, activity, null) ActivityCompat.startActivity(context, activity, null)
} }
} }
} }
} }
override fun createContentView(): View { override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_main_content) return wrapSlidingMusicPanel(R.layout.activity_main_content)
} }
override fun onCreate( override fun onCreate(
savedInstanceState: Bundle? savedInstanceState: Bundle?
) { ) {
setDrawUnderStatusBar() setDrawUnderStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
getBottomNavigationView().selectedItemId = PreferenceUtil.getInstance(this).lastPage
getBottomNavigationView().setOnNavigationItemSelectedListener {
PreferenceUtil.getInstance(this).lastPage = it.itemId
selectedFragment(it.itemId)
true
}
getBottomNavigationView().selectedItemId = PreferenceUtil.getInstance(this).lastPage if (savedInstanceState == null) {
setMusicChooser(PreferenceUtil.getInstance(this).lastMusicChooser)
} else {
restoreCurrentFragment()
}
getBottomNavigationView().setOnNavigationItemSelectedListener { checkShowChangelog()
PreferenceUtil.getInstance(this).lastPage = it.itemId AppRater.appLaunched(this)
selectedFragment(it.itemId) }
true
}
if (savedInstanceState == null) { private fun checkShowChangelog() {
setMusicChooser(PreferenceUtil.getInstance(this).lastMusicChooser) try {
} else { val pInfo = packageManager.getPackageInfo(packageName, 0)
restoreCurrentFragment() val currentVersion = pInfo.versionCode
} if (currentVersion != PreferenceUtil.getInstance(this).lastChangelogVersion) {
startActivityForResult(
Intent(this, WhatsNewActivity::class.java),
APP_INTRO_REQUEST
)
}
} catch (e: Throwable) {
e.printStackTrace()
}
checkShowChangelog() }
AppRater.appLaunched(this);
}
private fun checkShowChangelog() { override fun onResume() {
try { super.onResume()
val pInfo = packageManager.getPackageInfo(packageName, 0) val screenOnOff = IntentFilter()
val currentVersion = pInfo.versionCode screenOnOff.addAction(Intent.ACTION_SCREEN_OFF)
if (currentVersion != PreferenceUtil.getInstance(this).lastChangelogVersion) { registerReceiver(broadcastReceiver, screenOnOff)
startActivityForResult(
Intent(this, WhatsNewActivity::class.java),
APP_INTRO_REQUEST
)
}
} catch (e: Throwable) {
e.printStackTrace()
}
} PreferenceUtil.getInstance(this).registerOnSharedPreferenceChangedListener(this)
override fun onResume() { if (intent.hasExtra("expand")) {
super.onResume() if (intent.getBooleanExtra("expand", false)) {
val screenOnOff = IntentFilter() expandPanel()
screenOnOff.addAction(Intent.ACTION_SCREEN_OFF) intent.putExtra("expand", false)
registerReceiver(broadcastReceiver, screenOnOff) }
}
}
PreferenceUtil.getInstance(this).registerOnSharedPreferenceChangedListener(this) override fun onDestroy() {
super.onDestroy()
disposable.clear()
unregisterReceiver(broadcastReceiver)
PreferenceUtil.getInstance(this).unregisterOnSharedPreferenceChangedListener(this)
}
if (intent.hasExtra("expand")) { private fun setCurrentFragment(fragment: Fragment, tag: String) {
if (intent.getBooleanExtra("expand", false)) { if (tag != supportFragmentManager.findFragmentById(R.id.fragment_container)?.tag) {
expandPanel() supportFragmentManager.beginTransaction()
intent.putExtra("expand", false) .replace(R.id.fragment_container, fragment, tag).commit()
} currentFragment = fragment as MainActivityFragmentCallbacks
} }
} }
override fun onDestroy() { private fun restoreCurrentFragment() {
super.onDestroy() currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as MainActivityFragmentCallbacks
disposable.clear() }
unregisterReceiver(broadcastReceiver)
PreferenceUtil.getInstance(this).unregisterOnSharedPreferenceChangedListener(this)
}
private fun setCurrentFragment(fragment: Fragment, tag: String) { private fun handlePlaybackIntent(intent: Intent?) {
println("setCurrentFragment -> $tag -> ${supportFragmentManager.findFragmentById(R.id.fragment_container)?.tag}") if (intent == null) {
if (tag != supportFragmentManager.findFragmentById(R.id.fragment_container)?.tag) { return
supportFragmentManager.beginTransaction() }
.replace(R.id.fragment_container, fragment, tag).commit() val uri = intent.data
currentFragment = fragment as MainActivityFragmentCallbacks val mimeType = intent.type
} var handled = false
} 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) {
MusicPlayerRemote.openAndShuffleQueue(songs, true)
} else {
MusicPlayerRemote.openQueue(songs, 0, true)
}
handled = true
}
private fun restoreCurrentFragment() { if (uri != null && uri.toString().isNotEmpty()) {
currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as MainActivityFragmentCallbacks MusicPlayerRemote.playFromUri(uri)
} handled = true
} else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "playlistId", "playlist").toInt()
if (id >= 0) {
val position = intent.getIntExtra("position", 0)
val songs = ArrayList(PlaylistSongsLoader.getPlaylistSongList(this, id))
MusicPlayerRemote.openQueue(songs, position, true)
handled = true
}
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
if (id >= 0) {
val position = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue(AlbumLoader.getAlbum(this, id).songs!!, position, true)
handled = true
}
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
if (id >= 0) {
val position = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).songs, position, true)
handled = true
}
}
if (handled) {
setIntent(Intent())
}
}
private fun handlePlaybackIntent(intent: Intent?) { private fun parseIdFromIntent(intent: Intent, longKey: String, stringKey: String): Long {
if (intent == null) { var id = intent.getLongExtra(longKey, -1)
return if (id < 0) {
} val idString = intent.getStringExtra(stringKey)
if (idString != null) {
try {
id = java.lang.Long.parseLong(idString)
} catch (e: NumberFormatException) {
Log.e(TAG, e.message)
}
}
}
return id
}
val uri = intent.data override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val mimeType = intent.type super.onActivityResult(requestCode, resultCode, data)
var handled = false when (requestCode) {
if (intent.action != null && intent.action == MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH) { APP_INTRO_REQUEST -> {
val songs = SearchQueryHelper.getSongs(this, intent.extras!!) blockRequestPermissions = false
if (MusicPlayerRemote.shuffleMode == MusicService.SHUFFLE_MODE_SHUFFLE) { if (!hasPermissions()) {
MusicPlayerRemote.openAndShuffleQueue(songs, true) requestPermissions()
} else { }
MusicPlayerRemote.openQueue(songs, 0, true) }
} REQUEST_CODE_THEME, APP_USER_INFO_REQUEST -> postRecreate()
handled = true PURCHASE_REQUEST -> {
} if (resultCode == RESULT_OK) {
//checkSetUpPro();
}
}
}
if (uri != null && uri.toString().isNotEmpty()) { }
MusicPlayerRemote.playFromUri(uri)
handled = true
} else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "playlistId", "playlist").toInt()
if (id >= 0) {
val position = intent.getIntExtra("position", 0)
val songs = ArrayList(PlaylistSongsLoader.getPlaylistSongList(this, id))
MusicPlayerRemote.openQueue(songs, position, true)
handled = true
}
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
if (id >= 0) {
val position = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue(AlbumLoader.getAlbum(this, id).songs!!, position, true)
handled = true
}
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
if (id >= 0) {
val position = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).songs, position, true)
handled = true
}
}
if (handled) {
setIntent(Intent())
}
}
private fun parseIdFromIntent(intent: Intent, longKey: String, stringKey: String): Long { override fun handleBackPress(): Boolean {
var id = intent.getLongExtra(longKey, -1) return super.handleBackPress() || currentFragment.handleBackPress()
if (id < 0) { }
val idString = intent.getStringExtra(stringKey)
if (idString != null) {
try {
id = java.lang.Long.parseLong(idString)
} catch (e: NumberFormatException) {
Log.e(TAG, e.message)
}
}
}
return id
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onServiceConnected() {
super.onActivityResult(requestCode, resultCode, data) super.onServiceConnected()
when (requestCode) { handlePlaybackIntent(intent)
APP_INTRO_REQUEST -> { }
blockRequestPermissions = false
if (!hasPermissions()) {
requestPermissions()
}
}
REQUEST_CODE_THEME, APP_USER_INFO_REQUEST -> postRecreate()
PURCHASE_REQUEST -> {
if (resultCode == RESULT_OK) {
//checkSetUpPro();
}
}
}
} override fun requestPermissions() {
if (!blockRequestPermissions) {
super.requestPermissions()
}
}
override fun handleBackPress(): Boolean { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
return super.handleBackPress() || currentFragment.handleBackPress() if (key == PreferenceUtil.GENERAL_THEME || key == PreferenceUtil.BLACK_THEME || key == PreferenceUtil.ADAPTIVE_COLOR_APP || key == PreferenceUtil.DOMINANT_COLOR || key == PreferenceUtil.USER_NAME || key == PreferenceUtil.TOGGLE_FULL_SCREEN || key == PreferenceUtil.TOGGLE_VOLUME || key == PreferenceUtil.ROUND_CORNERS || key == PreferenceUtil.CAROUSEL_EFFECT || key == PreferenceUtil.NOW_PLAYING_SCREEN_ID || key == PreferenceUtil.TOGGLE_GENRE || key == PreferenceUtil.BANNER_IMAGE_PATH || key == PreferenceUtil.PROFILE_IMAGE_PATH || key == PreferenceUtil.CIRCULAR_ALBUM_ART || key == PreferenceUtil.KEEP_SCREEN_ON || key == PreferenceUtil.TOGGLE_SEPARATE_LINE || key == PreferenceUtil.ALBUM_GRID_STYLE || key == PreferenceUtil.ARTIST_GRID_STYLE || key == PreferenceUtil.TOGGLE_HOME_BANNER || key == PreferenceUtil.TOGGLE_ADD_CONTROLS || key == PreferenceUtil.ALBUM_COVER_STYLE || key == PreferenceUtil.HOME_ARTIST_GRID_STYLE || key == PreferenceUtil.ALBUM_COVER_TRANSFORM || key == PreferenceUtil.DESATURATED_COLOR || key == PreferenceUtil.TAB_TEXT_MODE || key == PreferenceUtil.LIBRARY_CATEGORIES) postRecreate()
}
override fun onServiceConnected() { }
super.onServiceConnected()
handlePlaybackIntent(intent)
}
override fun requestPermissions() { private fun showPromotionalOffer() {
if (!blockRequestPermissions) { /*MaterialDialog(this).show {
super.requestPermissions() positiveButton(text = "Buy") { startActivity(Intent(this@MainActivity, PurchaseActivity::class.java)) }
} negativeButton(android.R.string.cancel)
} customView(R.layout.dialog_promotional_offer)
onDismiss {
PreferenceManager.getDefaultSharedPreferences(this@MainActivity)
.edit()
.putBoolean("shown", true)
.apply()
}
}*/
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { private fun selectedFragment(itemId: Int) {
if (key == PreferenceUtil.GENERAL_THEME || key == PreferenceUtil.BLACK_THEME || key == PreferenceUtil.ADAPTIVE_COLOR_APP || key == PreferenceUtil.DOMINANT_COLOR || key == PreferenceUtil.USER_NAME || key == PreferenceUtil.TOGGLE_FULL_SCREEN || key == PreferenceUtil.TOGGLE_VOLUME || key == PreferenceUtil.ROUND_CORNERS || key == PreferenceUtil.CAROUSEL_EFFECT || key == PreferenceUtil.NOW_PLAYING_SCREEN_ID || key == PreferenceUtil.TOGGLE_GENRE || key == PreferenceUtil.BANNER_IMAGE_PATH || key == PreferenceUtil.PROFILE_IMAGE_PATH || key == PreferenceUtil.CIRCULAR_ALBUM_ART || key == PreferenceUtil.KEEP_SCREEN_ON || key == PreferenceUtil.TOGGLE_SEPARATE_LINE || key == PreferenceUtil.ALBUM_GRID_STYLE || key == PreferenceUtil.ARTIST_GRID_STYLE || key == PreferenceUtil.TOGGLE_HOME_BANNER || key == PreferenceUtil.TOGGLE_ADD_CONTROLS || key == PreferenceUtil.ALBUM_COVER_STYLE || key == PreferenceUtil.HOME_ARTIST_GRID_STYLE || key == PreferenceUtil.ALBUM_COVER_TRANSFORM || key == PreferenceUtil.DESATURATED_COLOR || key == PreferenceUtil.TAB_TEXT_MODE || key == PreferenceUtil.LIBRARY_CATEGORIES) postRecreate() when (itemId) {
R.id.action_album, R.id.action_artist, R.id.action_playlist, R.id.action_genre, R.id.action_song -> setCurrentFragment(
LibraryFragment.newInstance(itemId),
itemId.toString()
)
R.id.action_home -> setCurrentFragment(
BannerHomeFragment.newInstance(),
BannerHomeFragment.TAG
)
else -> {
setCurrentFragment(BannerHomeFragment.newInstance(), BannerHomeFragment.TAG)
}
}
}
} fun setMusicChooser(key: Int) {
PreferenceUtil.getInstance(this).lastMusicChooser = key
when (key) {
FOLDER -> setCurrentFragment(FoldersFragment.newInstance(this), FoldersFragment.TAG)
else -> selectedFragment(PreferenceUtil.getInstance(this).lastPage)
}
}
private fun showPromotionalOffer() { companion object {
/*MaterialDialog(this).show { const val APP_INTRO_REQUEST = 2323
positiveButton(text = "Buy") { startActivity(Intent(this@MainActivity, PurchaseActivity::class.java)) } const val HOME = 0
negativeButton(android.R.string.cancel) const val FOLDER = 1
customView(R.layout.dialog_promotional_offer) const val LIBRARY = 2
onDismiss { private const val TAG = "MainActivity"
PreferenceManager.getDefaultSharedPreferences(this@MainActivity) private const val APP_USER_INFO_REQUEST = 9003
.edit() private const val REQUEST_CODE_THEME = 9002
.putBoolean("shown", true) private const val PURCHASE_REQUEST = 101
.apply() }
}
}*/
}
private fun selectedFragment(itemId: Int) {
when (itemId) {
R.id.action_album, R.id.action_artist, R.id.action_playlist, R.id.action_genre, R.id.action_song -> setCurrentFragment(
LibraryFragment.newInstance(itemId),
itemId.toString()
)
R.id.action_home -> setCurrentFragment(
BannerHomeFragment.newInstance(),
BannerHomeFragment.TAG
)
else -> {
setCurrentFragment(BannerHomeFragment.newInstance(), BannerHomeFragment.TAG)
}
}
}
fun setMusicChooser(key: Int) {
PreferenceUtil.getInstance(this).lastMusicChooser = key
when (key) {
FOLDER -> setCurrentFragment(FoldersFragment.newInstance(this), FoldersFragment.TAG)
else -> selectedFragment(PreferenceUtil.getInstance(this).lastPage)
}
}
companion object {
const val APP_INTRO_REQUEST = 2323
const val HOME = 0
const val FOLDER = 1
const val LIBRARY = 2
private const val TAG = "MainActivity"
private const val APP_USER_INFO_REQUEST = 9003
private const val REQUEST_CODE_THEME = 9002
private const val PURCHASE_REQUEST = 101
}
} }

View file

@ -190,10 +190,15 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli
private fun checkIsEmpty() { private fun checkIsEmpty() {
checkForPadding() checkForPadding()
emptyEmoji.text = getEmojiByUnicode(0x1F631)
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
} }
private fun getEmojiByUnicode(unicode: Int): String {
return String(Character.toChars(unicode))
}
public override fun onPause() { public override fun onPause() {
if (recyclerViewDragDropManager != null) { if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.cancelDrag() recyclerViewDragDropManager!!.cancelDrag()

View file

@ -79,7 +79,7 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch
keyboardPopup.iconTint = this keyboardPopup.iconTint = this
} }
if (savedInstanceState != null) { if (savedInstanceState != null) {
query = savedInstanceState.getString(QUERY); query = savedInstanceState.getString(QUERY)
} }
} }

View file

@ -60,9 +60,7 @@ public class WhatsNewActivity extends AbsBaseActivity {
toolbar = findViewById(R.id.toolbar); toolbar = findViewById(R.id.toolbar);
appBarLayout = findViewById(R.id.appBarLayout); appBarLayout = findViewById(R.id.appBarLayout);
int primaryColor = INSTANCE.resolveColor(this, R.attr.colorSurface); toolbar.setBackgroundColor(INSTANCE.resolveColor(this, R.attr.colorSurface));
toolbar.setBackgroundColor(primaryColor);
appBarLayout.setBackgroundColor(primaryColor);
//setSupportActionBar(toolbar); //setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(v -> onBackPressed()); toolbar.setNavigationOnClickListener(v -> onBackPressed());
@ -79,7 +77,7 @@ public class WhatsNewActivity extends AbsBaseActivity {
// Inject color values for WebView body background and links // Inject color values for WebView body background and links
final boolean isDark = INSTANCE.isWindowBackgroundDark(this); final boolean isDark = INSTANCE.isWindowBackgroundDark(this);
final String backgroundColor = colorToCSS(INSTANCE.resolveColor(this, android.R.attr.windowBackground, Color.parseColor(isDark ? "#424242" : "#ffffff"))); final String backgroundColor = colorToCSS(INSTANCE.resolveColor(this, R.attr.colorSurface, Color.parseColor(isDark ? "#424242" : "#ffffff")));
final String contentColor = colorToCSS(Color.parseColor(isDark ? "#ffffff" : "#000000")); final String contentColor = colorToCSS(Color.parseColor(isDark ? "#ffffff" : "#000000"));
final String changeLog = buf.toString() final String changeLog = buf.toString()
.replace("{style-placeholder}", String.format("body { background-color: %s; color: %s; }", backgroundColor, contentColor)) .replace("{style-placeholder}", String.format("body { background-color: %s; color: %s; }", backgroundColor, contentColor))

View file

@ -2,9 +2,7 @@ package code.name.monkey.retromusic.activities.base
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.graphics.Color import android.graphics.Color
import android.graphics.Rect
import android.os.Bundle import android.os.Bundle
import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
@ -338,12 +336,13 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlay
bottomNavigationView.menu.add(0, menu.id, 0, menu.stringRes).setIcon(menu.icon) bottomNavigationView.menu.add(0, menu.id, 0, menu.stringRes).setIcon(menu.icon)
} }
} }
print("Tabs -> ${currentTabs.size}")
if (currentTabs.size <= 1) { if (currentTabs.size <= 1) {
toggleBottomNavigationView(true) toggleBottomNavigationView(true)
} }
} }
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean { /*override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
if (ev?.action == MotionEvent.ACTION_DOWN) { if (ev?.action == MotionEvent.ACTION_DOWN) {
if (panelState == BottomSheetBehavior.STATE_EXPANDED) { if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
val outRect = Rect() val outRect = Rect()
@ -354,5 +353,5 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlay
} }
} }
return super.dispatchTouchEvent(ev) return super.dispatchTouchEvent(ev)
} }*/
} }

View file

@ -1,7 +1,9 @@
package code.name.monkey.retromusic.adapter package code.name.monkey.retromusic.adapter
import android.app.Activity import android.app.Activity
import android.view.* import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
@ -14,49 +16,39 @@ import java.util.*
*/ */
class GenreAdapter( class GenreAdapter(
private val activity: Activity, dataSet: ArrayList<Genre>, private val mItemLayoutRes: Int private val activity: Activity, dataSet: ArrayList<Genre>, private val mItemLayoutRes: Int
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() { ) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
var dataSet = ArrayList<Genre>() var dataSet = ArrayList<Genre>()
private set private set
init { init {
this.dataSet = dataSet this.dataSet = dataSet
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false)) return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false))
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val genre = dataSet[position] val genre = dataSet[position]
if (holder.title != null) { holder.title?.text = genre.name
holder.title!!.text = genre.name holder.text?.text = String.format(Locale.getDefault(), "%d %s", genre.songCount, if (genre.songCount > 1) activity.getString(R.string.songs) else activity.getString(R.string.song))
} }
if (holder.text != null) {
holder.text!!.text = String.format(
Locale.getDefault(),
"%d %s",
genre.songCount,
if (genre.songCount > 1) activity.getString(R.string.songs)
else activity.getString(R.string.song)
)
}
}
override fun getItemCount(): Int { override fun getItemCount(): Int {
return dataSet.size return dataSet.size
} }
fun swapDataSet(list: ArrayList<Genre>) { fun swapDataSet(list: ArrayList<Genre>) {
dataSet = list dataSet = list
notifyDataSetChanged() notifyDataSetChanged()
} }
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
override fun onClick(v: View?) { override fun onClick(v: View?) {
super.onClick(v) super.onClick(v)
val genre = dataSet[adapterPosition] val genre = dataSet[adapterPosition]
NavigationUtil.goToGenre(activity, genre) NavigationUtil.goToGenre(activity, genre)
} }
} }
} }

View file

@ -1,140 +1,140 @@
package code.name.monkey.retromusic.adapter package code.name.monkey.retromusic.adapter
import android.app.ActivityOptions import android.app.ActivityOptions
import android.view.* import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.* import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.menu.SongMenuHelper import code.name.monkey.retromusic.helper.menu.SongMenuHelper
import code.name.monkey.retromusic.model.* import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.util.* import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Genre
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 com.bumptech.glide.Glide
import java.util.*
import kotlin.collections.ArrayList
import android.util.Pair as UtilPair import android.util.Pair as UtilPair
class SearchAdapter( class SearchAdapter(
private val activity: AppCompatActivity, private var dataSet: List<Any>? private val activity: AppCompatActivity, private var dataSet: List<Any>?
) : RecyclerView.Adapter<SearchAdapter.ViewHolder>() { ) : RecyclerView.Adapter<SearchAdapter.ViewHolder>() {
fun swapDataSet(dataSet: MutableList<Any>) { fun swapDataSet(dataSet: MutableList<Any>) {
this.dataSet = dataSet this.dataSet = dataSet
notifyDataSetChanged() notifyDataSetChanged()
} }
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
if (dataSet!![position] is Album) return ALBUM if (dataSet!![position] is Album) return ALBUM
if (dataSet!![position] is Artist) return ARTIST if (dataSet!![position] is Artist) return ARTIST
return if (dataSet!![position] is Song) SONG else HEADER if (dataSet!![position] is Genre) return GENRE
} return if (dataSet!![position] is Song) SONG else HEADER
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return if (viewType == HEADER) ViewHolder( return if (viewType == HEADER) ViewHolder(LayoutInflater.from(activity).inflate(R.layout.sub_header, parent, false), viewType)
LayoutInflater.from(activity).inflate( else
R.layout.sub_header, ViewHolder(LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false), viewType)
parent, }
false
), viewType
) else ViewHolder(
LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false),
viewType
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (getItemViewType(position)) { when (getItemViewType(position)) {
ALBUM -> { ALBUM -> {
val album = dataSet?.get(position) as Album val album = dataSet?.get(position) as Album
holder.title?.text = album.title holder.title?.text = album.title
holder.text?.text = album.artistName holder.text?.text = album.artistName
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore(activity).build().into(holder.image) .checkIgnoreMediaStore(activity).build().into(holder.image)
} }
ARTIST -> { ARTIST -> {
val artist = dataSet?.get(position) as Artist val artist = dataSet?.get(position) as Artist
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).build() ArtistGlideRequest.Builder.from(Glide.with(activity), artist).build()
.into(holder.image) .into(holder.image)
} }
SONG -> { SONG -> {
val song = dataSet?.get(position) as Song val song = dataSet?.get(position) as Song
holder.title?.text = song.title holder.title?.text = song.title
holder.text?.text = song.albumName holder.text?.text = song.albumName
} }
else -> { GENRE -> {
holder.title?.text = dataSet?.get(position).toString() val genre = dataSet?.get(position) as Genre
holder.title?.setTextColor(ThemeStore.accentColor(activity)) holder.title?.text = genre.name
} holder.text?.text = String.format(Locale.getDefault(), "%d %s", genre.songCount, if (genre.songCount > 1) activity.getString(R.string.songs) else activity.getString(R.string.song))
} }
} else -> {
holder.title?.text = dataSet?.get(position).toString()
holder.title?.setTextColor(ThemeStore.accentColor(activity))
}
}
}
override fun getItemCount(): Int { override fun getItemCount(): Int {
return dataSet!!.size return dataSet!!.size
} }
inner class ViewHolder(itemView: View, itemViewType: Int) : MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View, itemViewType: Int) : MediaEntryViewHolder(itemView) {
init { init {
itemView.setOnLongClickListener(null) itemView.setOnLongClickListener(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) {
ALBUM -> setImageTransitionName(activity.getString(R.string.transition_album_art)) ALBUM -> setImageTransitionName(activity.getString(R.string.transition_album_art))
ARTIST -> setImageTransitionName(activity.getString(R.string.transition_artist_image)) ARTIST -> setImageTransitionName(activity.getString(R.string.transition_artist_image))
else -> { else -> {
val container = itemView.findViewById<View>(R.id.imageContainer) val container = itemView.findViewById<View>(R.id.imageContainer)
container?.visibility = View.GONE container?.visibility = View.GONE
} }
} }
} }
override fun onClick(v: View?) { override fun onClick(v: View?) {
val item = dataSet!![adapterPosition] val item = dataSet!![adapterPosition]
when (itemViewType) { when (itemViewType) {
ALBUM -> { ALBUM -> {
val options = ActivityOptions.makeSceneTransitionAnimation( val options = ActivityOptions.makeSceneTransitionAnimation(activity, UtilPair.create(image, activity.getString(R.string.transition_album_art)))
activity, NavigationUtil.goToAlbumOptions(activity, (item as Album).id, options)
UtilPair.create( }
image, ARTIST -> {
activity.getString(R.string.transition_album_art) val options = ActivityOptions.makeSceneTransitionAnimation(activity, UtilPair.create(image, activity.getString(R.string.transition_artist_image)))
) NavigationUtil.goToArtistOptions(activity, (item as Artist).id, options)
) }
NavigationUtil.goToAlbumOptions(activity, (item as Album).id, options) GENRE -> {
} NavigationUtil.goToGenre(activity, item as Genre)
ARTIST -> { }
val options = ActivityOptions.makeSceneTransitionAnimation( SONG -> {
activity, val playList = ArrayList<Song>()
UtilPair.create( playList.add(item as Song)
image, MusicPlayerRemote.openQueue(playList, 0, true)
activity.getString(R.string.transition_artist_image) }
) }
) }
NavigationUtil.goToArtistOptions(activity, (item as Artist).id, options) }
}
SONG -> {
val playList = ArrayList<Song>()
playList.add(item as Song)
MusicPlayerRemote.openQueue(playList, 0, true)
}
}
}
}
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
private const val SONG = 3 private const val SONG = 3
} private const val GENRE = 4
}
} }

View file

@ -60,14 +60,14 @@ class SimplePlayerFragment : AbsPlayerFragment() {
} }
override fun toolbarIconColor(): Int { override fun toolbarIconColor(): Int {
return ATHUtil.resolveColor(requireContext(), R.attr.iconColor) return ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal)
} }
override fun onColorChanged(color: Int) { override fun onColorChanged(color: Int) {
lastColor = color lastColor = color
callbacks?.onPaletteColorChanged() callbacks?.onPaletteColorChanged()
simplePlaybackControlsFragment.setDark(color) simplePlaybackControlsFragment.setDark(color)
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(requireContext(), R.attr.iconColor), requireActivity()) ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(requireContext(), R.attr.colorControlNormal), requireActivity())
} }
@ -87,7 +87,7 @@ class SimplePlayerFragment : AbsPlayerFragment() {
inflateMenu(R.menu.menu_player) inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() } setNavigationOnClickListener { requireActivity().onBackPressed() }
setOnMenuItemClickListener(this@SimplePlayerFragment) setOnMenuItemClickListener(this@SimplePlayerFragment)
ToolbarContentTintHelper.colorizeToolbar(this, ATHUtil.resolveColor(context, R.attr.iconColor), requireActivity()) ToolbarContentTintHelper.colorizeToolbar(this, ATHUtil.resolveColor(context, R.attr.colorControlNormal), requireActivity())
} }
} }
} }

View file

@ -19,34 +19,21 @@ import android.database.Cursor
import android.net.Uri import android.net.Uri
import android.provider.BaseColumns import android.provider.BaseColumns
import android.provider.MediaStore.Audio.Genres import android.provider.MediaStore.Audio.Genres
import code.name.monkey.retromusic.Constants.baseProjection
import code.name.monkey.retromusic.Constants.BASE_SELECTION import code.name.monkey.retromusic.Constants.BASE_SELECTION
import code.name.monkey.retromusic.Constants.baseProjection
import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import io.reactivex.Observable
import java.util.* import java.util.*
object GenreLoader { object GenreLoader {
fun getAllGenresFlowable(context: Context): Observable<ArrayList<Genre>> {
return getGenresFromCursorFlowable(context, makeGenreCursor(context))
}
fun getAllGenres(context: Context): ArrayList<Genre> { fun getAllGenres(context: Context): ArrayList<Genre> {
return getGenresFromCursor(context, makeGenreCursor(context)) return getGenresFromCursor(context, makeGenreCursor(context))
} }
fun getSongsFlowable(context: Context, genreId: Int): Observable<ArrayList<Song>> {
// The genres table only stores songs that have a genre specified,
// so we need to get songs without a genre a different way.
return if (genreId == -1) {
getSongsWithNoGenreFlowable(context)
} else SongLoader.getSongsFlowable(makeGenreSongCursor(context, genreId))
}
fun getSongs(context: Context, genreId: Int): ArrayList<Song> { fun getSongs(context: Context, genreId: Int): ArrayList<Song> {
// The genres table only stores songs that have a genre specified, // The genres table only stores songs that have a genre specified,
// so we need to get songs without a genre a different way. // so we need to get songs without a genre a different way.
@ -64,12 +51,6 @@ object GenreLoader {
} }
private fun getSongsWithNoGenreFlowable(context: Context): Observable<ArrayList<Song>> {
val selection = BaseColumns._ID + " NOT IN " +
"(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)"
return SongLoader.getSongsFlowable(SongLoader.makeSongCursor(context, selection, null))
}
private fun getSongsWithNoGenre(context: Context): ArrayList<Song> { private fun getSongsWithNoGenre(context: Context): ArrayList<Song> {
val selection = BaseColumns._ID + " NOT IN " + val selection = BaseColumns._ID + " NOT IN " +
"(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)" "(SELECT " + Genres.Members.AUDIO_ID + " FROM audio_genres_map)"
@ -112,34 +93,6 @@ object GenreLoader {
} }
private fun getGenresFromCursorFlowable(context: Context, cursor: Cursor?): Observable<ArrayList<Genre>> {
return Observable.create { e ->
val genres = ArrayList<Genre>()
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
val genre = getGenreFromCursor(context, cursor)
if (genre.songCount > 0) {
genres.add(genre)
} else {
// try to remove the empty genre from the media store
try {
context.contentResolver.delete(Genres.EXTERNAL_CONTENT_URI, Genres._ID + " == " + genre.id, null)
} catch (ex: Exception) {
ex.printStackTrace()
// nothing we can do then
}
}
} while (cursor.moveToNext())
}
cursor.close()
}
e.onNext(genres)
e.onComplete()
}
}
private fun getGenresFromCursor(context: Context, cursor: Cursor?): ArrayList<Genre> { private fun getGenresFromCursor(context: Context, cursor: Cursor?): ArrayList<Genre> {
val genres = arrayListOf<Genre>() val genres = arrayListOf<Genre>()
if (cursor != null) { if (cursor != null) {

View file

@ -16,31 +16,40 @@ 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 code.name.monkey.retromusic.model.Genre
import java.util.*
object SearchLoader { object SearchLoader {
fun searchAll(context: Context, query: String?): MutableList<Any> { fun searchAll(context: Context, query: String?): MutableList<Any> {
val results = mutableListOf<Any>() val results = mutableListOf<Any>()
query?.let { query?.let { searchString ->
val songs = SongLoader.getSongs(context, it) val songs = SongLoader.getSongs(context, searchString)
if (songs.isNotEmpty()) { if (songs.isNotEmpty()) {
results.add(context.resources.getString(R.string.songs)) results.add(context.resources.getString(R.string.songs))
results.addAll(songs) results.addAll(songs)
} }
val artists = ArtistLoader.getArtists(context, it) val artists = ArtistLoader.getArtists(context, searchString)
if (artists.isNotEmpty()) { if (artists.isNotEmpty()) {
results.add(context.resources.getString(R.string.artists)) results.add(context.resources.getString(R.string.artists))
results.addAll(artists) results.addAll(artists)
} }
val albums = AlbumLoader.getAlbums(context, it) val albums = AlbumLoader.getAlbums(context, searchString)
if (albums.isNotEmpty()) { if (albums.isNotEmpty()) {
results.add(context.resources.getString(R.string.albums)) results.add(context.resources.getString(R.string.albums))
results.addAll(albums) results.addAll(albums)
} }
val genres: List<Genre> = GenreLoader.getAllGenres(context).filter { genre -> genre.name.toLowerCase(Locale.getDefault()).contains(searchString.toLowerCase(Locale.getDefault())) }
genres.forEach {
println(it.name)
}
if (genres.isNotEmpty()) {
results.add(context.resources.getString(R.string.genres))
results.addAll(genres)
}
} }
return results return results
} }
} }

View file

@ -53,9 +53,7 @@ interface SearchPresenter : Presenter<SearchView> {
override fun search(query: String?) { override fun search(query: String?) {
launch { launch {
when (val result = repository.search(query)) { when (val result = repository.search(query)) {
is Success -> withContext(Dispatchers.Main) { is Success -> withContext(Dispatchers.Main) { view?.showData(result.data) }
view?.showData(result.data)
}
is Error -> withContext(Dispatchers.Main) { view?.showEmptyView() } is Error -> withContext(Dispatchers.Main) { view?.showEmptyView() }
} }
} }

View file

@ -247,12 +247,6 @@ class RepositoryImpl(private val context: Context) : Repository {
} }
} }
override fun getSongFlowable(id: Int): Observable<Song> {
return SongLoader.getSongFlowable(context, id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
override fun getAlbumFlowable(albumId: Int): Observable<Album> { override fun getAlbumFlowable(albumId: Int): Observable<Album> {
return AlbumLoader.getAlbumFlowable(context, albumId) return AlbumLoader.getAlbumFlowable(context, albumId)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
@ -271,70 +265,12 @@ class RepositoryImpl(private val context: Context) : Repository {
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
} }
override fun getGenreFlowable(genreId: Int): Observable<ArrayList<Song>> {
return GenreLoader.getSongsFlowable(context, genreId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
override val favoritePlaylistFlowable: Observable<ArrayList<Playlist>> override val favoritePlaylistFlowable: Observable<ArrayList<Playlist>>
get() = PlaylistLoader.getFavoritePlaylistFlowable(context) get() = PlaylistLoader.getFavoritePlaylistFlowable(context)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
override val allSongsFlowable: Observable<ArrayList<Song>>
get() = SongLoader.getAllSongsFlowable(context)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
override val suggestionSongsFlowable: Observable<ArrayList<Song>>
get() = SongLoader.suggestSongs(context)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
override val allAlbumsFlowable: Observable<ArrayList<Album>>
get() = AlbumLoader.getAllAlbumsFlowable(context)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
override val recentAlbumsFlowable: Observable<ArrayList<Album>>
get() = LastAddedSongsLoader.getLastAddedAlbumsFlowable(context)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
override val topAlbumsFlowable: Observable<ArrayList<Album>>
get() = TopAndRecentlyPlayedTracksLoader.getTopAlbumsFlowable(context)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
override val allArtistsFlowable: Observable<ArrayList<Artist>>
get() = ArtistLoader.getAllArtistsFlowable(context)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
override val recentArtistsFlowable: Observable<ArrayList<Artist>>
get() = LastAddedSongsLoader.getLastAddedArtistsFlowable(context)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
override val topArtistsFlowable: Observable<ArrayList<Artist>>
get() = TopAndRecentlyPlayedTracksLoader.getTopArtistsFlowable(context)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
override val allPlaylistsFlowable: Observable<ArrayList<Playlist>>
get() = PlaylistLoader.getAllPlaylistsFlowoable(context)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
override val allGenresFlowable: Observable<ArrayList<Genre>>
get() = GenreLoader.getAllGenresFlowable(context)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
override fun getSong(id: Int): Song { override fun getSong(id: Int): Song {
return SongLoader.getSong(context, id) return SongLoader.getSong(context, id)
} }
@ -347,11 +283,10 @@ class RepositoryImpl(private val context: Context) : Repository {
return ArtistLoader.getArtist(context, artistId.toInt()) return ArtistLoader.getArtist(context, artistId.toInt())
} }
} }
suspend fun <T : Any> safeApiCall(call: suspend () -> Result<T>, errorMessage: String): Result<T> = try { suspend fun <T : Any> safeApiCall(call: suspend () -> Result<T>, errorMessage: String): Result<T> = try {
call.invoke() call.invoke()
} catch (e: Exception) { } catch (e: Exception) {
Result.Error(IOException(errorMessage, e)) Error(IOException(errorMessage, e))
} }

View file

@ -55,28 +55,6 @@ interface Repository {
suspend fun artistById(artistId: Int): Result<Artist> suspend fun artistById(artistId: Int): Result<Artist>
val allSongsFlowable: Observable<ArrayList<Song>>
val suggestionSongsFlowable: Observable<ArrayList<Song>>
val allAlbumsFlowable: Observable<ArrayList<Album>>
val recentAlbumsFlowable: Observable<ArrayList<Album>>
val topAlbumsFlowable: Observable<ArrayList<Album>>
val allArtistsFlowable: Observable<ArrayList<Artist>>
val recentArtistsFlowable: Observable<ArrayList<Artist>>
val topArtistsFlowable: Observable<ArrayList<Artist>>
val allPlaylistsFlowable: Observable<ArrayList<Playlist>>
val allGenresFlowable: Observable<ArrayList<Genre>>
fun getSongFlowable(id: Int): Observable<Song>
fun getSong(id: Int): Song fun getSong(id: Int): Song
fun getAlbumFlowable(albumId: Int): Observable<Album> fun getAlbumFlowable(albumId: Int): Observable<Album>
@ -89,10 +67,6 @@ interface Repository {
fun getPlaylistSongsFlowable(playlist: Playlist): Observable<ArrayList<Song>> fun getPlaylistSongsFlowable(playlist: Playlist): Observable<ArrayList<Song>>
fun getGenreFlowable(genreId: Int): Observable<ArrayList<Song>>
val favoritePlaylistFlowable: Observable<ArrayList<Playlist>> val favoritePlaylistFlowable: Observable<ArrayList<Playlist>>
} }

View file

@ -16,6 +16,7 @@ package code.name.monkey.retromusic.views
import android.content.Context import android.content.Context
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.RippleDrawable import android.graphics.drawable.RippleDrawable
import android.util.AttributeSet import android.util.AttributeSet
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@ -45,7 +46,7 @@ class BottomNavigationBarTinted @JvmOverloads constructor(
itemBackground = RippleDrawable(RippleUtils.convertToRippleDrawableColor(ColorStateList.valueOf(ThemeStore.accentColor(context).addAlpha())), ContextCompat.getDrawable(context, R.drawable.bottom_navigation_item_background), ContextCompat.getDrawable(context, R.drawable.bottom_navigation_item_background_mask)) itemBackground = RippleDrawable(RippleUtils.convertToRippleDrawableColor(ColorStateList.valueOf(ThemeStore.accentColor(context).addAlpha())), ContextCompat.getDrawable(context, R.drawable.bottom_navigation_item_background), ContextCompat.getDrawable(context, R.drawable.bottom_navigation_item_background_mask))
setOnApplyWindowInsetsListener(null) setOnApplyWindowInsetsListener(null)
//itemRippleColor = ColorStateList.valueOf(accentColor) //itemRippleColor = ColorStateList.valueOf(accentColor)
backgroundTintList = ColorStateList.valueOf(ATHUtil.resolveColor(context, android.R.attr.windowBackground)) background = ColorDrawable(ATHUtil.resolveColor(context, R.attr.colorSurface))
} }
} }

View file

@ -65,21 +65,22 @@
android:visibility="gone" android:visibility="gone"
tools:visibility="visible"> tools:visibility="visible">
<androidx.appcompat.widget.AppCompatImageView <com.google.android.material.textview.MaterialTextView
android:layout_width="96dp" android:id="@+id/emptyEmoji"
android:layout_height="96dp" android:layout_width="wrap_content"
app:srcCompat="@drawable/ic_disc_full_black_24dp" android:layout_height="wrap_content"
app:tint="?colorOnBackground" /> android:layout_marginBottom="16dp"
android:text="@string/empty_text_emoji"
android:textAppearance="@style/TextViewHeadline3" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/emptyText" android:id="@+id/emptyText"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:text="@string/playlist_empty_text" android:text="@string/no_songs"
android:textAppearance="@style/TextViewNormal" android:textAppearance="@style/TextViewHeadline5"
android:textColor="?colorOnBackground" android:textColor="?android:attr/textColorSecondary"
android:visibility="gone"
tools:visibility="visible" /> tools:visibility="visible" />
</LinearLayout> </LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -105,8 +105,8 @@
android:layout_margin="16dp" android:layout_margin="16dp"
android:gravity="center" android:gravity="center"
android:padding="12dp" android:padding="12dp"
android:src="@drawable/ic_add_photo_white_24dp" app:tint="?attr/colorControlNormal"
app:tint="?iconColor" /> android:src="@drawable/ic_add_photo_white_24dp" />
</FrameLayout> </FrameLayout>
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout

View file

@ -23,6 +23,9 @@
android:id="@+id/appBarLayout" android:id="@+id/appBarLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:elevation="0dp"
app:elevation="0dp"
app:liftOnScroll="true"> app:liftOnScroll="true">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar

View file

@ -13,7 +13,7 @@
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:textAppearance="@style/TextViewNormal" android:textAppearance="@style/TextViewNormal"
android:textColor="?attr/colorOnPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" /> android:textSize="16sp" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
@ -24,7 +24,7 @@
android:paddingTop="16dp" android:paddingTop="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:textAppearance="@style/TextViewNormal" android:textAppearance="@style/TextViewNormal"
android:textColor="?attr/colorOnPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" /> android:textSize="16sp" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
@ -35,7 +35,7 @@
android:paddingTop="16dp" android:paddingTop="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:textAppearance="@style/TextViewNormal" android:textAppearance="@style/TextViewNormal"
android:textColor="?attr/colorOnPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" /> android:textSize="16sp" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
@ -46,7 +46,7 @@
android:paddingTop="16dp" android:paddingTop="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:textAppearance="@style/TextViewNormal" android:textAppearance="@style/TextViewNormal"
android:textColor="?attr/colorOnPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" /> android:textSize="16sp" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
@ -57,7 +57,7 @@
android:paddingTop="16dp" android:paddingTop="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:textAppearance="@style/TextViewNormal" android:textAppearance="@style/TextViewNormal"
android:textColor="?attr/colorOnPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" /> android:textSize="16sp" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
@ -68,7 +68,7 @@
android:paddingTop="16dp" android:paddingTop="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:textAppearance="@style/TextViewNormal" android:textAppearance="@style/TextViewNormal"
android:textColor="?attr/colorOnPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" /> android:textSize="16sp" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
@ -80,7 +80,7 @@
android:paddingEnd="16dp" android:paddingEnd="16dp"
android:paddingBottom="16dp" android:paddingBottom="16dp"
android:textAppearance="@style/TextViewNormal" android:textAppearance="@style/TextViewNormal"
android:textColor="?attr/colorOnPrimary" android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" /> android:textSize="16sp" />
</LinearLayout> </LinearLayout>

View file

@ -39,6 +39,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:elevation="0dp"
app:elevation="0dp"
app:liftOnScroll="true"> app:liftOnScroll="true">
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView

View file

@ -40,7 +40,7 @@
android:layout_gravity="center" android:layout_gravity="center"
android:text="@string/empty" android:text="@string/empty"
android:textAppearance="@style/TextViewHeadline5" android:textAppearance="@style/TextViewHeadline5"
android:textColor="?attr/colorOnSecondary" android:textColor="?android:attr/textColorSecondary"
tools:visibility="visible" /> tools:visibility="visible" />
</LinearLayout> </LinearLayout>
</FrameLayout> </FrameLayout>

View file

@ -28,6 +28,7 @@
android:layout_marginEnd="4dp" android:layout_marginEnd="4dp"
android:layout_weight="1" android:layout_weight="1"
android:text="@string/action_play_all" android:text="@string/action_play_all"
app:backgroundTint="?attr/colorSurface"
app:icon="@drawable/ic_play_arrow_white_24dp" /> app:icon="@drawable/ic_play_arrow_white_24dp" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
@ -38,6 +39,7 @@
android:layout_marginEnd="4dp" android:layout_marginEnd="4dp"
android:layout_weight="1" android:layout_weight="1"
android:text="@string/shuffle" android:text="@string/shuffle"
app:backgroundTint="?attr/colorSurface"
app:icon="@drawable/ic_shuffle_white_24dp" /> app:icon="@drawable/ic_shuffle_white_24dp" />
</LinearLayout> </LinearLayout>

View file

@ -29,7 +29,7 @@
android:maxLines="1" android:maxLines="1"
android:minHeight="40dp" android:minHeight="40dp"
android:textAppearance="@style/TextViewNormal" android:textAppearance="@style/TextViewNormal"
android:textColor="?attr/colorOnSecondary" android:textColor="?android:attr/textColorSecondary"
tools:text="@tools:sample/date/hhmm" /> tools:text="@tools:sample/date/hhmm" />
</FrameLayout> </FrameLayout>
@ -55,7 +55,7 @@
android:layout_weight="0" android:layout_weight="0"
android:fontFeatureSettings="onum" android:fontFeatureSettings="onum"
android:padding="4dp" android:padding="4dp"
android:textColor="?attr/colorOnSecondary" android:textColor="?android:attr/textColorSecondary"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/menu" app:layout_constraintEnd_toStartOf="@+id/menu"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"

View file

@ -53,7 +53,6 @@
android:layout_gravity="bottom" android:layout_gravity="bottom"
android:elevation="0dp" android:elevation="0dp"
android:visibility="gone" android:visibility="gone"
app:backgroundTint="?android:attr/windowBackground"
app:itemHorizontalTranslationEnabled="false" app:itemHorizontalTranslationEnabled="false"
app:itemIconTint="@drawable/bottom_navigation_item_colors" app:itemIconTint="@drawable/bottom_navigation_item_colors"
app:itemTextAppearanceActive="@style/BottomSheetItemTextAppearanceActive" app:itemTextAppearanceActive="@style/BottomSheetItemTextAppearanceActive"

View file

@ -5,7 +5,7 @@
<item name="md_font_title">@font/circular</item> <item name="md_font_title">@font/circular</item>
<item name="md_font_body">@font/circular</item> <item name="md_font_body">@font/circular</item>
<item name="md_font_button">@font/circular</item> <item name="md_font_button">@font/circular</item>
<item name="md_background_color">@color/md_red_500</item>
<item name="android:windowActionBarOverlay">true</item> <item name="android:windowActionBarOverlay">true</item>
<item name="android:windowActivityTransitions">true</item> <item name="android:windowActivityTransitions">true</item>
<item name="android:fontFamily">@font/circular</item> <item name="android:fontFamily">@font/circular</item>
@ -20,6 +20,7 @@
<item name="rectSelector">@drawable/rect_selector</item> <item name="rectSelector">@drawable/rect_selector</item>
<item name="rectSelectorStrong">@drawable/rect_selector_strong</item> <item name="rectSelectorStrong">@drawable/rect_selector_strong</item>
</style> </style>
<style name="Theme.RetroMusic.Base" parent="Theme.MaterialComponents.NoActionBar"> <style name="Theme.RetroMusic.Base" parent="Theme.MaterialComponents.NoActionBar">
@ -158,7 +159,6 @@
<item name="cornerRadius">8dp</item> <item name="cornerRadius">8dp</item>
<item name="iconGravity">textStart</item> <item name="iconGravity">textStart</item>
<item name="iconTint">?attr/colorControlNormal</item> <item name="iconTint">?attr/colorControlNormal</item>
<item name="backgroundTint">?attr/colorSurface</item>
<item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textAppearance">@style/TextViewNormal</item> <item name="android:textAppearance">@style/TextViewNormal</item>
<item name="android:textAllCaps">false</item> <item name="android:textAllCaps">false</item>