Crash fixed

This commit is contained in:
h4h13 2019-11-15 23:14:42 +05:30
parent 9672a8a23d
commit e455684544
60 changed files with 5987 additions and 5855 deletions

View file

@ -108,7 +108,7 @@ 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-rc01' implementation 'androidx.fragment:fragment:1.2.0-rc02'
implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0-rc01' implementation 'androidx.recyclerview:recyclerview:1.1.0-rc01'
implementation "androidx.gridlayout:gridlayout:1.0.0" implementation "androidx.gridlayout:gridlayout:1.0.0"
@ -118,9 +118,10 @@ dependencies {
implementation 'androidx.preference:preference:1.1.0' implementation 'androidx.preference:preference:1.1.0'
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 'androidx.core:core-ktx:1.1.0'
implementation 'com.google.android.material:material:1.2.0-alpha01' 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.4'
implementation 'com.squareup.retrofit2:retrofit:2.6.2' implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.6.2' implementation 'com.squareup.retrofit2:converter-gson:2.6.2'

View file

@ -119,13 +119,6 @@
android:name=".activities.SearchActivity" android:name=".activities.SearchActivity"
android:windowSoftInputMode="stateVisible" /> android:windowSoftInputMode="stateVisible" />
<activity
android:name=".activities.bugreport.ErrorHandlerActivity"
android:immersive="true"
android:label="@string/error"
android:launchMode="singleInstance"
android:theme="@style/ErrorHandlingTheme" />
<activity <activity
android:name=".activities.LockScreenActivity" android:name=".activities.LockScreenActivity"
android:noHistory="true" android:noHistory="true"

View file

@ -4,13 +4,10 @@ import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.*
import android.view.View
import androidx.core.app.ShareCompat import androidx.core.app.ShareCompat
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.LinearLayoutManager import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.Constants.APP_INSTAGRAM_LINK import code.name.monkey.retromusic.Constants.APP_INSTAGRAM_LINK
import code.name.monkey.retromusic.Constants.APP_TELEGRAM_LINK import code.name.monkey.retromusic.Constants.APP_TELEGRAM_LINK
import code.name.monkey.retromusic.Constants.APP_TWITTER_LINK import code.name.monkey.retromusic.Constants.APP_TWITTER_LINK
@ -24,10 +21,8 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.adapter.ContributorAdapter import code.name.monkey.retromusic.adapter.ContributorAdapter
import code.name.monkey.retromusic.model.Contributor import code.name.monkey.retromusic.model.Contributor
import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.PreferenceUtil import com.afollestad.materialdialogs.*
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.list.listItems import com.afollestad.materialdialogs.list.listItems
import com.google.gson.Gson import com.google.gson.Gson
@ -42,136 +37,132 @@ import java.nio.charset.StandardCharsets
class AboutActivity : AbsBaseActivity(), View.OnClickListener { class AboutActivity : AbsBaseActivity(), View.OnClickListener {
private val assetJsonData: String? private val assetJsonData: String?
get() { get() {
val json: String val json: String
try { try {
val inputStream = assets.open("contributors.json") val inputStream = assets.open("contributors.json")
val size = inputStream.available() val size = inputStream.available()
val buffer = ByteArray(size) val buffer = ByteArray(size)
inputStream.read(buffer) inputStream.read(buffer)
inputStream.close() inputStream.close()
json = String(buffer, StandardCharsets.UTF_8) json = String(buffer, StandardCharsets.UTF_8)
} catch (ex: IOException) { } catch (ex: IOException) {
ex.printStackTrace() ex.printStackTrace()
return null return null
} }
return json return json
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_about) setContentView(R.layout.activity_about)
setStatusbarColorAuto() setStatusbarColorAuto()
setNavigationBarColorPrimary() setNavigationBarColorPrimary()
setLightNavigationBar(true) setLightNavigationBar(true)
loadContributors() loadContributors()
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
toolbar.apply { toolbar.apply {
setTitleTextColor(ATHUtil.resolveColor(this@AboutActivity, R.attr.colorOnPrimary)) setTitleTextColor(ATHUtil.resolveColor(this@AboutActivity, R.attr.colorOnPrimary))
setBackgroundColor(ATHUtil.resolveColor(this@AboutActivity, R.attr.colorPrimary)) setBackgroundColor(ATHUtil.resolveColor(this@AboutActivity, R.attr.colorPrimary))
setNavigationOnClickListener { onBackPressed() } setNavigationOnClickListener { onBackPressed() }
ToolbarContentTintHelper.colorBackButton(toolbar) ToolbarContentTintHelper.colorBackButton(toolbar)
} }
version.setSummary(getAppVersion()) version.setSummary(getAppVersion())
setUpView() setUpView()
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
return true
}
return super.onOptionsItemSelected(item)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { private fun openUrl(url: String) {
if (item.itemId == android.R.id.home) { val i = Intent(Intent.ACTION_VIEW)
onBackPressed() i.data = Uri.parse(url)
return true i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
} startActivity(i)
return super.onOptionsItemSelected(item) }
}
private fun openUrl(url: String) { private fun setUpView() {
val i = Intent(Intent.ACTION_VIEW) appGithub.setOnClickListener(this)
i.data = Uri.parse(url) faqLink.setOnClickListener(this)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK telegramLink.setOnClickListener(this)
startActivity(i) appRate.setOnClickListener(this)
} appTranslation.setOnClickListener(this)
appShare.setOnClickListener(this)
donateLink.setOnClickListener(this)
instagramLink.setOnClickListener(this)
twitterLink.setOnClickListener(this)
changelog.setOnClickListener(this)
openSource.setOnClickListener(this)
pinterestLink.setOnClickListener(this)
bugReportLink.setOnClickListener(this)
private fun setUpView() { }
appGithub.setOnClickListener(this)
faqLink.setOnClickListener(this)
telegramLink.setOnClickListener(this)
appRate.setOnClickListener(this)
appTranslation.setOnClickListener(this)
appShare.setOnClickListener(this)
donateLink.setOnClickListener(this)
instagramLink.setOnClickListener(this)
twitterLink.setOnClickListener(this)
changelog.setOnClickListener(this)
openSource.setOnClickListener(this)
pinterestLink.setOnClickListener(this)
bugReportLink.setOnClickListener(this)
} override fun onClick(view: View) {
when (view.id) {
R.id.pinterestLink -> openUrl(PINTEREST)
R.id.faqLink -> openUrl(FAQ_LINK)
R.id.telegramLink -> openUrl(APP_TELEGRAM_LINK)
R.id.appGithub -> openUrl(GITHUB_PROJECT)
R.id.appTranslation -> openUrl(TRANSLATE)
R.id.appRate -> openUrl(RATE_ON_GOOGLE_PLAY)
R.id.appShare -> shareApp()
R.id.donateLink -> NavigationUtil.goToSupportDevelopment(this)
R.id.instagramLink -> openUrl(APP_INSTAGRAM_LINK)
R.id.twitterLink -> openUrl(APP_TWITTER_LINK)
R.id.changelog -> showChangeLogOptions()
R.id.openSource -> NavigationUtil.goToOpenSource(this)
R.id.bugReportLink -> NavigationUtil.bugReport(this)
}
}
override fun onClick(view: View) { private fun showChangeLogOptions() {
when (view.id) { MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
R.id.pinterestLink -> openUrl(PINTEREST) cornerRadius(PreferenceUtil.getInstance(this@AboutActivity).dialogCorner)
R.id.faqLink -> openUrl(FAQ_LINK) listItems(items = listOf("Telegram Channel", "App")) { _, position, _ ->
R.id.telegramLink -> openUrl(APP_TELEGRAM_LINK) if (position == 0) {
R.id.appGithub -> openUrl(GITHUB_PROJECT) openUrl(TELEGRAM_CHANGE_LOG)
R.id.appTranslation -> openUrl(TRANSLATE) } else {
R.id.appRate -> openUrl(RATE_ON_GOOGLE_PLAY) NavigationUtil.gotoWhatNews(this@AboutActivity)
R.id.appShare -> shareApp() }
R.id.donateLink -> NavigationUtil.goToSupportDevelopment(this) }
R.id.instagramLink -> openUrl(APP_INSTAGRAM_LINK) }
R.id.twitterLink -> openUrl(APP_TWITTER_LINK) }
R.id.changelog -> showChangeLogOptions()
R.id.openSource -> NavigationUtil.goToOpenSource(this)
R.id.bugReportLink -> NavigationUtil.bugReport(this)
}
}
private fun showChangeLogOptions() { private fun getAppVersion(): String {
MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)) return try {
.show { val packageInfo = packageManager.getPackageInfo(packageName, 0)
cornerRadius(PreferenceUtil.getInstance(this@AboutActivity).dialogCorner) packageInfo.versionName
listItems(items = listOf("Telegram Channel", "App")) { _, position, _ -> } catch (e: PackageManager.NameNotFoundException) {
if (position == 0) { e.printStackTrace()
openUrl(TELEGRAM_CHANGE_LOG) "0.0.0"
} else { }
NavigationUtil.gotoWhatNews(this@AboutActivity) }
}
}
}
}
private fun getAppVersion(): String { private fun shareApp() {
return try { ShareCompat.IntentBuilder.from(this).setType("text/plain")
val packageInfo = packageManager.getPackageInfo(packageName, 0) .setChooserTitle(R.string.share_app)
packageInfo.versionName .setText(String.format(getString(R.string.app_share), packageName)).startChooser()
} catch (e: PackageManager.NameNotFoundException) { }
e.printStackTrace()
"0.0.0"
}
}
private fun shareApp() { private fun loadContributors() {
ShareCompat.IntentBuilder.from(this) val data = assetJsonData
.setType("text/plain") val type = object : TypeToken<List<Contributor>>() {
.setChooserTitle(R.string.share_app)
.setText(String.format(getString(R.string.app_share), packageName))
.startChooser()
}
private fun loadContributors() { }.type
val data = assetJsonData val contributors = Gson().fromJson<List<Contributor>>(data, type)
val type = object : TypeToken<List<Contributor>>() {
}.type val contributorAdapter = ContributorAdapter(contributors)
val contributors = Gson().fromJson<List<Contributor>>(data, type) recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.itemAnimator = DefaultItemAnimator()
val contributorAdapter = ContributorAdapter(contributors) recyclerView.adapter = contributorAdapter
recyclerView.layoutManager = LinearLayoutManager(this) }
recyclerView.itemAnimator = DefaultItemAnimator()
recyclerView.adapter = contributorAdapter
}
} }

View file

@ -4,41 +4,25 @@ import android.app.ActivityOptions
import android.content.Intent import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.*
import android.view.MenuItem
import android.view.SubMenu
import android.view.View
import android.widget.ImageView import android.widget.ImageView
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.retromusic.*
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity import code.name.monkey.retromusic.activities.tageditor.*
import code.name.monkey.retromusic.activities.tageditor.AlbumTagEditorActivity
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.*
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
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.*
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
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.SortOrder.AlbumSongSortOrder import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.mvp.presenter.*
import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsPresenter import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsView
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.activity_album.* import kotlinx.android.synthetic.main.activity_album.*
import kotlinx.android.synthetic.main.activity_album_content.* import kotlinx.android.synthetic.main.activity_album_content.*
@ -46,236 +30,263 @@ import java.util.*
import javax.inject.Inject import javax.inject.Inject
import android.util.Pair as UtilPair import android.util.Pair as UtilPair
class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView { class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView {
private lateinit var simpleSongAdapter: SimpleSongAdapter private lateinit var simpleSongAdapter: SimpleSongAdapter
private lateinit var album: Album private lateinit var album: Album
private lateinit var artistImage: ImageView private lateinit var artistImage: ImageView
private val savedSortOrder: String private val savedSortOrder: String
get() = PreferenceUtil.getInstance(this).albumDetailSongSortOrder get() = PreferenceUtil.getInstance(this).albumDetailSongSortOrder
override fun createContentView(): View { override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_album) return wrapSlidingMusicPanel(R.layout.activity_album)
} }
@Inject @Inject
lateinit var albumDetailsPresenter: AlbumDetailsPresenter lateinit var albumDetailsPresenter: AlbumDetailsPresenter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar() setDrawUnderStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
toggleBottomNavigationView(true) toggleBottomNavigationView(true)
setStatusbarColor(Color.TRANSPARENT) setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto() setNavigationbarColorAuto()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
setLightNavigationBar(true) setLightNavigationBar(true)
setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary))) setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
ActivityCompat.postponeEnterTransition(this) ActivityCompat.postponeEnterTransition(this)
App.musicComponent.inject(this) App.musicComponent.inject(this)
artistImage = findViewById(R.id.artistImage) artistImage = findViewById(R.id.artistImage)
setupRecyclerView() setupRecyclerView()
artistImage.setOnClickListener { artistImage.setOnClickListener {
val artistPairs = ActivityOptions.makeSceneTransitionAnimation(this, UtilPair.create(artistImage, getString(R.string.transition_artist_image))) val artistPairs = ActivityOptions.makeSceneTransitionAnimation(
NavigationUtil.goToArtistOptions(this, album.artistId, artistPairs) this,
} UtilPair.create(
playAction.apply { artistImage,
setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) } getString(R.string.transition_artist_image)
} )
shuffleAction.apply { )
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album.songs!!, true) } NavigationUtil.goToArtistOptions(this, album.artistId, artistPairs)
} }
playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
}
shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album.songs!!, true) }
}
albumDetailsPresenter.attachView(this) albumDetailsPresenter.attachView(this)
if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) { if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) } intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) }
} else { } else {
finish() finish()
} }
} }
private fun setupRecyclerView() { private fun setupRecyclerView() {
simpleSongAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song) simpleSongAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song)
recyclerView.apply { recyclerView.apply {
layoutManager = LinearLayoutManager(this@AlbumDetailsActivity) layoutManager = LinearLayoutManager(this@AlbumDetailsActivity)
itemAnimator = DefaultItemAnimator() itemAnimator = DefaultItemAnimator()
isNestedScrollingEnabled = false isNestedScrollingEnabled = false
adapter = simpleSongAdapter adapter = simpleSongAdapter
} }
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
albumDetailsPresenter.detachView() albumDetailsPresenter.detachView()
} }
override fun complete() { override fun complete() {
ActivityCompat.startPostponedEnterTransition(this) ActivityCompat.startPostponedEnterTransition(this)
} }
override fun album(album: Album) { override fun album(album: Album) {
if (album.songs!!.isEmpty()) { if (album.songs!!.isEmpty()) {
finish() finish()
return return
} }
this.album = album this.album = album
albumTitle.text = album.title albumTitle.text = album.title
if (MusicUtil.getYearString(album.year) == "-") { if (MusicUtil.getYearString(album.year) == "-") {
albumText.text = String.format("%s • %s", album.artistName, MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, album.songs))) albumText.text = String.format(
} else { "%s • %s",
albumText.text = String.format("%s • %s • %s", album.artistName, MusicUtil.getYearString(album.year), MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, album.songs))) album.artistName,
} MusicUtil.getReadableDurationString(
loadAlbumCover() MusicUtil.getTotalDuration(
simpleSongAdapter.swapDataSet(album.songs) this,
albumDetailsPresenter.loadMore(album.artistId) album.songs
} )
)
)
} else {
albumText.text = String.format(
"%s • %s • %s",
album.artistName,
MusicUtil.getYearString(album.year),
MusicUtil.getReadableDurationString(
MusicUtil.getTotalDuration(
this,
album.songs
)
)
)
}
loadAlbumCover()
simpleSongAdapter.swapDataSet(album.songs)
albumDetailsPresenter.loadMore(album.artistId)
}
override fun moreAlbums(albums: ArrayList<Album>) {
moreTitle.show()
moreRecyclerView.show()
moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName)
override fun moreAlbums(albums: ArrayList<Album>) { val albumAdapter = HorizontalAlbumAdapter(this, albums, false, null)
moreTitle.show() moreRecyclerView.layoutManager = GridLayoutManager(
moreRecyclerView.show() this,
moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName) 1,
GridLayoutManager.HORIZONTAL,
false
)
moreRecyclerView.adapter = albumAdapter
}
val albumAdapter = HorizontalAlbumAdapter(this, albums, false, null) override fun loadArtistImage(artist: Artist) {
moreRecyclerView.layoutManager = GridLayoutManager(this, 1, GridLayoutManager.HORIZONTAL, false) ArtistGlideRequest.Builder.from(Glide.with(this), artist).generatePalette(this).build()
moreRecyclerView.adapter = albumAdapter .dontAnimate().dontTransform().into(object : RetroMusicColoredTarget(artistImage) {
} override fun onColorReady(color: Int) {
override fun loadArtistImage(artist: Artist) { }
ArtistGlideRequest.Builder.from(Glide.with(this), artist) })
.generatePalette(this).build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(artistImage) {
override fun onColorReady(color: Int) {
} }
})
} private fun loadAlbumCover() {
SongGlideRequest.Builder.from(Glide.with(this), album.safeGetFirstSong())
.checkIgnoreMediaStore(this).generatePalette(this).build().dontAnimate().dontTransform()
.into(object : RetroMusicColoredTarget(image) {
override fun onColorReady(color: Int) {
setColors(color)
}
})
}
private fun loadAlbumCover() { private fun setColors(color: Int) {
SongGlideRequest.Builder.from(Glide.with(this), album.safeGetFirstSong()) val themeColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
.checkIgnoreMediaStore(this) else ThemeStore.accentColor(this)
.generatePalette(this).build()
.dontAnimate().dontTransform()
.into(object : RetroMusicColoredTarget(image) {
override fun onColorReady(color: Int) {
setColors(color)
}
})
}
private fun setColors(color: Int) { songTitle.setTextColor(themeColor)
val themeColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color moreTitle.setTextColor(themeColor)
else ThemeStore.accentColor(this)
songTitle.setTextColor(themeColor) val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
moreTitle.setTextColor(themeColor) else ATHUtil.resolveColor(this, R.attr.cardBackgroundColor)
val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color MaterialUtil.setTint(button = shuffleAction, color = buttonColor)
else ATHUtil.resolveColor(this, R.attr.cardBackgroundColor) MaterialUtil.setTint(button = playAction, color = buttonColor)
MaterialUtil.setTint(button = shuffleAction, color = buttonColor) toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
MaterialUtil.setTint(button = playAction, color = buttonColor) setSupportActionBar(toolbar)
supportActionBar?.title = null
}
toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary)) override fun onCreateOptionsMenu(menu: Menu): Boolean {
setSupportActionBar(toolbar) menuInflater.inflate(R.menu.menu_album_detail, menu)
supportActionBar?.title = null val sortOrder = menu.findItem(R.id.action_sort_order)
} setUpSortOrderMenu(sortOrder.subMenu)
return super.onCreateOptionsMenu(menu)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
menuInflater.inflate(R.menu.menu_album_detail, menu) return handleSortOrderMenuItem(item)
val sortOrder = menu.findItem(R.id.action_sort_order) }
setUpSortOrderMenu(sortOrder.subMenu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
return handleSortOrderMenuItem(item) var sortOrder: String? = null
} val songs = simpleSongAdapter.dataSet
when (item.itemId) {
R.id.action_play_next -> {
MusicPlayerRemote.playNext(songs)
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(songs)
return true
}
R.id.action_add_to_playlist -> {
AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
return true
}
R.id.action_delete_from_device -> {
DeleteSongsDialog.create(songs).show(supportFragmentManager, "DELETE_SONGS")
return true
}
android.R.id.home -> {
super.onBackPressed()
return true
}
R.id.action_tag_editor -> {
val intent = Intent(this, AlbumTagEditorActivity::class.java)
intent.putExtra(AbsTagEditorActivity.EXTRA_ID, album.id)
startActivityForResult(intent, TAG_EDITOR_REQUEST)
return true
}
/*Sort*/
R.id.action_sort_order_title -> sortOrder = AlbumSongSortOrder.SONG_A_Z
R.id.action_sort_order_title_desc -> sortOrder = AlbumSongSortOrder.SONG_Z_A
R.id.action_sort_order_track_list -> sortOrder = AlbumSongSortOrder.SONG_TRACK_LIST
R.id.action_sort_order_artist_song_duration -> sortOrder = AlbumSongSortOrder.SONG_DURATION
}
if (sortOrder != null) {
item.isChecked = true
setSaveSortOrder(sortOrder)
}
return true
}
private fun handleSortOrderMenuItem(item: MenuItem): Boolean { private fun setUpSortOrderMenu(sortOrder: SubMenu) {
var sortOrder: String? = null when (savedSortOrder) {
val songs = simpleSongAdapter.dataSet AlbumSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title)
when (item.itemId) { .isChecked = true
R.id.action_play_next -> { AlbumSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc)
MusicPlayerRemote.playNext(songs) .isChecked = true
return true AlbumSongSortOrder.SONG_TRACK_LIST -> sortOrder.findItem(R.id.action_sort_order_track_list)
} .isChecked = true
R.id.action_add_to_current_playing -> { AlbumSongSortOrder.SONG_DURATION -> sortOrder.findItem(R.id.action_sort_order_artist_song_duration)
MusicPlayerRemote.enqueue(songs) .isChecked = true
return true }
} }
R.id.action_add_to_playlist -> {
AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
return true
}
R.id.action_delete_from_device -> {
DeleteSongsDialog.create(songs).show(supportFragmentManager, "DELETE_SONGS")
return true
}
android.R.id.home -> {
super.onBackPressed()
return true
}
R.id.action_tag_editor -> {
val intent = Intent(this, AlbumTagEditorActivity::class.java)
intent.putExtra(AbsTagEditorActivity.EXTRA_ID, album.id)
startActivityForResult(intent, TAG_EDITOR_REQUEST)
return true
}
/*Sort*/
R.id.action_sort_order_title -> sortOrder = AlbumSongSortOrder.SONG_A_Z
R.id.action_sort_order_title_desc -> sortOrder = AlbumSongSortOrder.SONG_Z_A
R.id.action_sort_order_track_list -> sortOrder = AlbumSongSortOrder.SONG_TRACK_LIST
R.id.action_sort_order_artist_song_duration -> sortOrder = AlbumSongSortOrder.SONG_DURATION
}
if (sortOrder != null) {
item.isChecked = true
setSaveSortOrder(sortOrder)
}
return true
}
private fun setUpSortOrderMenu(sortOrder: SubMenu) { private fun setSaveSortOrder(sortOrder: String?) {
when (savedSortOrder) { PreferenceUtil.getInstance(this).albumDetailSongSortOrder = sortOrder
AlbumSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title).isChecked = true reload()
AlbumSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc).isChecked = true }
AlbumSongSortOrder.SONG_TRACK_LIST -> sortOrder.findItem(R.id.action_sort_order_track_list).isChecked = true
AlbumSongSortOrder.SONG_DURATION -> sortOrder.findItem(R.id.action_sort_order_artist_song_duration).isChecked = true
}
}
private fun setSaveSortOrder(sortOrder: String?) { override fun onMediaStoreChanged() {
PreferenceUtil.getInstance(this).albumDetailSongSortOrder = sortOrder super.onMediaStoreChanged()
reload() reload()
} }
override fun onMediaStoreChanged() { private fun reload() {
super.onMediaStoreChanged() if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
reload() intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) }
} } else {
finish()
}
}
private fun reload() { companion object {
if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) }
} else {
finish()
}
}
companion object { const val EXTRA_ALBUM_ID = "extra_album_id"
private const val TAG_EDITOR_REQUEST = 2001
const val EXTRA_ALBUM_ID = "extra_album_id" }
private const val TAG_EDITOR_REQUEST = 2001
}
} }

View file

@ -3,35 +3,23 @@ package code.name.monkey.retromusic.activities
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.os.Build import android.os.*
import android.os.Bundle import android.text.*
import android.text.Html import android.view.*
import android.text.Spanned
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.retromusic.*
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.adapter.album.AlbumAdapter import code.name.monkey.retromusic.adapter.album.*
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.glide.ArtistGlideRequest import code.name.monkey.retromusic.glide.*
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsPresenter import code.name.monkey.retromusic.mvp.presenter.*
import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsView
import code.name.monkey.retromusic.rest.LastFMRestClient import code.name.monkey.retromusic.rest.LastFMRestClient
import code.name.monkey.retromusic.rest.model.LastFmArtist import code.name.monkey.retromusic.rest.model.LastFmArtist
import code.name.monkey.retromusic.util.* import code.name.monkey.retromusic.util.*
@ -44,257 +32,267 @@ import kotlin.collections.ArrayList
class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView { class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView {
private var biography: Spanned? = null private var biography: Spanned? = null
private lateinit var artist: Artist private lateinit var artist: Artist
private var lastFMRestClient: LastFMRestClient? = null private var lastFMRestClient: LastFMRestClient? = null
private lateinit var songAdapter: SimpleSongAdapter private lateinit var songAdapter: SimpleSongAdapter
private lateinit var albumAdapter: AlbumAdapter private lateinit var albumAdapter: AlbumAdapter
private var forceDownload: Boolean = false private var forceDownload: Boolean = false
override fun createContentView(): View { override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_artist_details) return wrapSlidingMusicPanel(R.layout.activity_artist_details)
} }
@Inject @Inject
lateinit var artistDetailsPresenter: ArtistDetailsPresenter lateinit var artistDetailsPresenter: ArtistDetailsPresenter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar() setDrawUnderStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
toggleBottomNavigationView(true) toggleBottomNavigationView(true)
setStatusbarColor(Color.TRANSPARENT) setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto() setNavigationbarColorAuto()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
setLightNavigationBar(true) setLightNavigationBar(true)
setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary))) setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
ActivityCompat.postponeEnterTransition(this) ActivityCompat.postponeEnterTransition(this)
lastFMRestClient = LastFMRestClient(this) lastFMRestClient = LastFMRestClient(this)
setUpViews() setUpViews()
playAction.apply { playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) } setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
} }
shuffleAction.apply { shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) } setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
} }
biographyText.setOnClickListener { biographyText.setOnClickListener {
if (biographyText.maxLines == 4) { if (biographyText.maxLines == 4) {
biographyText.maxLines = Integer.MAX_VALUE biographyText.maxLines = Integer.MAX_VALUE
} else { } else {
biographyText.maxLines = 4 biographyText.maxLines = 4
} }
} }
App.musicComponent.inject(this) App.musicComponent.inject(this)
artistDetailsPresenter.attachView(this) artistDetailsPresenter.attachView(this)
if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) { if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) } intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) }
} else { } else {
finish() finish()
} }
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
artistDetailsPresenter.detachView() artistDetailsPresenter.detachView()
} }
private fun setUpViews() { private fun setUpViews() {
setupRecyclerView() setupRecyclerView()
setupContainerHeight() setupContainerHeight()
} }
private fun setupContainerHeight() { private fun setupContainerHeight() {
imageContainer?.let { imageContainer?.let {
val params = it.layoutParams val params = it.layoutParams
params.width = DensityUtil.getScreenHeight(this) / 2 params.width = DensityUtil.getScreenHeight(this) / 2
it.layoutParams = params it.layoutParams = params
} }
} }
private fun setupRecyclerView() {
albumAdapter = HorizontalAlbumAdapter(this, ArrayList(), false, null)
albumRecyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false)
adapter = albumAdapter
}
songAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song)
recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(this.context)
adapter = songAdapter
}
}
private fun setupRecyclerView() { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
albumAdapter = HorizontalAlbumAdapter(this, ArrayList(), false, null) super.onActivityResult(requestCode, resultCode, data)
albumRecyclerView.apply { when (requestCode) {
itemAnimator = DefaultItemAnimator() REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false) data?.data?.let {
adapter = albumAdapter CustomArtistImageUtil.getInstance(this).setCustomArtistImage(artist, it)
} }
songAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song) }
recyclerView.apply { else -> if (resultCode == Activity.RESULT_OK) {
itemAnimator = DefaultItemAnimator() reload()
layoutManager = LinearLayoutManager(this.context) }
adapter = songAdapter }
} }
}
override fun showEmptyView() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { }
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let { CustomArtistImageUtil.getInstance(this).setCustomArtistImage(artist, it) }
}
else -> if (resultCode == Activity.RESULT_OK) {
reload()
}
}
}
override fun showEmptyView() { override fun complete() {
ActivityCompat.startPostponedEnterTransition(this)
}
} override fun artist(artist: Artist) {
if (artist.songCount <= 0) {
finish()
}
this.artist = artist
loadArtistImage()
override fun complete() { if (RetroUtil.isAllowedToDownloadMetadata(this)) {
ActivityCompat.startPostponedEnterTransition(this) loadBiography(artist.name)
} }
artistTitle.text = artist.name
text.text = String.format(
"%s • %s",
MusicUtil.getArtistInfoString(this, artist),
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, artist.songs))
)
override fun artist(artist: Artist) { songAdapter.swapDataSet(artist.songs)
if (artist.songCount <= 0) { albumAdapter.swapDataSet(artist.albums!!)
finish() }
}
this.artist = artist
loadArtistImage()
if (RetroUtil.isAllowedToDownloadMetadata(this)) { private fun loadBiography(
loadBiography(artist.name) name: String, lang: String? = Locale.getDefault().language
} ) {
artistTitle.text = artist.name biography = null
text.text = String.format("%s • %s", MusicUtil.getArtistInfoString(this, artist), MusicUtil this.lang = lang
.getReadableDurationString(MusicUtil.getTotalDuration(this, artist.songs))) artistDetailsPresenter.loadBiography(name, lang, null)
}
songAdapter.swapDataSet(artist.songs) override fun artistInfo(lastFmArtist: LastFmArtist?) {
albumAdapter.swapDataSet(artist.albums!!) if (lastFmArtist != null && lastFmArtist.artist != null) {
} val bioContent = lastFmArtist.artist.bio.content
if (bioContent != null && bioContent.trim { it <= ' ' }.isNotEmpty()) {
biographyText.visibility = View.VISIBLE
biographyTitle.visibility = View.VISIBLE
biography = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(bioContent, Html.FROM_HTML_MODE_LEGACY)
} else {
Html.fromHtml(bioContent)
}
biographyText.text = biography
}
}
private fun loadBiography(name: String, // If the "lang" parameter is set and no biography is given, retry with default language
lang: String? = Locale.getDefault().language) { if (biography == null && lang != null) {
biography = null loadBiography(artist.name, null)
this.lang = lang }
artistDetailsPresenter.loadBiography(name, lang, null) }
}
override fun artistInfo(lastFmArtist: LastFmArtist?) { private var lang: String? = null
if (lastFmArtist != null && lastFmArtist.artist != null) {
val bioContent = lastFmArtist.artist.bio.content
if (bioContent != null && bioContent.trim { it <= ' ' }.isNotEmpty()) {
biographyText.visibility = View.VISIBLE
biographyTitle.visibility = View.VISIBLE
biography = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(bioContent, Html.FROM_HTML_MODE_LEGACY)
} else {
Html.fromHtml(bioContent)
}
biographyText.text = biography
}
}
// If the "lang" parameter is set and no biography is given, retry with default language private fun loadArtistImage() {
if (biography == null && lang != null) { ArtistGlideRequest.Builder.from(Glide.with(this), artist).generatePalette(this).build()
loadBiography(artist.name, null) .dontAnimate().into(object : RetroMusicColoredTarget(artistImage) {
} override fun onColorReady(color: Int) {
} setColors(color)
}
})
}
private var lang: String? = null private fun setColors(color: Int) {
private fun loadArtistImage() { val textColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
ArtistGlideRequest.Builder.from(Glide.with(this), artist) else ThemeStore.accentColor(this)
.generatePalette(this).build()
.dontAnimate()
.into(object : RetroMusicColoredTarget(artistImage) {
override fun onColorReady(color: Int) {
setColors(color)
}
})
}
private fun setColors(color: Int) { albumTitle.setTextColor(textColor)
songTitle.setTextColor(textColor)
biographyTitle.setTextColor(textColor)
val textColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
else ThemeStore.accentColor(this) else ATHUtil.resolveColor(this, R.attr.cardBackgroundColor)
albumTitle.setTextColor(textColor) MaterialUtil.setTint(button = shuffleAction, color = buttonColor)
songTitle.setTextColor(textColor) MaterialUtil.setTint(button = playAction, color = buttonColor)
biographyTitle.setTextColor(textColor)
val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
else ATHUtil.resolveColor(this, R.attr.cardBackgroundColor) setSupportActionBar(toolbar)
supportActionBar?.title = null
}
MaterialUtil.setTint(button = shuffleAction, color = buttonColor) override fun onOptionsItemSelected(item: MenuItem): Boolean {
MaterialUtil.setTint(button = playAction, color = buttonColor) return handleSortOrderMenuItem(item)
}
toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary)) private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
setSupportActionBar(toolbar) val songs = artist.songs
supportActionBar?.title = null when (item.itemId) {
} android.R.id.home -> {
super.onBackPressed()
return true
}
R.id.action_play_next -> {
MusicPlayerRemote.playNext(songs)
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(songs)
return true
}
R.id.action_add_to_playlist -> {
AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
return true
}
R.id.action_set_artist_image -> {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(
Intent.createChooser(
intent,
getString(R.string.pick_from_local_storage)
), REQUEST_CODE_SELECT_IMAGE
)
return true
}
R.id.action_reset_artist_image -> {
Toast.makeText(
this@ArtistDetailActivity,
resources.getString(R.string.updating),
Toast.LENGTH_SHORT
).show()
CustomArtistImageUtil.getInstance(this@ArtistDetailActivity)
.resetCustomArtistImage(artist)
forceDownload = true
return true
}
}
return true
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_artist_detail, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onMediaStoreChanged() {
return handleSortOrderMenuItem(item) super.onMediaStoreChanged()
} reload()
}
private fun handleSortOrderMenuItem(item: MenuItem): Boolean { private fun reload() {
val songs = artist.songs if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
when (item.itemId) { intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) }
android.R.id.home -> { } else {
super.onBackPressed() finish()
return true }
} }
R.id.action_play_next -> {
MusicPlayerRemote.playNext(songs)
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(songs)
return true
}
R.id.action_add_to_playlist -> {
AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
return true
}
R.id.action_set_artist_image -> {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(Intent.createChooser(intent, getString(R.string.pick_from_local_storage)), REQUEST_CODE_SELECT_IMAGE)
return true
}
R.id.action_reset_artist_image -> {
Toast.makeText(this@ArtistDetailActivity, resources.getString(R.string.updating),
Toast.LENGTH_SHORT).show()
CustomArtistImageUtil.getInstance(this@ArtistDetailActivity).resetCustomArtistImage(artist)
forceDownload = true
return true
}
}
return true
}
override fun onCreateOptionsMenu(menu: Menu): Boolean { companion object {
menuInflater.inflate(R.menu.menu_artist_detail, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onMediaStoreChanged() { const val EXTRA_ARTIST_ID = "extra_artist_id"
super.onMediaStoreChanged() const val REQUEST_CODE_SELECT_IMAGE = 9003
reload() }
}
private fun reload() {
if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) }
} else {
finish()
}
}
companion object {
const val EXTRA_ARTIST_ID = "extra_artist_id"
const val REQUEST_CODE_SELECT_IMAGE = 9003
}
} }

View file

@ -2,26 +2,18 @@ package code.name.monkey.retromusic.activities
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.*
import android.view.MenuItem import androidx.recyclerview.widget.*
import android.view.View import code.name.monkey.appthemehelper.util.*
import androidx.recyclerview.widget.DefaultItemAnimator import code.name.monkey.retromusic.*
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.adapter.song.ShuffleButtonSongAdapter import code.name.monkey.retromusic.adapter.song.ShuffleButtonSongAdapter
import code.name.monkey.retromusic.extensions.applyToolbar import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.helper.menu.GenreMenuHelper import code.name.monkey.retromusic.helper.menu.GenreMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.mvp.presenter.*
import code.name.monkey.retromusic.mvp.presenter.GenreDetailsPresenter import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.mvp.presenter.GenreDetailsView
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.ViewUtil import code.name.monkey.retromusic.util.ViewUtil
import com.afollestad.materialcab.MaterialCab import com.afollestad.materialcab.MaterialCab
import kotlinx.android.synthetic.main.activity_playlist_detail.* import kotlinx.android.synthetic.main.activity_playlist_detail.*
@ -34,124 +26,127 @@ import javax.inject.Inject
class GenreDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder, GenreDetailsView { class GenreDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder, GenreDetailsView {
@Inject @Inject
lateinit var genreDetailsPresenter: GenreDetailsPresenter lateinit var genreDetailsPresenter: GenreDetailsPresenter
private lateinit var genre: Genre private lateinit var genre: Genre
private lateinit var songAdapter: ShuffleButtonSongAdapter private lateinit var songAdapter: ShuffleButtonSongAdapter
private var cab: MaterialCab? = null private var cab: MaterialCab? = null
private fun checkIsEmpty() { private fun checkIsEmpty() {
empty?.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE empty?.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar() setDrawUnderStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setStatusbarColor(Color.TRANSPARENT) setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto() setNavigationbarColorAuto()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
setLightNavigationBar(true) setLightNavigationBar(true)
setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary))) setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
toggleBottomNavigationView(true) toggleBottomNavigationView(true)
if (intent.extras != null) { if (intent.extras != null) {
genre = intent?.extras?.getParcelable(EXTRA_GENRE_ID)!! genre = intent?.extras?.getParcelable(EXTRA_GENRE_ID)!!
} else { } else {
finish() finish()
} }
setUpToolBar() setUpToolBar()
setupRecyclerView() setupRecyclerView()
App.musicComponent.inject(this) App.musicComponent.inject(this)
genreDetailsPresenter.attachView(this) genreDetailsPresenter.attachView(this)
} }
private fun setUpToolBar() { private fun setUpToolBar() {
val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary) val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary)
appBarLayout.setBackgroundColor(primaryColor) appBarLayout.setBackgroundColor(primaryColor)
applyToolbar(toolbar) applyToolbar(toolbar)
title = genre.name title = genre.name
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
genreDetailsPresenter.loadGenreSongs(genre.id) genreDetailsPresenter.loadGenreSongs(genre.id)
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
genreDetailsPresenter.detachView() genreDetailsPresenter.detachView()
} }
override fun createContentView(): View { override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_playlist_detail) return wrapSlidingMusicPanel(R.layout.activity_playlist_detail)
} }
override fun showEmptyView() { override fun showEmptyView() {
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_genre_detail, menu) menuInflater.inflate(R.menu.menu_genre_detail, menu)
return super.onCreateOptionsMenu(menu) return super.onCreateOptionsMenu(menu)
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) { if (item.itemId == android.R.id.home) {
onBackPressed() onBackPressed()
} }
return GenreMenuHelper.handleMenuClick(this, genre, item) return GenreMenuHelper.handleMenuClick(this, genre, item)
} }
private fun setupRecyclerView() { private fun setupRecyclerView() {
ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView ) ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
songAdapter = ShuffleButtonSongAdapter(this, ArrayList(), R.layout.item_list, false, this) songAdapter = ShuffleButtonSongAdapter(this, ArrayList(), R.layout.item_list, false, this)
recyclerView.apply { recyclerView.apply {
itemAnimator = DefaultItemAnimator() itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(this@GenreDetailsActivity) layoutManager = LinearLayoutManager(this@GenreDetailsActivity)
adapter = songAdapter adapter = songAdapter
} }
songAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { songAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() { override fun onChanged() {
super.onChanged() super.onChanged()
checkIsEmpty() checkIsEmpty()
} }
}) })
} }
override fun songs(songs: ArrayList<Song>) { override fun songs(songs: ArrayList<Song>) {
songAdapter.swapDataSet(songs) songAdapter.swapDataSet(songs)
} }
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab { override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
if (cab != null && cab!!.isActive) cab!!.finish() if (cab != null && cab!!.isActive) cab!!.finish()
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).setBackgroundColor(
.setCloseDrawableRes(R.drawable.ic_close_white_24dp) RetroColorUtil.shiftBackgroundColorForLightText(
.setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorPrimary))) ATHUtil.resolveColor(
.start(callback) this,
return cab!! R.attr.colorPrimary
} )
)
).start(callback)
return cab!!
}
override fun onBackPressed() { override fun onBackPressed() {
if (cab != null && cab!!.isActive) if (cab != null && cab!!.isActive) cab!!.finish()
cab!!.finish() else {
else { recyclerView!!.stopScroll()
recyclerView!!.stopScroll() super.onBackPressed()
super.onBackPressed() }
} }
}
override fun onMediaStoreChanged() { override fun onMediaStoreChanged() {
super.onMediaStoreChanged() super.onMediaStoreChanged()
genreDetailsPresenter.loadGenreSongs(genre.id) genreDetailsPresenter.loadGenreSongs(genre.id)
} }
companion object { companion object {
const val EXTRA_GENRE_ID = "extra_genre_id" const val EXTRA_GENRE_ID = "extra_genre_id"
} }
} }

View file

@ -30,7 +30,6 @@ import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import code.name.monkey.appthemehelper.ThemeStore; import code.name.monkey.appthemehelper.ThemeStore;
import code.name.monkey.appthemehelper.util.ATHUtil;
import code.name.monkey.appthemehelper.util.ColorUtil; import code.name.monkey.appthemehelper.util.ColorUtil;
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper; import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper;
import code.name.monkey.retromusic.R; import code.name.monkey.retromusic.R;

View file

@ -2,110 +2,100 @@ package code.name.monkey.retromusic.activities
import android.app.KeyguardManager import android.app.KeyguardManager
import android.content.Context import android.content.Context
import android.os.Build import android.os.*
import android.os.Bundle import android.view.*
import android.view.View
import android.view.WindowManager
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.fragments.player.lockscreen.LockScreenPlayerControlsFragment import code.name.monkey.retromusic.fragments.player.lockscreen.LockScreenPlayerControlsFragment
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.*
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.r0adkll.slidr.Slidr import com.r0adkll.slidr.Slidr
import com.r0adkll.slidr.model.SlidrConfig import com.r0adkll.slidr.model.*
import com.r0adkll.slidr.model.SlidrListener
import com.r0adkll.slidr.model.SlidrPosition
import kotlinx.android.synthetic.main.activity_lock_screen.* import kotlinx.android.synthetic.main.activity_lock_screen.*
class LockScreenActivity : AbsMusicServiceActivity() { class LockScreenActivity : AbsMusicServiceActivity() {
private var fragment: LockScreenPlayerControlsFragment? = null private var fragment: LockScreenPlayerControlsFragment? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setShowWhenLocked(true) setShowWhenLocked(true)
setTurnScreenOn(true) setTurnScreenOn(true)
} else { } else {
this.window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or this.window.addFlags(
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) )
} }
setDrawUnderStatusBar() setDrawUnderStatusBar()
setContentView(R.layout.activity_lock_screen) setContentView(R.layout.activity_lock_screen)
hideStatusBar() hideStatusBar()
setStatusbarColorAuto() setStatusbarColorAuto()
setNavigationBarColorPrimary() setNavigationBarColorPrimary()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
setLightNavigationBar(true) setLightNavigationBar(true)
val config = SlidrConfig.Builder() val config = SlidrConfig.Builder().listener(object : SlidrListener {
.listener(object : SlidrListener { override fun onSlideStateChanged(state: Int) {
override fun onSlideStateChanged(state: Int) {
} }
override fun onSlideChange(percent: Float) { override fun onSlideChange(percent: Float) {
} }
override fun onSlideOpened() { override fun onSlideOpened() {
} }
override fun onSlideClosed(): Boolean { override fun onSlideClosed(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
keyguardManager.requestDismissKeyguard(this@LockScreenActivity, null) keyguardManager.requestDismissKeyguard(this@LockScreenActivity, null)
} }
finish() finish()
return true return true
} }
}) }).position(SlidrPosition.BOTTOM).build()
.position(SlidrPosition.BOTTOM)
.build()
Slidr.attach(this, config) Slidr.attach(this, config)
fragment = supportFragmentManager.findFragmentById(R.id.playback_controls_fragment) as LockScreenPlayerControlsFragment? fragment = supportFragmentManager.findFragmentById(R.id.playback_controls_fragment) as LockScreenPlayerControlsFragment?
findViewById<View>(R.id.slide).apply { findViewById<View>(R.id.slide).apply {
translationY = 100f translationY = 100f
alpha = 0f alpha = 0f
ViewCompat.animate(this) ViewCompat.animate(this).translationY(0f).alpha(1f).setDuration(1500).start()
.translationY(0f) }
.alpha(1f)
.setDuration(1500)
.start()
}
findViewById<View>(R.id.root_layout).setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary)) findViewById<View>(R.id.root_layout).setBackgroundColor(
} ATHUtil.resolveColor(
this, R.attr.colorPrimary
)
)
}
override fun onPlayingMetaChanged() { override fun onPlayingMetaChanged() {
super.onPlayingMetaChanged() super.onPlayingMetaChanged()
updateSongs() updateSongs()
} }
override fun onServiceConnected() { override fun onServiceConnected() {
super.onServiceConnected() super.onServiceConnected()
updateSongs() updateSongs()
} }
private fun updateSongs() { private fun updateSongs() {
val song = MusicPlayerRemote.currentSong val song = MusicPlayerRemote.currentSong
SongGlideRequest.Builder.from(Glide.with(this), song) SongGlideRequest.Builder.from(Glide.with(this), song).checkIgnoreMediaStore(this)
.checkIgnoreMediaStore(this) .generatePalette(this).build().dontAnimate()
.generatePalette(this).build() .into(object : RetroMusicColoredTarget(image) {
.dontAnimate() override fun onColorReady(color: Int) {
.into(object : RetroMusicColoredTarget(image ) { fragment?.setDark(color)
override fun onColorReady(color: Int) { }
fragment?.setDark(color) })
} }
})
}
} }

View file

@ -95,7 +95,13 @@ class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener, ViewPage
appBarLayout.setBackgroundColor(primaryColor) appBarLayout.setBackgroundColor(primaryColor)
toolbar.apply { toolbar.apply {
setBackgroundColor(primaryColor) setBackgroundColor(primaryColor)
navigationIcon = TintHelper.createTintedDrawable(ContextCompat.getDrawable(this@LyricsActivity, R.drawable.ic_keyboard_backspace_black_24dp), ThemeStore.textColorSecondary(this@LyricsActivity)) navigationIcon = TintHelper.createTintedDrawable(
ContextCompat.getDrawable(
this@LyricsActivity,
R.drawable.ic_keyboard_backspace_black_24dp
),
ThemeStore.textColorSecondary(this@LyricsActivity)
)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
} }
@ -160,12 +166,17 @@ class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener, ViewPage
e.printStackTrace() e.printStackTrace()
} }
val materialDialog = MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show { val materialDialog = MaterialDialog(
this,
BottomSheet(LayoutMode.WRAP_CONTENT)
).show {
title(R.string.add_time_framed_lryics) title(R.string.add_time_framed_lryics)
negativeButton(R.string.action_search) { RetroUtil.openUrl(this@LyricsActivity, googleSearchLrcUrl) } negativeButton(R.string.action_search) { RetroUtil.openUrl(this@LyricsActivity, googleSearchLrcUrl) }
input(hint = getString(R.string.paste_lyrics_here), input(
hint = getString(R.string.paste_lyrics_here),
prefill = content, prefill = content,
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE) { _, input -> inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
) { _, input ->
LyricUtil.writeLrcToLoc(song.data, song.artistName, input.toString()) LyricUtil.writeLrcToLoc(song.data, song.artistName, input.toString())
} }
positiveButton(android.R.string.ok) { positiveButton(android.R.string.ok) {
@ -189,12 +200,16 @@ class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener, ViewPage
lyricsString!! lyricsString!!
} }
val materialDialog = MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show { val materialDialog = MaterialDialog(
this, BottomSheet(LayoutMode.WRAP_CONTENT)
).show {
title(R.string.add_lyrics) title(R.string.add_lyrics)
negativeButton(R.string.action_search) { RetroUtil.openUrl(this@LyricsActivity, getGoogleSearchUrl()) } negativeButton(R.string.action_search) { RetroUtil.openUrl(this@LyricsActivity, getGoogleSearchUrl()) }
input(hint = getString(R.string.paste_lyrics_here), input(
hint = getString(R.string.paste_lyrics_here),
prefill = content, prefill = content,
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE) { _, input -> inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
) { _, input ->
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java) val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.LYRICS] = input.toString() fieldKeyValueMap[FieldKey.LYRICS] = input.toString()
WriteTagsAsyncTask(this@LyricsActivity).execute(WriteTagsAsyncTask.LoadingInfo(getSongPaths(song), fieldKeyValueMap, null)) WriteTagsAsyncTask(this@LyricsActivity).execute(WriteTagsAsyncTask.LoadingInfo(getSongPaths(song), fieldKeyValueMap, null))
@ -221,8 +236,10 @@ class LyricsActivity : AbsMusicServiceActivity(), View.OnClickListener, ViewPage
} }
class PagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { class PagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
class Tabs(@StringRes val title: Int, class Tabs(
val fragment: Fragment) @StringRes val title: Int,
val fragment: Fragment
)
private var tabs = ArrayList<Tabs>() private var tabs = ArrayList<Tabs>()

View file

@ -12,288 +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.MusicPlayerRemote import code.name.monkey.retromusic.helper.*
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.AlbumLoader import code.name.monkey.retromusic.loaders.*
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.AppRater import code.name.monkey.retromusic.util.*
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().selectedItemId = PreferenceUtil.getInstance(this).lastPage
getBottomNavigationView().setOnNavigationItemSelectedListener { getBottomNavigationView().setOnNavigationItemSelectedListener {
PreferenceUtil.getInstance(this).lastPage = it.itemId PreferenceUtil.getInstance(this).lastPage = it.itemId
selectedFragment(it.itemId) selectedFragment(it.itemId)
true true
} }
if (savedInstanceState == null) { if (savedInstanceState == null) {
setMusicChooser(PreferenceUtil.getInstance(this).lastMusicChooser) setMusicChooser(PreferenceUtil.getInstance(this).lastMusicChooser)
} else { } else {
restoreCurrentFragment() restoreCurrentFragment()
} }
checkShowChangelog() checkShowChangelog()
AppRater.appLaunched(this); AppRater.appLaunched(this);
} }
private fun checkShowChangelog() { private fun checkShowChangelog() {
try { try {
val pInfo = packageManager.getPackageInfo(packageName, 0) val pInfo = packageManager.getPackageInfo(packageName, 0)
val currentVersion = pInfo.versionCode val currentVersion = pInfo.versionCode
if (currentVersion != PreferenceUtil.getInstance(this).lastChangelogVersion) { if (currentVersion != PreferenceUtil.getInstance(this).lastChangelogVersion) {
startActivityForResult(Intent(this, WhatsNewActivity::class.java), APP_INTRO_REQUEST) startActivityForResult(
} Intent(this, WhatsNewActivity::class.java),
} catch (e: Throwable) { APP_INTRO_REQUEST
e.printStackTrace() )
} }
} catch (e: Throwable) {
e.printStackTrace()
}
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
val screenOnOff = IntentFilter() val screenOnOff = IntentFilter()
screenOnOff.addAction(Intent.ACTION_SCREEN_OFF) screenOnOff.addAction(Intent.ACTION_SCREEN_OFF)
registerReceiver(broadcastReceiver, screenOnOff) registerReceiver(broadcastReceiver, screenOnOff)
PreferenceUtil.getInstance(this).registerOnSharedPreferenceChangedListener(this) PreferenceUtil.getInstance(this).registerOnSharedPreferenceChangedListener(this)
if (intent.hasExtra("expand")) { if (intent.hasExtra("expand")) {
if (intent.getBooleanExtra("expand", false)) { if (intent.getBooleanExtra("expand", false)) {
expandPanel() expandPanel()
intent.putExtra("expand", false) intent.putExtra("expand", false)
} }
} }
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
disposable.clear() disposable.clear()
unregisterReceiver(broadcastReceiver) unregisterReceiver(broadcastReceiver)
PreferenceUtil.getInstance(this).unregisterOnSharedPreferenceChangedListener(this) PreferenceUtil.getInstance(this).unregisterOnSharedPreferenceChangedListener(this)
} }
private fun setCurrentFragment(fragment: Fragment, tag: String) { private fun setCurrentFragment(fragment: Fragment, tag: String) {
println("setCurrentFragment -> $tag -> ${supportFragmentManager.findFragmentById(R.id.fragment_container)?.tag}") println("setCurrentFragment -> $tag -> ${supportFragmentManager.findFragmentById(R.id.fragment_container)?.tag}")
if (tag != supportFragmentManager.findFragmentById(R.id.fragment_container)?.tag) { if (tag != supportFragmentManager.findFragmentById(R.id.fragment_container)?.tag) {
supportFragmentManager.beginTransaction().replace(R.id.fragment_container, fragment, tag).commit() supportFragmentManager.beginTransaction()
currentFragment = fragment as MainActivityFragmentCallbacks .replace(R.id.fragment_container, fragment, tag).commit()
} currentFragment = fragment as MainActivityFragmentCallbacks
} }
}
private fun restoreCurrentFragment() { private fun restoreCurrentFragment() {
currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as MainActivityFragmentCallbacks currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as MainActivityFragmentCallbacks
} }
private fun handlePlaybackIntent(intent: Intent?) { private fun handlePlaybackIntent(intent: Intent?) {
if (intent == null) { if (intent == null) {
return return
} }
val uri = intent.data val uri = intent.data
val mimeType = intent.type val mimeType = intent.type
var handled = false var handled = false
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) {
MusicPlayerRemote.openAndShuffleQueue(songs, true) MusicPlayerRemote.openAndShuffleQueue(songs, true)
} else { } else {
MusicPlayerRemote.openQueue(songs, 0, true) MusicPlayerRemote.openQueue(songs, 0, true)
} }
handled = true handled = true
} }
if (uri != null && uri.toString().isNotEmpty()) { if (uri != null && uri.toString().isNotEmpty()) {
MusicPlayerRemote.playFromUri(uri) MusicPlayerRemote.playFromUri(uri)
handled = true handled = true
} else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) { } else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "playlistId", "playlist").toInt() val id = parseIdFromIntent(intent, "playlistId", "playlist").toInt()
if (id >= 0) { if (id >= 0) {
val position = intent.getIntExtra("position", 0) val position = intent.getIntExtra("position", 0)
val songs = ArrayList(PlaylistSongsLoader.getPlaylistSongList(this, id)) val songs = ArrayList(PlaylistSongsLoader.getPlaylistSongList(this, id))
MusicPlayerRemote.openQueue(songs, position, true) MusicPlayerRemote.openQueue(songs, position, true)
handled = true handled = true
} }
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) { } else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "albumId", "album").toInt() val id = parseIdFromIntent(intent, "albumId", "album").toInt()
if (id >= 0) { if (id >= 0) {
val position = intent.getIntExtra("position", 0) val position = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue(AlbumLoader.getAlbum(this, id).songs!!, position, true) MusicPlayerRemote.openQueue(AlbumLoader.getAlbum(this, id).songs!!, position, true)
handled = true handled = true
} }
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) { } else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
val id = parseIdFromIntent(intent, "artistId", "artist").toInt() val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
if (id >= 0) { if (id >= 0) {
val position = intent.getIntExtra("position", 0) val position = intent.getIntExtra("position", 0)
MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).songs, position, true) MusicPlayerRemote.openQueue(ArtistLoader.getArtist(this, id).songs, position, true)
handled = true handled = true
} }
} }
if (handled) { if (handled) {
setIntent(Intent()) setIntent(Intent())
} }
} }
private fun parseIdFromIntent(intent: Intent, longKey: String, stringKey: String): Long { private fun parseIdFromIntent(intent: Intent, longKey: String, stringKey: String): Long {
var id = intent.getLongExtra(longKey, -1) var id = intent.getLongExtra(longKey, -1)
if (id < 0) { if (id < 0) {
val idString = intent.getStringExtra(stringKey) val idString = intent.getStringExtra(stringKey)
if (idString != null) { if (idString != null) {
try { try {
id = java.lang.Long.parseLong(idString) id = java.lang.Long.parseLong(idString)
} catch (e: NumberFormatException) { } catch (e: NumberFormatException) {
Log.e(TAG, e.message) Log.e(TAG, e.message)
} }
} }
} }
return id return id
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
when (requestCode) { when (requestCode) {
APP_INTRO_REQUEST -> { APP_INTRO_REQUEST -> {
blockRequestPermissions = false blockRequestPermissions = false
if (!hasPermissions()) { if (!hasPermissions()) {
requestPermissions() requestPermissions()
} }
} }
REQUEST_CODE_THEME, APP_USER_INFO_REQUEST -> postRecreate() REQUEST_CODE_THEME, APP_USER_INFO_REQUEST -> postRecreate()
PURCHASE_REQUEST -> { PURCHASE_REQUEST -> {
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
//checkSetUpPro(); //checkSetUpPro();
} }
} }
} }
} }
override fun handleBackPress(): Boolean { override fun handleBackPress(): Boolean {
return super.handleBackPress() || currentFragment.handleBackPress() return super.handleBackPress() || currentFragment.handleBackPress()
} }
override fun onServiceConnected() { override fun onServiceConnected() {
super.onServiceConnected() super.onServiceConnected()
handlePlaybackIntent(intent) handlePlaybackIntent(intent)
} }
override fun requestPermissions() { override fun requestPermissions() {
if (!blockRequestPermissions) { if (!blockRequestPermissions) {
super.requestPermissions() super.requestPermissions()
} }
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
if (key == PreferenceUtil.GENERAL_THEME || 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()
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()
} }
private fun showPromotionalOffer() { private fun showPromotionalOffer() {
/*MaterialDialog(this).show { /*MaterialDialog(this).show {
positiveButton(text = "Buy") { startActivity(Intent(this@MainActivity, PurchaseActivity::class.java)) } positiveButton(text = "Buy") { startActivity(Intent(this@MainActivity, PurchaseActivity::class.java)) }
negativeButton(android.R.string.cancel) negativeButton(android.R.string.cancel)
customView(R.layout.dialog_promotional_offer) customView(R.layout.dialog_promotional_offer)
onDismiss { onDismiss {
PreferenceManager.getDefaultSharedPreferences(this@MainActivity) PreferenceManager.getDefaultSharedPreferences(this@MainActivity)
.edit() .edit()
.putBoolean("shown", true) .putBoolean("shown", true)
.apply() .apply()
} }
}*/ }*/
} }
private fun selectedFragment(itemId: Int) { private fun selectedFragment(itemId: Int) {
when (itemId) { when (itemId) {
R.id.action_album, R.id.action_album, R.id.action_artist, R.id.action_playlist, R.id.action_genre, R.id.action_song -> setCurrentFragment(
R.id.action_artist, LibraryFragment.newInstance(itemId),
R.id.action_playlist, itemId.toString()
R.id.action_genre, )
R.id.action_song -> setCurrentFragment(LibraryFragment.newInstance(itemId), itemId.toString()) R.id.action_home -> setCurrentFragment(
R.id.action_home -> setCurrentFragment(BannerHomeFragment.newInstance(), BannerHomeFragment.TAG) BannerHomeFragment.newInstance(),
else -> { BannerHomeFragment.TAG
setCurrentFragment(BannerHomeFragment.newInstance(), BannerHomeFragment.TAG) )
} else -> {
} setCurrentFragment(BannerHomeFragment.newInstance(), BannerHomeFragment.TAG)
} }
}
}
fun setMusicChooser(key: Int) { fun setMusicChooser(key: Int) {
PreferenceUtil.getInstance(this).lastMusicChooser = key PreferenceUtil.getInstance(this).lastMusicChooser = key
when (key) { when (key) {
FOLDER -> setCurrentFragment(FoldersFragment.newInstance(this), FoldersFragment.TAG) FOLDER -> setCurrentFragment(FoldersFragment.newInstance(this), FoldersFragment.TAG)
else -> selectedFragment(PreferenceUtil.getInstance(this).lastPage) else -> selectedFragment(PreferenceUtil.getInstance(this).lastPage)
} }
} }
companion object { companion object {
const val APP_INTRO_REQUEST = 2323 const val APP_INTRO_REQUEST = 2323
const val HOME = 0 const val HOME = 0
const val FOLDER = 1 const val FOLDER = 1
const val LIBRARY = 2 const val LIBRARY = 2
private const val TAG = "MainActivity" private const val TAG = "MainActivity"
private const val APP_USER_INFO_REQUEST = 9003 private const val APP_USER_INFO_REQUEST = 9003
private const val REQUEST_CODE_THEME = 9002 private const val REQUEST_CODE_THEME = 9002
private const val PURCHASE_REQUEST = 101 private const val PURCHASE_REQUEST = 101
} }
} }

View file

@ -3,182 +3,186 @@ package code.name.monkey.retromusic.activities
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
import code.name.monkey.retromusic.extensions.applyToolbar import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.ViewUtil import code.name.monkey.retromusic.util.ViewUtil
import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
import kotlinx.android.synthetic.main.activity_playing_queue.* import kotlinx.android.synthetic.main.activity_playing_queue.*
open class PlayingQueueActivity : AbsMusicServiceActivity() { open class PlayingQueueActivity : AbsMusicServiceActivity() {
private var wrappedAdapter: RecyclerView.Adapter<*>? = null private var wrappedAdapter: RecyclerView.Adapter<*>? = null
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
private var playingQueueAdapter: PlayingQueueAdapter? = null private var playingQueueAdapter: PlayingQueueAdapter? = null
private lateinit var linearLayoutManager: LinearLayoutManager private lateinit var linearLayoutManager: LinearLayoutManager
private fun getUpNextAndQueueTime(): String {
val duration = MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.position)
private fun getUpNextAndQueueTime(): String { return MusicUtil.buildInfoString(
val duration = MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.position) resources.getString(R.string.up_next), MusicUtil.getReadableDurationString(duration)
)
}
return MusicUtil.buildInfoString( override fun onCreate(
resources.getString(R.string.up_next), savedInstanceState: Bundle?
MusicUtil.getReadableDurationString(duration) ) {
) super.onCreate(savedInstanceState)
} setContentView(R.layout.activity_playing_queue)
override fun onCreate( setStatusbarColorAuto()
savedInstanceState: Bundle? setNavigationBarColorPrimary()
) { setTaskDescriptionColorAuto()
super.onCreate(savedInstanceState) setLightNavigationBar(true)
setContentView(R.layout.activity_playing_queue)
setStatusbarColorAuto() setupToolbar()
setNavigationBarColorPrimary() setUpRecyclerView()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setupToolbar() clearQueue.setOnClickListener {
setUpRecyclerView() MusicPlayerRemote.clearQueue()
}
checkForPadding()
}
clearQueue.setOnClickListener { override fun onOptionsItemSelected(item: MenuItem): Boolean {
MusicPlayerRemote.clearQueue() return when (item.itemId) {
} android.R.id.home -> {
checkForPadding() onBackPressed()
} true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { private fun setUpRecyclerView() {
return when (item.itemId) { recyclerViewDragDropManager = RecyclerViewDragDropManager()
android.R.id.home -> { val animator = RefactoredDefaultItemAnimator()
onBackPressed()
true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun setUpRecyclerView() { playingQueueAdapter = PlayingQueueAdapter(
recyclerViewDragDropManager = RecyclerViewDragDropManager() this,
val animator = RefactoredDefaultItemAnimator() MusicPlayerRemote.playingQueue,
MusicPlayerRemote.position,
R.layout.item_queue
)
wrappedAdapter = recyclerViewDragDropManager?.createWrappedAdapter(playingQueueAdapter!!)
playingQueueAdapter = PlayingQueueAdapter( linearLayoutManager = LinearLayoutManager(this)
this,
MusicPlayerRemote.playingQueue,
MusicPlayerRemote.position,
R.layout.item_queue)
wrappedAdapter = recyclerViewDragDropManager?.createWrappedAdapter(playingQueueAdapter!!)
linearLayoutManager = LinearLayoutManager(this) recyclerView.apply {
layoutManager = linearLayoutManager
adapter = wrappedAdapter
itemAnimator = animator
recyclerViewDragDropManager?.attachRecyclerView(this)
}
recyclerView.apply { linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
layoutManager = linearLayoutManager
adapter = wrappedAdapter
itemAnimator = animator
recyclerViewDragDropManager?.attachRecyclerView(this)
}
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0) recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy > 0) {
clearQueue.shrink()
} else if (dy < 0) {
clearQueue.extend()
}
}
})
ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
}
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { private fun checkForPadding() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy > 0) {
clearQueue.shrink()
} else if (dy < 0) {
clearQueue.extend()
}
}
})
ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
}
private fun checkForPadding() { }
} override fun onQueueChanged() {
if (MusicPlayerRemote.playingQueue.isEmpty()) {
finish()
return
}
checkForPadding()
updateQueue()
updateCurrentSong()
}
override fun onQueueChanged() { override fun onMediaStoreChanged() {
if (MusicPlayerRemote.playingQueue.isEmpty()) { updateQueue()
finish() updateCurrentSong()
return }
}
checkForPadding()
updateQueue()
updateCurrentSong()
}
override fun onMediaStoreChanged() { private fun updateCurrentSong() {
updateQueue() playerQueueSubHeader.text = getUpNextAndQueueTime()
updateCurrentSong() }
}
private fun updateCurrentSong() { override fun onPlayingMetaChanged() {
playerQueueSubHeader.text = getUpNextAndQueueTime() updateQueuePosition()
} }
override fun onPlayingMetaChanged() { private fun updateQueuePosition() {
updateQueuePosition() playingQueueAdapter?.setCurrent(MusicPlayerRemote.position)
} resetToCurrentPosition()
playerQueueSubHeader.text = getUpNextAndQueueTime()
}
private fun updateQueuePosition() { private fun updateQueue() {
playingQueueAdapter?.setCurrent(MusicPlayerRemote.position) playingQueueAdapter?.swapDataSet(MusicPlayerRemote.playingQueue, MusicPlayerRemote.position)
resetToCurrentPosition() resetToCurrentPosition()
playerQueueSubHeader.text = getUpNextAndQueueTime() }
}
private fun updateQueue() { private fun resetToCurrentPosition() {
playingQueueAdapter?.swapDataSet(MusicPlayerRemote.playingQueue, MusicPlayerRemote.position) recyclerView.stopScroll()
resetToCurrentPosition() linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
} }
private fun resetToCurrentPosition() { override fun onPause() {
recyclerView.stopScroll() if (recyclerViewDragDropManager != null) {
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0) recyclerViewDragDropManager!!.cancelDrag()
} }
super.onPause()
}
override fun onPause() { override fun onDestroy() {
if (recyclerViewDragDropManager != null) { if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.cancelDrag() recyclerViewDragDropManager!!.release()
} recyclerViewDragDropManager = null
super.onPause() }
}
override fun onDestroy() { if (wrappedAdapter != null) {
if (recyclerViewDragDropManager != null) { WrapperAdapterUtils.releaseAll(wrappedAdapter)
recyclerViewDragDropManager!!.release() wrappedAdapter = null
recyclerViewDragDropManager = null }
} playingQueueAdapter = null
super.onDestroy()
}
if (wrappedAdapter != null) { private fun setupToolbar() {
WrapperAdapterUtils.releaseAll(wrappedAdapter) playerQueueSubHeader.text = getUpNextAndQueueTime()
wrappedAdapter = null playerQueueSubHeader.setTextColor(ThemeStore.accentColor(this))
}
playingQueueAdapter = null
super.onDestroy()
}
private fun setupToolbar() { applyToolbar(toolbar)
playerQueueSubHeader.text = getUpNextAndQueueTime() appBarLayout.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
playerQueueSubHeader.setTextColor(ThemeStore.accentColor(this))
applyToolbar(toolbar) clearQueue.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
appBarLayout.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary)) ColorStateList.valueOf(
MaterialValueHelper.getPrimaryTextColor(
clearQueue.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this)) this,
ColorStateList.valueOf(MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.accentColor(this)))).apply { ColorUtil.isColorLight(
clearQueue.setTextColor(this) ThemeStore.accentColor(
clearQueue.iconTint = this this
} )
} )
)
).apply {
clearQueue.setTextColor(this)
clearQueue.iconTint = this
}
}
} }

View file

@ -2,31 +2,19 @@ package code.name.monkey.retromusic.activities
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.*
import android.view.MenuItem import androidx.recyclerview.widget.*
import android.view.View import code.name.monkey.appthemehelper.util.*
import androidx.recyclerview.widget.LinearLayoutManager import code.name.monkey.retromusic.*
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter import code.name.monkey.retromusic.adapter.song.*
import code.name.monkey.retromusic.adapter.song.PlaylistSongAdapter
import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.extensions.applyToolbar import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.loaders.PlaylistLoader import code.name.monkey.retromusic.loaders.PlaylistLoader
import code.name.monkey.retromusic.model.AbsCustomPlaylist import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.mvp.presenter.*
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsPresenter
import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsView
import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.PlaylistsUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.ViewUtil import code.name.monkey.retromusic.util.ViewUtil
import com.afollestad.materialcab.MaterialCab import com.afollestad.materialcab.MaterialCab
import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator
@ -35,197 +23,219 @@ import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
import kotlinx.android.synthetic.main.activity_playlist_detail.* import kotlinx.android.synthetic.main.activity_playlist_detail.*
import javax.inject.Inject import javax.inject.Inject
class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, PlaylistSongsView { class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, PlaylistSongsView {
@Inject @Inject
lateinit var playlistSongsPresenter: PlaylistSongsPresenter lateinit var playlistSongsPresenter: PlaylistSongsPresenter
private lateinit var playlist: Playlist private lateinit var playlist: Playlist
private var cab: MaterialCab? = null private var cab: MaterialCab? = null
private lateinit var adapter: SongAdapter private lateinit var adapter: SongAdapter
private var wrappedAdapter: RecyclerView.Adapter<*>? = null private var wrappedAdapter: RecyclerView.Adapter<*>? = null
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar() setDrawUnderStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
App.musicComponent.inject(this) App.musicComponent.inject(this)
playlistSongsPresenter.attachView(this) playlistSongsPresenter.attachView(this)
setStatusbarColor(Color.TRANSPARENT) setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto() setNavigationbarColorAuto()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
setLightNavigationBar(true) setLightNavigationBar(true)
setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary))) setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
toggleBottomNavigationView(true) toggleBottomNavigationView(true)
if (intent.extras != null) { if (intent.extras != null) {
playlist = intent.extras!!.getParcelable(EXTRA_PLAYLIST)!! playlist = intent.extras!!.getParcelable(EXTRA_PLAYLIST)!!
} else { } else {
finish() finish()
} }
setUpToolBar() setUpToolBar()
setUpRecyclerView() setUpRecyclerView()
} }
override fun createContentView(): View { override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_playlist_detail) return wrapSlidingMusicPanel(R.layout.activity_playlist_detail)
} }
private fun setUpRecyclerView() { private fun setUpRecyclerView() {
ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView) ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.layoutManager = LinearLayoutManager(this)
if (playlist is AbsCustomPlaylist) { if (playlist is AbsCustomPlaylist) {
adapter = PlaylistSongAdapter(this, ArrayList(), R.layout.item_list, false, this) adapter = PlaylistSongAdapter(this, ArrayList(), R.layout.item_list, false, this)
recyclerView.adapter = adapter recyclerView.adapter = adapter
} else { } else {
recyclerViewDragDropManager = RecyclerViewDragDropManager() recyclerViewDragDropManager = RecyclerViewDragDropManager()
val animator = RefactoredDefaultItemAnimator() val animator = RefactoredDefaultItemAnimator()
adapter = OrderablePlaylistSongAdapter(this, ArrayList(), R.layout.item_list, false, this, adapter = OrderablePlaylistSongAdapter(this,
object : OrderablePlaylistSongAdapter.OnMoveItemListener { ArrayList(),
override fun onMoveItem(fromPosition: Int, toPosition: Int) { R.layout.item_list,
if (PlaylistsUtil.moveItem(this@PlaylistDetailActivity, playlist.id, fromPosition, toPosition)) { false,
val song = adapter.dataSet.removeAt(fromPosition) this,
adapter.dataSet.add(toPosition, song) object : OrderablePlaylistSongAdapter.OnMoveItemListener {
adapter.notifyItemMoved(fromPosition, toPosition) override fun onMoveItem(
} fromPosition: Int,
} toPosition: Int
}) ) {
wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(adapter) if (PlaylistsUtil.moveItem(
this@PlaylistDetailActivity,
playlist.id,
fromPosition,
toPosition
)) {
val song = adapter.dataSet.removeAt(
fromPosition
)
adapter.dataSet.add(toPosition, song)
adapter.notifyItemMoved(
fromPosition,
toPosition
)
}
}
})
wrappedAdapter = recyclerViewDragDropManager!!.createWrappedAdapter(adapter)
recyclerView.adapter = wrappedAdapter recyclerView.adapter = wrappedAdapter
recyclerView.itemAnimator = animator recyclerView.itemAnimator = animator
recyclerViewDragDropManager?.attachRecyclerView(recyclerView) recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
} }
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() { override fun onChanged() {
super.onChanged() super.onChanged()
checkIsEmpty() checkIsEmpty()
} }
}) })
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
playlistSongsPresenter.loadPlaylistSongs(playlist) playlistSongsPresenter.loadPlaylistSongs(playlist)
} }
private fun setUpToolBar() { private fun setUpToolBar() {
applyToolbar(toolbar) applyToolbar(toolbar)
title = playlist.name title = playlist.name
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(if (playlist is AbsCustomPlaylist) R.menu.menu_smart_playlist_detail else R.menu.menu_playlist_detail, menu) menuInflater.inflate(
return super.onCreateOptionsMenu(menu) if (playlist is AbsCustomPlaylist) R.menu.menu_smart_playlist_detail
} else R.menu.menu_playlist_detail, menu
)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
android.R.id.home -> { android.R.id.home -> {
onBackPressed() onBackPressed()
return true return true
} }
} }
return PlaylistMenuHelper.handleMenuClick(this, playlist, item) return PlaylistMenuHelper.handleMenuClick(this, playlist, item)
} }
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab { override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
if (cab != null && cab!!.isActive) { if (cab != null && cab!!.isActive) {
cab!!.finish() cab!!.finish()
} }
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).setBackgroundColor(
.setCloseDrawableRes(R.drawable.ic_close_white_24dp) RetroColorUtil.shiftBackgroundColorForLightText(
.setBackgroundColor( ATHUtil.resolveColor(
RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorPrimary))) this,
.start(callback) R.attr.colorPrimary
return cab!! )
} )
).start(callback)
return cab!!
}
override fun onBackPressed() { override fun onBackPressed() {
if (cab != null && cab!!.isActive) { if (cab != null && cab!!.isActive) {
cab!!.finish() cab!!.finish()
} else { } else {
recyclerView!!.stopScroll() recyclerView!!.stopScroll()
super.onBackPressed() super.onBackPressed()
} }
} }
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) {
playlist = PlaylistLoader.getPlaylist(this, playlist.id) playlist = PlaylistLoader.getPlaylist(this, playlist.id)
setToolbarTitle(playlist.name) setToolbarTitle(playlist.name)
} }
} }
playlistSongsPresenter.loadPlaylistSongs(playlist) playlistSongsPresenter.loadPlaylistSongs(playlist)
} }
private fun setToolbarTitle(title: String) { private fun setToolbarTitle(title: String) {
supportActionBar!!.title = title supportActionBar!!.title = title
} }
private fun checkForPadding() { private fun checkForPadding() {
val height = DensityUtil.dip2px(this, 52f) val height = DensityUtil.dip2px(this, 52f)
recyclerView.setPadding(0, 0, 0, (height)) recyclerView.setPadding(0, 0, 0, (height))
} }
private fun checkIsEmpty() { private fun checkIsEmpty() {
checkForPadding() 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
} }
public override fun onPause() { public override fun onPause() {
if (recyclerViewDragDropManager != null) { if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.cancelDrag() recyclerViewDragDropManager!!.cancelDrag()
} }
super.onPause() super.onPause()
} }
override fun onDestroy() { override fun onDestroy() {
if (recyclerViewDragDropManager != null) { if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.release() recyclerViewDragDropManager!!.release()
recyclerViewDragDropManager = null recyclerViewDragDropManager = null
} }
if (recyclerView != null) { if (recyclerView != null) {
recyclerView!!.itemAnimator = null recyclerView!!.itemAnimator = null
recyclerView!!.adapter = null recyclerView!!.adapter = null
} }
if (wrappedAdapter != null) { if (wrappedAdapter != null) {
WrapperAdapterUtils.releaseAll(wrappedAdapter) WrapperAdapterUtils.releaseAll(wrappedAdapter)
wrappedAdapter = null wrappedAdapter = null
} }
super.onDestroy() super.onDestroy()
playlistSongsPresenter.detachView() playlistSongsPresenter.detachView()
} }
override fun showEmptyView() { override fun showEmptyView() {
empty.visibility = View.VISIBLE empty.visibility = View.VISIBLE
emptyText.visibility = View.VISIBLE emptyText.visibility = View.VISIBLE
} }
override fun songs(songs: ArrayList<Song>) { override fun songs(songs: ArrayList<Song>) {
adapter.swapDataSet(songs) adapter.swapDataSet(songs)
} }
companion object { companion object {
var EXTRA_PLAYLIST = "extra_playlist" var EXTRA_PLAYLIST = "extra_playlist"
} }
} }

View file

@ -1,155 +1,157 @@
package code.name.monkey.retromusic.activities package code.name.monkey.retromusic.activities
import android.content.Intent import android.content.Intent
import android.os.AsyncTask import android.os.*
import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.MenuItem import android.view.MenuItem
import android.widget.Toast import android.widget.Toast
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.MaterialUtil import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.BuildConfig import code.name.monkey.retromusic.BuildConfig
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.extensions.applyToolbar import code.name.monkey.retromusic.extensions.applyToolbar
import com.anjlab.android.iab.v3.BillingProcessor import com.anjlab.android.iab.v3.*
import com.anjlab.android.iab.v3.TransactionDetails
import kotlinx.android.synthetic.main.activity_pro_version.* import kotlinx.android.synthetic.main.activity_pro_version.*
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler { class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
private lateinit var billingProcessor: BillingProcessor
private var restorePurchaseAsyncTask: AsyncTask<*, *, *>? = null
private lateinit var billingProcessor: BillingProcessor override fun onCreate(savedInstanceState: Bundle?) {
private var restorePurchaseAsyncTask: AsyncTask<*, *, *>? = null super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pro_version)
setDrawUnderStatusBar()
override fun onCreate(savedInstanceState: Bundle?) { setStatusbarColorAuto()
super.onCreate(savedInstanceState) setNavigationBarColorPrimary()
setContentView(R.layout.activity_pro_version) setTaskDescriptionColorAuto()
setDrawUnderStatusBar() setLightNavigationBar(true)
setStatusbarColorAuto() val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary)
setNavigationBarColorPrimary() toolbar.setBackgroundColor(primaryColor)
setTaskDescriptionColorAuto() appBarLayout.setBackgroundColor(primaryColor)
setLightNavigationBar(true)
val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary) applyToolbar(toolbar)
toolbar.setBackgroundColor(primaryColor)
appBarLayout.setBackgroundColor(primaryColor)
applyToolbar(toolbar) restoreButton.isEnabled = false
purchaseButton.isEnabled = false
restoreButton.isEnabled = false billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this)
purchaseButton.isEnabled = false
billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this) MaterialUtil.setTint(restoreButton, false)
MaterialUtil.setTint(purchaseButton, true)
MaterialUtil.setTint(restoreButton, false) restoreButton.setOnClickListener {
MaterialUtil.setTint(purchaseButton, true) if (restorePurchaseAsyncTask == null || restorePurchaseAsyncTask!!.status != AsyncTask.Status.RUNNING) {
restorePurchase()
}
restoreButton.setOnClickListener { }
if (restorePurchaseAsyncTask == null || restorePurchaseAsyncTask!!.status != AsyncTask.Status.RUNNING) { purchaseButton.setOnClickListener {
restorePurchase() billingProcessor.purchase(this@PurchaseActivity, App.PRO_VERSION_PRODUCT_ID)
} }
}
} private fun restorePurchase() {
purchaseButton.setOnClickListener { if (restorePurchaseAsyncTask != null) {
billingProcessor.purchase(this@PurchaseActivity, App.PRO_VERSION_PRODUCT_ID) restorePurchaseAsyncTask!!.cancel(false)
} }
} restorePurchaseAsyncTask = RestorePurchaseAsyncTask(this).execute()
}
private fun restorePurchase() { override fun onProductPurchased(productId: String, details: TransactionDetails?) {
if (restorePurchaseAsyncTask != null) { Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show()
restorePurchaseAsyncTask!!.cancel(false) setResult(RESULT_OK)
} }
restorePurchaseAsyncTask = RestorePurchaseAsyncTask(this).execute()
}
override fun onPurchaseHistoryRestored() {
if (App.isProVersion()) {
Toast.makeText(
this,
R.string.restored_previous_purchase_please_restart,
Toast.LENGTH_LONG
).show()
setResult(RESULT_OK)
} else {
Toast.makeText(this, R.string.no_purchase_found, Toast.LENGTH_SHORT).show()
}
}
override fun onProductPurchased(productId: String, details: TransactionDetails?) { override fun onBillingError(errorCode: Int, error: Throwable?) {
Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show() Log.e(TAG, "Billing error: code = $errorCode", error)
setResult(RESULT_OK) }
}
override fun onPurchaseHistoryRestored() { override fun onBillingInitialized() {
if (App.isProVersion()) { restoreButton.isEnabled = true
Toast.makeText(this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG).show() purchaseButton.isEnabled = true
setResult(RESULT_OK) }
} else {
Toast.makeText(this, R.string.no_purchase_found, Toast.LENGTH_SHORT).show()
}
}
override fun onBillingError(errorCode: Int, error: Throwable?) { public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
Log.e(TAG, "Billing error: code = $errorCode", error) if (!billingProcessor.handleActivityResult(requestCode, resultCode, data)) {
} super.onActivityResult(requestCode, resultCode, data)
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> finish()
}
return super.onOptionsItemSelected(item)
}
override fun onBillingInitialized() { override fun onDestroy() {
restoreButton.isEnabled = true billingProcessor.release()
purchaseButton.isEnabled = true super.onDestroy()
} }
private class RestorePurchaseAsyncTask internal constructor(purchaseActivity: PurchaseActivity) : AsyncTask<Void, Void, Boolean>() {
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { private val buyActivityWeakReference: WeakReference<PurchaseActivity> = WeakReference(
if (!billingProcessor.handleActivityResult(requestCode, resultCode, data)) { purchaseActivity
super.onActivityResult(requestCode, resultCode, data) )
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onPreExecute() {
when (item.itemId) { super.onPreExecute()
android.R.id.home -> finish() val purchaseActivity = buyActivityWeakReference.get()
} if (purchaseActivity != null) {
return super.onOptionsItemSelected(item) Toast.makeText(purchaseActivity, R.string.restoring_purchase, Toast.LENGTH_SHORT)
} .show()
} else {
cancel(false)
}
}
override fun onDestroy() { override fun doInBackground(vararg params: Void): Boolean? {
billingProcessor.release() val purchaseActivity = buyActivityWeakReference.get()
super.onDestroy() if (purchaseActivity != null) {
} return purchaseActivity.billingProcessor.loadOwnedPurchasesFromGoogle()
}
cancel(false)
return null
}
private class RestorePurchaseAsyncTask internal constructor(purchaseActivity: PurchaseActivity) : AsyncTask<Void, Void, Boolean>() { override fun onPostExecute(b: Boolean?) {
super.onPostExecute(b)
val purchaseActivity = buyActivityWeakReference.get()
if (purchaseActivity == null || b == null) {
return
}
private val buyActivityWeakReference: WeakReference<PurchaseActivity> = WeakReference(purchaseActivity) if (b) {
purchaseActivity.onPurchaseHistoryRestored()
} else {
Toast.makeText(
purchaseActivity,
R.string.could_not_restore_purchase,
Toast.LENGTH_SHORT
).show()
}
}
}
override fun onPreExecute() { companion object {
super.onPreExecute() private const val TAG: String = "PurchaseActivity"
val purchaseActivity = buyActivityWeakReference.get() }
if (purchaseActivity != null) {
Toast.makeText(purchaseActivity, R.string.restoring_purchase, Toast.LENGTH_SHORT).show()
} else {
cancel(false)
}
}
override fun doInBackground(vararg params: Void): Boolean? {
val purchaseActivity = buyActivityWeakReference.get()
if (purchaseActivity != null) {
return purchaseActivity.billingProcessor.loadOwnedPurchasesFromGoogle()
}
cancel(false)
return null
}
override fun onPostExecute(b: Boolean?) {
super.onPostExecute(b)
val purchaseActivity = buyActivityWeakReference.get()
if (purchaseActivity == null || b == null) {
return
}
if (b) {
purchaseActivity.onPurchaseHistoryRestored()
} else {
Toast.makeText(purchaseActivity, R.string.could_not_restore_purchase, Toast.LENGTH_SHORT).show()
}
}
}
companion object {
private const val TAG: String = "PurchaseActivity"
}
} }

View file

@ -1,212 +1,215 @@
package code.name.monkey.retromusic.activities package code.name.monkey.retromusic.activities
import android.app.Activity import android.app.*
import android.app.Service import android.content.*
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.os.Bundle import android.os.Bundle
import android.speech.RecognizerIntent import android.speech.RecognizerIntent
import android.text.Editable import android.text.*
import android.text.TextWatcher
import android.view.View import android.view.View
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.TextView.BufferType import android.widget.TextView.BufferType
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.widget.SearchView.OnQueryTextListener import androidx.appcompat.widget.SearchView.OnQueryTextListener
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.retromusic.*
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.adapter.SearchAdapter import code.name.monkey.retromusic.adapter.SearchAdapter
import code.name.monkey.retromusic.mvp.presenter.SearchPresenter import code.name.monkey.retromusic.mvp.presenter.*
import code.name.monkey.retromusic.mvp.presenter.SearchView import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil
import kotlinx.android.synthetic.main.activity_search.* import kotlinx.android.synthetic.main.activity_search.*
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatcher, SearchView { class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatcher, SearchView {
@Inject @Inject
lateinit var searchPresenter: SearchPresenter lateinit var searchPresenter: SearchPresenter
private var searchAdapter: SearchAdapter? = null private var searchAdapter: SearchAdapter? = null
private var query: String? = null private var query: String? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar() setDrawUnderStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search) setContentView(R.layout.activity_search)
App.musicComponent.inject(this) App.musicComponent.inject(this)
searchPresenter.attachView(this) searchPresenter.attachView(this)
setStatusbarColorAuto() setStatusbarColorAuto()
setNavigationBarColorPrimary() setNavigationBarColorPrimary()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
setLightNavigationBar(true) setLightNavigationBar(true)
setupRecyclerView() setupRecyclerView()
setUpToolBar() setUpToolBar()
setupSearchView() setupSearchView()
if (intent.getBooleanExtra(EXTRA_SHOW_MIC, false)) { if (intent.getBooleanExtra(EXTRA_SHOW_MIC, false)) {
startMicSearch() startMicSearch()
} }
back.setOnClickListener { onBackPressed() } back.setOnClickListener { onBackPressed() }
voiceSearch.setOnClickListener { startMicSearch() } voiceSearch.setOnClickListener { startMicSearch() }
searchContainer.setCardBackgroundColor(RetroColorUtil.toolbarColor(this)) searchContainer.setCardBackgroundColor(RetroColorUtil.toolbarColor(this))
keyboardPopup.setOnClickListener { keyboardPopup.setOnClickListener {
val inputManager = getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager val inputManager = getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
inputManager.showSoftInput(searchView, InputMethodManager.SHOW_IMPLICIT) inputManager.showSoftInput(searchView, InputMethodManager.SHOW_IMPLICIT)
} }
keyboardPopup.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this)) keyboardPopup.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
ColorStateList.valueOf(MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.accentColor(this)))).apply { ColorStateList.valueOf(
keyboardPopup.setTextColor(this) MaterialValueHelper.getPrimaryTextColor(
keyboardPopup.iconTint = this this,
} ColorUtil.isColorLight(
if (savedInstanceState != null) { ThemeStore.accentColor(
query = savedInstanceState.getString(QUERY); this
} )
)
)
).apply {
keyboardPopup.setTextColor(this)
keyboardPopup.iconTint = this
}
if (savedInstanceState != null) {
query = savedInstanceState.getString(QUERY);
}
} }
private fun setupRecyclerView() { private fun setupRecyclerView() {
searchAdapter = SearchAdapter(this, emptyList()) searchAdapter = SearchAdapter(this, emptyList())
searchAdapter!!.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { searchAdapter!!.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() { override fun onChanged() {
super.onChanged() super.onChanged()
empty.visibility = if (searchAdapter!!.itemCount < 1) View.VISIBLE else View.GONE empty.visibility = if (searchAdapter!!.itemCount < 1) View.VISIBLE else View.GONE
} }
}) })
recyclerView.apply { recyclerView.apply {
layoutManager = LinearLayoutManager(this@SearchActivity) layoutManager = LinearLayoutManager(this@SearchActivity)
adapter = searchAdapter adapter = searchAdapter
} }
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy) super.onScrolled(recyclerView, dx, dy)
if (dy > 0) { if (dy > 0) {
keyboardPopup.shrink() keyboardPopup.shrink()
} else if (dy < 0) { } else if (dy < 0) {
keyboardPopup.extend() keyboardPopup.extend()
} }
} }
}) })
} }
private fun setupSearchView() { private fun setupSearchView() {
searchView.addTextChangedListener(this) searchView.addTextChangedListener(this)
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
searchPresenter.detachView() searchPresenter.detachView()
} }
override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
outState.putString(QUERY, query) outState.putString(QUERY, 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))
} }
private fun search(query: String) {
this.query = query
voiceSearch.visibility = if (query.isNotEmpty()) View.GONE else View.VISIBLE
searchPresenter.search(query)
}
private fun search(query: String) { override fun onMediaStoreChanged() {
this.query = query super.onMediaStoreChanged()
voiceSearch.visibility = if (query.isNotEmpty()) View.GONE else View.VISIBLE query?.let { search(it) }
searchPresenter.search(query) }
}
override fun onMediaStoreChanged() { override fun onQueryTextSubmit(query: String): Boolean {
super.onMediaStoreChanged() hideSoftKeyboard()
query?.let { search(it) } return false
} }
override fun onQueryTextSubmit(query: String): Boolean { override fun onQueryTextChange(newText: String): Boolean {
hideSoftKeyboard() search(newText)
return false return false
} }
override fun onQueryTextChange(newText: String): Boolean { private fun hideSoftKeyboard() {
search(newText) RetroUtil.hideSoftKeyboard(this@SearchActivity)
return false if (searchView != null) {
} searchView.clearFocus()
}
}
private fun hideSoftKeyboard() { override fun showEmptyView() {
RetroUtil.hideSoftKeyboard(this@SearchActivity) searchAdapter?.swapDataSet(ArrayList())
if (searchView != null) { }
searchView.clearFocus()
}
}
override fun showEmptyView() { override fun showData(data: MutableList<Any>) {
searchAdapter?.swapDataSet(ArrayList()) searchAdapter?.swapDataSet(data)
} }
override fun showData(data: MutableList<Any>) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
searchAdapter?.swapDataSet(data) super.onActivityResult(requestCode, resultCode, data)
} when (requestCode) {
REQ_CODE_SPEECH_INPUT -> {
if (resultCode == Activity.RESULT_OK && null != data) {
val result: ArrayList<String>? = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
query = result?.get(0)
searchView.setText(query, BufferType.EDITABLE)
searchPresenter.search(query!!)
}
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { private fun startMicSearch() {
super.onActivityResult(requestCode, resultCode, data) val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
when (requestCode) { intent.putExtra(
REQ_CODE_SPEECH_INPUT -> { RecognizerIntent.EXTRA_LANGUAGE_MODEL,
if (resultCode == Activity.RESULT_OK && null != data) { RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
val result: ArrayList<String>? = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS) )
query = result?.get(0) intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())
searchView.setText(query, BufferType.EDITABLE) intent.putExtra(RecognizerIntent.EXTRA_PROMPT, getString(R.string.speech_prompt))
searchPresenter.search(query!!) try {
} startActivityForResult(intent, REQ_CODE_SPEECH_INPUT)
} } catch (e: ActivityNotFoundException) {
} e.printStackTrace()
} Toast.makeText(this, getString(R.string.speech_not_supported), Toast.LENGTH_SHORT)
.show()
}
private fun startMicSearch() { }
val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, getString(R.string.speech_prompt))
try {
startActivityForResult(intent, REQ_CODE_SPEECH_INPUT)
} catch (e: ActivityNotFoundException) {
e.printStackTrace()
Toast.makeText(this, getString(R.string.speech_not_supported), Toast.LENGTH_SHORT).show()
}
} override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { }
} override fun onTextChanged(newText: CharSequence, start: Int, before: Int, count: Int) {
search(newText.toString())
}
override fun onTextChanged(newText: CharSequence, start: Int, before: Int, count: Int) { override fun afterTextChanged(s: Editable) {
search(newText.toString())
}
override fun afterTextChanged(s: Editable) { }
} companion object {
val TAG: String = SearchActivity::class.java.simpleName
companion object { const val EXTRA_SHOW_MIC = "extra_show_mic"
val TAG: String = SearchActivity::class.java.simpleName const val QUERY: String = "query"
const val EXTRA_SHOW_MIC = "extra_show_mic" private const val REQ_CODE_SPEECH_INPUT = 9002
const val QUERY: String = "query" }
private const val REQ_CODE_SPEECH_INPUT = 9002
}
} }

View file

@ -5,14 +5,12 @@ import android.view.MenuItem
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.transition.TransitionManager import androidx.transition.TransitionManager
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.fragments.settings.MainSettingsFragment import code.name.monkey.retromusic.fragments.settings.MainSettingsFragment
import kotlinx.android.synthetic.main.activity_settings.* import kotlinx.android.synthetic.main.activity_settings.*
class SettingsActivity : AbsBaseActivity() { class SettingsActivity : AbsBaseActivity() {
private val fragmentManager = supportFragmentManager private val fragmentManager = supportFragmentManager

View file

@ -2,237 +2,238 @@ package code.name.monkey.retromusic.activities
import android.content.Intent import android.content.Intent
import android.graphics.Paint import android.graphics.Paint
import android.os.AsyncTask import android.os.*
import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.*
import android.view.MenuItem import android.widget.*
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.BuildConfig import code.name.monkey.retromusic.BuildConfig
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.extensions.applyToolbar import code.name.monkey.retromusic.extensions.applyToolbar
import com.anjlab.android.iab.v3.BillingProcessor import com.anjlab.android.iab.v3.*
import com.anjlab.android.iab.v3.SkuDetails
import com.anjlab.android.iab.v3.TransactionDetails
import kotlinx.android.synthetic.main.activity_donation.* import kotlinx.android.synthetic.main.activity_donation.*
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.* import java.util.*
class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler { class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
companion object { companion object {
val TAG: String = SupportDevelopmentActivity::class.java.simpleName val TAG: String = SupportDevelopmentActivity::class.java.simpleName
const val DONATION_PRODUCT_IDS = R.array.donation_ids const val DONATION_PRODUCT_IDS = R.array.donation_ids
private const val TEZ_REQUEST_CODE = 123 private const val TEZ_REQUEST_CODE = 123
} }
var billingProcessor: BillingProcessor? = null var billingProcessor: BillingProcessor? = null
private var skuDetailsLoadAsyncTask: AsyncTask<*, *, *>? = null private var skuDetailsLoadAsyncTask: AsyncTask<*, *, *>? = null
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) { if (item.itemId == android.R.id.home) {
onBackPressed() onBackPressed()
return true return true
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
fun donate(i: Int) { fun donate(i: Int) {
val ids = resources.getStringArray(DONATION_PRODUCT_IDS) val ids = resources.getStringArray(DONATION_PRODUCT_IDS)
billingProcessor!!.purchase(this, ids[i]) billingProcessor!!.purchase(this, ids[i])
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_donation) setContentView(R.layout.activity_donation)
setStatusbarColorAuto() setStatusbarColorAuto()
setNavigationBarColorPrimary() setNavigationBarColorPrimary()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
setLightNavigationBar(true) setLightNavigationBar(true)
setupToolbar() setupToolbar()
billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this) billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this)
TintHelper.setTint(progress, ThemeStore.accentColor(this)) TintHelper.setTint(progress, ThemeStore.accentColor(this))
donation.setTextColor(ThemeStore.accentColor(this)) donation.setTextColor(ThemeStore.accentColor(this))
} }
private fun setupToolbar() { private fun setupToolbar() {
val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary) val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary)
appBarLayout.setBackgroundColor(primaryColor) appBarLayout.setBackgroundColor(primaryColor)
applyToolbar(toolbar) applyToolbar(toolbar)
} }
override fun onBillingInitialized() { override fun onBillingInitialized() {
loadSkuDetails() loadSkuDetails()
} }
private fun loadSkuDetails() { private fun loadSkuDetails() {
if (skuDetailsLoadAsyncTask != null) { if (skuDetailsLoadAsyncTask != null) {
skuDetailsLoadAsyncTask!!.cancel(false) skuDetailsLoadAsyncTask!!.cancel(false)
} }
skuDetailsLoadAsyncTask = SkuDetailsLoadAsyncTask(this).execute() skuDetailsLoadAsyncTask = SkuDetailsLoadAsyncTask(this).execute()
} }
override fun onProductPurchased(productId: String, details: TransactionDetails?) { override fun onProductPurchased(productId: String, details: TransactionDetails?) {
//loadSkuDetails(); //loadSkuDetails();
Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show()
} }
override fun onBillingError(errorCode: Int, error: Throwable?) { override fun onBillingError(errorCode: Int, error: Throwable?) {
Log.e(TAG, "Billing error: code = $errorCode", error) Log.e(TAG, "Billing error: code = $errorCode", error)
} }
override fun onPurchaseHistoryRestored() { override fun onPurchaseHistoryRestored() {
//loadSkuDetails(); //loadSkuDetails();
Toast.makeText(this, R.string.restored_previous_purchases, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.restored_previous_purchases, Toast.LENGTH_SHORT).show()
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (!billingProcessor!!.handleActivityResult(requestCode, resultCode, data)) { if (!billingProcessor!!.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
} }
if (requestCode == TEZ_REQUEST_CODE) { if (requestCode == TEZ_REQUEST_CODE) {
// Process based on the data in response. // Process based on the data in response.
Log.d("result", data!!.getStringExtra("Status")) Log.d("result", data!!.getStringExtra("Status"))
} }
} }
override fun onDestroy() { override fun onDestroy() {
if (billingProcessor != null) { if (billingProcessor != null) {
billingProcessor!!.release() billingProcessor!!.release()
} }
if (skuDetailsLoadAsyncTask != null) { if (skuDetailsLoadAsyncTask != null) {
skuDetailsLoadAsyncTask!!.cancel(true) skuDetailsLoadAsyncTask!!.cancel(true)
} }
super.onDestroy() super.onDestroy()
} }
} }
private class SkuDetailsLoadAsyncTask internal constructor(supportDevelopmentActivity: SupportDevelopmentActivity) : AsyncTask<Void, Void, List<SkuDetails>>() { private class SkuDetailsLoadAsyncTask internal constructor(supportDevelopmentActivity: SupportDevelopmentActivity) : AsyncTask<Void, Void, List<SkuDetails>>() {
private val weakReference: WeakReference<SupportDevelopmentActivity> = WeakReference(supportDevelopmentActivity) private val weakReference: WeakReference<SupportDevelopmentActivity> = WeakReference(
supportDevelopmentActivity
)
override fun onPreExecute() { override fun onPreExecute() {
super.onPreExecute() super.onPreExecute()
val supportDevelopmentActivity = weakReference.get() ?: return val supportDevelopmentActivity = weakReference.get() ?: return
supportDevelopmentActivity.progressContainer.visibility = View.VISIBLE supportDevelopmentActivity.progressContainer.visibility = View.VISIBLE
supportDevelopmentActivity.recyclerView.visibility = View.GONE supportDevelopmentActivity.recyclerView.visibility = View.GONE
} }
override fun doInBackground(vararg params: Void): List<SkuDetails>? { override fun doInBackground(vararg params: Void): List<SkuDetails>? {
val dialog = weakReference.get() val dialog = weakReference.get()
if (dialog != null) { if (dialog != null) {
val ids = dialog.resources.getStringArray(SupportDevelopmentActivity.DONATION_PRODUCT_IDS) val ids = dialog.resources.getStringArray(SupportDevelopmentActivity.DONATION_PRODUCT_IDS)
return dialog.billingProcessor!!.getPurchaseListingDetails(ArrayList(Arrays.asList(*ids))) return dialog.billingProcessor!!.getPurchaseListingDetails(ArrayList(Arrays.asList(*ids)))
} }
cancel(false) cancel(false)
return null return null
} }
override fun onPostExecute(skuDetails: List<SkuDetails>?) { override fun onPostExecute(skuDetails: List<SkuDetails>?) {
super.onPostExecute(skuDetails) super.onPostExecute(skuDetails)
val dialog = weakReference.get() ?: return val dialog = weakReference.get() ?: return
if (skuDetails == null || skuDetails.isEmpty()) { if (skuDetails == null || skuDetails.isEmpty()) {
dialog.progressContainer.visibility = View.GONE dialog.progressContainer.visibility = View.GONE
return return
} }
dialog.progressContainer.visibility = View.GONE dialog.progressContainer.visibility = View.GONE
dialog.recyclerView.itemAnimator = DefaultItemAnimator() dialog.recyclerView.itemAnimator = DefaultItemAnimator()
dialog.recyclerView.layoutManager = GridLayoutManager(dialog, 2) dialog.recyclerView.layoutManager = GridLayoutManager(dialog, 2)
dialog.recyclerView.adapter = SkuDetailsAdapter(dialog, skuDetails) dialog.recyclerView.adapter = SkuDetailsAdapter(dialog, skuDetails)
dialog.recyclerView.visibility = View.VISIBLE dialog.recyclerView.visibility = View.VISIBLE
} }
} }
class SkuDetailsAdapter( class SkuDetailsAdapter(
private var donationsDialog: SupportDevelopmentActivity, private var donationsDialog: SupportDevelopmentActivity, objects: List<SkuDetails>
objects: List<SkuDetails>
) : RecyclerView.Adapter<SkuDetailsAdapter.ViewHolder>() { ) : RecyclerView.Adapter<SkuDetailsAdapter.ViewHolder>() {
private var skuDetailsList: List<SkuDetails> = ArrayList() private var skuDetailsList: List<SkuDetails> = ArrayList()
init { init {
skuDetailsList = objects skuDetailsList = objects
} }
private fun getIcon(position: Int): Int { private fun getIcon(position: Int): Int {
return when (position) { return when (position) {
0 -> R.drawable.ic_cookie_white_24dp 0 -> R.drawable.ic_cookie_white_24dp
1 -> R.drawable.ic_take_away_white_24dp 1 -> R.drawable.ic_take_away_white_24dp
2 -> R.drawable.ic_take_away_coffe_white_24dp 2 -> R.drawable.ic_take_away_coffe_white_24dp
3 -> R.drawable.ic_beer_white_24dp 3 -> R.drawable.ic_beer_white_24dp
4 -> R.drawable.ic_fast_food_meal_white_24dp 4 -> R.drawable.ic_fast_food_meal_white_24dp
5 -> R.drawable.ic_popcorn_white_24dp 5 -> R.drawable.ic_popcorn_white_24dp
6 -> R.drawable.ic_card_giftcard_white_24dp 6 -> R.drawable.ic_card_giftcard_white_24dp
else -> R.drawable.ic_card_giftcard_white_24dp else -> R.drawable.ic_card_giftcard_white_24dp
} }
} }
override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder { override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(donationsDialog).inflate(LAYOUT_RES_ID, viewGroup, false)) return ViewHolder(
} LayoutInflater.from(donationsDialog).inflate(
LAYOUT_RES_ID,
viewGroup,
false
)
)
}
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
val skuDetails = skuDetailsList[i] val skuDetails = skuDetailsList[i]
viewHolder.title.text = skuDetails.title.replace("(Retro Music Player)", "").trim { it <= ' ' } viewHolder.title.text = skuDetails.title.replace("(Retro Music Player)", "")
viewHolder.text.text = skuDetails.description .trim { it <= ' ' }
viewHolder.text.visibility = View.GONE viewHolder.text.text = skuDetails.description
viewHolder.price.text = skuDetails.priceText viewHolder.text.visibility = View.GONE
viewHolder.image.setImageResource(getIcon(i)) viewHolder.price.text = skuDetails.priceText
viewHolder.image.setImageResource(getIcon(i))
val purchased = donationsDialog.billingProcessor!!.isPurchased(skuDetails.productId) val purchased = donationsDialog.billingProcessor!!.isPurchased(skuDetails.productId)
val titleTextColor = if (purchased) ATHUtil.resolveColor(donationsDialog, android.R.attr.textColorHint) else ThemeStore.textColorPrimary(donationsDialog) val titleTextColor = if (purchased) ATHUtil.resolveColor(
val contentTextColor = if (purchased) titleTextColor else ThemeStore.textColorSecondary(donationsDialog) donationsDialog,
android.R.attr.textColorHint
) else ThemeStore.textColorPrimary(donationsDialog)
val contentTextColor = if (purchased) titleTextColor else ThemeStore.textColorSecondary(
donationsDialog
)
viewHolder.title.setTextColor(titleTextColor) viewHolder.title.setTextColor(titleTextColor)
viewHolder.text.setTextColor(contentTextColor) viewHolder.text.setTextColor(contentTextColor)
viewHolder.price.setTextColor(titleTextColor) viewHolder.price.setTextColor(titleTextColor)
strikeThrough(viewHolder.title, purchased) strikeThrough(viewHolder.title, purchased)
strikeThrough(viewHolder.text, purchased) strikeThrough(viewHolder.text, purchased)
strikeThrough(viewHolder.price, purchased) strikeThrough(viewHolder.price, purchased)
viewHolder.itemView.setOnTouchListener { _, _ -> purchased } viewHolder.itemView.setOnTouchListener { _, _ -> purchased }
viewHolder.itemView.setOnClickListener { donationsDialog.donate(i) } viewHolder.itemView.setOnClickListener { donationsDialog.donate(i) }
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
return skuDetailsList.size return skuDetailsList.size
} }
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var title: TextView = view.findViewById(R.id.itemTitle) var title: TextView = view.findViewById(R.id.itemTitle)
var text: TextView = view.findViewById(R.id.itemText) var text: TextView = view.findViewById(R.id.itemText)
var price: TextView = view.findViewById(R.id.itemPrice) var price: TextView = view.findViewById(R.id.itemPrice)
var image: AppCompatImageView = view.findViewById(R.id.itemImage) var image: AppCompatImageView = view.findViewById(R.id.itemImage)
} }
companion object { companion object {
@LayoutRes @LayoutRes
private val LAYOUT_RES_ID = R.layout.item_donation_option private val LAYOUT_RES_ID = R.layout.item_donation_option
private fun strikeThrough(textView: TextView, strikeThrough: Boolean) { private fun strikeThrough(textView: TextView, strikeThrough: Boolean) {
textView.paintFlags = if (strikeThrough) textView.paintFlags = if (strikeThrough) textView.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
textView.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG else textView.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
else }
textView.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv() }
}
}
} }

View file

@ -1,10 +1,7 @@
package code.name.monkey.retromusic.activities package code.name.monkey.retromusic.activities
import android.app.Activity import android.app.Activity
import android.content.ContentUris import android.content.*
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Bitmap import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
@ -16,275 +13,298 @@ import android.text.TextUtils
import android.view.MenuItem import android.view.MenuItem
import android.widget.Toast import android.widget.Toast
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.retromusic.*
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.Constants.USER_BANNER import code.name.monkey.retromusic.Constants.USER_BANNER
import code.name.monkey.retromusic.Constants.USER_PROFILE import code.name.monkey.retromusic.Constants.USER_PROFILE
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.extensions.applyToolbar import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.util.Compressor import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.ImageUtil.getResizedBitmap import code.name.monkey.retromusic.util.ImageUtil.getResizedBitmap
import code.name.monkey.retromusic.util.PreferenceUtil import com.afollestad.materialdialogs.*
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.list.listItems import com.afollestad.materialdialogs.list.listItems
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.activity_user_info.* import kotlinx.android.synthetic.main.activity_user_info.*
import java.io.File import java.io.*
import java.io.FileOutputStream
import java.io.IOException
class UserInfoActivity : AbsBaseActivity() { class UserInfoActivity : AbsBaseActivity() {
private var disposable = CompositeDisposable() private var disposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user_info) setContentView(R.layout.activity_user_info)
setStatusbarColorAuto() setStatusbarColorAuto()
setNavigationBarColorPrimary() setNavigationBarColorPrimary()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
setLightNavigationBar(true) setLightNavigationBar(true)
setupToolbar() setupToolbar()
MaterialUtil.setTint(nameContainer, false) MaterialUtil.setTint(nameContainer, false)
name.setText(PreferenceUtil.getInstance(this).userName) name.setText(PreferenceUtil.getInstance(this).userName)
if (PreferenceUtil.getInstance(this).profileImage.isNotEmpty()) { if (PreferenceUtil.getInstance(this).profileImage.isNotEmpty()) {
loadImageFromStorage(PreferenceUtil.getInstance(this).profileImage) loadImageFromStorage(PreferenceUtil.getInstance(this).profileImage)
} }
if (PreferenceUtil.getInstance(this).bannerImage.isNotEmpty()) { if (PreferenceUtil.getInstance(this).bannerImage.isNotEmpty()) {
loadBannerFromStorage(PreferenceUtil.getInstance(this).bannerImage) loadBannerFromStorage(PreferenceUtil.getInstance(this).bannerImage)
} }
userImage.setOnClickListener { userImage.setOnClickListener {
MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show { MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(text = getString(R.string.set_photo)) title(text = getString(R.string.set_photo))
listItems(items = listOf(getString(R.string.new_profile_photo), getString(R.string.remove_profile_photo))) { _, position, _ -> listItems(
when (position) { items = listOf(
0 -> pickNewPhoto() getString(R.string.new_profile_photo),
1 -> PreferenceUtil.getInstance(this@UserInfoActivity).saveProfileImage("") getString(R.string.remove_profile_photo)
} )
} ) { _, position, _ ->
} when (position) {
} 0 -> pickNewPhoto()
bannerSelect.setOnClickListener { 1 -> PreferenceUtil.getInstance(this@UserInfoActivity).saveProfileImage("")
showBannerOptions() }
} }
next.setOnClickListener { }
val nameString = name.text.toString().trim { it <= ' ' } }
if (TextUtils.isEmpty(nameString)) { bannerSelect.setOnClickListener {
Toast.makeText(this, "Umm name is empty", Toast.LENGTH_SHORT).show() showBannerOptions()
return@setOnClickListener }
} next.setOnClickListener {
/*val bioString = bio.text.toString().trim() { it <= ' ' } val nameString = name.text.toString().trim { it <= ' ' }
if (TextUtils.isEmpty(bioString)) { if (TextUtils.isEmpty(nameString)) {
Toast.makeText(this, "Umm bio is empty", Toast.LENGTH_SHORT).show() Toast.makeText(this, "Umm name is empty", Toast.LENGTH_SHORT).show()
return@setOnClickListener return@setOnClickListener
}
/*val bioString = bio.text.toString().trim() { it <= ' ' }
if (TextUtils.isEmpty(bioString)) {
Toast.makeText(this, "Umm bio is empty", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}*/ }*/
PreferenceUtil.getInstance(this).userName = nameString PreferenceUtil.getInstance(this).userName = nameString
//PreferenceUtil.getInstance().userBio = bioString //PreferenceUtil.getInstance().userBio = bioString
setResult(Activity.RESULT_OK) setResult(Activity.RESULT_OK)
finish() finish()
} }
next.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this)) next.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
ColorStateList.valueOf(MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.accentColor(this)))).apply { ColorStateList.valueOf(
next.setTextColor(this) MaterialValueHelper.getPrimaryTextColor(
next.iconTint = this this,
} ColorUtil.isColorLight(
} ThemeStore.accentColor(
this
)
)
)
).apply {
next.setTextColor(this)
next.iconTint = this
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) { if (item.itemId == android.R.id.home) {
onBackPressed() onBackPressed()
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
private fun setupToolbar() { private fun setupToolbar() {
val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary) val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary)
applyToolbar(toolbar) applyToolbar(toolbar)
appBarLayout.setBackgroundColor(primaryColor) appBarLayout.setBackgroundColor(primaryColor)
} }
private fun showBannerOptions() { private fun showBannerOptions() {
MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show { MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(R.string.select_banner_photo) title(R.string.select_banner_photo)
listItems(items = listOf(getString(R.string.new_banner_photo), getString(R.string.remove_banner_photo))) listItems(
{ _, position, _ -> items = listOf(
when (position) { getString(R.string.new_banner_photo),
0 -> selectBannerImage() getString(R.string.remove_banner_photo)
1 -> PreferenceUtil.getInstance(this@UserInfoActivity).setBannerImagePath("") )
} ) { _, position, _ ->
} when (position) {
} 0 -> selectBannerImage()
} 1 -> PreferenceUtil.getInstance(this@UserInfoActivity).setBannerImagePath("")
}
}
}
}
private fun selectBannerImage() { private fun selectBannerImage() {
if (TextUtils.isEmpty(PreferenceUtil.getInstance(this).bannerImage)) { if (TextUtils.isEmpty(PreferenceUtil.getInstance(this).bannerImage)) {
val pickImageIntent = Intent(Intent.ACTION_PICK, Media.EXTERNAL_CONTENT_URI) val pickImageIntent = Intent(Intent.ACTION_PICK, Media.EXTERNAL_CONTENT_URI)
pickImageIntent.type = "image/*" pickImageIntent.type = "image/*"
//pickImageIntent.putExtra("crop", "true") //pickImageIntent.putExtra("crop", "true")
pickImageIntent.putExtra("outputX", 1290) pickImageIntent.putExtra("outputX", 1290)
pickImageIntent.putExtra("outputY", 720) pickImageIntent.putExtra("outputY", 720)
pickImageIntent.putExtra("aspectX", 16) pickImageIntent.putExtra("aspectX", 16)
pickImageIntent.putExtra("aspectY", 9) pickImageIntent.putExtra("aspectY", 9)
pickImageIntent.putExtra("scale", true) pickImageIntent.putExtra("scale", true)
//intent.setAction(Intent.ACTION_GET_CONTENT); //intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(pickImageIntent, "Select Picture"), PICK_BANNER_REQUEST) startActivityForResult(
} else { Intent.createChooser(pickImageIntent, "Select Picture"),
PreferenceUtil.getInstance(this).setBannerImagePath("") PICK_BANNER_REQUEST
bannerImage.setImageResource(android.R.color.transparent) )
} } else {
} PreferenceUtil.getInstance(this).setBannerImagePath("")
bannerImage.setImageResource(android.R.color.transparent)
}
}
private fun pickNewPhoto() {
val pickImageIntent = Intent(Intent.ACTION_PICK, Media.EXTERNAL_CONTENT_URI)
pickImageIntent.type = "image/*"
pickImageIntent.putExtra("crop", "true")
pickImageIntent.putExtra("outputX", 512)
pickImageIntent.putExtra("outputY", 512)
pickImageIntent.putExtra("aspectX", 1)
pickImageIntent.putExtra("aspectY", 1)
pickImageIntent.putExtra("scale", true)
startActivityForResult(
Intent.createChooser(pickImageIntent, "Select Picture"),
PICK_IMAGE_REQUEST
)
}
private fun pickNewPhoto() { public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val pickImageIntent = Intent(Intent.ACTION_PICK, Media.EXTERNAL_CONTENT_URI) super.onActivityResult(requestCode, resultCode, data)
pickImageIntent.type = "image/*" if (resultCode == Activity.RESULT_OK && data != null) {
pickImageIntent.putExtra("crop", "true") when (requestCode) {
pickImageIntent.putExtra("outputX", 512) PICK_IMAGE_REQUEST -> {
pickImageIntent.putExtra("outputY", 512) try {
pickImageIntent.putExtra("aspectX", 1) data.data?.let {
pickImageIntent.putExtra("aspectY", 1) val bitmap = getResizedBitmap(
pickImageIntent.putExtra("scale", true) getBitmap(contentResolver, it),
startActivityForResult(Intent.createChooser(pickImageIntent, "Select Picture"), PICK_IMAGE_REQUEST) PROFILE_ICON_SIZE
} )
val profileImagePath = saveToInternalStorage(bitmap, USER_PROFILE)
PreferenceUtil.getInstance(this).saveProfileImage(profileImagePath)
loadImageFromStorage(profileImagePath)
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { } catch (e: IOException) {
super.onActivityResult(requestCode, resultCode, data) e.printStackTrace()
if (resultCode == Activity.RESULT_OK && data != null) { }
when (requestCode) { }
PICK_IMAGE_REQUEST -> { PICK_BANNER_REQUEST -> {
try { try {
data.data?.let { data.data?.let {
val bitmap = getResizedBitmap(getBitmap(contentResolver, it), PROFILE_ICON_SIZE) val bitmap = getBitmap(contentResolver, it)
val profileImagePath = saveToInternalStorage(bitmap, USER_PROFILE) val profileImagePath = saveToInternalStorage(bitmap, USER_BANNER)
PreferenceUtil.getInstance(this).saveProfileImage(profileImagePath) PreferenceUtil.getInstance(this).setBannerImagePath(profileImagePath)
loadImageFromStorage(profileImagePath) loadBannerFromStorage(profileImagePath)
} }
} catch (e: IOException) {
e.printStackTrace()
}
}
}
}
}
} catch (e: IOException) { private fun getImagePathFromUri(aUri: Uri?): String? {
e.printStackTrace() var imagePath: String? = null
} if (aUri == null) {
} return imagePath
PICK_BANNER_REQUEST -> { }
try { if (DocumentsContract.isDocumentUri(App.getContext(), aUri)) {
data.data?.let { val documentId = DocumentsContract.getDocumentId(aUri)
val bitmap = getBitmap(contentResolver, it) if ("com.android.providers.media.documents" == aUri.authority) {
val profileImagePath = saveToInternalStorage(bitmap, USER_BANNER) val id = documentId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]
PreferenceUtil.getInstance(this).setBannerImagePath(profileImagePath) val selection = Media._ID + "=" + id
loadBannerFromStorage(profileImagePath) imagePath = getImagePath(Media.EXTERNAL_CONTENT_URI, selection)
} } else if ("com.android.providers.downloads.documents" == aUri.authority) {
} catch (e: IOException) { val contentUri = ContentUris.withAppendedId(
e.printStackTrace() Uri.parse("content://downloads/public_downloads"),
} java.lang.Long.valueOf(documentId)
} )
} imagePath = getImagePath(contentUri, null)
} }
} } else if ("content".equals(aUri.scheme!!, ignoreCase = true)) {
imagePath = getImagePath(aUri, null)
} else if ("file".equals(aUri.scheme!!, ignoreCase = true)) {
imagePath = aUri.path
}
return imagePath
}
private fun getImagePath(aUri: Uri, aSelection: String?): String? {
var path: String? = null
val cursor = App.getContext().contentResolver.query(aUri, null, aSelection, null, null)
if (cursor != null) {
if (cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(Media.DATA))
}
cursor.close()
}
return path
}
private fun getImagePathFromUri(aUri: Uri?): String? { private fun loadBannerFromStorage(profileImagePath: String) {
var imagePath: String? = null disposable.add(
if (aUri == null) { Compressor(this).setQuality(100).setCompressFormat(Bitmap.CompressFormat.WEBP).compressToBitmapAsFlowable(
return imagePath File(profileImagePath, USER_BANNER)
} ).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
if (DocumentsContract.isDocumentUri(App.getContext(), aUri)) { { bitmap -> bannerImage.setImageBitmap(bitmap) },
val documentId = DocumentsContract.getDocumentId(aUri) { t -> println() })
if ("com.android.providers.media.documents" == aUri.authority) { )
val id = documentId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1] }
val selection = Media._ID + "=" + id
imagePath = getImagePath(Media.EXTERNAL_CONTENT_URI, selection)
} else if ("com.android.providers.downloads.documents" == aUri.authority) {
val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
java.lang.Long.valueOf(documentId))
imagePath = getImagePath(contentUri, null)
}
} else if ("content".equals(aUri.scheme!!, ignoreCase = true)) {
imagePath = getImagePath(aUri, null)
} else if ("file".equals(aUri.scheme!!, ignoreCase = true)) {
imagePath = aUri.path
}
return imagePath
}
private fun getImagePath(aUri: Uri, aSelection: String?): String? { private fun loadImageFromStorage(path: String) {
var path: String? = null disposable.add(
val cursor = App.getContext().contentResolver.query(aUri, null, aSelection, null, null) Compressor(this).setMaxHeight(300).setMaxWidth(300).setQuality(75).setCompressFormat(
if (cursor != null) { Bitmap.CompressFormat.WEBP
if (cursor.moveToFirst()) { ).compressToBitmapAsFlowable(
path = cursor.getString(cursor.getColumnIndex(Media.DATA)) File(
} path,
cursor.close() USER_PROFILE
} )
return path ).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
} { bitmap -> userImage!!.setImageBitmap(bitmap) },
{ t -> println() })
)
}
private fun loadBannerFromStorage(profileImagePath: String) { private fun saveToInternalStorage(bitmapImage: Bitmap, userBanner: String): String {
disposable.add(Compressor(this) val cw = ContextWrapper(this)
.setQuality(100) val directory = cw.getDir("imageDir", Context.MODE_PRIVATE)
.setCompressFormat(Bitmap.CompressFormat.WEBP) val myPath = File(directory, userBanner)
.compressToBitmapAsFlowable(File(profileImagePath, USER_BANNER)) var fos: FileOutputStream? = null
.subscribeOn(Schedulers.io()) try {
.observeOn(AndroidSchedulers.mainThread()) fos = FileOutputStream(myPath)
.subscribe({ bitmap -> bannerImage.setImageBitmap(bitmap) }, { t -> println() })) // Use the compress method on the BitMap object to write image to the OutputStream
} bitmapImage.compress(Bitmap.CompressFormat.WEBP, 100, fos)
} catch (e: Exception) {
e.printStackTrace()
} finally {
try {
fos?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return directory.absolutePath
}
private fun loadImageFromStorage(path: String) { companion object {
disposable.add(Compressor(this)
.setMaxHeight(300)
.setMaxWidth(300)
.setQuality(75)
.setCompressFormat(Bitmap.CompressFormat.WEBP)
.compressToBitmapAsFlowable(File(path, USER_PROFILE))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ bitmap -> userImage!!.setImageBitmap(bitmap) }, { t -> println() }))
}
private fun saveToInternalStorage(bitmapImage: Bitmap, userBanner: String): String { private const val PICK_IMAGE_REQUEST = 9002
val cw = ContextWrapper(this) private const val PICK_BANNER_REQUEST = 9004
val directory = cw.getDir("imageDir", Context.MODE_PRIVATE) private const val PROFILE_ICON_SIZE = 400
val myPath = File(directory, userBanner) }
var fos: FileOutputStream? = null
try {
fos = FileOutputStream(myPath)
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.WEBP, 100, fos)
} catch (e: Exception) {
e.printStackTrace()
} finally {
try {
fos?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
return directory.absolutePath
}
companion object {
private const val PICK_IMAGE_REQUEST = 9002
private const val PICK_BANNER_REQUEST = 9004
private const val PROFILE_ICON_SIZE = 400
}
} }
fun Activity.pickImage(requestCode: Int) { fun Activity.pickImage(requestCode: Int) {
Intent(Intent.ACTION_GET_CONTENT).apply { Intent(Intent.ACTION_GET_CONTENT).apply {
addCategory(Intent.CATEGORY_OPENABLE) addCategory(Intent.CATEGORY_OPENABLE)
type = "image/*" type = "image/*"
startActivityForResult(this, requestCode) startActivityForResult(this, requestCode)
} }
} }

View file

@ -5,134 +5,139 @@ import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.media.AudioManager import android.media.AudioManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.*
import android.os.Bundle
import android.provider.Settings import android.provider.Settings
import android.view.KeyEvent import android.view.*
import android.view.View
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
abstract class AbsBaseActivity : AbsThemeActivity() { abstract class AbsBaseActivity : AbsThemeActivity() {
private var hadPermissions: Boolean = false private var hadPermissions: Boolean = false
private lateinit var permissions: Array<String> private lateinit var permissions: Array<String>
private var permissionDeniedMessage: String? = null private var permissionDeniedMessage: String? = null
open fun getPermissionsToRequest(): Array<String> {
return arrayOf()
}
open fun getPermissionsToRequest(): Array<String> { protected fun setPermissionDeniedMessage(message: String) {
return arrayOf() permissionDeniedMessage = message
} }
protected fun setPermissionDeniedMessage(message: String) { fun getPermissionDeniedMessage(): String {
permissionDeniedMessage = message return if (permissionDeniedMessage == null) getString(code.name.monkey.retromusic.R.string.permissions_denied) else permissionDeniedMessage!!
} }
fun getPermissionDeniedMessage(): String { private val snackBarContainer: View
return if (permissionDeniedMessage == null) getString(code.name.monkey.retromusic.R.string.permissions_denied) else permissionDeniedMessage!! get() = window.decorView
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
volumeControlStream = AudioManager.STREAM_MUSIC
permissions = getPermissionsToRequest()
hadPermissions = hasPermissions()
permissionDeniedMessage = null
}
private val snackBarContainer: View override fun onPostCreate(savedInstanceState: Bundle?) {
get() = window.decorView super.onPostCreate(savedInstanceState)
if (!hasPermissions()) {
requestPermissions()
}
}
override fun onResume() {
super.onResume()
val hasPermissions = hasPermissions()
if (hasPermissions != hadPermissions) {
hadPermissions = hasPermissions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
onHasPermissionsChanged(hasPermissions)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) { protected open fun onHasPermissionsChanged(hasPermissions: Boolean) {
super.onCreate(savedInstanceState) // implemented by sub classes
volumeControlStream = AudioManager.STREAM_MUSIC }
permissions = getPermissionsToRequest()
hadPermissions = hasPermissions()
permissionDeniedMessage = null
}
override fun onPostCreate(savedInstanceState: Bundle?) { override fun dispatchKeyEvent(event: KeyEvent): Boolean {
super.onPostCreate(savedInstanceState) if (event.keyCode == KeyEvent.KEYCODE_MENU && event.action == KeyEvent.ACTION_UP) {
if (!hasPermissions()) { showOverflowMenu()
requestPermissions() return true
} }
} return super.dispatchKeyEvent(event)
}
override fun onResume() { protected fun showOverflowMenu() {
super.onResume()
val hasPermissions = hasPermissions()
if (hasPermissions != hadPermissions) {
hadPermissions = hasPermissions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
onHasPermissionsChanged(hasPermissions)
}
}
}
protected open fun onHasPermissionsChanged(hasPermissions: Boolean) { }
// implemented by sub classes
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean { protected open fun requestPermissions() {
if (event.keyCode == KeyEvent.KEYCODE_MENU && event.action == KeyEvent.ACTION_UP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
showOverflowMenu() requestPermissions(permissions, PERMISSION_REQUEST)
return true }
} }
return super.dispatchKeyEvent(event)
}
protected fun showOverflowMenu() { protected fun hasPermissions(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (permission in permissions) {
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
return false
}
}
}
return true
}
} override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_REQUEST) {
for (grantResult in grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this@AbsBaseActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE
)) {
//User has deny from permission dialog
Snackbar.make(
snackBarContainer,
permissionDeniedMessage!!,
Snackbar.LENGTH_INDEFINITE
)
.setAction(code.name.monkey.retromusic.R.string.action_grant) { requestPermissions() }
.setActionTextColor(ThemeStore.accentColor(this)).show()
} else {
// User has deny permission and checked never show permission dialog so you can redirect to Application settings page
Snackbar.make(
snackBarContainer,
permissionDeniedMessage!!,
Snackbar.LENGTH_INDEFINITE
).setAction(code.name.monkey.retromusic.R.string.action_settings) {
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts(
"package",
this@AbsBaseActivity.packageName,
null
)
intent.data = uri
startActivity(intent)
}.setActionTextColor(ThemeStore.accentColor(this)).show()
}
return
}
}
hadPermissions = true
onHasPermissionsChanged(true)
}
}
protected open fun requestPermissions() { companion object {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { const val PERMISSION_REQUEST = 100
requestPermissions(permissions, PERMISSION_REQUEST) }
}
}
protected fun hasPermissions(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (permission in permissions) {
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
return false
}
}
}
return true
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_REQUEST) {
for (grantResult in grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this@AbsBaseActivity,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
//User has deny from permission dialog
Snackbar.make(snackBarContainer, permissionDeniedMessage!!,
Snackbar.LENGTH_INDEFINITE)
.setAction(code.name.monkey.retromusic.R.string.action_grant) { requestPermissions() }
.setActionTextColor(ThemeStore.accentColor(this))
.show()
} else {
// User has deny permission and checked never show permission dialog so you can redirect to Application settings page
Snackbar.make(snackBarContainer, permissionDeniedMessage!!,
Snackbar.LENGTH_INDEFINITE)
.setAction(code.name.monkey.retromusic.R.string.action_settings) {
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts("package", this@AbsBaseActivity.packageName, null)
intent.data = uri
startActivity(intent)
}
.setActionTextColor(ThemeStore.accentColor(this))
.show()
}
return
}
}
hadPermissions = true
onHasPermissionsChanged(true)
}
}
companion object {
const val PERMISSION_REQUEST = 100
}
} }

View file

@ -1,12 +0,0 @@
package code.name.monkey.retromusic.activities.base
import android.os.Bundle
import code.name.monkey.appthemehelper.ATHActivity
import code.name.monkey.retromusic.helper.TopExceptionHandler
abstract class AbsCrashCollector : ATHActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Thread.setDefaultUncaughtExceptionHandler(TopExceptionHandler())
}
}

View file

@ -2,8 +2,7 @@ package code.name.monkey.retromusic.activities.base
import android.Manifest import android.Manifest
import android.content.* import android.content.*
import android.os.Bundle import android.os.*
import android.os.IBinder
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.MusicServiceEventListener import code.name.monkey.retromusic.interfaces.MusicServiceEventListener
@ -11,155 +10,158 @@ import code.name.monkey.retromusic.service.MusicService.*
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.* import java.util.*
abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener { abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener {
private val mMusicServiceEventListeners = ArrayList<MusicServiceEventListener>() private val mMusicServiceEventListeners = ArrayList<MusicServiceEventListener>()
private var serviceToken: MusicPlayerRemote.ServiceToken? = null private var serviceToken: MusicPlayerRemote.ServiceToken? = null
private var musicStateReceiver: MusicStateReceiver? = null private var musicStateReceiver: MusicStateReceiver? = null
private var receiverRegistered: Boolean = false private var receiverRegistered: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
serviceToken = MusicPlayerRemote.bindToService(this, object : ServiceConnection { serviceToken = MusicPlayerRemote.bindToService(this, object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) { override fun onServiceConnected(name: ComponentName, service: IBinder) {
this@AbsMusicServiceActivity.onServiceConnected() this@AbsMusicServiceActivity.onServiceConnected()
} }
override fun onServiceDisconnected(name: ComponentName) { override fun onServiceDisconnected(name: ComponentName) {
this@AbsMusicServiceActivity.onServiceDisconnected() this@AbsMusicServiceActivity.onServiceDisconnected()
} }
}) })
setPermissionDeniedMessage(getString(R.string.permission_external_storage_denied)); setPermissionDeniedMessage(getString(R.string.permission_external_storage_denied));
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
MusicPlayerRemote.unbindFromService(serviceToken) MusicPlayerRemote.unbindFromService(serviceToken)
if (receiverRegistered) { if (receiverRegistered) {
unregisterReceiver(musicStateReceiver) unregisterReceiver(musicStateReceiver)
receiverRegistered = false receiverRegistered = false
} }
} }
fun addMusicServiceEventListener(listener: MusicServiceEventListener?) { fun addMusicServiceEventListener(listener: MusicServiceEventListener?) {
if (listener != null) { if (listener != null) {
mMusicServiceEventListeners.add(listener) mMusicServiceEventListeners.add(listener)
} }
} }
fun removeMusicServiceEventListener(listener: MusicServiceEventListener?) { fun removeMusicServiceEventListener(listener: MusicServiceEventListener?) {
if (listener != null) { if (listener != null) {
mMusicServiceEventListeners.remove(listener) mMusicServiceEventListeners.remove(listener)
} }
} }
override fun onServiceConnected() { override fun onServiceConnected() {
if (!receiverRegistered) { if (!receiverRegistered) {
musicStateReceiver = MusicStateReceiver(this) musicStateReceiver = MusicStateReceiver(this)
val filter = IntentFilter() val filter = IntentFilter()
filter.addAction(PLAY_STATE_CHANGED) filter.addAction(PLAY_STATE_CHANGED)
filter.addAction(SHUFFLE_MODE_CHANGED) filter.addAction(SHUFFLE_MODE_CHANGED)
filter.addAction(REPEAT_MODE_CHANGED) filter.addAction(REPEAT_MODE_CHANGED)
filter.addAction(META_CHANGED) filter.addAction(META_CHANGED)
filter.addAction(QUEUE_CHANGED) filter.addAction(QUEUE_CHANGED)
filter.addAction(MEDIA_STORE_CHANGED) filter.addAction(MEDIA_STORE_CHANGED)
filter.addAction(FAVORITE_STATE_CHANGED) filter.addAction(FAVORITE_STATE_CHANGED)
registerReceiver(musicStateReceiver, filter) registerReceiver(musicStateReceiver, filter)
receiverRegistered = true receiverRegistered = true
} }
for (listener in mMusicServiceEventListeners) { for (listener in mMusicServiceEventListeners) {
listener.onServiceConnected() listener.onServiceConnected()
} }
} }
override fun onServiceDisconnected() { override fun onServiceDisconnected() {
if (receiverRegistered) { if (receiverRegistered) {
unregisterReceiver(musicStateReceiver) unregisterReceiver(musicStateReceiver)
receiverRegistered = false receiverRegistered = false
} }
for (listener in mMusicServiceEventListeners) { for (listener in mMusicServiceEventListeners) {
listener.onServiceDisconnected() listener.onServiceDisconnected()
} }
} }
override fun onPlayingMetaChanged() { override fun onPlayingMetaChanged() {
for (listener in mMusicServiceEventListeners) { for (listener in mMusicServiceEventListeners) {
listener.onPlayingMetaChanged() listener.onPlayingMetaChanged()
} }
} }
override fun onQueueChanged() { override fun onQueueChanged() {
for (listener in mMusicServiceEventListeners) { for (listener in mMusicServiceEventListeners) {
listener.onQueueChanged() listener.onQueueChanged()
} }
} }
override fun onPlayStateChanged() { override fun onPlayStateChanged() {
for (listener in mMusicServiceEventListeners) { for (listener in mMusicServiceEventListeners) {
listener.onPlayStateChanged() listener.onPlayStateChanged()
} }
} }
override fun onMediaStoreChanged() { override fun onMediaStoreChanged() {
for (listener in mMusicServiceEventListeners) { for (listener in mMusicServiceEventListeners) {
listener.onMediaStoreChanged() listener.onMediaStoreChanged()
} }
} }
override fun onRepeatModeChanged() { override fun onRepeatModeChanged() {
for (listener in mMusicServiceEventListeners) { for (listener in mMusicServiceEventListeners) {
listener.onRepeatModeChanged() listener.onRepeatModeChanged()
} }
} }
override fun onShuffleModeChanged() { override fun onShuffleModeChanged() {
for (listener in mMusicServiceEventListeners) { for (listener in mMusicServiceEventListeners) {
listener.onShuffleModeChanged() listener.onShuffleModeChanged()
} }
} }
override fun onHasPermissionsChanged(hasPermissions: Boolean) { override fun onHasPermissionsChanged(hasPermissions: Boolean) {
super.onHasPermissionsChanged(hasPermissions) super.onHasPermissionsChanged(hasPermissions)
val intent = Intent(MEDIA_STORE_CHANGED) val intent = Intent(MEDIA_STORE_CHANGED)
intent.putExtra("from_permissions_changed", true) // just in case we need to know this at some point intent.putExtra(
sendBroadcast(intent) "from_permissions_changed",
} true
) // just in case we need to know this at some point
sendBroadcast(intent)
}
override fun getPermissionsToRequest(): Array<String> {
return arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
}
override fun getPermissionsToRequest(): Array<String> { private class MusicStateReceiver(activity: AbsMusicServiceActivity) : BroadcastReceiver() {
return arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
private class MusicStateReceiver(activity: AbsMusicServiceActivity) : BroadcastReceiver() { private val reference: WeakReference<AbsMusicServiceActivity> = WeakReference(activity)
private val reference: WeakReference<AbsMusicServiceActivity> = WeakReference(activity) override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
val activity = reference.get()
if (activity != null && action != null) {
when (action) {
FAVORITE_STATE_CHANGED, META_CHANGED -> activity.onPlayingMetaChanged()
QUEUE_CHANGED -> activity.onQueueChanged()
PLAY_STATE_CHANGED -> activity.onPlayStateChanged()
REPEAT_MODE_CHANGED -> activity.onRepeatModeChanged()
SHUFFLE_MODE_CHANGED -> activity.onShuffleModeChanged()
MEDIA_STORE_CHANGED -> activity.onMediaStoreChanged()
}
}
}
}
override fun onReceive(context: Context, intent: Intent) { companion object {
val action = intent.action val TAG: String = AbsMusicServiceActivity::class.java.simpleName
val activity = reference.get() }
if (activity != null && action != null) {
when (action) {
FAVORITE_STATE_CHANGED,
META_CHANGED -> activity.onPlayingMetaChanged()
QUEUE_CHANGED -> activity.onQueueChanged()
PLAY_STATE_CHANGED -> activity.onPlayStateChanged()
REPEAT_MODE_CHANGED -> activity.onRepeatModeChanged()
SHUFFLE_MODE_CHANGED -> activity.onShuffleModeChanged()
MEDIA_STORE_CHANGED -> activity.onMediaStoreChanged()
}
}
}
}
companion object {
val TAG: String = AbsMusicServiceActivity::class.java.simpleName
}
} }

View file

@ -2,22 +2,15 @@ package code.name.monkey.retromusic.activities.base
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.graphics.Color import android.graphics.*
import android.graphics.Rect
import android.os.Bundle import android.os.Bundle
import android.view.MotionEvent import android.view.*
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.fragments.*
import code.name.monkey.retromusic.fragments.MiniPlayerFragment
import code.name.monkey.retromusic.fragments.NowPlayingScreen
import code.name.monkey.retromusic.fragments.NowPlayingScreen.* import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.player.adaptive.AdaptiveFragment import code.name.monkey.retromusic.fragments.player.adaptive.AdaptiveFragment
@ -35,333 +28,330 @@ import code.name.monkey.retromusic.fragments.player.plain.PlainPlayerFragment
import code.name.monkey.retromusic.fragments.player.simple.SimplePlayerFragment import code.name.monkey.retromusic.fragments.player.simple.SimplePlayerFragment
import code.name.monkey.retromusic.fragments.player.tiny.TinyPlayerFragment import code.name.monkey.retromusic.fragments.player.tiny.TinyPlayerFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.DensityUtil import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.views.BottomNavigationBarTinted import code.name.monkey.retromusic.views.BottomNavigationBarTinted
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import kotlinx.android.synthetic.main.sliding_music_panel_layout.* import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlayerFragment.Callbacks { abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlayerFragment.Callbacks {
companion object { companion object {
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
} }
private lateinit var bottomSheetBehavior: BottomSheetBehavior<MaterialCardView> private lateinit var bottomSheetBehavior: BottomSheetBehavior<MaterialCardView>
private var miniPlayerFragment: MiniPlayerFragment? = null private var miniPlayerFragment: MiniPlayerFragment? = null
private var playerFragment: AbsPlayerFragment? = null private var playerFragment: AbsPlayerFragment? = null
private var currentNowPlayingScreen: NowPlayingScreen? = null private var currentNowPlayingScreen: NowPlayingScreen? = null
private var navigationBarColor: Int = 0 private var navigationBarColor: Int = 0
private var taskColor: Int = 0 private var taskColor: Int = 0
private var lightStatusBar: Boolean = false private var lightStatusBar: Boolean = false
private var lightNavigationBar: Boolean = false private var lightNavigationBar: Boolean = false
private var navigationBarColorAnimator: ValueAnimator? = null private var navigationBarColorAnimator: ValueAnimator? = null
protected abstract fun createContentView(): View protected abstract fun createContentView(): View
private val panelState: Int private val panelState: Int
get() = bottomSheetBehavior.state get() = bottomSheetBehavior.state
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() { private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) { override fun onSlide(bottomSheet: View, slideOffset: Float) {
setMiniPlayerAlphaProgress(slideOffset) setMiniPlayerAlphaProgress(slideOffset)
dimBackground.show() dimBackground.show()
dimBackground.alpha = slideOffset dimBackground.alpha = slideOffset
} }
override fun onStateChanged(bottomSheet: View, newState: Int) { override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) { when (newState) {
BottomSheetBehavior.STATE_EXPANDED -> { BottomSheetBehavior.STATE_EXPANDED -> {
onPanelExpanded() onPanelExpanded()
} }
BottomSheetBehavior.STATE_COLLAPSED -> { BottomSheetBehavior.STATE_COLLAPSED -> {
onPanelCollapsed() onPanelCollapsed()
dimBackground.hide() dimBackground.hide()
} }
else -> { else -> {
} }
} }
} }
} }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(createContentView())
chooseFragmentForTheme()
setupSlidingUpPanel()
updateTabs()
bottomSheetBehavior = BottomSheetBehavior.from(slidingPanel)
val themeColor = ATHUtil.resolveColor(this, R.attr.colorPrimary, Color.GRAY)
dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
}
override fun onResume() {
super.onResume()
if (currentNowPlayingScreen != PreferenceUtil.getInstance(this).nowPlayingScreen) {
postRecreate()
}
bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) {
setMiniPlayerAlphaProgress(1f)
}
}
override fun onDestroy() {
super.onDestroy()
bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList)
if (navigationBarColorAnimator != null) navigationBarColorAnimator!!.cancel() // just in case
}
protected fun wrapSlidingMusicPanel(@LayoutRes resId: Int): View {
@SuppressLint("InflateParams") val slidingMusicPanelLayout = layoutInflater.inflate(
R.layout.sliding_music_panel_layout, null
)
val contentContainer = slidingMusicPanelLayout.findViewById<ViewGroup>(R.id.mainContentFrame)
layoutInflater.inflate(resId, contentContainer)
return slidingMusicPanelLayout
}
private fun collapsePanel() {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
fun expandPanel() {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
setMiniPlayerAlphaProgress(1f)
}
private fun setMiniPlayerAlphaProgress(progress: Float) {
if (miniPlayerFragment?.view == null) return
val alpha = 1 - progress
miniPlayerFragment?.view?.alpha = alpha
// necessary to make the views below clickable
miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE
bottomNavigationView.translationY = progress * 500
bottomNavigationView.alpha = alpha
}
open fun onPanelCollapsed() {
// restore values
super.setLightStatusbar(lightStatusBar)
super.setTaskDescriptionColor(taskColor)
super.setNavigationbarColor(navigationBarColor)
super.setLightNavigationBar(lightNavigationBar)
override fun onCreate(savedInstanceState: Bundle?) { playerFragment?.setMenuVisibility(false)
super.onCreate(savedInstanceState) playerFragment?.userVisibleHint = false
setContentView(createContentView()) playerFragment?.onHide()
}
chooseFragmentForTheme() open fun onPanelExpanded() {
setupSlidingUpPanel() val playerFragmentColor = playerFragment!!.paletteColor
super.setTaskDescriptionColor(playerFragmentColor)
updateTabs() playerFragment?.setMenuVisibility(true)
playerFragment?.userVisibleHint = true
playerFragment?.onShow()
onPaletteColorChanged()
}
bottomSheetBehavior = BottomSheetBehavior.from(slidingPanel) private fun setupSlidingUpPanel() {
slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
if (currentNowPlayingScreen != PEAK) {
val params = slidingPanel.layoutParams as ViewGroup.LayoutParams
params.height = ViewGroup.LayoutParams.MATCH_PARENT
slidingPanel.layoutParams = params
}
when (panelState) {
BottomSheetBehavior.STATE_EXPANDED -> onPanelExpanded()
BottomSheetBehavior.STATE_COLLAPSED -> onPanelCollapsed()
else -> playerFragment!!.onHide()
}
}
})
}
val themeColor = ATHUtil.resolveColor(this, R.attr.colorPrimary, Color.GRAY) fun toggleBottomNavigationView(toggle: Boolean) {
dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f)) bottomNavigationView.visibility = if (toggle) View.GONE else View.VISIBLE
} }
override fun onResume() { fun getBottomNavigationView(): BottomNavigationBarTinted {
super.onResume() return bottomNavigationView
if (currentNowPlayingScreen != PreferenceUtil.getInstance(this).nowPlayingScreen) { }
postRecreate()
}
bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) { private fun hideBottomBar(hide: Boolean) {
setMiniPlayerAlphaProgress(1f) val heightOfBar = resources.getDimensionPixelSize(R.dimen.mini_player_height)
} val heightOfBarWithTabs = resources.getDimensionPixelSize(R.dimen.mini_player_height_expanded)
}
override fun onDestroy() { if (hide) {
super.onDestroy() bottomSheetBehavior.isHideable = true
bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList) bottomSheetBehavior.peekHeight = 0
if (navigationBarColorAnimator != null) navigationBarColorAnimator!!.cancel() // just in case collapsePanel()
} bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat()
} else {
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
slidingPanel.cardElevation = DensityUtil.dip2px(this, 10f).toFloat()
bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat()
bottomSheetBehavior.isHideable = false
bottomSheetBehavior.peekHeight = if (bottomNavigationView.visibility == View.VISIBLE) heightOfBarWithTabs else heightOfBar
}
}
}
fun setBottomBarVisibility(gone: Int) {
bottomNavigationView.visibility = gone
hideBottomBar(false)
}
protected fun wrapSlidingMusicPanel(@LayoutRes resId: Int): View { private fun chooseFragmentForTheme() {
@SuppressLint("InflateParams") currentNowPlayingScreen = PreferenceUtil.getInstance(this).nowPlayingScreen
val slidingMusicPanelLayout = layoutInflater.inflate(R.layout.sliding_music_panel_layout, null)
val contentContainer = slidingMusicPanelLayout.findViewById<ViewGroup>(R.id.mainContentFrame)
layoutInflater.inflate(resId, contentContainer)
return slidingMusicPanelLayout
}
private fun collapsePanel() { val fragment: Fragment = when (currentNowPlayingScreen) {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED BLUR -> BlurPlayerFragment()
} ADAPTIVE -> AdaptiveFragment()
NORMAL -> PlayerFragment()
CARD -> CardFragment()
BLUR_CARD -> CardBlurFragment()
FIT -> FitFragment()
FLAT -> FlatPlayerFragment()
FULL -> FullPlayerFragment()
PLAIN -> PlainPlayerFragment()
SIMPLE -> SimplePlayerFragment()
MATERIAL -> MaterialFragment()
COLOR -> ColorFragment()
TINY -> TinyPlayerFragment()
PEAK -> PeakPlayerFragment()
else -> PlayerFragment()
} // must implement AbsPlayerFragment
supportFragmentManager.beginTransaction().replace(R.id.playerFragmentContainer, fragment)
.commit()
supportFragmentManager.executePendingTransactions()
fun expandPanel() { playerFragment = supportFragmentManager.findFragmentById(R.id.playerFragmentContainer) as AbsPlayerFragment
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED miniPlayerFragment = supportFragmentManager.findFragmentById(R.id.miniPlayerFragment) as MiniPlayerFragment
setMiniPlayerAlphaProgress(1f) miniPlayerFragment?.view?.setOnClickListener { expandPanel() }
} }
private fun setMiniPlayerAlphaProgress(progress: Float) { override fun onServiceConnected() {
if (miniPlayerFragment?.view == null) return super.onServiceConnected()
val alpha = 1 - progress if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
miniPlayerFragment?.view?.alpha = alpha slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
// necessary to make the views below clickable override fun onGlobalLayout() {
miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
hideBottomBar(false)
}
})
} // don't call hideBottomBar(true) here as it causes a bug with the SlidingUpPanelLayout
}
bottomNavigationView.translationY = progress * 500 override fun onQueueChanged() {
bottomNavigationView.alpha = alpha super.onQueueChanged()
} hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
}
open fun onPanelCollapsed() { override fun onBackPressed() {
// restore values if (!handleBackPress()) super.onBackPressed()
super.setLightStatusbar(lightStatusBar) }
super.setTaskDescriptionColor(taskColor)
super.setNavigationbarColor(navigationBarColor)
super.setLightNavigationBar(lightNavigationBar)
open fun handleBackPress(): Boolean {
if (bottomSheetBehavior.peekHeight != 0 && playerFragment!!.onBackPressed()) return true
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
collapsePanel()
return true
}
return false
}
playerFragment?.setMenuVisibility(false) override fun onPaletteColorChanged() {
playerFragment?.userVisibleHint = false if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
playerFragment?.onHide() val paletteColor = playerFragment!!.paletteColor
} super.setTaskDescriptionColor(paletteColor)
open fun onPanelExpanded() { val isColorLight = ColorUtil.isColorLight(paletteColor)
val playerFragmentColor = playerFragment!!.paletteColor
super.setTaskDescriptionColor(playerFragmentColor)
playerFragment?.setMenuVisibility(true) if (PreferenceUtil.getInstance(this).adaptiveColor && (currentNowPlayingScreen == NORMAL || currentNowPlayingScreen == FLAT)) {
playerFragment?.userVisibleHint = true super.setLightNavigationBar(true)
playerFragment?.onShow() super.setLightStatusbar(isColorLight)
onPaletteColorChanged() } else if (currentNowPlayingScreen == FULL || currentNowPlayingScreen == CARD || currentNowPlayingScreen == FIT || currentNowPlayingScreen == BLUR || currentNowPlayingScreen == BLUR_CARD) {
} super.setLightStatusbar(false)
super.setLightNavigationBar(true)
} else if (currentNowPlayingScreen == COLOR || currentNowPlayingScreen == TINY) {
super.setNavigationbarColor(paletteColor)
super.setLightNavigationBar(isColorLight)
super.setLightStatusbar(isColorLight)
} else {
super.setLightStatusbar(
ColorUtil.isColorLight(
ATHUtil.resolveColor(
this, R.attr.colorPrimary
)
)
)
super.setLightNavigationBar(true)
}
}
}
private fun setupSlidingUpPanel() { override fun setLightStatusbar(enabled: Boolean) {
slidingPanel.viewTreeObserver lightStatusBar = enabled
.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
override fun onGlobalLayout() { super.setLightStatusbar(enabled)
slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this) }
if (currentNowPlayingScreen != PEAK) { }
val params = slidingPanel.layoutParams as ViewGroup.LayoutParams
params.height = ViewGroup.LayoutParams.MATCH_PARENT
slidingPanel.layoutParams = params
}
when (panelState) {
BottomSheetBehavior.STATE_EXPANDED -> {
onPanelExpanded()
}
BottomSheetBehavior.STATE_COLLAPSED -> onPanelCollapsed()
else -> playerFragment!!.onHide()
}
}
})
}
fun toggleBottomNavigationView(toggle: Boolean) { override fun setLightNavigationBar(enabled: Boolean) {
bottomNavigationView.visibility = if (toggle) View.GONE else View.VISIBLE lightNavigationBar = enabled
} if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
super.setLightNavigationBar(enabled)
}
}
fun getBottomNavigationView(): BottomNavigationBarTinted { override fun setNavigationbarColor(color: Int) {
return bottomNavigationView navigationBarColor = color
} if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
if (navigationBarColorAnimator != null) navigationBarColorAnimator!!.cancel()
super.setNavigationbarColor(color)
}
}
private fun hideBottomBar(hide: Boolean) { override fun setTaskDescriptionColor(color: Int) {
val heightOfBar = resources.getDimensionPixelSize(R.dimen.mini_player_height) taskColor = color
val heightOfBarWithTabs = resources.getDimensionPixelSize(R.dimen.mini_player_height_expanded) if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
super.setTaskDescriptionColor(color)
}
}
if (hide) { private fun updateTabs() {
bottomSheetBehavior.isHideable = true bottomNavigationView.menu.clear()
bottomSheetBehavior.peekHeight = 0 val currentTabs = PreferenceUtil.getInstance(this).libraryCategoryInfos
collapsePanel() for (tab in currentTabs) {
bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat() if (tab.visible) {
} else { val menu = tab.category
if (MusicPlayerRemote.playingQueue.isNotEmpty()) { bottomNavigationView.menu.add(
slidingPanel.cardElevation = DensityUtil.dip2px(this, 10f).toFloat() 0, menu.id, 0, menu.stringRes
bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat() ).setIcon(menu.icon)
bottomSheetBehavior.isHideable = false }
bottomSheetBehavior.peekHeight = if (bottomNavigationView.visibility == View.VISIBLE) heightOfBarWithTabs else heightOfBar }
} }
}
}
fun setBottomBarVisibility(gone: Int) { override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
bottomNavigationView.visibility = gone if (ev?.action == MotionEvent.ACTION_DOWN) {
hideBottomBar(false) if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
} val outRect = Rect()
slidingPanel.getGlobalVisibleRect(outRect)
private fun chooseFragmentForTheme() { if (!outRect.contains(ev.rawX.toInt(), ev.rawY.toInt())) {
currentNowPlayingScreen = PreferenceUtil.getInstance(this).nowPlayingScreen bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
val fragment: Fragment = when (currentNowPlayingScreen) { }
BLUR -> BlurPlayerFragment() }
ADAPTIVE -> AdaptiveFragment() return super.dispatchTouchEvent(ev)
NORMAL -> PlayerFragment() }
CARD -> CardFragment()
BLUR_CARD -> CardBlurFragment()
FIT -> FitFragment()
FLAT -> FlatPlayerFragment()
FULL -> FullPlayerFragment()
PLAIN -> PlainPlayerFragment()
SIMPLE -> SimplePlayerFragment()
MATERIAL -> MaterialFragment()
COLOR -> ColorFragment()
TINY -> TinyPlayerFragment()
PEAK -> PeakPlayerFragment()
else -> PlayerFragment()
} // must implement AbsPlayerFragment
supportFragmentManager.beginTransaction().replace(R.id.playerFragmentContainer, fragment).commit()
supportFragmentManager.executePendingTransactions()
playerFragment = supportFragmentManager.findFragmentById(R.id.playerFragmentContainer) as AbsPlayerFragment
miniPlayerFragment = supportFragmentManager.findFragmentById(R.id.miniPlayerFragment) as MiniPlayerFragment
miniPlayerFragment!!.view!!.setOnClickListener { expandPanel() }
}
override fun onServiceConnected() {
super.onServiceConnected()
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
hideBottomBar(false)
}
})
} // don't call hideBottomBar(true) here as it causes a bug with the SlidingUpPanelLayout
}
override fun onQueueChanged() {
super.onQueueChanged()
hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
}
override fun onBackPressed() {
if (!handleBackPress())
super.onBackPressed()
}
open fun handleBackPress(): Boolean {
if (bottomSheetBehavior.peekHeight != 0 && playerFragment!!.onBackPressed())
return true
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
collapsePanel()
return true
}
return false
}
override fun onPaletteColorChanged() {
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
val paletteColor = playerFragment!!.paletteColor
super.setTaskDescriptionColor(paletteColor)
val isColorLight = ColorUtil.isColorLight(paletteColor)
if (PreferenceUtil.getInstance(this).adaptiveColor &&
(currentNowPlayingScreen == NORMAL || currentNowPlayingScreen == FLAT)) {
super.setLightNavigationBar(true)
super.setLightStatusbar(isColorLight)
} else if (currentNowPlayingScreen == FULL || currentNowPlayingScreen == CARD ||
currentNowPlayingScreen == FIT || currentNowPlayingScreen == BLUR || currentNowPlayingScreen == BLUR_CARD) {
super.setLightStatusbar(false)
super.setLightNavigationBar(true)
} else if (currentNowPlayingScreen == COLOR || currentNowPlayingScreen == TINY) {
super.setNavigationbarColor(paletteColor)
super.setLightNavigationBar(isColorLight)
super.setLightStatusbar(isColorLight)
} else {
super.setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
super.setLightNavigationBar(true)
}
}
}
override fun setLightStatusbar(enabled: Boolean) {
lightStatusBar = enabled
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
super.setLightStatusbar(enabled)
}
}
override fun setLightNavigationBar(enabled: Boolean) {
lightNavigationBar = enabled
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
super.setLightNavigationBar(enabled)
}
}
override fun setNavigationbarColor(color: Int) {
navigationBarColor = color
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
if (navigationBarColorAnimator != null) navigationBarColorAnimator!!.cancel()
super.setNavigationbarColor(color)
}
}
override fun setTaskDescriptionColor(color: Int) {
taskColor = color
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
super.setTaskDescriptionColor(color)
}
}
private fun updateTabs() {
bottomNavigationView.menu.clear()
val currentTabs = PreferenceUtil.getInstance(this).libraryCategoryInfos
for (tab in currentTabs) {
if (tab.visible) {
val menu = tab.category
bottomNavigationView.menu.add(0, menu.id, 0, menu.stringRes)
.setIcon(menu.icon)
}
}
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
if (ev?.action == MotionEvent.ACTION_DOWN) {
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
val outRect = Rect()
slidingPanel.getGlobalVisibleRect(outRect)
if (!outRect.contains(ev.rawX.toInt(), ev.rawY.toInt())) {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
}
return super.dispatchTouchEvent(ev)
}
} }

View file

@ -2,207 +2,199 @@ package code.name.monkey.retromusic.activities.base
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Bundle import android.os.*
import android.os.Handler import android.view.*
import android.view.KeyEvent
import android.view.View
import android.view.WindowManager
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import code.name.monkey.appthemehelper.ATH import code.name.monkey.appthemehelper.*
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.common.ATHToolbarActivity import code.name.monkey.appthemehelper.common.ATHToolbarActivity
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.ThemeManager
abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable { abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
private val handler = Handler() private val handler = Handler()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setTheme(ThemeManager.getThemeResValue(this)) setTheme(ThemeManager.getThemeResValue(this))
hideStatusBar() hideStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
changeBackgroundShape() changeBackgroundShape()
setImmersiveFullscreen() setImmersiveFullscreen()
registerSystemUiVisibility() registerSystemUiVisibility()
toggleScreenOn() toggleScreenOn()
} }
private fun toggleScreenOn() { private fun toggleScreenOn() {
if (PreferenceUtil.getInstance(this).isScreenOnEnabled) { if (PreferenceUtil.getInstance(this).isScreenOnEnabled) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else { } else {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} }
} }
override fun onWindowFocusChanged(hasFocus: Boolean) { override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus) super.onWindowFocusChanged(hasFocus)
if (hasFocus) { if (hasFocus) {
hideStatusBar() hideStatusBar()
handler.removeCallbacks(this) handler.removeCallbacks(this)
handler.postDelayed(this, 300) handler.postDelayed(this, 300)
} else { } else {
handler.removeCallbacks(this) handler.removeCallbacks(this)
} }
} }
fun hideStatusBar() { fun hideStatusBar() {
hideStatusBar(PreferenceUtil.getInstance(this).fullScreenMode) hideStatusBar(PreferenceUtil.getInstance(this).fullScreenMode)
} }
private fun hideStatusBar(fullscreen: Boolean) { private fun hideStatusBar(fullscreen: Boolean) {
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar) val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
if (statusBar != null) { if (statusBar != null) {
statusBar.visibility = if (fullscreen) View.GONE else View.VISIBLE statusBar.visibility = if (fullscreen) View.GONE else View.VISIBLE
} }
} }
private fun changeBackgroundShape() {
var background: Drawable? = if (PreferenceUtil.getInstance(this).isRoundCorners) ContextCompat.getDrawable(
this,
R.drawable.round_window
)
else ContextCompat.getDrawable(this, R.drawable.square_window)
background = TintHelper.createTintedDrawable(
background,
ATHUtil.resolveColor(this, R.attr.colorPrimary)
)
window.setBackgroundDrawable(background)
}
private fun changeBackgroundShape() { fun setDrawUnderStatusBar() {
var background: Drawable? = if (PreferenceUtil.getInstance(this).isRoundCorners) RetroUtil.setAllowDrawUnderStatusBar(window)
ContextCompat.getDrawable(this, R.drawable.round_window) }
else
ContextCompat.getDrawable(this, R.drawable.square_window)
background = TintHelper.createTintedDrawable(background, ATHUtil.resolveColor(this, R.attr.colorPrimary))
window.setBackgroundDrawable(background)
}
fun setDrawUnderStatusBar() { fun setDrawUnderNavigationBar() {
RetroUtil.setAllowDrawUnderStatusBar(window) RetroUtil.setAllowDrawUnderNavigationBar(window)
} }
fun setDrawUnderNavigationBar() { /**
RetroUtil.setAllowDrawUnderNavigationBar(window) * This will set the color of the view with the id "status_bar" on KitKat and Lollipop. On
} * Lollipop if no such view is found it will set the statusbar color using the native method.
*
* @param color the new statusbar color (will be shifted down on Lollipop and above)
*/
fun setStatusbarColor(color: Int) {
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
if (statusBar != null) {
when {
VersionUtils.hasMarshmallow() -> window.statusBarColor = color
VersionUtils.hasLollipop() -> statusBar.setBackgroundColor(
ColorUtil.darkenColor(
color
)
)
else -> statusBar.setBackgroundColor(color)
}
} else {
when {
VersionUtils.hasMarshmallow() -> window.statusBarColor = color
else -> window.statusBarColor = ColorUtil.darkenColor(color)
}
}
setLightStatusbarAuto(color)
}
/** fun setStatusbarColorAuto() {
* This will set the color of the view with the id "status_bar" on KitKat and Lollipop. On // we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat
* Lollipop if no such view is found it will set the statusbar color using the native method. setStatusbarColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
* }
* @param color the new statusbar color (will be shifted down on Lollipop and above)
*/
fun setStatusbarColor(color: Int) {
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
if (statusBar != null) {
when {
VersionUtils.hasMarshmallow() -> window.statusBarColor = color
VersionUtils.hasLollipop() -> statusBar.setBackgroundColor(ColorUtil.darkenColor(color))
else -> statusBar.setBackgroundColor(color)
}
} else {
when {
VersionUtils.hasMarshmallow() -> window.statusBarColor = color
else -> window.statusBarColor = ColorUtil.darkenColor(color)
}
}
setLightStatusbarAuto(color)
}
fun setStatusbarColorAuto() { open fun setTaskDescriptionColor(@ColorInt color: Int) {
// we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat ATH.setTaskDescriptionColor(this, color)
setStatusbarColor(ATHUtil.resolveColor(this, R.attr.colorPrimary)) }
}
open fun setTaskDescriptionColor(@ColorInt color: Int) { fun setTaskDescriptionColorAuto() {
ATH.setTaskDescriptionColor(this, color) setTaskDescriptionColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
} }
fun setTaskDescriptionColorAuto() { open fun setNavigationbarColor(color: Int) {
setTaskDescriptionColor(ATHUtil.resolveColor(this, R.attr.colorPrimary)) if (ThemeStore.coloredNavigationBar(this)) {
} ATH.setNavigationbarColor(this, color)
} else {
ATH.setNavigationbarColor(this, Color.BLACK)
}
}
open fun setNavigationbarColor(color: Int) { open fun setNavigationBarColorPrimary() {
if (ThemeStore.coloredNavigationBar(this)) { ATH.setNavigationbarColor(this, ATHUtil.resolveColor(this, R.attr.colorPrimary))
ATH.setNavigationbarColor(this, color) }
} else {
ATH.setNavigationbarColor(this, Color.BLACK)
}
}
open fun setNavigationBarColorPrimary() { fun setNavigationbarColorAuto() {
ATH.setNavigationbarColor(this, ATHUtil.resolveColor(this, R.attr.colorPrimary)) setNavigationbarColor(ATHUtil.resolveColor(this, R.attr.colorSecondary))
} }
fun setNavigationbarColorAuto() { open fun setLightStatusbar(enabled: Boolean) {
setNavigationbarColor(ATHUtil.resolveColor(this, R.attr.colorSecondary)) ATH.setLightStatusbar(this, enabled)
} }
open fun setLightStatusbar(enabled: Boolean) { fun setLightStatusbarAuto(bgColor: Int) {
ATH.setLightStatusbar(this, enabled) setLightStatusbar(ColorUtil.isColorLight(bgColor))
} }
fun setLightStatusbarAuto(bgColor: Int) { open fun setLightNavigationBar(enabled: Boolean) {
setLightStatusbar(ColorUtil.isColorLight(bgColor)) if (!ATHUtil.isWindowBackgroundDark(this) and ThemeStore.coloredNavigationBar(this)) {
} ATH.setLightNavigationbar(this, enabled)
}
}
open fun setLightNavigationBar(enabled: Boolean) { private fun registerSystemUiVisibility() {
if (!ATHUtil.isWindowBackgroundDark(this) and ThemeStore.coloredNavigationBar(this)) { val decorView = window.decorView
ATH.setLightNavigationbar(this, enabled) decorView.setOnSystemUiVisibilityChangeListener { visibility ->
} if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
} setImmersiveFullscreen()
}
}
}
private fun registerSystemUiVisibility() { private fun unregisterSystemUiVisibility() {
val decorView = window.decorView val decorView = window.decorView
decorView.setOnSystemUiVisibilityChangeListener { visibility -> decorView.setOnSystemUiVisibilityChangeListener(null)
if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) { }
setImmersiveFullscreen()
}
}
}
private fun unregisterSystemUiVisibility() { private fun setImmersiveFullscreen() {
val decorView = window.decorView val flags = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
decorView.setOnSystemUiVisibilityChangeListener(null)
}
private fun setImmersiveFullscreen() { if (PreferenceUtil.getInstance(this).fullScreenMode) {
val flags = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE window.decorView.systemUiVisibility = flags
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION }
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN }
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
if (PreferenceUtil.getInstance(this).fullScreenMode) { private fun exitFullscreen() {
window.decorView.systemUiVisibility = flags window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
} }
}
private fun exitFullscreen() { override fun run() {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE setImmersiveFullscreen()
} }
override fun run() { override fun onStop() {
setImmersiveFullscreen() handler.removeCallbacks(this)
} super.onStop()
}
override fun onStop() { public override fun onDestroy() {
handler.removeCallbacks(this) super.onDestroy()
super.onStop() unregisterSystemUiVisibility()
} exitFullscreen()
}
public override fun onDestroy() { override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
super.onDestroy() if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
unregisterSystemUiVisibility() handler.removeCallbacks(this)
exitFullscreen() handler.postDelayed(this, 500)
} }
return super.onKeyDown(keyCode, event)
}
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
handler.removeCallbacks(this)
handler.postDelayed(this, 500)
}
return super.onKeyDown(keyCode, event)
}
} }

View file

@ -1,32 +1,21 @@
package code.name.monkey.retromusic.activities.bugreport package code.name.monkey.retromusic.activities.bugreport
import android.app.Activity import android.app.*
import android.app.Dialog import android.content.*
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.view.MenuItem import android.view.MenuItem
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.Toast import android.widget.Toast
import androidx.annotation.StringDef import androidx.annotation.*
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsThemeActivity import code.name.monkey.retromusic.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.activities.bugreport.model.DeviceInfo import code.name.monkey.retromusic.activities.bugreport.model.*
import code.name.monkey.retromusic.activities.bugreport.model.Report import code.name.monkey.retromusic.activities.bugreport.model.github.*
import code.name.monkey.retromusic.activities.bugreport.model.github.ExtraInfo
import code.name.monkey.retromusic.activities.bugreport.model.github.GithubLogin
import code.name.monkey.retromusic.activities.bugreport.model.github.GithubTarget
import code.name.monkey.retromusic.misc.DialogAsyncTask import code.name.monkey.retromusic.misc.DialogAsyncTask
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.callbacks.onCancel import com.afollestad.materialdialogs.callbacks.onCancel
@ -36,8 +25,7 @@ import kotlinx.android.synthetic.main.activity_bug_report.*
import kotlinx.android.synthetic.main.bug_report_card_device_info.* import kotlinx.android.synthetic.main.bug_report_card_device_info.*
import kotlinx.android.synthetic.main.bug_report_card_report.* import kotlinx.android.synthetic.main.bug_report_card_report.*
import org.eclipse.egit.github.core.Issue import org.eclipse.egit.github.core.Issue
import org.eclipse.egit.github.core.client.GitHubClient import org.eclipse.egit.github.core.client.*
import org.eclipse.egit.github.core.client.RequestException
import org.eclipse.egit.github.core.service.IssueService import org.eclipse.egit.github.core.service.IssueService
import java.io.IOException import java.io.IOException
@ -47,268 +35,285 @@ private const val RESULT_INVALID_TOKEN = "RESULT_INVALID_TOKEN"
private const val RESULT_ISSUES_NOT_ENABLED = "RESULT_ISSUES_NOT_ENABLED" private const val RESULT_ISSUES_NOT_ENABLED = "RESULT_ISSUES_NOT_ENABLED"
private const val RESULT_UNKNOWN = "RESULT_UNKNOWN" private const val RESULT_UNKNOWN = "RESULT_UNKNOWN"
@StringDef(RESULT_SUCCESS, RESULT_BAD_CREDENTIALS, RESULT_INVALID_TOKEN, RESULT_ISSUES_NOT_ENABLED, RESULT_UNKNOWN) @StringDef(
RESULT_SUCCESS,
RESULT_BAD_CREDENTIALS,
RESULT_INVALID_TOKEN,
RESULT_ISSUES_NOT_ENABLED,
RESULT_UNKNOWN
)
@Retention(AnnotationRetention.SOURCE) @Retention(AnnotationRetention.SOURCE)
private annotation class Result private annotation class Result
open class BugReportActivity : AbsThemeActivity() { open class BugReportActivity : AbsThemeActivity() {
private var deviceInfo: DeviceInfo? = null private var deviceInfo: DeviceInfo? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bug_report) setContentView(R.layout.activity_bug_report)
setStatusbarColorAuto() setStatusbarColorAuto()
setNavigationbarColorAuto() setNavigationbarColorAuto()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
initViews() initViews()
if (TextUtils.isEmpty(title)) if (TextUtils.isEmpty(title)) setTitle(R.string.report_an_issue)
setTitle(R.string.report_an_issue)
deviceInfo = DeviceInfo(this) deviceInfo = DeviceInfo(this)
airTextDeviceInfo.text = deviceInfo.toString() airTextDeviceInfo.text = deviceInfo.toString()
} }
private fun initViews() { private fun initViews() {
val accentColor = ThemeStore.accentColor(this) val accentColor = ThemeStore.accentColor(this)
val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary) val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary)
toolbar.setBackgroundColor(primaryColor) toolbar.setBackgroundColor(primaryColor)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
ToolbarContentTintHelper.colorBackButton(toolbar) ToolbarContentTintHelper.colorBackButton(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
TintHelper.setTintAuto(optionUseAccount, accentColor, false) TintHelper.setTintAuto(optionUseAccount, accentColor, false)
optionUseAccount?.setOnClickListener { optionUseAccount?.setOnClickListener {
inputTitle.isEnabled = true inputTitle.isEnabled = true
inputDescription.isEnabled = true inputDescription.isEnabled = true
inputUsername.isEnabled = true inputUsername.isEnabled = true
inputPassword.isEnabled = true inputPassword.isEnabled = true
optionAnonymous.isChecked = false optionAnonymous.isChecked = false
sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() { sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
override fun onHidden(fab: FloatingActionButton?) { override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab) super.onHidden(fab)
sendFab.setImageResource(R.drawable.ic_send_white_24dp) sendFab.setImageResource(R.drawable.ic_send_white_24dp)
sendFab.show() sendFab.show()
} }
}) })
} }
TintHelper.setTintAuto(optionAnonymous, accentColor, false) TintHelper.setTintAuto(optionAnonymous, accentColor, false)
optionAnonymous.setOnClickListener { optionAnonymous.setOnClickListener {
inputTitle.isEnabled = false inputTitle.isEnabled = false
inputDescription.isEnabled = false inputDescription.isEnabled = false
inputUsername.isEnabled = false inputUsername.isEnabled = false
inputPassword.isEnabled = false inputPassword.isEnabled = false
optionUseAccount.isChecked = false optionUseAccount.isChecked = false
sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() { sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
override fun onHidden(fab: FloatingActionButton?) { override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab) super.onHidden(fab)
sendFab.setImageResource(R.drawable.ic_open_in_browser_white_24dp) sendFab.setImageResource(R.drawable.ic_open_in_browser_white_24dp)
sendFab.show() sendFab.show()
} }
}) })
} }
inputPassword.setOnEditorActionListener { _, actionId, _ -> inputPassword.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEND) { if (actionId == EditorInfo.IME_ACTION_SEND) {
reportIssue() reportIssue()
return@setOnEditorActionListener true return@setOnEditorActionListener true
} }
false false
} }
airTextDeviceInfo.setOnClickListener { copyDeviceInfoToClipBoard() } airTextDeviceInfo.setOnClickListener { copyDeviceInfoToClipBoard() }
TintHelper.setTintAuto(sendFab, accentColor, true) TintHelper.setTintAuto(sendFab, accentColor, true)
sendFab.setOnClickListener { reportIssue() } sendFab.setOnClickListener { reportIssue() }
MaterialUtil.setTint(inputLayoutTitle, false) MaterialUtil.setTint(inputLayoutTitle, false)
MaterialUtil.setTint(inputLayoutDescription, false) MaterialUtil.setTint(inputLayoutDescription, false)
MaterialUtil.setTint(inputLayoutUsername, false) MaterialUtil.setTint(inputLayoutUsername, false)
MaterialUtil.setTint(inputLayoutPassword, false) MaterialUtil.setTint(inputLayoutPassword, false)
} }
private fun reportIssue() { private fun reportIssue() {
if (optionUseAccount.isChecked) { if (optionUseAccount.isChecked) {
if (!validateInput()) return if (!validateInput()) return
val username = inputUsername.text.toString() val username = inputUsername.text.toString()
val password = inputPassword.text.toString() val password = inputPassword.text.toString()
sendBugReport(GithubLogin(username, password)) sendBugReport(GithubLogin(username, password))
} else { } else {
copyDeviceInfoToClipBoard() copyDeviceInfoToClipBoard()
val i = Intent(Intent.ACTION_VIEW) val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(ISSUE_TRACKER_LINK) i.data = Uri.parse(ISSUE_TRACKER_LINK)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(i) startActivity(i)
} }
} }
private fun copyDeviceInfoToClipBoard() { private fun copyDeviceInfoToClipBoard() {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.device_info), deviceInfo?.toMarkdown()) val clip = ClipData.newPlainText(getString(R.string.device_info), deviceInfo?.toMarkdown())
clipboard.primaryClip = clip clipboard.primaryClip = clip
Toast.makeText(this@BugReportActivity, R.string.copied_device_info_to_clipboard, Toast.LENGTH_LONG).show() Toast.makeText(
} this@BugReportActivity,
R.string.copied_device_info_to_clipboard,
Toast.LENGTH_LONG
).show()
}
private fun validateInput(): Boolean { private fun validateInput(): Boolean {
var hasErrors = false var hasErrors = false
if (optionUseAccount.isChecked) { if (optionUseAccount.isChecked) {
if (TextUtils.isEmpty(inputUsername.text)) { if (TextUtils.isEmpty(inputUsername.text)) {
setError(inputLayoutUsername, R.string.bug_report_no_username) setError(inputLayoutUsername, R.string.bug_report_no_username)
hasErrors = true hasErrors = true
} else { } else {
removeError(inputLayoutUsername) removeError(inputLayoutUsername)
} }
if (TextUtils.isEmpty(inputPassword.text)) { if (TextUtils.isEmpty(inputPassword.text)) {
setError(inputLayoutPassword, R.string.bug_report_no_password) setError(inputLayoutPassword, R.string.bug_report_no_password)
hasErrors = true hasErrors = true
} else { } else {
removeError(inputLayoutPassword) removeError(inputLayoutPassword)
} }
} }
if (TextUtils.isEmpty(inputTitle.text)) { if (TextUtils.isEmpty(inputTitle.text)) {
setError(inputLayoutTitle, R.string.bug_report_no_title) setError(inputLayoutTitle, R.string.bug_report_no_title)
hasErrors = true hasErrors = true
} else { } else {
removeError(inputLayoutTitle) removeError(inputLayoutTitle)
} }
if (TextUtils.isEmpty(inputDescription.text)) { if (TextUtils.isEmpty(inputDescription.text)) {
setError(inputLayoutDescription, R.string.bug_report_no_description) setError(inputLayoutDescription, R.string.bug_report_no_description)
hasErrors = true hasErrors = true
} else { } else {
removeError(inputLayoutDescription) removeError(inputLayoutDescription)
} }
return !hasErrors return !hasErrors
} }
private fun setError(editTextLayout: TextInputLayout, @StringRes errorRes: Int) { private fun setError(editTextLayout: TextInputLayout, @StringRes errorRes: Int) {
editTextLayout.error = getString(errorRes) editTextLayout.error = getString(errorRes)
} }
private fun removeError(editTextLayout: TextInputLayout) { private fun removeError(editTextLayout: TextInputLayout) {
editTextLayout.error = null editTextLayout.error = null
} }
private fun sendBugReport(login: GithubLogin) { private fun sendBugReport(login: GithubLogin) {
if (!validateInput()) return if (!validateInput()) return
val bugTitle = inputTitle.text.toString() val bugTitle = inputTitle.text.toString()
val bugDescription = inputDescription.text.toString() val bugDescription = inputDescription.text.toString()
val extraInfo = ExtraInfo() val extraInfo = ExtraInfo()
onSaveExtraInfo() onSaveExtraInfo()
val report = Report(bugTitle, bugDescription, deviceInfo, extraInfo) val report = Report(bugTitle, bugDescription, deviceInfo, extraInfo)
val target = GithubTarget("h4h13", "RetroMusicPlayer") val target = GithubTarget("h4h13", "RetroMusicPlayer")
ReportIssueAsyncTask.report(this, report, target, login) ReportIssueAsyncTask.report(this, report, target, login)
} }
private fun onSaveExtraInfo() {} private fun onSaveExtraInfo() {}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) { if (item.itemId == android.R.id.home) {
onBackPressed() onBackPressed()
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
private class ReportIssueAsyncTask private constructor(activity: Activity, private val report: Report, private val target: GithubTarget, private class ReportIssueAsyncTask private constructor(
private val login: GithubLogin) : DialogAsyncTask<Void, Void, String>(activity) { activity: Activity,
override fun createDialog(context: Context): Dialog { private val report: Report,
return AlertDialog.Builder(context) private val target: GithubTarget,
.show() private val login: GithubLogin
} ) : DialogAsyncTask<Void, Void, String>(activity) {
override fun createDialog(context: Context): Dialog {
return AlertDialog.Builder(context).show()
}
@Result @Result
override fun doInBackground(vararg params: Void): String { override fun doInBackground(vararg params: Void): String {
val client: GitHubClient = if (login.shouldUseApiToken()) { val client: GitHubClient = if (login.shouldUseApiToken()) {
GitHubClient().setOAuth2Token(login.apiToken) GitHubClient().setOAuth2Token(login.apiToken)
} else { } else {
GitHubClient().setCredentials(login.username, login.password) GitHubClient().setCredentials(login.username, login.password)
} }
val issue = Issue().setTitle(report.title).setBody(report.description) val issue = Issue().setTitle(report.title).setBody(report.description)
try { try {
IssueService(client).createIssue(target.username, target.repository, issue) IssueService(client).createIssue(target.username, target.repository, issue)
return RESULT_SUCCESS return RESULT_SUCCESS
} catch (e: RequestException) { } catch (e: RequestException) {
return when (e.status) { return when (e.status) {
STATUS_BAD_CREDENTIALS -> { STATUS_BAD_CREDENTIALS -> {
if (login.shouldUseApiToken()) RESULT_INVALID_TOKEN else RESULT_BAD_CREDENTIALS if (login.shouldUseApiToken()) RESULT_INVALID_TOKEN else RESULT_BAD_CREDENTIALS
} }
STATUS_ISSUES_NOT_ENABLED -> RESULT_ISSUES_NOT_ENABLED STATUS_ISSUES_NOT_ENABLED -> RESULT_ISSUES_NOT_ENABLED
else -> { else -> {
e.printStackTrace() e.printStackTrace()
RESULT_UNKNOWN RESULT_UNKNOWN
} }
} }
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() e.printStackTrace()
return RESULT_UNKNOWN return RESULT_UNKNOWN
} }
} }
override fun onPostExecute(@Result result: String) { override fun onPostExecute(@Result result: String) {
super.onPostExecute(result) super.onPostExecute(result)
val context = context ?: return val context = context ?: return
when (result) { when (result) {
RESULT_SUCCESS -> tryToFinishActivity() RESULT_SUCCESS -> tryToFinishActivity()
RESULT_BAD_CREDENTIALS -> MaterialDialog(context).show { RESULT_BAD_CREDENTIALS -> MaterialDialog(context).show {
title(R.string.bug_report_failed) title(R.string.bug_report_failed)
message(R.string.bug_report_failed_wrong_credentials) message(R.string.bug_report_failed_wrong_credentials)
positiveButton(android.R.string.ok) positiveButton(android.R.string.ok)
} }
RESULT_INVALID_TOKEN -> MaterialDialog(context).show { RESULT_INVALID_TOKEN -> MaterialDialog(context).show {
title(R.string.bug_report_failed) title(R.string.bug_report_failed)
message(R.string.bug_report_failed_invalid_token) message(R.string.bug_report_failed_invalid_token)
positiveButton(android.R.string.ok) positiveButton(android.R.string.ok)
} }
RESULT_ISSUES_NOT_ENABLED -> MaterialDialog(context).show { RESULT_ISSUES_NOT_ENABLED -> MaterialDialog(context).show {
title(R.string.bug_report_failed) title(R.string.bug_report_failed)
message(R.string.bug_report_failed_issues_not_available) message(R.string.bug_report_failed_issues_not_available)
positiveButton(android.R.string.ok) positiveButton(android.R.string.ok)
} }
else -> MaterialDialog(context).show { else -> MaterialDialog(context).show {
title(R.string.bug_report_failed) title(R.string.bug_report_failed)
message(R.string.bug_report_failed_unknown) message(R.string.bug_report_failed_unknown)
positiveButton(android.R.string.ok) { tryToFinishActivity() } positiveButton(android.R.string.ok) { tryToFinishActivity() }
onCancel { tryToFinishActivity() } onCancel { tryToFinishActivity() }
} }
} }
} }
private fun tryToFinishActivity() { private fun tryToFinishActivity() {
val context = context val context = context
if (context is Activity && !context.isFinishing) { if (context is Activity && !context.isFinishing) {
context.finish() context.finish()
} }
} }
companion object { companion object {
fun report(activity: Activity, report: Report, target: GithubTarget, login: GithubLogin) { fun report(
ReportIssueAsyncTask(activity, report, target, login).execute() activity: Activity,
} report: Report,
} target: GithubTarget,
} login: GithubLogin
) {
ReportIssueAsyncTask(activity, report, target, login).execute()
}
}
}
companion object { companion object {
private const val STATUS_BAD_CREDENTIALS = 401 private const val STATUS_BAD_CREDENTIALS = 401
private const val STATUS_ISSUES_NOT_ENABLED = 410 private const val STATUS_ISSUES_NOT_ENABLED = 410
private const val ISSUE_TRACKER_LINK = "https://github.com/h4h13/RetroMusicPlayer" private const val ISSUE_TRACKER_LINK = "https://github.com/h4h13/RetroMusicPlayer"
} }
} }

View file

@ -1 +0,0 @@
package code.name.monkey.retromusic.activities.bugreport import android.content.ActivityNotFoundException import android.content.Intent import android.net.Uri import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.bugreport.model.DeviceInfo import kotlinx.android.synthetic.main.activity_error_handler.* class ErrorHandlerActivity : AppCompatActivity() { private var deviceInfo: DeviceInfo? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_error_handler) deviceInfo = DeviceInfo(this) clearAppData.setOnClickListener { try { val intent = Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS) intent.data = Uri.parse("package:$packageName") startActivity(intent) } catch (e: ActivityNotFoundException) { val intent = Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS) startActivity(intent) } } sendCrashLog.setOnClickListener { val sendIntent = Intent(Intent.ACTION_SEND) val subject = "Error report" val body = intent.getStringExtra("error") + "\n" + deviceInfo!!.toString() sendIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf("monkeycodeapp@gmail.com")) sendIntent.putExtra(Intent.EXTRA_TEXT, body) sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject) sendIntent.type = "message/rfc822" startActivity(Intent.createChooser(sendIntent, "Send crash log")) deleteFile("stack.trace") } showCrashError.text = String.format("%s", intent.getStringExtra("error")) showCrashError.append(deviceInfo!!.toString()) } }

View file

@ -6,9 +6,10 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build; import android.os.Build;
import androidx.annotation.IntRange;
import java.util.Arrays; import java.util.Arrays;
import androidx.annotation.IntRange;
import code.name.monkey.retromusic.util.PreferenceUtil; import code.name.monkey.retromusic.util.PreferenceUtil;
public class DeviceInfo { public class DeviceInfo {

View file

@ -1,405 +1,416 @@
package code.name.monkey.retromusic.activities.tageditor package code.name.monkey.retromusic.activities.tageditor
import android.app.Activity import android.app.*
import android.app.SearchManager
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Bitmap import android.graphics.*
import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.*
import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.MenuItem import android.view.*
import android.view.View
import android.view.animation.OvershootInterpolator import android.view.animation.OvershootInterpolator
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity import code.name.monkey.retromusic.activities.saf.SAFGuideActivity
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.RetroUtil import com.afollestad.materialdialogs.*
import code.name.monkey.retromusic.util.SAFUtil
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.list.listItems import com.afollestad.materialdialogs.list.listItems
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import kotlinx.android.synthetic.main.activity_album_tag_editor.* import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import org.jaudiotagger.audio.AudioFile import org.jaudiotagger.audio.*
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.tag.FieldKey import org.jaudiotagger.tag.FieldKey
import java.io.File import java.io.File
import java.util.* import java.util.*
abstract class AbsTagEditorActivity : AbsBaseActivity() { abstract class AbsTagEditorActivity : AbsBaseActivity() {
protected var id: Int = 0
private set
private var paletteColorPrimary: Int = 0
private var isInNoImageMode: Boolean = false
private var songPaths: List<String>? = null
lateinit var saveFab: MaterialButton
protected var id: Int = 0 private var savedSongPaths: List<String>? = null
private set private val currentSongPath: String? = null
private var paletteColorPrimary: Int = 0 private var savedTags: Map<FieldKey, String>? = null
private var isInNoImageMode: Boolean = false private var savedArtworkInfo: ArtworkInfo? = null
private var songPaths: List<String>? = null
lateinit var saveFab: MaterialButton
private var savedSongPaths: List<String>? = null protected val show: MaterialDialog
private val currentSongPath: String? = null get() = MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
private var savedTags: Map<FieldKey, String>? = null cornerRadius(PreferenceUtil.getInstance(this@AbsTagEditorActivity).dialogCorner)
private var savedArtworkInfo: ArtworkInfo? = null title(R.string.update_image)
listItems(items = items) { _, position, _ ->
when (position) {
0 -> startImagePicker()
1 -> searchImageOnWeb()
2 -> deleteImage()
}
}
}
protected abstract val contentViewLayout: Int
protected val show: MaterialDialog internal val albumArtist: String?
get() = MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)) get() {
.show { return try {
cornerRadius(PreferenceUtil.getInstance(this@AbsTagEditorActivity).dialogCorner) getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
title(R.string.update_image) } catch (ignored: Exception) {
listItems(items = items) { _, position, _ -> null
when (position) { }
0 -> startImagePicker()
1 -> searchImageOnWeb()
2 -> deleteImage()
}
}
}
protected abstract val contentViewLayout: Int
internal val albumArtist: String? }
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault
.getFirst(FieldKey.ALBUM_ARTIST)
} catch (ignored: Exception) {
null
}
} protected val songTitle: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TITLE)
} catch (ignored: Exception) {
null
}
protected val songTitle: String? }
get() { protected val composer: String?
return try { get() {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TITLE) return try {
} catch (ignored: Exception) { getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.COMPOSER)
null } catch (ignored: Exception) {
} null
}
} }
protected val composer: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.COMPOSER)
} catch (ignored: Exception) {
null
}
} protected val albumTitle: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM)
} catch (ignored: Exception) {
null
}
protected val albumTitle: String? }
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM)
} catch (ignored: Exception) {
null
}
} protected val artistName: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ARTIST)
} catch (ignored: Exception) {
null
}
protected val artistName: String? }
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ARTIST)
} catch (ignored: Exception) {
null
}
} protected val albumArtistName: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.ALBUM_ARTIST)
} catch (ignored: Exception) {
null
}
protected val albumArtistName: String? }
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault
.getFirst(FieldKey.ALBUM_ARTIST)
} catch (ignored: Exception) {
null
}
} protected val genreName: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.GENRE)
} catch (ignored: Exception) {
null
}
protected val genreName: String? }
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.GENRE)
} catch (ignored: Exception) {
null
}
} protected val songYear: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.YEAR)
} catch (ignored: Exception) {
null
}
protected val songYear: String? }
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.YEAR)
} catch (ignored: Exception) {
null
}
} protected val trackNumber: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TRACK)
} catch (ignored: Exception) {
null
}
protected val trackNumber: String? }
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TRACK)
} catch (ignored: Exception) {
null
}
} protected val lyrics: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.LYRICS)
} catch (ignored: Exception) {
null
}
protected val lyrics: String? }
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.LYRICS)
} catch (ignored: Exception) {
null
}
} protected val albumArt: Bitmap?
get() {
try {
val artworkTag = getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.firstArtwork
if (artworkTag != null) {
val artworkBinaryData = artworkTag.binaryData
return BitmapFactory.decodeByteArray(
artworkBinaryData,
0,
artworkBinaryData.size
)
}
return null
} catch (ignored: Exception) {
return null
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(contentViewLayout)
saveFab = findViewById(R.id.saveTags)
getIntentExtras()
songPaths = getSongPaths()
if (songPaths!!.isEmpty()) {
finish()
return
}
setUpViews()
protected val albumArt: Bitmap? setNavigationbarColorAuto()
get() { setTaskDescriptionColorAuto()
try { }
val artworkTag = getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault
.firstArtwork
if (artworkTag != null) {
val artworkBinaryData = artworkTag.binaryData
return BitmapFactory.decodeByteArray(artworkBinaryData, 0, artworkBinaryData.size)
}
return null
} catch (ignored: Exception) {
return null
}
} private fun setUpViews() {
setUpScrollView()
setUpFab()
setUpImageView()
}
override fun onCreate(savedInstanceState: Bundle?) { private fun setUpScrollView() {
super.onCreate(savedInstanceState) //observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks);
setContentView(contentViewLayout) }
saveFab = findViewById(R.id.saveTags) private lateinit var items: List<String>
getIntentExtras()
songPaths = getSongPaths() private fun setUpImageView() {
if (songPaths!!.isEmpty()) { loadCurrentImage()
finish() items = listOf(
return getString(code.name.monkey.retromusic.R.string.pick_from_local_storage),
} getString(code.name.monkey.retromusic.R.string.web_search),
getString(code.name.monkey.retromusic.R.string.remove_cover)
)
editorImage?.setOnClickListener { show }
}
setUpViews() private fun startImagePicker() {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(
Intent.createChooser(
intent,
getString(code.name.monkey.retromusic.R.string.pick_from_local_storage)
), REQUEST_CODE_SELECT_IMAGE
)
}
protected abstract fun loadCurrentImage()
setNavigationbarColorAuto() protected abstract fun searchImageOnWeb()
setTaskDescriptionColorAuto()
}
private fun setUpViews() { protected abstract fun deleteImage()
setUpScrollView()
setUpFab()
setUpImageView()
}
private fun setUpScrollView() { private fun setUpFab() {
//observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks); saveFab.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
} ColorStateList.valueOf(
MaterialValueHelper.getPrimaryTextColor(
this,
ColorUtil.isColorLight(
ThemeStore.accentColor(
this
)
)
)
).apply {
saveFab.setTextColor(this)
saveFab.iconTint = this
}
saveFab.apply {
scaleX = 0f
scaleY = 0f
isEnabled = false
setOnClickListener { save() }
TintHelper.setTintAuto(this, ThemeStore.accentColor(this@AbsTagEditorActivity), true)
}
}
private lateinit var items: List<String> protected abstract fun save()
private fun setUpImageView() { private fun getIntentExtras() {
loadCurrentImage() val intentExtras = intent.extras
items = listOf(getString(code.name.monkey.retromusic.R.string.pick_from_local_storage), getString(code.name.monkey.retromusic.R.string.web_search), getString(code.name.monkey.retromusic.R.string.remove_cover)) if (intentExtras != null) {
editorImage?.setOnClickListener { show } id = intentExtras.getInt(EXTRA_ID)
} }
}
private fun startImagePicker() { protected abstract fun getSongPaths(): List<String>
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(Intent.createChooser(intent, getString(code.name.monkey.retromusic.R.string.pick_from_local_storage)), REQUEST_CODE_SELECT_IMAGE)
}
protected abstract fun loadCurrentImage() protected fun searchWebFor(vararg keys: String) {
val stringBuilder = StringBuilder()
for (key in keys) {
stringBuilder.append(key)
stringBuilder.append(" ")
}
val intent = Intent(Intent.ACTION_WEB_SEARCH)
intent.putExtra(SearchManager.QUERY, stringBuilder.toString())
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
protected abstract fun searchImageOnWeb() startActivity(intent)
}
protected abstract fun deleteImage() override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
super.onBackPressed()
return true
}
}
return super.onOptionsItemSelected(item)
}
private fun setUpFab() { protected fun setNoImageMode() {
saveFab.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this)) isInNoImageMode = true
ColorStateList.valueOf(MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.accentColor(this)))).apply { imageContainer?.visibility = View.GONE
saveFab.setTextColor(this) editorImage?.visibility = View.GONE
saveFab.iconTint = this editorImage?.isEnabled = false
}
saveFab.apply {
scaleX = 0f
scaleY = 0f
isEnabled = false
setOnClickListener { save() }
TintHelper.setTintAuto(this, ThemeStore.accentColor(this@AbsTagEditorActivity), true)
}
}
protected abstract fun save() setColors(
intent.getIntExtra(
EXTRA_PALETTE,
ATHUtil.resolveColor(this, R.attr.colorPrimary)
)
)
}
private fun getIntentExtras() { protected fun dataChanged() {
val intentExtras = intent.extras showFab()
if (intentExtras != null) { }
id = intentExtras.getInt(EXTRA_ID)
}
}
protected abstract fun getSongPaths(): List<String> private fun showFab() {
saveFab.animate().setDuration(500).setInterpolator(OvershootInterpolator()).scaleX(1f)
.scaleY(1f).start()
saveFab.isEnabled = true
}
protected fun searchWebFor(vararg keys: String) { private fun hideFab() {
val stringBuilder = StringBuilder() saveFab.animate().setDuration(500).setInterpolator(OvershootInterpolator()).scaleX(0.0f)
for (key in keys) { .scaleY(0.0f).start()
stringBuilder.append(key) saveFab.isEnabled = false
stringBuilder.append(" ") }
}
val intent = Intent(Intent.ACTION_WEB_SEARCH)
intent.putExtra(SearchManager.QUERY, stringBuilder.toString())
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent) protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) {
} if (bitmap == null) {
editorImage.setImageResource(code.name.monkey.retromusic.R.drawable.default_album_art)
} else {
editorImage.setImageBitmap(bitmap)
}
setColors(bgColor)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { protected open fun setColors(color: Int) {
when (item.itemId) { paletteColorPrimary = color
android.R.id.home -> { }
super.onBackPressed()
return true
}
}
return super.onOptionsItemSelected(item)
}
protected fun setNoImageMode() { protected fun writeValuesToFiles(
isInNoImageMode = true fieldKeyValueMap: Map<FieldKey, String>, artworkInfo: ArtworkInfo?
imageContainer?.visibility = View.GONE ) {
editorImage?.visibility = View.GONE RetroUtil.hideSoftKeyboard(this)
editorImage?.isEnabled = false
setColors(intent.getIntExtra(EXTRA_PALETTE, ATHUtil.resolveColor(this, R.attr.colorPrimary))) hideFab()
}
protected fun dataChanged() { savedSongPaths = getSongPaths()
showFab() savedTags = fieldKeyValueMap
} savedArtworkInfo = artworkInfo
private fun showFab() { if (!SAFUtil.isSAFRequired(savedSongPaths)) {
saveFab.animate() writeTags(savedSongPaths)
.setDuration(500) } else {
.setInterpolator(OvershootInterpolator()) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
.scaleX(1f) if (SAFUtil.isSDCardAccessGranted(this)) {
.scaleY(1f) writeTags(savedSongPaths)
.start() } else {
saveFab.isEnabled = true startActivityForResult(
} Intent(this, SAFGuideActivity::class.java),
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE
)
}
}
}
}
private fun hideFab() { private fun writeTags(paths: List<String>?) {
saveFab.animate() WriteTagsAsyncTask(this).execute(
.setDuration(500) WriteTagsAsyncTask.LoadingInfo(
.setInterpolator(OvershootInterpolator()) paths,
.scaleX(0.0f) savedTags,
.scaleY(0.0f) savedArtworkInfo
.start() )
saveFab.isEnabled = false )
} }
protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) { override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
if (bitmap == null) { super.onActivityResult(requestCode, resultCode, intent)
editorImage.setImageResource(code.name.monkey.retromusic.R.drawable.default_album_art) when (requestCode) {
} else { REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
editorImage.setImageBitmap(bitmap) intent?.data?.let {
} loadImageFromFile(it)
setColors(bgColor) }
} }
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE -> {
SAFUtil.openTreePicker(this)
}
SAFUtil.REQUEST_SAF_PICK_TREE -> {
if (resultCode == Activity.RESULT_OK) {
SAFUtil.saveTreeUri(this, intent)
writeTags(savedSongPaths)
}
}
SAFUtil.REQUEST_SAF_PICK_FILE -> {
if (resultCode == Activity.RESULT_OK) {
writeTags(Collections.singletonList(currentSongPath + SAFUtil.SEPARATOR + intent!!.dataString))
}
}
}
}
protected open fun setColors(color: Int) { protected abstract fun loadImageFromFile(selectedFile: Uri?)
paletteColorPrimary = color
}
protected fun writeValuesToFiles(fieldKeyValueMap: Map<FieldKey, String>, private fun getAudioFile(path: String): AudioFile {
artworkInfo: ArtworkInfo?) { return try {
RetroUtil.hideSoftKeyboard(this) AudioFileIO.read(File(path))
} catch (e: Exception) {
Log.e(TAG, "Could not read audio file $path", e)
AudioFile()
}
}
hideFab() class ArtworkInfo constructor(val albumId: Int, val artwork: Bitmap?)
savedSongPaths = getSongPaths() companion object {
savedTags = fieldKeyValueMap
savedArtworkInfo = artworkInfo
if (!SAFUtil.isSAFRequired(savedSongPaths)) { const val EXTRA_ID = "extra_id"
writeTags(savedSongPaths) const val EXTRA_PALETTE = "extra_palette"
} else { private val TAG = AbsTagEditorActivity::class.java.simpleName
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { private const val REQUEST_CODE_SELECT_IMAGE = 1000
if (SAFUtil.isSDCardAccessGranted(this)) { }
writeTags(savedSongPaths)
} else {
startActivityForResult(Intent(this, SAFGuideActivity::class.java), SAFGuideActivity.REQUEST_CODE_SAF_GUIDE)
}
}
}
}
private fun writeTags(paths: List<String>?) {
WriteTagsAsyncTask(this).execute(WriteTagsAsyncTask.LoadingInfo(paths, savedTags, savedArtworkInfo))
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
super.onActivityResult(requestCode, resultCode, intent)
when (requestCode) {
REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
intent?.data?.let {
loadImageFromFile(it)
}
}
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE -> {
SAFUtil.openTreePicker(this)
}
SAFUtil.REQUEST_SAF_PICK_TREE -> {
if (resultCode == Activity.RESULT_OK) {
SAFUtil.saveTreeUri(this, intent)
writeTags(savedSongPaths)
}
}
SAFUtil.REQUEST_SAF_PICK_FILE -> {
if (resultCode == Activity.RESULT_OK) {
writeTags(Collections.singletonList(currentSongPath + SAFUtil.SEPARATOR + intent!!.dataString))
}
}
}
}
protected abstract fun loadImageFromFile(selectedFile: Uri?)
private fun getAudioFile(path: String): AudioFile {
return try {
AudioFileIO.read(File(path))
} catch (e: Exception) {
Log.e(TAG, "Could not read audio file $path", e)
AudioFile()
}
}
class ArtworkInfo constructor(val albumId: Int, val artwork: Bitmap?)
companion object {
const val EXTRA_ID = "extra_id"
const val EXTRA_PALETTE = "extra_palette"
private val TAG = AbsTagEditorActivity::class.java.simpleName
private const val REQUEST_CODE_SELECT_IMAGE = 1000
}
} }

View file

@ -2,27 +2,20 @@ package code.name.monkey.retromusic.activities.tageditor
import android.app.Activity import android.app.Activity
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Bitmap import android.graphics.*
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.*
import android.text.TextUtils
import android.text.TextWatcher
import android.widget.Toast import android.widget.Toast
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.appHandleColor import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder import code.name.monkey.retromusic.glide.palette.*
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.loaders.AlbumLoader import code.name.monkey.retromusic.loaders.AlbumLoader
import code.name.monkey.retromusic.rest.LastFMRestClient import code.name.monkey.retromusic.rest.LastFMRestClient
import code.name.monkey.retromusic.rest.model.LastFmAlbum import code.name.monkey.retromusic.rest.model.LastFmAlbum
import code.name.monkey.retromusic.util.ImageUtil import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.LastFMUtil
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette
import code.name.monkey.retromusic.util.RetroColorUtil.getColor import code.name.monkey.retromusic.util.RetroColorUtil.getColor
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
@ -34,181 +27,224 @@ import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import org.jaudiotagger.tag.FieldKey import org.jaudiotagger.tag.FieldKey
import java.util.* import java.util.*
class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher { class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
override val contentViewLayout: Int override val contentViewLayout: Int
get() = R.layout.activity_album_tag_editor get() = R.layout.activity_album_tag_editor
override fun loadImageFromFile(selectedFileUri: Uri?) { override fun loadImageFromFile(selectedFileUri: Uri?) {
Glide.with(this@AlbumTagEditorActivity) Glide.with(this@AlbumTagEditorActivity).load(selectedFileUri).asBitmap()
.load(selectedFileUri) .transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java)
.asBitmap() .diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
.transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java) .into(object : SimpleTarget<BitmapPaletteWrapper>() {
.diskCacheStrategy(DiskCacheStrategy.NONE) override fun onResourceReady(
.skipMemoryCache(true) resource: BitmapPaletteWrapper?,
.into(object : SimpleTarget<BitmapPaletteWrapper>() { glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?
override fun onResourceReady(resource: BitmapPaletteWrapper?, glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?) { ) {
getColor(resource?.palette, Color.TRANSPARENT) getColor(resource?.palette, Color.TRANSPARENT)
albumArtBitmap = resource?.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) } albumArtBitmap = resource?.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
setImageBitmap(albumArtBitmap, getColor(resource?.palette, ATHUtil.resolveColor(this@AlbumTagEditorActivity, R.attr.defaultFooterColor))) setImageBitmap(
deleteAlbumArt = false albumArtBitmap,
dataChanged() getColor(
setResult(Activity.RESULT_OK) resource?.palette,
} ATHUtil.resolveColor(
this@AlbumTagEditorActivity,
R.attr.defaultFooterColor
)
)
)
deleteAlbumArt = false
dataChanged()
setResult(Activity.RESULT_OK)
}
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) { override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
super.onLoadFailed(e, errorDrawable) super.onLoadFailed(e, errorDrawable)
Toast.makeText(this@AlbumTagEditorActivity, e.toString(), Toast.LENGTH_LONG).show() Toast.makeText(this@AlbumTagEditorActivity, e.toString(), Toast.LENGTH_LONG)
} .show()
}) }
} })
}
private var albumArtBitmap: Bitmap? = null private var albumArtBitmap: Bitmap? = null
private var deleteAlbumArt: Boolean = false private var deleteAlbumArt: Boolean = false
private var lastFMRestClient: LastFMRestClient? = null private var lastFMRestClient: LastFMRestClient? = null
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private fun setupToolbar() { private fun setupToolbar() {
toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary)) toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
supportActionBar?.setDisplayShowHomeEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true)
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar() setDrawUnderStatusBar()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
lastFMRestClient = LastFMRestClient(this) lastFMRestClient = LastFMRestClient(this)
setUpViews() setUpViews()
setupToolbar() setupToolbar()
} }
private fun setUpViews() {
fillViewsWithFileTags()
private fun setUpViews() { MaterialUtil.setTint(yearContainer, false)
fillViewsWithFileTags() MaterialUtil.setTint(genreContainer, false)
MaterialUtil.setTint(albumTitleContainer, false)
MaterialUtil.setTint(albumArtistContainer, false)
MaterialUtil.setTint(yearContainer, false) albumText.appHandleColor().addTextChangedListener(this)
MaterialUtil.setTint(genreContainer, false) albumArtistText.appHandleColor().addTextChangedListener(this)
MaterialUtil.setTint(albumTitleContainer, false) genreTitle.appHandleColor().addTextChangedListener(this)
MaterialUtil.setTint(albumArtistContainer, false) yearTitle.appHandleColor().addTextChangedListener(this)
}
albumText.appHandleColor().addTextChangedListener(this) private fun fillViewsWithFileTags() {
albumArtistText.appHandleColor().addTextChangedListener(this) albumText.setText(albumTitle)
genreTitle.appHandleColor().addTextChangedListener(this) albumArtistText.setText(albumArtistName)
yearTitle.appHandleColor().addTextChangedListener(this) genreTitle.setText(genreName)
} yearTitle.setText(songYear)
}
private fun fillViewsWithFileTags() { override fun loadCurrentImage() {
albumText.setText(albumTitle) val bitmap = albumArt
albumArtistText.setText(albumArtistName) setImageBitmap(
genreTitle.setText(genreName) bitmap,
yearTitle.setText(songYear) getColor(
} generatePalette(bitmap),
ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
)
)
deleteAlbumArt = false
}
override fun loadCurrentImage() { override fun onPause() {
val bitmap = albumArt super.onPause()
setImageBitmap(bitmap, getColor(generatePalette(bitmap), ATHUtil.resolveColor(this, R.attr.defaultFooterColor))) disposable.clear()
deleteAlbumArt = false }
}
override fun onPause() { private fun extractDetails(lastFmAlbum: LastFmAlbum) {
super.onPause() if (lastFmAlbum.album != null) {
disposable.clear()
}
private fun extractDetails(lastFmAlbum: LastFmAlbum) { val url = LastFMUtil.getLargestAlbumImageUrl(lastFmAlbum.album.image)
if (lastFmAlbum.album != null) {
val url = LastFMUtil.getLargestAlbumImageUrl(lastFmAlbum.album.image) if (!TextUtils.isEmpty(url) && url.trim { it <= ' ' }.isNotEmpty()) {
Glide.with(this@AlbumTagEditorActivity).load(url).asBitmap()
.transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java)
.diskCacheStrategy(DiskCacheStrategy.SOURCE).error(R.drawable.default_album_art)
.into(object : SimpleTarget<BitmapPaletteWrapper>() {
override fun onLoadFailed(
e: java.lang.Exception?,
errorDrawable: Drawable?
) {
super.onLoadFailed(e, errorDrawable)
Toast.makeText(
this@AlbumTagEditorActivity,
e.toString(),
Toast.LENGTH_LONG
).show()
}
if (!TextUtils.isEmpty(url) && url.trim { it <= ' ' }.isNotEmpty()) { override fun onResourceReady(
Glide.with(this@AlbumTagEditorActivity) resource: BitmapPaletteWrapper?,
.load(url) glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?
.asBitmap() ) {
.transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java) albumArtBitmap = resource?.bitmap?.let {
.diskCacheStrategy(DiskCacheStrategy.SOURCE) ImageUtil.resizeBitmap(
.error(R.drawable.default_album_art) it,
.into(object : SimpleTarget<BitmapPaletteWrapper>() { 2048
override fun onLoadFailed(e: java.lang.Exception?, errorDrawable: Drawable?) { )
super.onLoadFailed(e, errorDrawable) }
Toast.makeText(this@AlbumTagEditorActivity, e.toString(), Toast.LENGTH_LONG).show() setImageBitmap(
} albumArtBitmap,
getColor(
resource?.palette,
ATHUtil.resolveColor(
this@AlbumTagEditorActivity,
R.attr.defaultFooterColor
)
)
)
deleteAlbumArt = false
dataChanged()
setResult(RESULT_OK)
}
})
return
}
if (lastFmAlbum.album.tags.tag.size > 0) {
genreTitle.setText(lastFmAlbum.album.tags.tag[0].name)
}
override fun onResourceReady(resource: BitmapPaletteWrapper?, glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?) { }
albumArtBitmap = resource?.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) } toastLoadingFailed()
setImageBitmap(albumArtBitmap, getColor(resource?.palette, ATHUtil.resolveColor(this@AlbumTagEditorActivity, R.attr.defaultFooterColor))) }
deleteAlbumArt = false
dataChanged()
setResult(RESULT_OK)
}
})
return
}
if (lastFmAlbum.album.tags.tag.size > 0) {
genreTitle.setText(lastFmAlbum.album.tags.tag[0].name)
}
} private fun toastLoadingFailed() {
toastLoadingFailed() Toast.makeText(
} this@AlbumTagEditorActivity,
R.string.could_not_download_album_cover,
Toast.LENGTH_SHORT
).show()
}
private fun toastLoadingFailed() { override fun searchImageOnWeb() {
Toast.makeText(this@AlbumTagEditorActivity, R.string.could_not_download_album_cover, Toast.LENGTH_SHORT).show() searchWebFor(albumText.text.toString(), albumArtistText.text.toString())
} }
override fun searchImageOnWeb() { override fun deleteImage() {
searchWebFor(albumText.text.toString(), albumArtistText.text.toString()) setImageBitmap(
} BitmapFactory.decodeResource(resources, R.drawable.default_album_art),
ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
)
deleteAlbumArt = true
dataChanged()
}
override fun deleteImage() { override fun save() {
setImageBitmap(BitmapFactory.decodeResource(resources, R.drawable.default_album_art), ATHUtil.resolveColor(this, R.attr.defaultFooterColor)) val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
deleteAlbumArt = true fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
dataChanged() //android seems not to recognize album_artist field so we additionally write the normal artist field
} fieldKeyValueMap[FieldKey.ARTIST] = albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.GENRE] = genreTitle.text.toString()
fieldKeyValueMap[FieldKey.YEAR] = yearTitle.text.toString()
override fun save() { writeValuesToFiles(
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java) fieldKeyValueMap, if (deleteAlbumArt) ArtworkInfo(id, null)
fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString() else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!)
//android seems not to recognize album_artist field so we additionally write the normal artist field )
fieldKeyValueMap[FieldKey.ARTIST] = albumArtistText.text.toString() }
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.GENRE] = genreTitle.text.toString()
fieldKeyValueMap[FieldKey.YEAR] = yearTitle.text.toString()
writeValuesToFiles(fieldKeyValueMap, if (deleteAlbumArt) ArtworkInfo(id, null) override fun getSongPaths(): List<String> {
else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!)) val songs = AlbumLoader.getAlbum(this, id).songs
} val paths = ArrayList<String>(songs!!.size)
for (song in songs) {
paths.add(song.data)
}
return paths
}
override fun getSongPaths(): List<String> { override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
val songs = AlbumLoader.getAlbum(this, id).songs
val paths = ArrayList<String>(songs!!.size)
for (song in songs) {
paths.add(song.data)
}
return paths
}
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
} }
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { override fun afterTextChanged(s: Editable) {
dataChanged()
}
} override fun setColors(color: Int) {
super.setColors(color)
saveFab.backgroundTintList = ColorStateList.valueOf(color)
}
override fun afterTextChanged(s: Editable) { companion object {
dataChanged()
}
override fun setColors(color: Int) { val TAG: String = AlbumTagEditorActivity::class.java.simpleName
super.setColors(color) }
saveFab.backgroundTintList = ColorStateList.valueOf(color)
}
companion object {
val TAG: String = AlbumTagEditorActivity::class.java.simpleName
}
} }

View file

@ -2,13 +2,10 @@ package code.name.monkey.retromusic.activities.tageditor
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.*
import android.text.TextWatcher
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.appHandleColor import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.loaders.SongLoader import code.name.monkey.retromusic.loaders.SongLoader
@ -16,118 +13,127 @@ import kotlinx.android.synthetic.main.activity_song_tag_editor.*
import org.jaudiotagger.tag.FieldKey import org.jaudiotagger.tag.FieldKey
import java.util.* import java.util.*
class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher { class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
override val contentViewLayout: Int override val contentViewLayout: Int
get() = R.layout.activity_song_tag_editor get() = R.layout.activity_song_tag_editor
private fun setupToolbar() { private fun setupToolbar() {
appBarLayout.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary)) appBarLayout.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
toolbar.apply { toolbar.apply {
setBackgroundColor(ATHUtil.resolveColor(this@SongTagEditorActivity, R.attr.colorPrimary)) setBackgroundColor(
navigationIcon = TintHelper.createTintedDrawable(ContextCompat.getDrawable(context, R.drawable.ic_keyboard_backspace_black_24dp), ThemeStore.textColorPrimary(context)) ATHUtil.resolveColor(
setNavigationOnClickListener { onBackPressed() } this@SongTagEditorActivity,
setSupportActionBar(toolbar) R.attr.colorPrimary
} )
title = null )
} navigationIcon = TintHelper.createTintedDrawable(
ContextCompat.getDrawable(
context,
R.drawable.ic_keyboard_backspace_black_24dp
), ThemeStore.textColorPrimary(context)
)
setNavigationOnClickListener { onBackPressed() }
setSupportActionBar(toolbar)
}
title = null
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setNoImageMode() setNoImageMode()
setUpViews() setUpViews()
setupToolbar() setupToolbar()
setStatusbarColorAuto() setStatusbarColorAuto()
} }
private fun setUpViews() { private fun setUpViews() {
fillViewsWithFileTags() fillViewsWithFileTags()
MaterialUtil.setTint(songTextContainer, false) MaterialUtil.setTint(songTextContainer, false)
MaterialUtil.setTint(composerContainer, false) MaterialUtil.setTint(composerContainer, false)
MaterialUtil.setTint(albumTextContainer, false) MaterialUtil.setTint(albumTextContainer, false)
MaterialUtil.setTint(artistContainer, false) MaterialUtil.setTint(artistContainer, false)
MaterialUtil.setTint(albumArtistContainer, false) MaterialUtil.setTint(albumArtistContainer, false)
MaterialUtil.setTint(yearContainer, false) MaterialUtil.setTint(yearContainer, false)
MaterialUtil.setTint(genreContainer, false) MaterialUtil.setTint(genreContainer, false)
MaterialUtil.setTint(trackNumberContainer, false) MaterialUtil.setTint(trackNumberContainer, false)
MaterialUtil.setTint(lyricsContainer, false) MaterialUtil.setTint(lyricsContainer, false)
songText.appHandleColor().addTextChangedListener(this) songText.appHandleColor().addTextChangedListener(this)
albumText.appHandleColor().addTextChangedListener(this) albumText.appHandleColor().addTextChangedListener(this)
albumArtistText.appHandleColor().addTextChangedListener(this) albumArtistText.appHandleColor().addTextChangedListener(this)
artistText.appHandleColor().addTextChangedListener(this) artistText.appHandleColor().addTextChangedListener(this)
genreText.appHandleColor().addTextChangedListener(this) genreText.appHandleColor().addTextChangedListener(this)
yearText.appHandleColor().addTextChangedListener(this) yearText.appHandleColor().addTextChangedListener(this)
trackNumberText.appHandleColor().addTextChangedListener(this) trackNumberText.appHandleColor().addTextChangedListener(this)
lyricsText.appHandleColor().addTextChangedListener(this) lyricsText.appHandleColor().addTextChangedListener(this)
songComposerText.appHandleColor().addTextChangedListener(this) songComposerText.appHandleColor().addTextChangedListener(this)
} }
private fun fillViewsWithFileTags() { private fun fillViewsWithFileTags() {
songText.setText(songTitle) songText.setText(songTitle)
albumArtistText.setText(albumArtist) albumArtistText.setText(albumArtist)
albumText.setText(albumTitle) albumText.setText(albumTitle)
artistText.setText(artistName) artistText.setText(artistName)
genreText.setText(genreName) genreText.setText(genreName)
yearText.setText(songYear) yearText.setText(songYear)
trackNumberText.setText(trackNumber) trackNumberText.setText(trackNumber)
lyricsText.setText(lyrics) lyricsText.setText(lyrics)
songComposerText.setText(composer) songComposerText.setText(composer)
} }
override fun loadCurrentImage() { override fun loadCurrentImage() {
} }
override fun searchImageOnWeb() { override fun searchImageOnWeb() {
} }
override fun deleteImage() { override fun deleteImage() {
} }
override fun save() { override fun save() {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java) val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.TITLE] = songText.text.toString() fieldKeyValueMap[FieldKey.TITLE] = songText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString() fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
fieldKeyValueMap[FieldKey.ARTIST] = artistText.text.toString() fieldKeyValueMap[FieldKey.ARTIST] = artistText.text.toString()
fieldKeyValueMap[FieldKey.GENRE] = genreText.text.toString() fieldKeyValueMap[FieldKey.GENRE] = genreText.text.toString()
fieldKeyValueMap[FieldKey.YEAR] = yearText.text.toString() fieldKeyValueMap[FieldKey.YEAR] = yearText.text.toString()
fieldKeyValueMap[FieldKey.TRACK] = trackNumberText.text.toString() fieldKeyValueMap[FieldKey.TRACK] = trackNumberText.text.toString()
fieldKeyValueMap[FieldKey.LYRICS] = lyricsText.text.toString() fieldKeyValueMap[FieldKey.LYRICS] = lyricsText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString() fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.COMPOSER] = songComposerText.text.toString() fieldKeyValueMap[FieldKey.COMPOSER] = songComposerText.text.toString()
writeValuesToFiles(fieldKeyValueMap, null) writeValuesToFiles(fieldKeyValueMap, null)
} }
override fun getSongPaths(): List<String> { override fun getSongPaths(): List<String> {
val paths = ArrayList<String>(1) val paths = ArrayList<String>(1)
paths.add(SongLoader.getSong(this, id).data) paths.add(SongLoader.getSong(this, id).data)
return paths return paths
} }
override fun loadImageFromFile(selectedFile: Uri?) { override fun loadImageFromFile(selectedFile: Uri?) {
} }
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
} }
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
} }
override fun afterTextChanged(s: Editable) { override fun afterTextChanged(s: Editable) {
dataChanged() dataChanged()
} }
companion object { companion object {
val TAG: String = SongTagEditorActivity::class.java.simpleName val TAG: String = SongTagEditorActivity::class.java.simpleName
} }
} }

View file

@ -1,9 +1,7 @@
package code.name.monkey.retromusic.adapter package code.name.monkey.retromusic.adapter
import android.app.Activity import android.app.Activity
import android.view.LayoutInflater import android.view.*
import android.view.View
import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
@ -13,56 +11,64 @@ import code.name.monkey.retromusic.views.CircularImageView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
class ContributorAdapter( class ContributorAdapter(
private var contributors: List<Contributor> private var contributors: List<Contributor>
) : RecyclerView.Adapter<ContributorAdapter.ViewHolder>() { ) : RecyclerView.Adapter<ContributorAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return if (viewType == HEADER) { return if (viewType == HEADER) {
ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_contributor_header, parent, false)) ViewHolder(
} else LayoutInflater.from(parent.context).inflate(
ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_contributor, parent, false)) R.layout.item_contributor_header,
} parent,
false
)
)
} else ViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_contributor,
parent,
false
)
)
}
companion object { companion object {
const val HEADER: Int = 0 const val HEADER: Int = 0
const val ITEM: Int = 1 const val ITEM: Int = 1
} }
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return if (position == 0) { return if (position == 0) {
HEADER HEADER
} else { } else {
ITEM ITEM
} }
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val contributor = contributors[position] val contributor = contributors[position]
holder.bindData(contributor) holder.bindData(contributor)
holder.itemView.setOnClickListener { holder.itemView.setOnClickListener {
openUrl(it?.context as Activity, contributors[position].link) openUrl(it?.context as Activity, contributors[position].link)
} }
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
return contributors.size return contributors.size
} }
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.findViewById(R.id.title) val title: TextView = itemView.findViewById(R.id.title)
val text: TextView = itemView.findViewById(R.id.text) val text: TextView = itemView.findViewById(R.id.text)
val image: CircularImageView = itemView.findViewById(R.id.icon) val image: CircularImageView = itemView.findViewById(R.id.icon)
internal fun bindData(contributor: Contributor) { internal fun bindData(contributor: Contributor) {
title.text = contributor.name title.text = contributor.name
text.text = contributor.summary text.text = contributor.summary
println(contributor.profileImage) println(contributor.profileImage)
Glide.with(image.context) Glide.with(image.context).load(contributor.profileImage)
.load(contributor.profileImage) .error(R.drawable.ic_account_white_24dp)
.error(R.drawable.ic_account_white_24dp) .placeholder(R.drawable.ic_account_white_24dp).dontAnimate().into(image)
.placeholder(R.drawable.ic_account_white_24dp) }
.dontAnimate() }
.into(image)
}
}
} }

View file

@ -1,9 +1,7 @@
package code.name.monkey.retromusic.adapter package code.name.monkey.retromusic.adapter
import android.app.Activity import android.app.Activity
import android.view.LayoutInflater import android.view.*
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
@ -16,48 +14,49 @@ import java.util.*
*/ */
class GenreAdapter( class GenreAdapter(
private val mActivity: Activity, private val activity: Activity, dataSet: ArrayList<Genre>, private val mItemLayoutRes: Int
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(mActivity).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) { if (holder.title != null) {
holder.title!!.text = genre.name holder.title!!.text = genre.name
} }
if (holder.text != null) { if (holder.text != null) {
holder.text!!.text = String.format(Locale.getDefault(), "%d %s", genre.songCount, if (genre.songCount > 1) holder.text!!.text = String.format(
mActivity.getString(R.string.songs) Locale.getDefault(),
else "%d %s",
mActivity.getString(R.string.song)) 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(mActivity, genre) NavigationUtil.goToGenre(activity, genre)
} }
} }
} }

View file

@ -1,181 +1,221 @@
package code.name.monkey.retromusic.adapter package code.name.monkey.retromusic.adapter
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.LayoutInflater import android.view.*
import android.view.View
import android.view.ViewGroup
import androidx.annotation.IntDef import androidx.annotation.IntDef
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.AlbumFullWidthAdapter import code.name.monkey.retromusic.adapter.album.AlbumFullWidthAdapter
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
import code.name.monkey.retromusic.adapter.song.SongAdapter import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.extensions.show 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.*
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.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
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { ) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var list = ArrayList<Home>() private var list = ArrayList<Home>()
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return list[position].homeSection return list[position].homeSection
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layout = LayoutInflater.from(activity).inflate(R.layout.section_recycler_view, parent, false) val layout = LayoutInflater.from(activity)
return when (viewType) { .inflate(R.layout.section_recycler_view, parent, false)
RECENT_ARTISTS, TOP_ARTISTS -> ArtistViewHolder(layout) return when (viewType) {
PLAYLISTS -> PlaylistViewHolder(layout) RECENT_ARTISTS, TOP_ARTISTS -> ArtistViewHolder(layout)
else -> { PLAYLISTS -> PlaylistViewHolder(layout)
AlbumViewHolder(LayoutInflater.from(activity).inflate(R.layout.metal_section_recycler_view, parent, false)) else -> {
} AlbumViewHolder(
} LayoutInflater.from(activity).inflate(
} R.layout.metal_section_recycler_view,
parent,
false
)
)
}
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
println("ViewType ${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(list[position].arrayList.toAlbums(), R.string.recent_albums, R.string.recent_added_albums) viewHolder.bindView(
} list[position].arrayList.toAlbums(),
TOP_ALBUMS -> { R.string.recent_albums,
val viewHolder = holder as AlbumViewHolder R.string.recent_added_albums
viewHolder.bindView(list[position].arrayList.toAlbums(), R.string.top_albums, R.string.most_played_albums) )
} }
RECENT_ARTISTS -> { TOP_ALBUMS -> {
val viewHolder = holder as ArtistViewHolder val viewHolder = holder as AlbumViewHolder
viewHolder.bindView(list[position].arrayList.toArtists(), R.string.recent_artists, R.string.recent_added_artists) viewHolder.bindView(
} list[position].arrayList.toAlbums(),
TOP_ARTISTS -> { R.string.top_albums,
val viewHolder = holder as ArtistViewHolder R.string.most_played_albums
)
}
RECENT_ARTISTS -> {
val viewHolder = holder as ArtistViewHolder
viewHolder.bindView(
list[position].arrayList.toArtists(),
R.string.recent_artists,
R.string.recent_added_artists
)
}
TOP_ARTISTS -> {
val viewHolder = holder as ArtistViewHolder
viewHolder.bindView(list[position].arrayList.toArtists(), R.string.top_artists, R.string.most_played_artists) viewHolder.bindView(
} list[position].arrayList.toArtists(),
PLAYLISTS -> { R.string.top_artists,
val viewHolder = holder as PlaylistViewHolder R.string.most_played_artists
viewHolder.bindView(list[position].arrayList.toPlaylist(), R.string.favorites, R.string.favorites_songs) )
} }
} PLAYLISTS -> {
} val viewHolder = holder as PlaylistViewHolder
viewHolder.bindView(
list[position].arrayList.toPlaylist(),
R.string.favorites,
R.string.favorites_songs
)
}
}
}
override fun getItemCount(): Int { override fun getItemCount(): Int {
return list.size return list.size
} }
fun swapData(sections: ArrayList<Home>) { fun swapData(sections: ArrayList<Home>) {
list = sections list = sections
notifyDataSetChanged() notifyDataSetChanged()
} }
companion object { companion object {
@IntDef(RECENT_ALBUMS, TOP_ALBUMS, RECENT_ARTISTS, TOP_ARTISTS, PLAYLISTS) @IntDef(RECENT_ALBUMS, TOP_ALBUMS, RECENT_ARTISTS, TOP_ARTISTS, PLAYLISTS)
@Retention(AnnotationRetention.SOURCE) @Retention(AnnotationRetention.SOURCE)
annotation class HomeSection annotation class HomeSection
const val RECENT_ALBUMS = 3 const val RECENT_ALBUMS = 3
const val TOP_ALBUMS = 1 const val TOP_ALBUMS = 1
const val RECENT_ARTISTS = 2 const val RECENT_ARTISTS = 2
const val TOP_ARTISTS = 0 const val TOP_ARTISTS = 0
const val PLAYLISTS = 4 const val PLAYLISTS = 4
} }
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) { private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
fun bindView(list: ArrayList<Album>, titleRes: Int, subtitleRes: Int) { fun bindView(list: ArrayList<Album>, titleRes: Int, subtitleRes: Int) {
if (list.isNotEmpty()) { if (list.isNotEmpty()) {
recyclerView.apply { recyclerView.apply {
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) {
fun bindView(list: ArrayList<Artist>, titleRes: Int, subtitleRes: Int) { fun bindView(list: ArrayList<Artist>, titleRes: Int, subtitleRes: Int) {
if (list.isNotEmpty()) { if (list.isNotEmpty()) {
recyclerView.apply { recyclerView.apply {
show() show()
layoutManager = GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false) layoutManager = GridLayoutManager(
val artistAdapter = ArtistAdapter(activity, list, activity,
PreferenceUtil.getInstance(activity).getHomeGridStyle(activity), false, null) 1,
adapter = artistAdapter GridLayoutManager.HORIZONTAL,
} false
titleContainer.show() )
title.text = activity.getString(titleRes) val artistAdapter = ArtistAdapter(
text.text = activity.getString(subtitleRes) activity,
} list,
} PreferenceUtil.getInstance(activity).getHomeGridStyle(activity),
} false,
null
)
adapter = artistAdapter
}
titleContainer.show()
title.text = activity.getString(titleRes)
text.text = activity.getString(subtitleRes)
}
}
}
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) { private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
fun bindView(arrayList: ArrayList<Playlist>, titleRes: Int, subtitleRes: Int) { fun bindView(arrayList: ArrayList<Playlist>, titleRes: Int, subtitleRes: Int) {
if (arrayList.isNotEmpty()) { if (arrayList.isNotEmpty()) {
val songs = PlaylistSongsLoader.getPlaylistSongList(activity, arrayList[0]) val songs = PlaylistSongsLoader.getPlaylistSongList(activity, arrayList[0])
if (songs.isNotEmpty()) { if (songs.isNotEmpty()) {
recyclerView.apply { recyclerView.apply {
show() show()
val songAdapter = SongAdapter(activity, songs, R.layout.item_album_card, false, null) val songAdapter = SongAdapter(
layoutManager = GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false) activity,
adapter = songAdapter songs,
R.layout.item_album_card,
false,
null
)
layoutManager = GridLayoutManager(
activity,
1,
GridLayoutManager.HORIZONTAL,
false
)
adapter = songAdapter
} }
titleContainer.show() titleContainer.show()
title.text = activity.getString(titleRes) title.text = activity.getString(titleRes)
text.text = activity.getString(subtitleRes) text.text = activity.getString(subtitleRes)
} }
} }
} }
} }
open inner class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) { open inner class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView) val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView)
val titleContainer: View = itemView.findViewById(R.id.titleContainer) val titleContainer: View = itemView.findViewById(R.id.titleContainer)
val title: MaterialTextView = itemView.findViewById(R.id.title) val title: MaterialTextView = itemView.findViewById(R.id.title)
val text: MaterialTextView = itemView.findViewById(R.id.text) val text: MaterialTextView = itemView.findViewById(R.id.text)
} }
} }
private fun <E> ArrayList<E>.toAlbums(): ArrayList<Album> { private fun <E> ArrayList<E>.toAlbums(): ArrayList<Album> {
val arrayList = ArrayList<Album>() val arrayList = ArrayList<Album>()
for (x in this) { for (x in this) {
arrayList.add(x as Album) arrayList.add(x as Album)
} }
return arrayList; return arrayList;
} }
private fun <E> ArrayList<E>.toArtists(): ArrayList<Artist> { private fun <E> ArrayList<E>.toArtists(): ArrayList<Artist> {
val arrayList = ArrayList<Artist>() val arrayList = ArrayList<Artist>()
for (x in this) { for (x in this) {
arrayList.add(x as Artist) arrayList.add(x as Artist)
} }
return arrayList; return arrayList;
} }
private fun <E> ArrayList<E>.toPlaylist(): ArrayList<Playlist> { private fun <E> ArrayList<E>.toPlaylist(): ArrayList<Playlist> {
val arrayList = ArrayList<Playlist>() val arrayList = ArrayList<Playlist>()
for (x in this) { for (x in this) {
arrayList.add(x as Playlist) arrayList.add(x as Playlist)
} }
return arrayList; return arrayList;
} }

View file

@ -1,129 +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.LayoutInflater import android.view.*
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.ArtistGlideRequest import code.name.monkey.retromusic.glide.*
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.Album import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.util.*
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 android.util.Pair as UtilPair import android.util.Pair as UtilPair
class SearchAdapter( class SearchAdapter(
private val activity: AppCompatActivity, private val activity: AppCompatActivity, private var dataSet: List<Any>?
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 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(LayoutInflater.from(activity).inflate(R.layout.sub_header, parent, false), viewType) else ViewHolder(LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false), viewType) return if (viewType == HEADER) ViewHolder(
} LayoutInflater.from(activity).inflate(
R.layout.sub_header,
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() .checkIgnoreMediaStore(activity).build().into(holder.image)
.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) .into(holder.image)
.build().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 -> {
else -> { holder.title?.text = dataSet?.get(position).toString()
holder.title?.text = dataSet?.get(position).toString() holder.title?.setTextColor(ThemeStore.accentColor(activity))
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(activity, val options = ActivityOptions.makeSceneTransitionAnimation(
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)
} }
SONG -> { ARTIST -> {
val playList = ArrayList<Song>() val options = ActivityOptions.makeSceneTransitionAnimation(
playList.add(item as Song) activity,
MusicPlayerRemote.openQueue(playList, 0, true) UtilPair.create(
} image,
} 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
} }
} }

View file

@ -1,15 +1,11 @@
package code.name.monkey.retromusic.adapter package code.name.monkey.retromusic.adapter
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.view.LayoutInflater import android.view.*
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.*
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.audiocover.AudioFileCover import code.name.monkey.retromusic.glide.audiocover.AudioFileCover
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.RetroUtil
@ -20,162 +16,164 @@ import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
import java.io.File import java.io.File
import java.text.DecimalFormat import java.text.DecimalFormat
import java.util.* import java.util.*
import kotlin.math.log10 import kotlin.math.*
import kotlin.math.pow
class SongFileAdapter( class SongFileAdapter(
private val activity: AppCompatActivity, private val activity: AppCompatActivity,
private var dataSet: List<File>?, private var dataSet: List<File>?,
private val itemLayoutRes: Int, private val itemLayoutRes: Int,
private val callbacks: Callbacks?, private val callbacks: Callbacks?,
cabHolder: CabHolder? cabHolder: CabHolder?
) : AbsMultiSelectAdapter<SongFileAdapter.ViewHolder, File>(activity, cabHolder, R.menu.menu_media_selection), FastScrollRecyclerView.SectionedAdapter { ) : AbsMultiSelectAdapter<SongFileAdapter.ViewHolder, File>(
activity, cabHolder, R.menu.menu_media_selection
), FastScrollRecyclerView.SectionedAdapter {
init { init {
this.setHasStableIds(true) this.setHasStableIds(true)
} }
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return if (dataSet!![position].isDirectory) FOLDER else FILE return if (dataSet!![position].isDirectory) FOLDER else FILE
} }
override fun getItemId(position: Int): Long { override fun getItemId(position: Int): Long {
return dataSet!![position].hashCode().toLong() return dataSet!![position].hashCode().toLong()
} }
fun swapDataSet(songFiles: List<File>) { fun swapDataSet(songFiles: List<File>) {
this.dataSet = songFiles this.dataSet = songFiles
notifyDataSetChanged() notifyDataSetChanged()
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)) return ViewHolder(LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false))
} }
override fun onBindViewHolder(holder: ViewHolder, index: Int) { override fun onBindViewHolder(holder: ViewHolder, index: Int) {
val file = dataSet!![index] val file = dataSet!![index]
holder.itemView.isActivated = isChecked(file) holder.itemView.isActivated = isChecked(file)
holder.title?.text = getFileTitle(file) holder.title?.text = getFileTitle(file)
if (holder.text != null) { if (holder.text != null) {
if (holder.itemViewType == FILE) { if (holder.itemViewType == FILE) {
holder.text!!.text = getFileText(file) holder.text?.text = getFileText(file)
} else { } else {
holder.text!!.visibility = View.GONE holder.text?.visibility = View.GONE
} }
} }
if (holder.image != null) { if (holder.image != null) {
loadFileImage(file, holder) loadFileImage(file, holder)
} }
} }
private fun getFileTitle(file: File): String { private fun getFileTitle(file: File): String {
return file.name return file.name
} }
private fun getFileText(file: File): String? { private fun getFileText(file: File): String? {
return if (file.isDirectory) null else readableFileSize(file.length()) return if (file.isDirectory) null else readableFileSize(file.length())
} }
private fun loadFileImage(file: File, holder: ViewHolder) { private fun loadFileImage(file: File, holder: ViewHolder) {
val iconColor = ATHUtil.resolveColor(activity, R.attr.iconColor) val iconColor = ATHUtil.resolveColor(activity, R.attr.iconColor)
if (file.isDirectory) { if (file.isDirectory) {
holder.image?.let { holder.image?.let {
it.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN) it.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN)
it.setImageResource(R.drawable.ic_folder_white_24dp) it.setImageResource(R.drawable.ic_folder_white_24dp)
} }
holder.imageTextContainer?.setCardBackgroundColor(ATHUtil.resolveColor(activity, R.attr.colorPrimary)) holder.imageTextContainer?.setCardBackgroundColor(
ATHUtil.resolveColor(
activity, R.attr.colorPrimary
)
)
} else { } else {
val error = RetroUtil.getTintedVectorDrawable(activity, R.drawable.ic_file_music_white_24dp, iconColor) val error = RetroUtil.getTintedVectorDrawable(
Glide.with(activity) activity, R.drawable.ic_file_music_white_24dp, iconColor
.load(AudioFileCover(file.path)) )
.diskCacheStrategy(DiskCacheStrategy.NONE) Glide.with(activity).load(AudioFileCover(file.path))
.error(error) .diskCacheStrategy(DiskCacheStrategy.NONE).error(error).placeholder(error)
.placeholder(error) .animate(android.R.anim.fade_in)
.animate(android.R.anim.fade_in) .signature(MediaStoreSignature("", file.lastModified(), 0)).into(holder.image)
.signature(MediaStoreSignature("", file.lastModified(), 0)) }
.into(holder.image) }
}
}
override fun getItemCount(): Int { override fun getItemCount(): Int {
return dataSet!!.size return dataSet!!.size
} }
override fun getIdentifier(position: Int): File? { override fun getIdentifier(position: Int): File? {
return dataSet!![position] return dataSet!![position]
} }
override fun getName(`object`: File): String { override fun getName(`object`: File): String {
return getFileTitle(`object`) return getFileTitle(`object`)
} }
override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<File>) { override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<File>) {
if (callbacks == null) return if (callbacks == null) return
callbacks.onMultipleItemAction(menuItem, selection) callbacks.onMultipleItemAction(menuItem, selection)
} }
override fun getSectionName(position: Int): String { override fun getSectionName(position: Int): String {
return dataSet!![position].name[0].toString().toUpperCase() return dataSet!![position].name[0].toString().toUpperCase()
} }
interface Callbacks { interface Callbacks {
fun onFileSelected(file: File) fun onFileSelected(file: File)
fun onFileMenuClicked(file: File, view: View) fun onFileMenuClicked(file: File, view: View)
fun onMultipleItemAction(item: MenuItem, files: ArrayList<File>) fun onMultipleItemAction(item: MenuItem, files: ArrayList<File>)
} }
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
init { init {
if (menu != null && callbacks != null) { if (menu != null && callbacks != null) {
menu!!.setOnClickListener { v -> menu!!.setOnClickListener { v ->
val position = adapterPosition val position = adapterPosition
if (isPositionInRange(position)) { if (isPositionInRange(position)) {
callbacks.onFileMenuClicked(dataSet!![position], v) callbacks.onFileMenuClicked(dataSet!![position], v)
} }
} }
} }
if (imageTextContainer != null) { if (imageTextContainer != null) {
imageTextContainer?.cardElevation = 0f imageTextContainer?.cardElevation = 0f
} }
} }
override fun onClick(v: View?) { override fun onClick(v: View?) {
val position = adapterPosition val position = adapterPosition
if (isPositionInRange(position)) { if (isPositionInRange(position)) {
if (isInQuickSelectMode) { if (isInQuickSelectMode) {
toggleChecked(position) toggleChecked(position)
} else { } else {
callbacks?.onFileSelected(dataSet!![position]) callbacks?.onFileSelected(dataSet!![position])
} }
} }
} }
override fun onLongClick(v: View?): Boolean { override fun onLongClick(v: View?): Boolean {
val position = adapterPosition val position = adapterPosition
return isPositionInRange(position) && toggleChecked(position) return isPositionInRange(position) && toggleChecked(position)
} }
private fun isPositionInRange(position: Int): Boolean { private fun isPositionInRange(position: Int): Boolean {
return position >= 0 && position < dataSet!!.size return position >= 0 && position < dataSet!!.size
} }
} }
companion object { companion object {
private const val FILE = 0 private const val FILE = 0
private const val FOLDER = 1 private const val FOLDER = 1
fun readableFileSize(size: Long): String { fun readableFileSize(size: Long): String {
if (size <= 0) return "$size B" if (size <= 0) return "$size B"
val units = arrayOf("B", "KB", "MB", "GB", "TB") val units = arrayOf("B", "KB", "MB", "GB", "TB")
val digitGroups = (log10(size.toDouble()) / log10(1024.0)).toInt() val digitGroups = (log10(size.toDouble()) / log10(1024.0)).toInt()
return DecimalFormat("#,##0.##").format(size / 1024.0.pow(digitGroups.toDouble())) + " " + units[digitGroups] return DecimalFormat("#,##0.##").format(size / 1024.0.pow(digitGroups.toDouble())) + " " + units[digitGroups]
} }
} }
} }

View file

@ -3,186 +3,198 @@ package code.name.monkey.retromusic.adapter.album
import android.app.ActivityOptions import android.app.ActivityOptions
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.LayoutInflater import android.view.*
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.*
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import code.name.monkey.retromusic.glide.*
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.helper.*
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
open class AlbumAdapter(
protected val activity: AppCompatActivity,
dataSet: ArrayList<Album>,
protected var itemLayoutRes: Int,
usePalette: Boolean,
cabHolder: CabHolder?
) : AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album>(
activity, cabHolder, code.name.monkey.retromusic.R.menu.menu_media_selection
), FastScrollRecyclerView.SectionedAdapter {
var dataSet: ArrayList<Album>
protected set
open class AlbumAdapter(protected val activity: AppCompatActivity, protected var usePalette = false
dataSet: ArrayList<Album>,
@param:LayoutRes protected var itemLayoutRes: Int,
usePalette: Boolean,
cabHolder: CabHolder?) : AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album>(activity, cabHolder, code.name.monkey.retromusic.R.menu.menu_media_selection), FastScrollRecyclerView.SectionedAdapter {
var dataSet: ArrayList<Album>
protected set
protected var usePalette = false init {
this.dataSet = dataSet
this.usePalette = usePalette
this.setHasStableIds(true)
}
fun useItemLayout(itemLayoutRes: Int) {
this.itemLayoutRes = itemLayoutRes
notifyDataSetChanged()
}
init { fun usePalette(usePalette: Boolean) {
this.dataSet = dataSet this.usePalette = usePalette
this.usePalette = usePalette notifyDataSetChanged()
this.setHasStableIds(true) }
}
fun useItemLayout(itemLayoutRes: Int) { fun swapDataSet(dataSet: ArrayList<Album>) {
this.itemLayoutRes = itemLayoutRes this.dataSet = dataSet
notifyDataSetChanged() notifyDataSetChanged()
} }
fun usePalette(usePalette: Boolean) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
this.usePalette = usePalette val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)
notifyDataSetChanged() return createViewHolder(view, viewType)
} }
fun swapDataSet(dataSet: ArrayList<Album>) { protected open fun createViewHolder(view: View, viewType: Int): ViewHolder {
this.dataSet = dataSet return ViewHolder(view)
notifyDataSetChanged() }
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { private fun getAlbumTitle(album: Album): String? {
val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false) return album.title
return createViewHolder(view, viewType) }
}
protected open fun createViewHolder(view: View, viewType: Int): ViewHolder { protected open fun getAlbumText(album: Album): String? {
return ViewHolder(view) return album.artistName
} }
private fun getAlbumTitle(album: Album): String? { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
return album.title val album = dataSet[position]
} val isChecked = isChecked(album)
holder.itemView.isActivated = isChecked
holder.title?.text = getAlbumTitle(album)
holder.text?.text = getAlbumText(album)
holder.playSongs?.setOnClickListener {
album.songs?.let { songs ->
MusicPlayerRemote.openQueue(
songs, 0, true
)
}
}
loadAlbumCover(album, holder)
}
protected open fun getAlbumText(album: Album): String? { protected open fun setColors(color: Int, holder: ViewHolder) {
return album.artistName if (holder.paletteColorContainer != null) {
} holder.title?.setTextColor(
MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color))
)
holder.text?.setTextColor(
MaterialValueHelper.getSecondaryTextColor(
activity, ColorUtil.isColorLight(
color
)
)
)
holder.paletteColorContainer?.setBackgroundColor(color)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.mask?.backgroundTintList = ColorStateList.valueOf(color)
val album = dataSet[position] }
val isChecked = isChecked(album)
holder.itemView.isActivated = isChecked
holder.title?.text = getAlbumTitle(album)
holder.text?.text = getAlbumText(album)
holder.playSongs?.setOnClickListener { album.songs?.let { songs -> MusicPlayerRemote.openQueue(songs, 0, true) } }
loadAlbumCover(album, holder)
}
protected open fun setColors(color: Int, holder: ViewHolder) { protected open fun loadAlbumCover(album: Album, holder: ViewHolder) {
if (holder.paletteColorContainer != null) { if (holder.image == null) {
holder.title?.setTextColor( return
MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color))) }
holder.text?.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color)))
holder.paletteColorContainer?.setBackgroundColor(color)
}
holder.mask?.backgroundTintList = ColorStateList.valueOf(color) SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
} .checkIgnoreMediaStore(activity).generatePalette(activity).build()
.into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onLoadCleared(placeholder: Drawable?) {
super.onLoadCleared(placeholder)
setColors(defaultFooterColor, holder)
}
protected open fun loadAlbumCover(album: Album, holder: ViewHolder) { override fun onColorReady(color: Int) {
if (holder.image == null) { setColors(color, holder)
return }
} })
}
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) override fun getItemCount(): Int {
.checkIgnoreMediaStore(activity) return dataSet.size
.generatePalette(activity).build() }
.into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onLoadCleared(placeholder: Drawable?) {
super.onLoadCleared(placeholder)
setColors(defaultFooterColor, holder)
}
override fun onColorReady(color: Int) { override fun getItemId(position: Int): Long {
setColors(color, holder) return dataSet[position].id.toLong()
} }
})
}
override fun getItemCount(): Int { override fun getIdentifier(position: Int): Album? {
return dataSet.size return dataSet[position]
} }
override fun getItemId(position: Int): Long { override fun getName(album: Album): String {
return dataSet[position].id.toLong() return album.title!!
} }
override fun getIdentifier(position: Int): Album? { override fun onMultipleItemAction(
return dataSet[position] menuItem: MenuItem, selection: ArrayList<Album>
} ) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
}
override fun getName(album: Album): String { private fun getSongList(albums: List<Album>): ArrayList<Song> {
return album.title!! val songs = ArrayList<Song>()
} for (album in albums) {
songs.addAll(album.songs!!)
}
return songs
}
override fun onMultipleItemAction(menuItem: MenuItem, override fun getSectionName(position: Int): String {
selection: ArrayList<Album>) { var sectionName: String? = null
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId) when (PreferenceUtil.getInstance(activity).albumSortOrder) {
} SortOrder.AlbumSortOrder.ALBUM_A_Z, SortOrder.AlbumSortOrder.ALBUM_Z_A -> sectionName = dataSet[position].title
SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].artistName
SortOrder.AlbumSortOrder.ALBUM_YEAR -> return MusicUtil.getYearString(
dataSet[position].year
)
}
private fun getSongList(albums: List<Album>): ArrayList<Song> { return MusicUtil.getSectionName(sectionName)
val songs = ArrayList<Song>() }
for (album in albums) {
songs.addAll(album.songs!!)
}
return songs
}
override fun getSectionName(position: Int): String { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
var sectionName: String? = null
when (PreferenceUtil.getInstance(activity).albumSortOrder) {
SortOrder.AlbumSortOrder.ALBUM_A_Z, SortOrder.AlbumSortOrder.ALBUM_Z_A -> sectionName = dataSet[position].title
SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].artistName
SortOrder.AlbumSortOrder.ALBUM_YEAR -> return MusicUtil.getYearString(dataSet[position].year)
}
return MusicUtil.getSectionName(sectionName) init {
} setImageTransitionName(activity.getString(R.string.transition_album_art))
menu?.visibility = View.GONE
}
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) { override fun onClick(v: View?) {
super.onClick(v)
if (isInQuickSelectMode) {
toggleChecked(adapterPosition)
} else {
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
activity, image, activity.getString(
R.string.transition_album_art
)
)
NavigationUtil.goToAlbumOptions(
activity, dataSet[adapterPosition].id, activityOptions
)
}
}
init { override fun onLongClick(v: View?): Boolean {
setImageTransitionName(activity.getString(R.string.transition_album_art)) toggleChecked(adapterPosition)
menu?.visibility = View.GONE return super.onLongClick(v)
} }
}
override fun onClick(v: View?) { companion object {
super.onClick(v) val TAG: String = AlbumAdapter::class.java.simpleName
if (isInQuickSelectMode) { }
toggleChecked(adapterPosition)
} else {
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(activity, image, activity.getString(R.string.transition_album_art))
NavigationUtil.goToAlbumOptions(activity, dataSet[adapterPosition].id, activityOptions)
}
}
override fun onLongClick(v: View?): Boolean {
toggleChecked(adapterPosition)
return super.onLongClick(v)
}
}
companion object {
val TAG: String = AlbumAdapter::class.java.simpleName
}
} }

View file

@ -1,166 +1,165 @@
package code.name.monkey.retromusic.adapter.album package code.name.monkey.retromusic.adapter.album
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.*
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import androidx.fragment.app.Fragment import androidx.fragment.app.*
import androidx.fragment.app.FragmentManager
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.fragments.AlbumCoverStyle import code.name.monkey.retromusic.fragments.AlbumCoverStyle
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.*
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.misc.CustomFragmentStatePagerAdapter import code.name.monkey.retromusic.misc.CustomFragmentStatePagerAdapter
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import java.util.* import java.util.*
class AlbumCoverPagerAdapter(
fm: FragmentManager,
private val dataSet: ArrayList<Song>
) : CustomFragmentStatePagerAdapter(fm) {
class AlbumCoverPagerAdapter(fm: FragmentManager, private val dataSet: ArrayList<Song>) : CustomFragmentStatePagerAdapter(fm) { private var currentColorReceiver: AlbumCoverFragment.ColorReceiver? = null
private var currentColorReceiverPosition = -1
private var currentColorReceiver: AlbumCoverFragment.ColorReceiver? = null override fun getItem(position: Int): Fragment {
private var currentColorReceiverPosition = -1 return AlbumCoverFragment.newInstance(dataSet[position])
}
override fun getItem(position: Int): Fragment { override fun getCount(): Int {
return AlbumCoverFragment.newInstance(dataSet[position]) return dataSet.size
} }
override fun getCount(): Int { override fun instantiateItem(container: ViewGroup, position: Int): Any {
return dataSet.size val o = super.instantiateItem(container, position)
} if (currentColorReceiver != null && currentColorReceiverPosition == position) {
receiveColor(currentColorReceiver!!, currentColorReceiverPosition)
}
return o
}
override fun instantiateItem(container: ViewGroup, position: Int): Any { /**
val o = super.instantiateItem(container, position) * Only the latest passed [AlbumCoverFragment.ColorReceiver] is guaranteed to receive a
if (currentColorReceiver != null && currentColorReceiverPosition == position) { * response
receiveColor(currentColorReceiver!!, currentColorReceiverPosition) */
} fun receiveColor(colorReceiver: AlbumCoverFragment.ColorReceiver, position: Int) {
return o
}
/** if (getFragment(position) is AlbumCoverFragment) {
* Only the latest passed [AlbumCoverFragment.ColorReceiver] is guaranteed to receive a val fragment = getFragment(position) as AlbumCoverFragment
* response currentColorReceiver = null
*/ currentColorReceiverPosition = -1
fun receiveColor(colorReceiver: AlbumCoverFragment.ColorReceiver, position: Int) { fragment.receiveColor(colorReceiver, position)
} else {
currentColorReceiver = colorReceiver
currentColorReceiverPosition = position
}
}
if (getFragment(position) is AlbumCoverFragment) { class AlbumCoverFragment : Fragment() {
val fragment = getFragment(position) as AlbumCoverFragment
currentColorReceiver = null
currentColorReceiverPosition = -1
fragment.receiveColor(colorReceiver, position)
} else {
currentColorReceiver = colorReceiver
currentColorReceiverPosition = position
}
}
class AlbumCoverFragment : Fragment() { lateinit var albumCover: ImageView
private var isColorReady: Boolean = false
private var color: Int = 0
private lateinit var song: Song
private var colorReceiver: ColorReceiver? = null
private var request: Int = 0
lateinit var albumCover: ImageView private val layout: Int
private var isColorReady: Boolean = false get() {
private var color: Int = 0 return when (PreferenceUtil.getInstance(activity).albumCoverStyle) {
private lateinit var song: Song AlbumCoverStyle.NORMAL -> R.layout.fragment_album_cover
private var colorReceiver: ColorReceiver? = null AlbumCoverStyle.FLAT -> R.layout.fragment_album_flat_cover
private var request: Int = 0 AlbumCoverStyle.CIRCLE -> R.layout.fragment_album_circle_cover
AlbumCoverStyle.CARD -> R.layout.fragment_album_card_cover
AlbumCoverStyle.MATERIAL -> R.layout.fragment_album_material_cover
AlbumCoverStyle.FULL -> R.layout.fragment_album_full_cover
AlbumCoverStyle.FULL_CARD -> R.layout.fragment_album_full_card_cover
else -> R.layout.fragment_album_cover
}
}
private val layout: Int override fun onCreate(savedInstanceState: Bundle?) {
get() { super.onCreate(savedInstanceState)
return when (PreferenceUtil.getInstance(activity).albumCoverStyle) { if (arguments != null) {
AlbumCoverStyle.NORMAL -> R.layout.fragment_album_cover song = arguments!!.getParcelable(SONG_ARG)!!
AlbumCoverStyle.FLAT -> R.layout.fragment_album_flat_cover }
AlbumCoverStyle.CIRCLE -> R.layout.fragment_album_circle_cover }
AlbumCoverStyle.CARD -> R.layout.fragment_album_card_cover
AlbumCoverStyle.MATERIAL -> R.layout.fragment_album_material_cover
AlbumCoverStyle.FULL -> R.layout.fragment_album_full_cover
AlbumCoverStyle.FULL_CARD -> R.layout.fragment_album_full_card_cover
else -> R.layout.fragment_album_cover
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreateView(
super.onCreate(savedInstanceState) inflater: LayoutInflater,
if (arguments != null) { container: ViewGroup?,
song = arguments!!.getParcelable(SONG_ARG)!! savedInstanceState: Bundle?
} ): View? {
} val finalLayout = when {
PreferenceUtil.getInstance(activity).carouselEffect() -> R.layout.fragment_album_carousel_cover
else -> layout
}
val view = inflater.inflate(finalLayout, container, false)
albumCover = view.findViewById(R.id.player_image)
albumCover.setOnClickListener {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { NavigationUtil.goToLyrics(requireActivity())
val finalLayout = when { }
PreferenceUtil.getInstance(activity).carouselEffect() -> R.layout.fragment_album_carousel_cover return view
else -> layout }
}
val view = inflater.inflate(finalLayout, container, false)
albumCover = view.findViewById(R.id.player_image)
albumCover.setOnClickListener {
NavigationUtil.goToLyrics(requireActivity()) override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
} super.onViewCreated(view, savedInstanceState)
return view loadAlbumCover()
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onDestroyView() {
super.onViewCreated(view, savedInstanceState) super.onDestroyView()
loadAlbumCover() colorReceiver = null
} }
private fun loadAlbumCover() {
SongGlideRequest.Builder.from(Glide.with(requireContext()), song)
.checkIgnoreMediaStore(activity).generatePalette(activity).build()
.into(object : RetroMusicColoredTarget(albumCover) {
override fun onColorReady(color: Int) {
setColor(color)
}
})
}
override fun onDestroyView() { private fun setColor(color: Int) {
super.onDestroyView() this.color = color
colorReceiver = null isColorReady = true
} if (colorReceiver != null) {
colorReceiver!!.onColorReady(color, request)
colorReceiver = null
}
}
private fun loadAlbumCover() { internal fun receiveColor(colorReceiver: ColorReceiver, request: Int) {
SongGlideRequest.Builder.from(Glide.with(requireContext()), song) if (isColorReady) {
.checkIgnoreMediaStore(activity) colorReceiver.onColorReady(color, request)
.generatePalette(activity).build() } else {
.into(object : RetroMusicColoredTarget(albumCover) { this.colorReceiver = colorReceiver
override fun onColorReady(color: Int) { this.request = request
setColor(color) }
} }
})
}
private fun setColor(color: Int) { interface ColorReceiver {
this.color = color fun onColorReady(color: Int, request: Int)
isColorReady = true }
if (colorReceiver != null) {
colorReceiver!!.onColorReady(color, request)
colorReceiver = null
}
}
internal fun receiveColor(colorReceiver: ColorReceiver, request: Int) { companion object {
if (isColorReady) {
colorReceiver.onColorReady(color, request)
} else {
this.colorReceiver = colorReceiver
this.request = request
}
}
interface ColorReceiver { private const val SONG_ARG = "song"
fun onColorReady(color: Int, request: Int)
}
companion object { fun newInstance(song: Song): AlbumCoverFragment {
val frag = AlbumCoverFragment()
val args = Bundle()
args.putParcelable(SONG_ARG, song)
frag.arguments = args
return frag
}
}
}
private const val SONG_ARG = "song" companion object {
val TAG: String = AlbumCoverPagerAdapter::class.java.simpleName
fun newInstance(song: Song): AlbumCoverFragment { }
val frag = AlbumCoverFragment()
val args = Bundle()
args.putParcelable(SONG_ARG, song)
frag.arguments = args
return frag
}
}
}
companion object {
val TAG: String = AlbumCoverPagerAdapter::class.java.simpleName
}
} }

View file

@ -15,69 +15,87 @@
*/ */
package code.name.monkey.retromusic.adapter.album package code.name.monkey.retromusic.adapter.album
import android.app.Activity import android.app.*
import android.app.ActivityOptions
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.LayoutInflater import android.view.*
import android.view.View
import android.view.ViewGroup
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.*
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.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.views.MetalRecyclerViewPager import code.name.monkey.retromusic.views.MetalRecyclerViewPager
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
class AlbumFullWidthAdapter(private val activity: Activity, private val dataSet: ArrayList<Album>, metrics: DisplayMetrics) : class AlbumFullWidthAdapter(
MetalRecyclerViewPager.MetalAdapter<AlbumFullWidthAdapter.FullMetalViewHolder>(metrics) { private val activity: Activity,
private val dataSet: ArrayList<Album>,
metrics: DisplayMetrics
) : MetalRecyclerViewPager.MetalAdapter<AlbumFullWidthAdapter.FullMetalViewHolder>(metrics) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FullMetalViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FullMetalViewHolder {
return FullMetalViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.pager_item, parent, false)) return FullMetalViewHolder(
} LayoutInflater.from(parent.context).inflate(
R.layout.pager_item,
parent,
false
)
)
}
override fun onBindViewHolder(holder: FullMetalViewHolder, position: Int) { override fun onBindViewHolder(holder: FullMetalViewHolder, position: Int) {
// don't forget about calling supper.onBindViewHolder! // don't forget about calling supper.onBindViewHolder!
super.onBindViewHolder(holder, position) super.onBindViewHolder(holder, position)
val album = dataSet[position] val album = dataSet[position]
holder.title?.text = getAlbumTitle(album) holder.title?.text = getAlbumTitle(album)
holder.text?.text = getAlbumText(album) holder.text?.text = getAlbumText(album)
holder.playSongs?.setOnClickListener { album.songs?.let { songs -> MusicPlayerRemote.openQueue(songs, 0, true) } } holder.playSongs?.setOnClickListener {
loadAlbumCover(album, holder) album.songs?.let { songs ->
} MusicPlayerRemote.openQueue(
songs,
0,
true
)
}
}
loadAlbumCover(album, holder)
}
private fun getAlbumTitle(album: Album): String? { private fun getAlbumTitle(album: Album): String? {
return album.title return album.title
} }
private fun getAlbumText(album: Album): String? { private fun getAlbumText(album: Album): String? {
return album.artistName return album.artistName
} }
private fun loadAlbumCover(album: Album, holder: FullMetalViewHolder) { private fun loadAlbumCover(album: Album, holder: FullMetalViewHolder) {
if (holder.image == null) { if (holder.image == null) {
return return
} }
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore(activity) .checkIgnoreMediaStore(activity).generatePalette(activity).build()
.generatePalette(activity).build() .into(object : RetroMusicColoredTarget(holder.image!!) {
.into(object : RetroMusicColoredTarget(holder.image!!) { override fun onColorReady(color: Int) {
override fun onColorReady(color: Int) {
} }
}) })
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
return dataSet.size return dataSet.size
} }
inner class FullMetalViewHolder(itemView: View) : MetalRecyclerViewPager.MetalViewHolder(itemView) { inner class FullMetalViewHolder(itemView: View) : MetalRecyclerViewPager.MetalViewHolder(
itemView
) {
override fun onClick(v: View?) { override fun onClick(v: View?) {
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(activity, image, activity.getString(R.string.transition_album_art)) val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
NavigationUtil.goToAlbumOptions(activity, dataSet[adapterPosition].id, activityOptions) activity,
} image,
} activity.getString(R.string.transition_album_art)
)
NavigationUtil.goToAlbumOptions(activity, dataSet[adapterPosition].id, activityOptions)
}
}
} }

View file

@ -1,13 +1,10 @@
package code.name.monkey.retromusic.adapter.album package code.name.monkey.retromusic.adapter.album
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.View import android.view.*
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.retromusic.glide.*
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.HorizontalAdapterHelper import code.name.monkey.retromusic.helper.HorizontalAdapterHelper
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
@ -15,65 +12,71 @@ import code.name.monkey.retromusic.util.MusicUtil
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import java.util.* import java.util.*
class HorizontalAlbumAdapter( class HorizontalAlbumAdapter(
activity: AppCompatActivity, activity: AppCompatActivity,
dataSet: ArrayList<Album>, dataSet: ArrayList<Album>,
usePalette: Boolean, usePalette: Boolean,
cabHolder: CabHolder? cabHolder: CabHolder?
) : AlbumAdapter( ) : AlbumAdapter(
activity, activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, usePalette, cabHolder
dataSet,
HorizontalAdapterHelper.LAYOUT_RES,
usePalette,
cabHolder
) { ) {
override fun createViewHolder(view: View, viewType: Int): ViewHolder { override fun createViewHolder(view: View, viewType: Int): ViewHolder {
val params = view.layoutParams as ViewGroup.MarginLayoutParams val params = view.layoutParams as ViewGroup.MarginLayoutParams
HorizontalAdapterHelper.applyMarginToLayoutParams(activity, params, viewType) HorizontalAdapterHelper.applyMarginToLayoutParams(activity, params, viewType)
return ViewHolder(view) return ViewHolder(view)
} }
override fun setColors(color: Int, holder: ViewHolder) { override fun setColors(color: Int, holder: ViewHolder) {
holder.title?.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color))) holder.title?.setTextColor(
holder.text?.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color))) MaterialValueHelper.getPrimaryTextColor(
} activity,
ColorUtil.isColorLight(
color
)
)
)
holder.text?.setTextColor(
MaterialValueHelper.getSecondaryTextColor(
activity,
ColorUtil.isColorLight(
color
)
)
)
}
override fun loadAlbumCover(album: Album, holder: ViewHolder) { override fun loadAlbumCover(album: Album, holder: ViewHolder) {
if (holder.image == null) return if (holder.image == null) return
SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore(activity) .checkIgnoreMediaStore(activity).generatePalette(activity).build()
.generatePalette(activity).build() .into(object : RetroMusicColoredTarget(holder.image!!) {
.into(object : RetroMusicColoredTarget(holder.image!!) { override fun onLoadCleared(placeholder: Drawable?) {
override fun onLoadCleared(placeholder: Drawable?) { super.onLoadCleared(placeholder)
super.onLoadCleared(placeholder) setColors(albumArtistFooterColor, holder)
setColors(albumArtistFooterColor, holder) }
}
override fun onColorReady(color: Int) { override fun onColorReady(color: Int) {
if (usePalette) if (usePalette) setColors(color, holder)
setColors(color, holder) else setColors(albumArtistFooterColor, holder)
else }
setColors(albumArtistFooterColor, holder) })
} }
})
}
override fun getAlbumText(album: Album): String? { override fun getAlbumText(album: Album): String? {
return MusicUtil.getYearString(album.year) return MusicUtil.getYearString(album.year)
} }
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return HorizontalAdapterHelper.getItemViewtype(position, itemCount) return HorizontalAdapterHelper.getItemViewtype(position, itemCount)
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
return dataSet.size return dataSet.size
} }
companion object { companion object {
val TAG: String = AlbumAdapter::class.java.simpleName val TAG: String = AlbumAdapter::class.java.simpleName
} }
} }

View file

@ -3,145 +3,150 @@ package code.name.monkey.retromusic.adapter.artist
import android.app.ActivityOptions import android.app.ActivityOptions
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.LayoutInflater import android.view.*
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.*
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.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.*
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 com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
import java.util.* import java.util.*
class ArtistAdapter(
val activity: AppCompatActivity,
var dataSet: ArrayList<Artist>,
var itemLayoutRes: Int,
var usePalette: Boolean,
cabHolder: CabHolder?
) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>(
activity, cabHolder, R.menu.menu_media_selection
), FastScrollRecyclerView.SectionedAdapter {
class ArtistAdapter(val activity: AppCompatActivity, fun swapDataSet(dataSet: ArrayList<Artist>) {
var dataSet: ArrayList<Artist>, this.dataSet = dataSet
@LayoutRes var itemLayoutRes: Int, notifyDataSetChanged()
var usePalette: Boolean, }
cabHolder: CabHolder?
) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>(activity, cabHolder, R.menu.menu_media_selection), FastScrollRecyclerView.SectionedAdapter {
fun swapDataSet(dataSet: ArrayList<Artist>) { fun usePalette(usePalette: Boolean) {
this.dataSet = dataSet this.usePalette = usePalette
notifyDataSetChanged() notifyDataSetChanged()
} }
fun usePalette(usePalette: Boolean) { override fun getItemId(position: Int): Long {
this.usePalette = usePalette return dataSet[position].id.toLong()
notifyDataSetChanged() }
}
override fun getItemId(position: Int): Long { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return dataSet[position].id.toLong() val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)
} return createViewHolder(view)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { private fun createViewHolder(view: View): ViewHolder {
val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false) return ViewHolder(view)
return createViewHolder(view) }
}
private fun createViewHolder(view: View): ViewHolder { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
return ViewHolder(view) val artist = dataSet[position]
} val isChecked = isChecked(artist)
holder.itemView.isActivated = isChecked
holder.title?.text = artist.name
holder.text?.visibility = View.GONE
loadArtistImage(artist, holder)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) { fun setColors(color: Int, holder: ViewHolder) {
val artist = dataSet[position] if (holder.paletteColorContainer != null) {
val isChecked = isChecked(artist) holder.paletteColorContainer?.setBackgroundColor(color)
holder.itemView.isActivated = isChecked holder.title?.setTextColor(
holder.title?.text = artist.name MaterialValueHelper.getPrimaryTextColor(
holder.text?.visibility = View.GONE activity, ColorUtil.isColorLight(
loadArtistImage(artist, holder) color
} )
)
)
}
fun setColors(color: Int, holder: ViewHolder) { holder.mask?.backgroundTintList = ColorStateList.valueOf(color)
if (holder.paletteColorContainer != null) { }
holder.paletteColorContainer?.setBackgroundColor(color)
holder.title?.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color)))
}
holder.mask?.backgroundTintList = ColorStateList.valueOf(color) private fun loadArtistImage(artist: Artist, holder: ViewHolder) {
} if (holder.image == null) {
return
}
ArtistGlideRequest.Builder.from(Glide.with(activity), artist).generatePalette(activity)
.build().into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onLoadCleared(placeholder: Drawable?) {
super.onLoadCleared(placeholder)
setColors(defaultFooterColor, holder)
}
private fun loadArtistImage(artist: Artist, holder: ViewHolder) { override fun onColorReady(color: Int) {
if (holder.image == null) { setColors(color, holder)
return }
} })
ArtistGlideRequest.Builder.from(Glide.with(activity), artist) }
.generatePalette(activity).build()
.into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onLoadCleared(placeholder: Drawable?) {
super.onLoadCleared(placeholder)
setColors(defaultFooterColor, holder)
}
override fun onColorReady(color: Int) { override fun getItemCount(): Int {
setColors(color, holder) return dataSet.size
} }
})
}
override fun getItemCount(): Int { override fun getIdentifier(position: Int): Artist? {
return dataSet.size return dataSet[position]
} }
override fun getIdentifier(position: Int): Artist? { override fun getName(artist: Artist): String {
return dataSet[position] return artist.name
} }
override fun getName(artist: Artist): String { override fun onMultipleItemAction(
return artist.name menuItem: MenuItem, selection: ArrayList<Artist>
} ) {
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
}
override fun onMultipleItemAction(menuItem: MenuItem, private fun getSongList(artists: List<Artist>): ArrayList<Song> {
selection: ArrayList<Artist>) { val songs = ArrayList<Song>()
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId) for (artist in artists) {
} songs.addAll(artist.songs) // maybe async in future?
}
return songs
}
private fun getSongList(artists: List<Artist>): ArrayList<Song> { override fun getSectionName(position: Int): String {
val songs = ArrayList<Song>() return MusicUtil.getSectionName(dataSet[position].name)
for (artist in artists) { }
songs.addAll(artist.songs) // maybe async in future?
}
return songs
}
override fun getSectionName(position: Int): String { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
return MusicUtil.getSectionName(dataSet[position].name)
}
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) { init {
setImageTransitionName(activity.getString(R.string.transition_artist_image))
menu?.visibility = View.GONE
}
init { override fun onClick(v: View?) {
setImageTransitionName(activity.getString(R.string.transition_artist_image)) super.onClick(v)
menu?.visibility = View.GONE if (isInQuickSelectMode) {
} toggleChecked(adapterPosition)
} else {
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
activity, image, activity.getString(
R.string.transition_artist_image
)
)
NavigationUtil.goToArtistOptions(
activity, dataSet[adapterPosition].id, activityOptions
)
}
}
override fun onClick(v: View?) { override fun onLongClick(v: View?): Boolean {
super.onClick(v) toggleChecked(adapterPosition)
if (isInQuickSelectMode) { return super.onLongClick(v)
toggleChecked(adapterPosition) }
} else { }
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(activity, image, activity.getString(R.string.transition_artist_image))
NavigationUtil.goToArtistOptions(activity, dataSet[adapterPosition].id, activityOptions)
}
}
override fun onLongClick(v: View?): Boolean {
toggleChecked(adapterPosition)
return super.onLongClick(v)
}
}
} }

View file

@ -1,12 +1,13 @@
package code.name.monkey.retromusic.adapter.base; package code.name.monkey.retromusic.adapter.base;
import android.content.Context; import android.content.Context;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.MenuRes; import androidx.annotation.MenuRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
import com.afollestad.materialcab.MaterialCab; import com.afollestad.materialcab.MaterialCab;

View file

@ -1,212 +1,222 @@
package code.name.monkey.retromusic.adapter.playlist package code.name.monkey.retromusic.adapter.playlist
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.LayoutInflater import android.view.*
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.*
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import code.name.monkey.retromusic.dialogs.*
import code.name.monkey.retromusic.dialogs.ClearSmartPlaylistDialog import code.name.monkey.retromusic.helper.menu.*
import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
import code.name.monkey.retromusic.model.AbsCustomPlaylist import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.smartplaylist.*
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.NavigationUtil
import java.util.* import java.util.*
class PlaylistAdapter(
private val activity: AppCompatActivity,
var dataSet: ArrayList<Playlist>,
private var itemLayoutRes: Int,
cabHolder: CabHolder?
) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist>(
activity,
cabHolder,
R.menu.menu_playlists_selection
) {
class PlaylistAdapter(private val activity: AppCompatActivity, var songs = ArrayList<Song>()
var dataSet: ArrayList<Playlist>,
private var itemLayoutRes: Int,
cabHolder: CabHolder?) : AbsMultiSelectAdapter<PlaylistAdapter.ViewHolder, Playlist>(activity, cabHolder, R.menu.menu_playlists_selection) {
var songs = ArrayList<Song>() init {
setHasStableIds(true)
}
fun swapDataSet(dataSet: ArrayList<Playlist>) {
this.dataSet = dataSet
notifyDataSetChanged()
}
init { override fun getItemId(position: Int): Long {
setHasStableIds(true) return dataSet[position].id.toLong()
} }
fun swapDataSet(dataSet: ArrayList<Playlist>) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
this.dataSet = dataSet val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)
notifyDataSetChanged() return createViewHolder(view)
} }
override fun getItemId(position: Int): Long { protected fun createViewHolder(view: View): ViewHolder {
return dataSet[position].id.toLong() return ViewHolder(view)
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { protected fun getPlaylistTitle(playlist: Playlist): String {
val view = LayoutInflater.from(activity) return playlist.name
.inflate(itemLayoutRes, parent, false) }
return createViewHolder(view)
}
protected fun createViewHolder(view: View): ViewHolder { protected fun getPlaylistText(playlist: Playlist): String {
return ViewHolder(view) return MusicUtil.getPlaylistInfoString(activity, getSongs(playlist))
} }
protected fun getPlaylistTitle(playlist: Playlist): String { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
return playlist.name val playlist = dataSet[position]
} holder.itemView.isActivated = isChecked(playlist)
holder.title?.text = getPlaylistTitle(playlist)
holder.text?.text = getPlaylistText(playlist)
holder.image?.setImageDrawable(getIconRes(playlist))
}
protected fun getPlaylistText(playlist: Playlist): String { private fun getIconRes(playlist: Playlist): Drawable {
return MusicUtil.getPlaylistInfoString(activity, getSongs(playlist)) if (playlist is AbsSmartPlaylist) {
} return TintHelper.createTintedDrawable(
activity,
playlist.iconRes,
ATHUtil.resolveColor(activity, R.attr.iconColor)
)!!
}
return if (MusicUtil.isFavoritePlaylist(
activity,
playlist
)) TintHelper.createTintedDrawable(
activity,
R.drawable.ic_favorite_white_24dp,
ThemeStore.accentColor(activity)
)!!
else TintHelper.createTintedDrawable(
activity,
R.drawable.ic_playlist_play_white_24dp,
ATHUtil.resolveColor(activity, R.attr.iconColor)
)!!
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun getItemViewType(position: Int): Int {
val playlist = dataSet[position] return if (dataSet[position] is AbsSmartPlaylist) SMART_PLAYLIST else DEFAULT_PLAYLIST
holder.itemView.isActivated = isChecked(playlist) }
holder.title?.text = getPlaylistTitle(playlist)
holder.text?.text = getPlaylistText(playlist)
holder.image?.setImageDrawable(getIconRes(playlist))
}
private fun getIconRes(playlist: Playlist): Drawable { override fun getItemCount(): Int {
if (playlist is AbsSmartPlaylist) { return dataSet.size
return TintHelper.createTintedDrawable(activity, playlist.iconRes, ATHUtil.resolveColor(activity, R.attr.iconColor))!! }
}
return if (MusicUtil.isFavoritePlaylist(activity, playlist))
TintHelper.createTintedDrawable(activity, R.drawable.ic_favorite_white_24dp, ThemeStore.accentColor(activity))!!
else
TintHelper.createTintedDrawable(activity, R.drawable.ic_playlist_play_white_24dp, ATHUtil.resolveColor(activity, R.attr.iconColor))!!
}
override fun getItemViewType(position: Int): Int { override fun getIdentifier(position: Int): Playlist? {
return if (dataSet[position] is AbsSmartPlaylist) SMART_PLAYLIST else DEFAULT_PLAYLIST return dataSet[position]
} }
override fun getItemCount(): Int { override fun getName(playlist: Playlist): String {
return dataSet.size return playlist.name
} }
override fun getIdentifier(position: Int): Playlist? { override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<Playlist>) {
return dataSet[position] when (menuItem.itemId) {
} R.id.action_delete_playlist -> {
var i = 0
while (i < selection.size) {
val playlist = selection[i]
if (playlist is AbsSmartPlaylist) {
ClearSmartPlaylistDialog.create(playlist).show(
activity.supportFragmentManager, "CLEAR_PLAYLIST_" + playlist.name
)
selection.remove(playlist)
i--
}
i++
}
if (selection.size > 0) {
DeletePlaylistDialog.create(selection)
.show(activity.supportFragmentManager, "DELETE_PLAYLIST")
}
}
else -> SongsMenuHelper.handleMenuClick(
activity,
getSongList(selection),
menuItem.itemId
)
}
}
override fun getName(playlist: Playlist): String { private fun getSongList(playlists: List<Playlist>): ArrayList<Song> {
return playlist.name val songs = ArrayList<Song>()
} for (playlist in playlists) {
if (playlist is AbsCustomPlaylist) {
songs.addAll(playlist.getSongs(activity))
} else {
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
}
}
return songs
}
override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<Playlist>) { private fun getSongs(playlist: Playlist): ArrayList<Song> {
when (menuItem.itemId) { val songs = ArrayList<Song>()
R.id.action_delete_playlist -> { if (playlist is AbsSmartPlaylist) {
var i = 0 songs.addAll(playlist.getSongs(activity))
while (i < selection.size) { } else {
val playlist = selection[i] songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
if (playlist is AbsSmartPlaylist) { }
ClearSmartPlaylistDialog.create(playlist) return songs
.show(activity.supportFragmentManager, }
"CLEAR_PLAYLIST_" + playlist.name)
selection.remove(playlist)
i--
}
i++
}
if (selection.size > 0) {
DeletePlaylistDialog.create(selection)
.show(activity.supportFragmentManager, "DELETE_PLAYLIST")
}
}
else -> SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
}
}
private fun getSongList(playlists: List<Playlist>): ArrayList<Song> { inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
val songs = ArrayList<Song>() init {
for (playlist in playlists) {
if (playlist is AbsCustomPlaylist) {
songs.addAll(playlist.getSongs(activity))
} else {
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
}
}
return songs
}
private fun getSongs(playlist: Playlist): ArrayList<Song> { image?.apply {
val songs = ArrayList<Song>() val iconPadding = activity.resources.getDimensionPixelSize(R.dimen.list_item_image_icon_padding)
if (playlist is AbsSmartPlaylist) { setPadding(iconPadding, iconPadding, iconPadding, iconPadding)
songs.addAll(playlist.getSongs(activity)) //setColorFilter(ATHUtil.resolveColor(activity, R.attr.iconColor), PorterDuff.Mode.SRC_IN)
} else { }
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
}
return songs
}
menu?.setOnClickListener { view ->
val playlist = dataSet[adapterPosition]
val popupMenu = PopupMenu(activity, view)
popupMenu.inflate(
if (itemViewType == SMART_PLAYLIST) R.menu.menu_item_smart_playlist
else R.menu.menu_item_playlist
)
if (playlist is LastAddedPlaylist) {
popupMenu.menu.findItem(R.id.action_clear_playlist).isVisible = false
}
popupMenu.setOnMenuItemClickListener { item ->
if (item.itemId == R.id.action_clear_playlist) {
if (playlist is AbsSmartPlaylist) {
ClearSmartPlaylistDialog.create(playlist).show(
activity.supportFragmentManager,
"CLEAR_SMART_PLAYLIST_" + playlist.name
)
return@setOnMenuItemClickListener true
}
}
PlaylistMenuHelper.handleMenuClick(
activity, dataSet[adapterPosition], item
)
}
popupMenu.show()
}
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) { imageTextContainer?.apply {
init { cardElevation = 0f
setCardBackgroundColor(ATHUtil.resolveColor(activity, R.attr.colorPrimary))
}
}
image?.apply { override fun onClick(v: View?) {
val iconPadding = activity.resources.getDimensionPixelSize(R.dimen.list_item_image_icon_padding) if (isInQuickSelectMode) {
setPadding(iconPadding, iconPadding, iconPadding, iconPadding) toggleChecked(adapterPosition)
//setColorFilter(ATHUtil.resolveColor(activity, R.attr.iconColor), PorterDuff.Mode.SRC_IN) } else {
} val playlist = dataSet[adapterPosition]
NavigationUtil.goToPlaylistNew(activity, playlist)
}
}
menu?.setOnClickListener { view -> override fun onLongClick(v: View?): Boolean {
val playlist = dataSet[adapterPosition] toggleChecked(adapterPosition)
val popupMenu = PopupMenu(activity, view) return true
popupMenu.inflate(if (itemViewType == SMART_PLAYLIST) }
R.menu.menu_item_smart_playlist }
else
R.menu.menu_item_playlist)
if (playlist is LastAddedPlaylist) {
popupMenu.menu.findItem(R.id.action_clear_playlist).isVisible = false
}
popupMenu.setOnMenuItemClickListener { item ->
if (item.itemId == R.id.action_clear_playlist) {
if (playlist is AbsSmartPlaylist) {
ClearSmartPlaylistDialog.create(playlist)
.show(activity.supportFragmentManager,
"CLEAR_SMART_PLAYLIST_" + playlist.name)
return@setOnMenuItemClickListener true
}
}
PlaylistMenuHelper.handleMenuClick(
activity, dataSet[adapterPosition], item)
}
popupMenu.show()
}
imageTextContainer?.apply { companion object {
cardElevation = 0f val TAG: String = PlaylistAdapter::class.java.simpleName
setCardBackgroundColor(ATHUtil.resolveColor(activity, R.attr.colorPrimary)) private const val SMART_PLAYLIST = 0
} private const val DEFAULT_PLAYLIST = 1
} }
override fun onClick(v: View?) {
if (isInQuickSelectMode) {
toggleChecked(adapterPosition)
} else {
val playlist = dataSet[adapterPosition]
NavigationUtil.goToPlaylistNew(activity, playlist)
}
}
override fun onLongClick(v: View?): Boolean {
toggleChecked(adapterPosition)
return true
}
}
companion object {
val TAG: String = PlaylistAdapter::class.java.simpleName
private const val SMART_PLAYLIST = 0
private const val DEFAULT_PLAYLIST = 1
}
} }

View file

@ -1,8 +1,6 @@
package code.name.monkey.retromusic.adapter.song package code.name.monkey.retromusic.adapter.song
import android.view.LayoutInflater import android.view.*
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
@ -11,75 +9,87 @@ import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import java.util.* import java.util.*
abstract class AbsOffsetSongAdapter : SongAdapter { abstract class AbsOffsetSongAdapter : SongAdapter {
constructor(activity: AppCompatActivity, dataSet: ArrayList<Song>, @LayoutRes itemLayoutRes: Int, usePalette: Boolean, cabHolder: CabHolder?) : super(activity, dataSet, itemLayoutRes, usePalette, cabHolder) constructor(
activity: AppCompatActivity,
dataSet: ArrayList<Song>, @LayoutRes itemLayoutRes: Int,
usePalette: Boolean,
cabHolder: CabHolder?
) : super(activity, dataSet, itemLayoutRes, usePalette, cabHolder)
constructor(activity: AppCompatActivity, dataSet: ArrayList<Song>, @LayoutRes itemLayoutRes: Int, usePalette: Boolean, cabHolder: CabHolder?, showSectionName: Boolean) : super(activity, dataSet, itemLayoutRes, usePalette, cabHolder, showSectionName) {} constructor(
activity: AppCompatActivity,
dataSet: ArrayList<Song>, @LayoutRes itemLayoutRes: Int,
usePalette: Boolean,
cabHolder: CabHolder?,
showSectionName: Boolean
) : super(activity, dataSet, itemLayoutRes, usePalette, cabHolder, showSectionName) {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder {
if (viewType == OFFSET_ITEM) { if (viewType == OFFSET_ITEM) {
val view = LayoutInflater.from(activity).inflate(R.layout.item_list_quick_actions, parent, false) val view = LayoutInflater.from(activity)
return createViewHolder(view) .inflate(R.layout.item_list_quick_actions, parent, false)
} return createViewHolder(view)
return super.onCreateViewHolder(parent, viewType) }
} return super.onCreateViewHolder(parent, viewType)
}
override fun createViewHolder(view: View): SongAdapter.ViewHolder { override fun createViewHolder(view: View): SongAdapter.ViewHolder {
return ViewHolder(view) return ViewHolder(view)
} }
override fun getItemId(position: Int): Long { override fun getItemId(position: Int): Long {
var positionFinal = position var positionFinal = position
positionFinal-- positionFinal--
return if (positionFinal < 0) -2 else super.getItemId(positionFinal) return if (positionFinal < 0) -2 else super.getItemId(positionFinal)
} }
override fun getIdentifier(position: Int): Song? { override fun getIdentifier(position: Int): Song? {
var positionFinal = position var positionFinal = position
positionFinal-- positionFinal--
return if (positionFinal < 0) null else super.getIdentifier(positionFinal) return if (positionFinal < 0) null else super.getIdentifier(positionFinal)
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
val superItemCount = super.getItemCount() val superItemCount = super.getItemCount()
return if (superItemCount == 0) 0 else superItemCount + 1 return if (superItemCount == 0) 0 else superItemCount + 1
} }
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return if (position == 0) OFFSET_ITEM else SONG return if (position == 0) OFFSET_ITEM else SONG
} }
override fun getSectionName(position: Int): String { override fun getSectionName(position: Int): String {
var positionF = position var positionF = position
positionF-- positionF--
return if (positionF < 0) "" else super.getSectionName(positionF) return if (positionF < 0) "" else super.getSectionName(positionF)
} }
open inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) { open inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) {
override// could also return null, just to be safe return empty song override // could also return null, just to be safe return empty song
val song: Song val song: Song
get() = if (itemViewType == OFFSET_ITEM) Song.emptySong else dataSet[adapterPosition - 1] get() = if (itemViewType == OFFSET_ITEM) Song.emptySong else dataSet[adapterPosition - 1]
override fun onClick(v: View?) { override fun onClick(v: View?) {
if (isInQuickSelectMode && itemViewType != OFFSET_ITEM) { if (isInQuickSelectMode && itemViewType != OFFSET_ITEM) {
toggleChecked(adapterPosition) toggleChecked(adapterPosition)
} else { } else {
MusicPlayerRemote.openQueue(dataSet, adapterPosition - 1, true) MusicPlayerRemote.openQueue(dataSet, adapterPosition - 1, true)
} }
} }
override fun onLongClick(v: View?): Boolean { override fun onLongClick(v: View?): Boolean {
if (itemViewType == OFFSET_ITEM) return false if (itemViewType == OFFSET_ITEM) return false
toggleChecked(adapterPosition) toggleChecked(adapterPosition)
return true return true
} }
} }
companion object { companion object {
const val OFFSET_ITEM = 0 const val OFFSET_ITEM = 0
const val SONG = 1 const val SONG = 1
} }
} }

View file

@ -1,133 +1,134 @@
package code.name.monkey.retromusic.adapter.song package code.name.monkey.retromusic.adapter.song
import android.view.MenuItem import android.view.*
import android.view.View
import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.dialogs.RemoveFromPlaylistDialog import code.name.monkey.retromusic.dialogs.RemoveFromPlaylistDialog
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.PlaylistSong import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.ViewUtil import code.name.monkey.retromusic.util.ViewUtil
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter import com.h6ah4i.android.widget.advrecyclerview.draggable.*
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
class OrderablePlaylistSongAdapter(
activity: AppCompatActivity,
dataSet: ArrayList<Song>,
itemLayoutRes: Int,
usePalette: Boolean,
cabHolder: CabHolder?,
private val onMoveItemListener: OnMoveItemListener?
) : PlaylistSongAdapter(
activity, dataSet, itemLayoutRes, usePalette, cabHolder
), DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> {
class OrderablePlaylistSongAdapter(activity: AppCompatActivity, init {
dataSet: ArrayList<Song>, setMultiSelectMenuRes(code.name.monkey.retromusic.R.menu.menu_playlists_songs_selection)
@LayoutRes itemLayoutRes: Int, }
usePalette: Boolean,
cabHolder: CabHolder?,
private val onMoveItemListener: OnMoveItemListener?) : PlaylistSongAdapter(activity, dataSet, itemLayoutRes, usePalette, cabHolder), DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> {
init { override fun createViewHolder(view: View): SongAdapter.ViewHolder {
setMultiSelectMenuRes(code.name.monkey.retromusic.R.menu.menu_playlists_songs_selection) return ViewHolder(view)
} }
override fun createViewHolder(view: View): SongAdapter.ViewHolder { override fun getItemId(position: Int): Long {
return ViewHolder(view) var positionFinal = position
} positionFinal--
override fun getItemId(position: Int): Long { var long: Long = 0
var positionFinal = position if (positionFinal < 0) {
positionFinal-- long = -2
} else {
if (dataSet[positionFinal] is PlaylistSong) {
long = (dataSet[positionFinal] as PlaylistSong).idInPlayList.toLong()
}
}
return long
}
var long: Long = 0 override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<Song>) {
if (positionFinal < 0) { when (menuItem.itemId) {
long = -2 R.id.action_remove_from_playlist -> {
} else { RemoveFromPlaylistDialog.create(selection as ArrayList<PlaylistSong>)
if (dataSet[positionFinal] is PlaylistSong) { .show(activity.supportFragmentManager, "ADD_PLAYLIST")
long = (dataSet[positionFinal] as PlaylistSong).idInPlayList.toLong() return
} }
} }
return long super.onMultipleItemAction(menuItem, selection)
} }
override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<Song>) { override fun onCheckCanStartDrag(holder: ViewHolder, position: Int, x: Int, y: Int): Boolean {
when (menuItem.itemId) { return onMoveItemListener != null && position > 0 && (ViewUtil.hitTest(
R.id.action_remove_from_playlist -> { holder.dragView!!, x, y
RemoveFromPlaylistDialog.create(selection as ArrayList<PlaylistSong>).show(activity.supportFragmentManager, "ADD_PLAYLIST") ) || ViewUtil.hitTest(holder.image!!, x, y))
return }
}
}
super.onMultipleItemAction(menuItem, selection)
}
override fun onCheckCanStartDrag(holder: ViewHolder, position: Int, x: Int, y: Int): Boolean { override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange {
return onMoveItemListener != null && position > 0 && return ItemDraggableRange(1, dataSet.size)
(ViewUtil.hitTest(holder.dragView!!, x, y) || ViewUtil.hitTest(holder.image!!, x, y)) }
}
override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange { override fun onMoveItem(fromPosition: Int, toPosition: Int) {
return ItemDraggableRange(1, dataSet.size) if (onMoveItemListener != null && fromPosition != toPosition) {
} onMoveItemListener.onMoveItem(fromPosition - 1, toPosition - 1)
}
}
override fun onMoveItem(fromPosition: Int, toPosition: Int) { override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean {
if (onMoveItemListener != null && fromPosition != toPosition) { return dropPosition > 0
onMoveItemListener.onMoveItem(fromPosition - 1, toPosition - 1) }
}
}
override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean { override fun onItemDragStarted(position: Int) {
return dropPosition > 0 notifyDataSetChanged()
} }
override fun onItemDragStarted(position: Int) { override fun onItemDragFinished(fromPosition: Int, toPosition: Int, result: Boolean) {
notifyDataSetChanged() notifyDataSetChanged()
} }
override fun onItemDragFinished(fromPosition: Int, toPosition: Int, result: Boolean) { interface OnMoveItemListener {
notifyDataSetChanged() fun onMoveItem(fromPosition: Int, toPosition: Int)
} }
interface OnMoveItemListener { inner class ViewHolder(itemView: View) : PlaylistSongAdapter.ViewHolder(itemView), DraggableItemViewHolder {
fun onMoveItem(fromPosition: Int, toPosition: Int) @DraggableItemStateFlags
} private var mDragStateFlags: Int = 0
inner class ViewHolder(itemView: View) : PlaylistSongAdapter.ViewHolder(itemView), DraggableItemViewHolder { override var songMenuRes: Int
@DraggableItemStateFlags get() = code.name.monkey.retromusic.R.menu.menu_item_playlist_song
private var mDragStateFlags: Int = 0 set(value) {
super.songMenuRes = value
}
override var songMenuRes: Int init {
get() = code.name.monkey.retromusic.R.menu.menu_item_playlist_song if (dragView != null) {
set(value) { if (onMoveItemListener != null) {
super.songMenuRes = value dragView?.visibility = View.VISIBLE
} } else {
dragView?.visibility = View.GONE
}
}
}
init { override fun onSongMenuItemClick(item: MenuItem): Boolean {
if (dragView != null) { when (item.itemId) {
if (onMoveItemListener != null) { code.name.monkey.retromusic.R.id.action_remove_from_playlist -> {
dragView?.visibility = View.VISIBLE RemoveFromPlaylistDialog.create(song as PlaylistSong)
} else { .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
dragView?.visibility = View.GONE return true
} }
} }
} return super.onSongMenuItemClick(item)
}
override fun onSongMenuItemClick(item: MenuItem): Boolean { @DraggableItemStateFlags
when (item.itemId) { override fun getDragStateFlags(): Int {
code.name.monkey.retromusic.R.id.action_remove_from_playlist -> { return mDragStateFlags
RemoveFromPlaylistDialog.create(song as PlaylistSong).show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST") }
return true
}
}
return super.onSongMenuItemClick(item)
}
@DraggableItemStateFlags override fun setDragStateFlags(@DraggableItemStateFlags flags: Int) {
override fun getDragStateFlags(): Int { mDragStateFlags = flags
return mDragStateFlags }
} }
override fun setDragStateFlags(@DraggableItemStateFlags flags: Int) { companion object {
mDragStateFlags = flags val TAG: String = OrderablePlaylistSongAdapter::class.java.simpleName
} }
}
companion object {
val TAG: String = OrderablePlaylistSongAdapter::class.java.simpleName
}
} }

View file

@ -1,171 +1,167 @@
package code.name.monkey.retromusic.adapter.song package code.name.monkey.retromusic.adapter.song
import android.graphics.Color import android.graphics.*
import android.graphics.PorterDuff import android.view.*
import android.view.MenuItem
import android.view.View
import android.widget.ImageView import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.ViewUtil import com.h6ah4i.android.widget.advrecyclerview.draggable.*
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
import java.util.* import java.util.*
class PlayingQueueAdapter(
class PlayingQueueAdapter(activity: AppCompatActivity, activity: AppCompatActivity,
dataSet: ArrayList<Song>, dataSet: ArrayList<Song>,
private var current: Int, private var current: Int,
itemLayoutRes: Int) : SongAdapter( itemLayoutRes: Int
activity, ) : SongAdapter(
dataSet, activity, dataSet, itemLayoutRes, false, null
itemLayoutRes,
false,
null
), DraggableItemAdapter<PlayingQueueAdapter.ViewHolder> { ), DraggableItemAdapter<PlayingQueueAdapter.ViewHolder> {
private var color = -1 private var color = -1
override fun createViewHolder(view: View): SongAdapter.ViewHolder { override fun createViewHolder(view: View): SongAdapter.ViewHolder {
return ViewHolder(view) return ViewHolder(view)
} }
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) { override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
super.onBindViewHolder(holder, position) super.onBindViewHolder(holder, position)
holder.imageText?.text = (position - current).toString() holder.imageText?.text = (position - current).toString()
holder.time?.text = MusicUtil.getReadableDurationString(dataSet[position].duration) holder.time?.text = MusicUtil.getReadableDurationString(dataSet[position].duration)
if (holder.itemViewType == HISTORY || holder.itemViewType == CURRENT) { if (holder.itemViewType == HISTORY || holder.itemViewType == CURRENT) {
setAlpha(holder, 0.5f) setAlpha(holder, 0.5f)
} }
if (usePalette) { if (usePalette) {
setColor(holder, Color.WHITE) setColor(holder, Color.WHITE)
} }
} }
private fun setColor(holder: SongAdapter.ViewHolder, white: Int) { private fun setColor(holder: SongAdapter.ViewHolder, white: Int) {
if (holder.title != null) { if (holder.title != null) {
holder.title!!.setTextColor(white) holder.title!!.setTextColor(white)
if (color != -1) { if (color != -1) {
holder.title!!.setTextColor(color) holder.title!!.setTextColor(color)
} }
} }
holder.text?.setTextColor(white) holder.text?.setTextColor(white)
holder.time?.setTextColor(white) holder.time?.setTextColor(white)
holder.imageText?.setTextColor(white) holder.imageText?.setTextColor(white)
if (holder.menu != null) { if (holder.menu != null) {
(holder.menu as ImageView).setColorFilter(white, PorterDuff.Mode.SRC_IN) (holder.menu as ImageView).setColorFilter(white, PorterDuff.Mode.SRC_IN)
} }
} }
override fun usePalette(usePalette: Boolean) { override fun usePalette(usePalette: Boolean) {
super.usePalette(usePalette) super.usePalette(usePalette)
this.usePalette = usePalette this.usePalette = usePalette
notifyDataSetChanged() notifyDataSetChanged()
} }
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
if (position < current) { if (position < current) {
return HISTORY return HISTORY
} else if (position > current) { } else if (position > current) {
return UP_NEXT return UP_NEXT
} }
return CURRENT return CURRENT
} }
override fun loadAlbumCover(song: Song, holder: SongAdapter.ViewHolder) { override fun loadAlbumCover(song: Song, holder: SongAdapter.ViewHolder) {
// We don't want to load it in this adapter // We don't want to load it in this adapter
} }
fun swapDataSet(dataSet: ArrayList<Song>, position: Int) { fun swapDataSet(dataSet: ArrayList<Song>, position: Int) {
this.dataSet = dataSet this.dataSet = dataSet
current = position current = position
notifyDataSetChanged() notifyDataSetChanged()
} }
fun setCurrent(current: Int) { fun setCurrent(current: Int) {
this.current = current this.current = current
notifyDataSetChanged() notifyDataSetChanged()
} }
private fun setAlpha(holder: SongAdapter.ViewHolder, alpha: Float) { private fun setAlpha(holder: SongAdapter.ViewHolder, alpha: Float) {
holder.image?.alpha = alpha holder.image?.alpha = alpha
holder.title?.alpha = alpha holder.title?.alpha = alpha
holder.text?.alpha = alpha holder.text?.alpha = alpha
holder.imageText?.alpha = alpha holder.imageText?.alpha = alpha
holder.paletteColorContainer?.alpha = alpha holder.paletteColorContainer?.alpha = alpha
} }
override fun onCheckCanStartDrag(holder: ViewHolder, position: Int, x: Int, y: Int): Boolean { override fun onCheckCanStartDrag(holder: ViewHolder, position: Int, x: Int, y: Int): Boolean {
return ViewUtil.hitTest(holder.imageText!!, x, y) || ViewUtil.hitTest(holder.dragView!!, x, y) return ViewUtil.hitTest(holder.imageText!!, x, y) || ViewUtil.hitTest(
} holder.dragView!!,
x,
y
)
}
override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange? { override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange? {
return null return null
} }
override fun onMoveItem(fromPosition: Int, toPosition: Int) { override fun onMoveItem(fromPosition: Int, toPosition: Int) {
MusicPlayerRemote.moveSong(fromPosition, toPosition) MusicPlayerRemote.moveSong(fromPosition, toPosition)
} }
override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean { override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean {
return true return true
} }
override fun onItemDragStarted(position: Int) { override fun onItemDragStarted(position: Int) {
notifyDataSetChanged() notifyDataSetChanged()
} }
override fun onItemDragFinished(fromPosition: Int, toPosition: Int, result: Boolean) { override fun onItemDragFinished(fromPosition: Int, toPosition: Int, result: Boolean) {
notifyDataSetChanged() notifyDataSetChanged()
} }
inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView), DraggableItemViewHolder { inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView), DraggableItemViewHolder {
@DraggableItemStateFlags @DraggableItemStateFlags
private var mDragStateFlags: Int = 0 private var mDragStateFlags: Int = 0
override var songMenuRes: Int override var songMenuRes: Int
get() = R.menu.menu_item_playing_queue_song get() = R.menu.menu_item_playing_queue_song
set(value: Int) { set(value: Int) {
super.songMenuRes = value super.songMenuRes = value
} }
init { init {
imageText?.visibility = View.VISIBLE imageText?.visibility = View.VISIBLE
dragView?.visibility = View.VISIBLE dragView?.visibility = View.VISIBLE
} }
override fun onSongMenuItemClick(item: MenuItem): Boolean { override fun onSongMenuItemClick(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.action_remove_from_playing_queue -> { R.id.action_remove_from_playing_queue -> {
MusicPlayerRemote.removeFromQueue(adapterPosition) MusicPlayerRemote.removeFromQueue(adapterPosition)
return true return true
} }
} }
return super.onSongMenuItemClick(item) return super.onSongMenuItemClick(item)
} }
@DraggableItemStateFlags @DraggableItemStateFlags
override fun getDragStateFlags(): Int { override fun getDragStateFlags(): Int {
return mDragStateFlags return mDragStateFlags
} }
override fun setDragStateFlags(@DraggableItemStateFlags flags: Int) { override fun setDragStateFlags(@DraggableItemStateFlags flags: Int) {
mDragStateFlags = flags mDragStateFlags = flags
} }
} }
companion object { companion object {
private const val HISTORY = 0 private const val HISTORY = 0
private const val CURRENT = 1 private const val CURRENT = 1
private const val UP_NEXT = 2 private const val UP_NEXT = 2
} }
} }

View file

@ -2,89 +2,95 @@ package code.name.monkey.retromusic.adapter.song
import android.app.ActivityOptions import android.app.ActivityOptions
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.view.MenuItem import android.view.*
import android.view.View
import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.RetroColorUtil
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import java.util.* import java.util.*
open class PlaylistSongAdapter(
activity: AppCompatActivity,
dataSet: ArrayList<Song>,
itemLayoutRes: Int,
usePalette: Boolean,
cabHolder: CabHolder?
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, usePalette, cabHolder, false) {
open class PlaylistSongAdapter(activity: AppCompatActivity, init {
dataSet: ArrayList<Song>, this.setMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection)
@LayoutRes itemLayoutRes: Int, }
usePalette: Boolean,
cabHolder: CabHolder?) :
AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, usePalette, cabHolder, false) {
init { override fun createViewHolder(view: View): SongAdapter.ViewHolder {
this.setMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection) return ViewHolder(view)
} }
override fun createViewHolder(view: View): SongAdapter.ViewHolder { override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
return ViewHolder(view)
}
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) { if (holder.itemViewType == OFFSET_ITEM) {
if (holder.itemViewType == OFFSET_ITEM) { val buttonColor = RetroColorUtil.toolbarColor(activity)
val textColor = MaterialValueHelper.getPrimaryTextColor(
activity, ColorUtil.isColorLight(
buttonColor
)
)
val viewHolder = holder as ViewHolder
val buttonColor = RetroColorUtil.toolbarColor(activity) viewHolder.playAction?.let {
val textColor = MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(buttonColor)) it.backgroundTintList = ColorStateList.valueOf(buttonColor)
val viewHolder = holder as ViewHolder it.setTextColor(textColor)
it.iconTint = ColorStateList.valueOf(textColor)
it.setOnClickListener {
MusicPlayerRemote.openQueue(dataSet, 0, true)
}
}
viewHolder.shuffleAction?.let {
it.backgroundTintList = ColorStateList.valueOf(buttonColor)
it.setTextColor(textColor)
it.iconTint = ColorStateList.valueOf(textColor)
it.setOnClickListener {
MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
}
}
viewHolder.playAction?.let { } else {
it.backgroundTintList = ColorStateList.valueOf(buttonColor) super.onBindViewHolder(holder, position - 1)
it.setTextColor(textColor) }
it.iconTint = ColorStateList.valueOf(textColor) }
it.setOnClickListener {
MusicPlayerRemote.openQueue(dataSet, 0, true)
}
}
viewHolder.shuffleAction?.let {
it.backgroundTintList = ColorStateList.valueOf(buttonColor)
it.setTextColor(textColor)
it.iconTint = ColorStateList.valueOf(textColor)
it.setOnClickListener {
MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
}
}
} else { open inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) {
super.onBindViewHolder(holder, position - 1)
}
}
open inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) { val playAction: MaterialButton? = itemView.findViewById(R.id.playAction)
val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction)
val playAction: MaterialButton? = itemView.findViewById(R.id.playAction) override var songMenuRes: Int
val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction) get() = R.menu.menu_item_cannot_delete_single_songs_playlist_song
set(value) {
super.songMenuRes = value
}
override var songMenuRes: Int override fun onSongMenuItemClick(item: MenuItem): Boolean {
get() = R.menu.menu_item_cannot_delete_single_songs_playlist_song if (item.itemId == R.id.action_go_to_album) {
set(value) { val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
super.songMenuRes = value activity, image, activity.getString(
} R.string.transition_album_art
)
)
NavigationUtil.goToAlbumOptions(
activity, dataSet[adapterPosition - 1].albumId, activityOptions
)
return true
}
return super.onSongMenuItemClick(item)
}
}
override fun onSongMenuItemClick(item: MenuItem): Boolean { companion object {
if (item.itemId == R.id.action_go_to_album) { val TAG: String = PlaylistSongAdapter::class.java.simpleName
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(activity, image, activity.getString(R.string.transition_album_art)) }
NavigationUtil.goToAlbumOptions(activity, dataSet[adapterPosition - 1].albumId, activityOptions)
return true
}
return super.onSongMenuItemClick(item)
}
}
companion object {
val TAG: String = PlaylistSongAdapter::class.java.simpleName
}
} }

View file

@ -1,7 +1,6 @@
package code.name.monkey.retromusic.adapter.song package code.name.monkey.retromusic.adapter.song
import android.view.View import android.view.View
import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -10,45 +9,46 @@ import code.name.monkey.retromusic.model.Song
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import java.util.* import java.util.*
class ShuffleButtonSongAdapter(
activity: AppCompatActivity,
dataSet: ArrayList<Song>,
itemLayoutRes: Int,
usePalette: Boolean,
cabHolder: CabHolder?
) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, usePalette, cabHolder) {
class ShuffleButtonSongAdapter(activity: AppCompatActivity, override fun createViewHolder(view: View): SongAdapter.ViewHolder {
dataSet: ArrayList<Song>, return ViewHolder(view)
@LayoutRes itemLayoutRes: Int, }
usePalette: Boolean,
cabHolder: CabHolder?) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, usePalette, cabHolder) {
override fun createViewHolder(view: View): SongAdapter.ViewHolder { override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
return ViewHolder(view) if (holder.itemViewType == OFFSET_ITEM) {
} val viewHolder = holder as ViewHolder
viewHolder.playAction?.let {
it.setOnClickListener {
MusicPlayerRemote.openQueue(dataSet, 0, true)
}
}
viewHolder.shuffleAction?.let {
it.setOnClickListener {
MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
}
}
} else {
super.onBindViewHolder(holder, position - 1)
}
}
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) { inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) {
if (holder.itemViewType == OFFSET_ITEM) { val playAction: MaterialButton? = itemView.findViewById(R.id.playAction)
val viewHolder = holder as ViewHolder val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction)
viewHolder.playAction?.let {
it.setOnClickListener {
MusicPlayerRemote.openQueue(dataSet, 0, true)
}
}
viewHolder.shuffleAction?.let {
it.setOnClickListener {
MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
}
}
} else {
super.onBindViewHolder(holder, position - 1)
}
}
inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) { override fun onClick(v: View?) {
val playAction: MaterialButton? = itemView.findViewById(R.id.playAction) if (itemViewType == OFFSET_ITEM) {
val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction) MusicPlayerRemote.openAndShuffleQueue(dataSet, true)
return
override fun onClick(v: View?) { }
if (itemViewType == OFFSET_ITEM) { super.onClick(v)
MusicPlayerRemote.openAndShuffleQueue(dataSet, true) }
return }
}
super.onClick(v)
}
}
} }

View file

@ -1,38 +1,34 @@
package code.name.monkey.retromusic.adapter.song package code.name.monkey.retromusic.adapter.song
import android.view.LayoutInflater import android.view.*
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import java.util.* import java.util.*
class SimpleSongAdapter(
context: AppCompatActivity, songs: ArrayList<Song>, i: Int
) : SongAdapter(context, songs, i, false, null) {
class SimpleSongAdapter(context: AppCompatActivity, override fun swapDataSet(dataSet: ArrayList<Song>) {
songs: ArrayList<Song>, this.dataSet.clear()
@LayoutRes i: Int) : SongAdapter(context, songs, i, false, null) { this.dataSet = dataSet
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false))
}
override fun swapDataSet(dataSet: ArrayList<Song>) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
this.dataSet.clear() super.onBindViewHolder(holder, position)
this.dataSet = dataSet val fixedTrackNumber = MusicUtil.getFixedTrackNumber(dataSet[position].trackNumber)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { holder.imageText?.text = if (fixedTrackNumber > 0) fixedTrackNumber.toString() else "-"
return ViewHolder(LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)) holder.time?.text = MusicUtil.getReadableDurationString(dataSet[position].duration)
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun getItemCount(): Int {
super.onBindViewHolder(holder, position) return dataSet.size
val fixedTrackNumber = MusicUtil.getFixedTrackNumber(dataSet[position].trackNumber) }
holder.imageText?.text = if (fixedTrackNumber > 0) fixedTrackNumber.toString() else "-"
holder.time?.text = MusicUtil.getReadableDurationString(dataSet[position].duration)
}
override fun getItemCount(): Int {
return dataSet.size
}
} }

View file

@ -2,209 +2,214 @@ package code.name.monkey.retromusic.adapter.song
import android.app.ActivityOptions import android.app.ActivityOptions
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.view.LayoutInflater import android.view.*
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.*
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import code.name.monkey.retromusic.glide.*
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.helper.*
import code.name.monkey.retromusic.glide.SongGlideRequest import code.name.monkey.retromusic.helper.menu.*
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.helper.menu.SongMenuHelper
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import com.afollestad.materialcab.MaterialCab import com.afollestad.materialcab.MaterialCab
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
import java.util.* import java.util.*
/** /**
* Created by hemanths on 13/08/17. * Created by hemanths on 13/08/17.
*/ */
open class SongAdapter @JvmOverloads constructor( open class SongAdapter(
protected val activity: AppCompatActivity, protected val activity: AppCompatActivity,
dataSet: ArrayList<Song>, dataSet: ArrayList<Song>,
protected var itemLayoutRes: Int, protected var itemLayoutRes: Int,
usePalette: Boolean, usePalette: Boolean,
cabHolder: CabHolder?, cabHolder: CabHolder?,
showSectionName: Boolean = true showSectionName: Boolean = true
) : AbsMultiSelectAdapter<SongAdapter.ViewHolder, Song>(activity, cabHolder, R.menu.menu_media_selection), MaterialCab.Callback, FastScrollRecyclerView.SectionedAdapter { ) : AbsMultiSelectAdapter<SongAdapter.ViewHolder, Song>(
var dataSet: ArrayList<Song> activity, cabHolder, R.menu.menu_media_selection
), MaterialCab.Callback, FastScrollRecyclerView.SectionedAdapter {
var dataSet: ArrayList<Song>
protected var usePalette = false protected var usePalette = false
private var showSectionName = true private var showSectionName = true
init { init {
this.dataSet = dataSet this.dataSet = dataSet
this.usePalette = usePalette this.usePalette = usePalette
this.showSectionName = showSectionName this.showSectionName = showSectionName
this.setHasStableIds(true) this.setHasStableIds(true)
} }
open fun swapDataSet(dataSet: ArrayList<Song>) { open fun swapDataSet(dataSet: ArrayList<Song>) {
this.dataSet = dataSet this.dataSet = dataSet
notifyDataSetChanged() notifyDataSetChanged()
} }
open fun usePalette(usePalette: Boolean) { open fun usePalette(usePalette: Boolean) {
this.usePalette = usePalette this.usePalette = usePalette
notifyDataSetChanged() notifyDataSetChanged()
} }
override fun getItemId(position: Int): Long { override fun getItemId(position: Int): Long {
return dataSet[position].id.toLong() return dataSet[position].id.toLong()
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false) val view = LayoutInflater.from(activity).inflate(itemLayoutRes, parent, false)
return createViewHolder(view) return createViewHolder(view)
} }
protected open fun createViewHolder(view: View): ViewHolder { protected open fun createViewHolder(view: View): ViewHolder {
return ViewHolder(view) return ViewHolder(view)
} }
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val song = dataSet[position] val song = dataSet[position]
val isChecked = isChecked(song) val isChecked = isChecked(song)
holder.itemView.isActivated = isChecked holder.itemView.isActivated = isChecked
holder.title?.text = getSongTitle(song) holder.title?.text = getSongTitle(song)
holder.text?.text = getSongText(song) holder.text?.text = getSongText(song)
loadAlbumCover(song, holder) loadAlbumCover(song, holder)
} }
private fun setColors(color: Int, holder: ViewHolder) { private fun setColors(color: Int, holder: ViewHolder) {
if (holder.paletteColorContainer != null) { if (holder.paletteColorContainer != null) {
holder.paletteColorContainer?.setBackgroundColor(color) holder.paletteColorContainer?.setBackgroundColor(color)
holder.title?.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color))) holder.title?.setTextColor(
holder.text?.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color))) MaterialValueHelper.getPrimaryTextColor(
} activity, ColorUtil.isColorLight(
} color
)
)
)
holder.text?.setTextColor(
MaterialValueHelper.getSecondaryTextColor(
activity, ColorUtil.isColorLight(
color
)
)
)
}
}
protected open fun loadAlbumCover(song: Song, holder: ViewHolder) { protected open fun loadAlbumCover(song: Song, holder: ViewHolder) {
if (holder.image == null) { if (holder.image == null) {
return return
} }
SongGlideRequest.Builder.from(Glide.with(activity), song) SongGlideRequest.Builder.from(Glide.with(activity), song).checkIgnoreMediaStore(activity)
.checkIgnoreMediaStore(activity) .generatePalette(activity).build()
.generatePalette(activity).build() .into(object : RetroMusicColoredTarget(holder.image!!) {
.into(object : RetroMusicColoredTarget(holder.image!!) { override fun onLoadCleared(placeholder: Drawable?) {
override fun onLoadCleared(placeholder: Drawable?) { super.onLoadCleared(placeholder)
super.onLoadCleared(placeholder) setColors(defaultFooterColor, holder)
setColors(defaultFooterColor, holder) }
}
override fun onColorReady(color: Int) { override fun onColorReady(color: Int) {
if (usePalette) if (usePalette) setColors(color, holder)
setColors(color, holder) else setColors(defaultFooterColor, holder)
else }
setColors(defaultFooterColor, holder) })
} }
})
}
private fun getSongTitle(song: Song): String? { private fun getSongTitle(song: Song): String? {
return song.title return song.title
} }
private fun getSongText(song: Song): String? { private fun getSongText(song: Song): String? {
return song.artistName return song.artistName
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
return dataSet.size return dataSet.size
} }
override fun getIdentifier(position: Int): Song? { override fun getIdentifier(position: Int): Song? {
return dataSet[position] return dataSet[position]
} }
override fun getName(song: Song): String { override fun getName(song: Song): String {
return song.title return song.title
} }
override fun onMultipleItemAction(menuItem: MenuItem, override fun onMultipleItemAction(
selection: ArrayList<Song>) { menuItem: MenuItem, selection: ArrayList<Song>
SongsMenuHelper.handleMenuClick(activity, selection, menuItem.itemId) ) {
} SongsMenuHelper.handleMenuClick(activity, selection, menuItem.itemId)
}
override fun getSectionName(position: Int): String { override fun getSectionName(position: Int): String {
if (!showSectionName) { if (!showSectionName) {
return "" return ""
} }
val sectionName: String? = when (PreferenceUtil.getInstance(activity).songSortOrder) { val sectionName: String? = when (PreferenceUtil.getInstance(activity).songSortOrder) {
SortOrder.SongSortOrder.SONG_A_Z, SortOrder.SongSortOrder.SONG_Z_A -> dataSet[position].title SortOrder.SongSortOrder.SONG_A_Z, SortOrder.SongSortOrder.SONG_Z_A -> dataSet[position].title
SortOrder.SongSortOrder.SONG_ALBUM -> dataSet[position].albumName SortOrder.SongSortOrder.SONG_ALBUM -> dataSet[position].albumName
SortOrder.SongSortOrder.SONG_ARTIST -> dataSet[position].artistName SortOrder.SongSortOrder.SONG_ARTIST -> dataSet[position].artistName
SortOrder.SongSortOrder.SONG_YEAR -> return MusicUtil.getYearString(dataSet[position].year) SortOrder.SongSortOrder.SONG_YEAR -> return MusicUtil.getYearString(
SortOrder.SongSortOrder.COMPOSER -> dataSet[position].composer dataSet[position].year
else -> { )
return "" SortOrder.SongSortOrder.COMPOSER -> dataSet[position].composer
} else -> {
} return ""
return MusicUtil.getSectionName(sectionName) }
} }
return MusicUtil.getSectionName(sectionName)
}
open inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) { open inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
protected open var songMenuRes = SongMenuHelper.MENU_RES protected open var songMenuRes = SongMenuHelper.MENU_RES
protected open val song: Song protected open val song: Song
get() = dataSet[adapterPosition] get() = dataSet[adapterPosition]
init { init {
setImageTransitionName(activity.getString(R.string.transition_album_art)) setImageTransitionName(activity.getString(R.string.transition_album_art))
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) { menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
override val song: Song override val song: Song
get() = this@ViewHolder.song get() = this@ViewHolder.song
override val menuRes: Int override val menuRes: Int
get() = songMenuRes get() = songMenuRes
override fun onMenuItemClick(item: MenuItem): Boolean { override fun onMenuItemClick(item: MenuItem): Boolean {
return onSongMenuItemClick(item) || super.onMenuItemClick(item) return onSongMenuItemClick(item) || super.onMenuItemClick(item)
} }
}) })
} }
protected open fun onSongMenuItemClick(item: MenuItem): Boolean { protected open fun onSongMenuItemClick(item: MenuItem): Boolean {
if (image != null && image!!.visibility == View.VISIBLE) { if (image != null && image!!.visibility == View.VISIBLE) {
when (item.itemId) { when (item.itemId) {
R.id.action_go_to_album -> { R.id.action_go_to_album -> {
val options: ActivityOptions = ActivityOptions.makeSceneTransitionAnimation(activity, image, activity.getString(R.string.transition_album_art)) val options: ActivityOptions = ActivityOptions.makeSceneTransitionAnimation(
NavigationUtil.goToAlbumOptions(activity, song.albumId, options) activity, image, activity.getString(R.string.transition_album_art)
return true )
} NavigationUtil.goToAlbumOptions(activity, song.albumId, options)
} return true
} }
return false }
} }
return false
}
override fun onClick(v: View?) { override fun onClick(v: View?) {
if (isInQuickSelectMode) { if (isInQuickSelectMode) {
toggleChecked(adapterPosition) toggleChecked(adapterPosition)
} else { } else {
MusicPlayerRemote.openQueue(dataSet, adapterPosition, true) MusicPlayerRemote.openQueue(dataSet, adapterPosition, true)
} }
} }
override fun onLongClick(v: View?): Boolean { override fun onLongClick(v: View?): Boolean {
return toggleChecked(adapterPosition) return toggleChecked(adapterPosition)
} }
} }
companion object { companion object {
val TAG: String = SongAdapter::class.java.simpleName val TAG: String = SongAdapter::class.java.simpleName
} }
} }

View file

@ -15,67 +15,69 @@
package code.name.monkey.retromusic.appshortcuts package code.name.monkey.retromusic.appshortcuts
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.*
import android.graphics.Canvas import android.graphics.drawable.*
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.graphics.drawable.LayerDrawable
import android.os.Build import android.os.Build
import android.util.TypedValue import android.util.TypedValue
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
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.util.PreferenceUtil import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.RetroUtil
@RequiresApi(Build.VERSION_CODES.N_MR1) @RequiresApi(Build.VERSION_CODES.N_MR1)
object AppShortcutIconGenerator { object AppShortcutIconGenerator {
fun generateThemedIcon(context: Context, iconId: Int): Icon { fun generateThemedIcon(context: Context, iconId: Int): Icon {
return if (PreferenceUtil.getInstance(context).coloredAppShortcuts()) { return if (PreferenceUtil.getInstance(context).coloredAppShortcuts()) {
generateUserThemedIcon(context, iconId) generateUserThemedIcon(context, iconId)
} else { } else {
generateDefaultThemedIcon(context, iconId) generateDefaultThemedIcon(context, iconId)
} }
} }
private fun generateDefaultThemedIcon(context: Context, iconId: Int): Icon { private fun generateDefaultThemedIcon(context: Context, iconId: Int): Icon {
// Return an Icon of iconId with default colors // Return an Icon of iconId with default colors
return generateThemedIcon(context, iconId, return generateThemedIcon(
context.getColor(R.color.app_shortcut_default_foreground), context,
context.getColor(R.color.app_shortcut_default_background) iconId,
) context.getColor(R.color.app_shortcut_default_foreground),
} context.getColor(R.color.app_shortcut_default_background)
)
}
private fun generateUserThemedIcon(context: Context, iconId: Int): Icon { private fun generateUserThemedIcon(context: Context, iconId: Int): Icon {
// Get background color from context's theme // Get background color from context's theme
val typedColorBackground = TypedValue() val typedColorBackground = TypedValue()
context.theme.resolveAttribute(android.R.attr.colorBackground, typedColorBackground, true) context.theme.resolveAttribute(android.R.attr.colorBackground, typedColorBackground, true)
// Return an Icon of iconId with those colors // Return an Icon of iconId with those colors
return generateThemedIcon(context, iconId, return generateThemedIcon(
ThemeStore.accentColor(context), context, iconId, ThemeStore.accentColor(context), typedColorBackground.data
typedColorBackground.data )
) }
}
private fun generateThemedIcon(context: Context, iconId: Int, foregroundColor: Int, backgroundColor: Int): Icon { private fun generateThemedIcon(
// Get and tint foreground and background drawables context: Context, iconId: Int, foregroundColor: Int, backgroundColor: Int
val vectorDrawable = RetroUtil.getTintedVectorDrawable(context, iconId, foregroundColor) ): Icon {
val backgroundDrawable = RetroUtil.getTintedVectorDrawable(context, R.drawable.ic_app_shortcut_background, backgroundColor) // Get and tint foreground and background drawables
val vectorDrawable = RetroUtil.getTintedVectorDrawable(context, iconId, foregroundColor)
val backgroundDrawable = RetroUtil.getTintedVectorDrawable(
context, R.drawable.ic_app_shortcut_background, backgroundColor
)
// Squash the two drawables together // Squash the two drawables together
val layerDrawable = LayerDrawable(arrayOf(backgroundDrawable, vectorDrawable)) val layerDrawable = LayerDrawable(arrayOf(backgroundDrawable, vectorDrawable))
// Return as an Icon // Return as an Icon
return Icon.createWithBitmap(drawableToBitmap(layerDrawable)) return Icon.createWithBitmap(drawableToBitmap(layerDrawable))
} }
private fun drawableToBitmap(drawable: Drawable): Bitmap { private fun drawableToBitmap(drawable: Drawable): Bitmap {
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888) val bitmap = Bitmap.createBitmap(
val canvas = Canvas(bitmap) drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888
drawable.setBounds(0, 0, canvas.width, canvas.height) )
drawable.draw(canvas) val canvas = Canvas(bitmap)
return bitmap drawable.setBounds(0, 0, canvas.width, canvas.height)
} drawable.draw(canvas)
return bitmap
}
} }

View file

@ -18,74 +18,71 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import code.name.monkey.retromusic.activities.SearchActivity import code.name.monkey.retromusic.activities.SearchActivity
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType import code.name.monkey.retromusic.appshortcuts.shortcuttype.*
import code.name.monkey.retromusic.appshortcuts.shortcuttype.SearchShortCutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType
import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist import code.name.monkey.retromusic.model.smartplaylist.*
import code.name.monkey.retromusic.model.smartplaylist.MyTopTracksPlaylist
import code.name.monkey.retromusic.model.smartplaylist.ShuffleAllPlaylist
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.* import code.name.monkey.retromusic.service.MusicService.*
class AppShortcutLauncherActivity : Activity() { class AppShortcutLauncherActivity : Activity() {
public override fun onCreate(savedInstanceState: Bundle?) { public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
var shortcutType = SHORTCUT_TYPE_NONE var shortcutType = SHORTCUT_TYPE_NONE
// Set shortcutType from the intent extras // Set shortcutType from the intent extras
val extras = intent.extras val extras = intent.extras
if (extras != null) { if (extras != null) {
shortcutType = extras.getInt(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE) shortcutType = extras.getInt(KEY_SHORTCUT_TYPE, SHORTCUT_TYPE_NONE)
} }
when (shortcutType) { when (shortcutType) {
SHORTCUT_TYPE_SHUFFLE_ALL -> { SHORTCUT_TYPE_SHUFFLE_ALL -> {
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_SHUFFLE, startServiceWithPlaylist(
ShuffleAllPlaylist(applicationContext)) MusicService.SHUFFLE_MODE_SHUFFLE, ShuffleAllPlaylist(applicationContext)
DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.id) )
} DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.id)
SHORTCUT_TYPE_TOP_TRACKS -> { }
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE, SHORTCUT_TYPE_TOP_TRACKS -> {
MyTopTracksPlaylist(applicationContext)) startServiceWithPlaylist(
DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.id) MusicService.SHUFFLE_MODE_NONE, MyTopTracksPlaylist(applicationContext)
} )
SHORTCUT_TYPE_LAST_ADDED -> { DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.id)
startServiceWithPlaylist(MusicService.SHUFFLE_MODE_NONE, }
LastAddedPlaylist(applicationContext)) SHORTCUT_TYPE_LAST_ADDED -> {
DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.id) startServiceWithPlaylist(
} MusicService.SHUFFLE_MODE_NONE, LastAddedPlaylist(applicationContext)
SHORTCUT_TYPE_SEARCH -> { )
startActivity(Intent(this, SearchActivity::class.java)) DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.id)
DynamicShortcutManager.reportShortcutUsed(this, SearchShortCutType.id) }
} SHORTCUT_TYPE_SEARCH -> {
} startActivity(Intent(this, SearchActivity::class.java))
finish() DynamicShortcutManager.reportShortcutUsed(this, SearchShortCutType.id)
} }
}
finish()
}
private fun startServiceWithPlaylist(shuffleMode: Int, playlist: Playlist) { private fun startServiceWithPlaylist(shuffleMode: Int, playlist: Playlist) {
val intent = Intent(this, MusicService::class.java) val intent = Intent(this, MusicService::class.java)
intent.action = ACTION_PLAY_PLAYLIST intent.action = ACTION_PLAY_PLAYLIST
val bundle = Bundle() val bundle = Bundle()
bundle.putParcelable(INTENT_EXTRA_PLAYLIST, playlist) bundle.putParcelable(INTENT_EXTRA_PLAYLIST, playlist)
bundle.putInt(INTENT_EXTRA_SHUFFLE_MODE, shuffleMode) bundle.putInt(INTENT_EXTRA_SHUFFLE_MODE, shuffleMode)
intent.putExtras(bundle) intent.putExtras(bundle)
startService(intent) startService(intent)
} }
companion object { companion object {
const val KEY_SHORTCUT_TYPE = "code.name.monkey.retromusic.appshortcuts.ShortcutType" const val KEY_SHORTCUT_TYPE = "code.name.monkey.retromusic.appshortcuts.ShortcutType"
const val SHORTCUT_TYPE_SHUFFLE_ALL = 0 const val SHORTCUT_TYPE_SHUFFLE_ALL = 0
const val SHORTCUT_TYPE_TOP_TRACKS = 1 const val SHORTCUT_TYPE_TOP_TRACKS = 1
const val SHORTCUT_TYPE_LAST_ADDED = 2 const val SHORTCUT_TYPE_LAST_ADDED = 2
const val SHORTCUT_TYPE_SEARCH = 3 const val SHORTCUT_TYPE_SEARCH = 3
const val SHORTCUT_TYPE_NONE = 4 const val SHORTCUT_TYPE_NONE = 4
} }
} }

View file

@ -15,56 +15,52 @@
package code.name.monkey.retromusic.appshortcuts package code.name.monkey.retromusic.appshortcuts
import android.annotation.TargetApi import android.annotation.TargetApi
import android.content.Context import android.content.*
import android.content.Intent import android.content.pm.*
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.os.Build import android.os.Build
import code.name.monkey.retromusic.appshortcuts.shortcuttype.*
import java.util.Arrays import java.util.*
import code.name.monkey.retromusic.appshortcuts.shortcuttype.LastAddedShortcutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.SearchShortCutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.ShuffleAllShortcutType
import code.name.monkey.retromusic.appshortcuts.shortcuttype.TopTracksShortcutType
@TargetApi(Build.VERSION_CODES.N_MR1) @TargetApi(Build.VERSION_CODES.N_MR1)
class DynamicShortcutManager(private val context: Context) { class DynamicShortcutManager(private val context: Context) {
private val shortcutManager: ShortcutManager = this.context.getSystemService(ShortcutManager::class.java) private val shortcutManager: ShortcutManager = this.context.getSystemService(ShortcutManager::class.java)
private val defaultShortcuts: List<ShortcutInfo> private val defaultShortcuts: List<ShortcutInfo>
get() = Arrays.asList( get() = Arrays.asList(
SearchShortCutType(context).shortcutInfo, SearchShortCutType(context).shortcutInfo,
ShuffleAllShortcutType(context).shortcutInfo, ShuffleAllShortcutType(context).shortcutInfo,
TopTracksShortcutType(context).shortcutInfo, TopTracksShortcutType(context).shortcutInfo,
LastAddedShortcutType(context).shortcutInfo LastAddedShortcutType(context).shortcutInfo
) )
fun initDynamicShortcuts() { fun initDynamicShortcuts() {
//if (shortcutManager.dynamicShortcuts.size == 0) { //if (shortcutManager.dynamicShortcuts.size == 0) {
shortcutManager.dynamicShortcuts = defaultShortcuts shortcutManager.dynamicShortcuts = defaultShortcuts
//} //}
} }
fun updateDynamicShortcuts() { fun updateDynamicShortcuts() {
shortcutManager.updateShortcuts(defaultShortcuts) shortcutManager.updateShortcuts(defaultShortcuts)
} }
companion object { companion object {
fun createShortcut(context: Context, id: String, shortLabel: String, longLabel: String, icon: Icon, intent: Intent): ShortcutInfo { fun createShortcut(
return ShortcutInfo.Builder(context, id) context: Context,
.setShortLabel(shortLabel) id: String,
.setLongLabel(longLabel) shortLabel: String,
.setIcon(icon) longLabel: String,
.setIntent(intent) icon: Icon,
.build() intent: Intent
} ): ShortcutInfo {
return ShortcutInfo.Builder(context, id).setShortLabel(shortLabel)
.setLongLabel(longLabel).setIcon(icon).setIntent(intent).build()
}
fun reportShortcutUsed(context: Context, shortcutId: String) { fun reportShortcutUsed(context: Context, shortcutId: String) {
context.getSystemService(ShortcutManager::class.java).reportShortcutUsed(shortcutId) context.getSystemService(ShortcutManager::class.java).reportShortcutUsed(shortcutId)
} }
} }
} }

View file

@ -15,37 +15,34 @@
package code.name.monkey.retromusic.appshortcuts.shortcuttype package code.name.monkey.retromusic.appshortcuts.shortcuttype
import android.annotation.TargetApi import android.annotation.TargetApi
import android.content.Context import android.content.*
import android.content.Intent
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.os.Build import android.os.*
import android.os.Bundle
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity
@TargetApi(Build.VERSION_CODES.N_MR1) @TargetApi(Build.VERSION_CODES.N_MR1)
abstract class BaseShortcutType(internal var context: Context) { abstract class BaseShortcutType(internal var context: Context) {
internal abstract val shortcutInfo: ShortcutInfo internal abstract val shortcutInfo: ShortcutInfo
/** /**
* Creates an Intent that will launch MainActivtiy and immediately play {@param songs} in either shuffle or normal mode * Creates an Intent that will launch MainActivtiy and immediately play {@param songs} in either shuffle or normal mode
* *
* @param shortcutType Describes the type of shortcut to create (ShuffleAll, TopTracks, custom playlist, etc.) * @param shortcutType Describes the type of shortcut to create (ShuffleAll, TopTracks, custom playlist, etc.)
* @return * @return
*/ */
internal fun getPlaySongsIntent(shortcutType: Int): Intent { internal fun getPlaySongsIntent(shortcutType: Int): Intent {
val intent = Intent(context, AppShortcutLauncherActivity::class.java) val intent = Intent(context, AppShortcutLauncherActivity::class.java)
intent.action = Intent.ACTION_VIEW intent.action = Intent.ACTION_VIEW
val b = Bundle() val b = Bundle()
b.putInt(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType) b.putInt(AppShortcutLauncherActivity.KEY_SHORTCUT_TYPE, shortcutType)
intent.putExtras(b) intent.putExtras(b)
return intent return intent
} }
companion object { companion object {
internal const val ID_PREFIX = "code.name.monkey.retromusic.appshortcuts.id." internal const val ID_PREFIX = "code.name.monkey.retromusic.appshortcuts.id."
val id: String val id: String
get() = ID_PREFIX + "invalid" get() = ID_PREFIX + "invalid"
} }
} }

View file

@ -19,23 +19,27 @@ import android.content.Context
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.os.Build import android.os.Build
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator import code.name.monkey.retromusic.appshortcuts.*
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity
@TargetApi(Build.VERSION_CODES.N_MR1) @TargetApi(Build.VERSION_CODES.N_MR1)
class LastAddedShortcutType(context: Context) : BaseShortcutType(context) { class LastAddedShortcutType(context: Context) : BaseShortcutType(context) {
override val shortcutInfo: ShortcutInfo override val shortcutInfo: ShortcutInfo
get() = ShortcutInfo.Builder(context, id) get() = ShortcutInfo.Builder(
.setShortLabel(context.getString(R.string.app_shortcut_last_added_short)) context,
.setLongLabel(context.getString(R.string.app_shortcut_last_added_long)) id
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_last_added)) ).setShortLabel(context.getString(R.string.app_shortcut_last_added_short)).setLongLabel(
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_LAST_ADDED)) context.getString(R.string.app_shortcut_last_added_long)
.build() ).setIcon(
AppShortcutIconGenerator.generateThemedIcon(
context,
R.drawable.ic_app_shortcut_last_added
)
).setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_LAST_ADDED)).build()
companion object { companion object {
val id: String val id: String
get() = BaseShortcutType.ID_PREFIX + "last_added" get() = BaseShortcutType.ID_PREFIX + "last_added"
} }
} }

View file

@ -19,22 +19,24 @@ import android.content.Context
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.os.Build import android.os.Build
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator import code.name.monkey.retromusic.appshortcuts.*
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity
@TargetApi(Build.VERSION_CODES.N_MR1) @TargetApi(Build.VERSION_CODES.N_MR1)
class SearchShortCutType(context: Context) : BaseShortcutType(context) { class SearchShortCutType(context: Context) : BaseShortcutType(context) {
companion object { companion object {
val id: String val id: String
get() = BaseShortcutType.ID_PREFIX + "search" get() = BaseShortcutType.ID_PREFIX + "search"
} }
override val shortcutInfo: ShortcutInfo override val shortcutInfo: ShortcutInfo
get() = ShortcutInfo.Builder(context, id) get() = ShortcutInfo.Builder(
.setShortLabel(context.getString(R.string.action_search)) context,
.setLongLabel(context.getString(R.string.search_hint)) id
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_search)) ).setShortLabel(context.getString(R.string.action_search)).setLongLabel(context.getString(R.string.search_hint)).setIcon(
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SEARCH)) AppShortcutIconGenerator.generateThemedIcon(
.build() context,
R.drawable.ic_app_shortcut_search
)
).setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SEARCH)).build()
} }

View file

@ -18,26 +18,26 @@ import android.annotation.TargetApi
import android.content.Context import android.content.Context
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.os.Build import android.os.Build
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator import code.name.monkey.retromusic.appshortcuts.*
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity
import java.security.AccessController.getContext
@TargetApi(Build.VERSION_CODES.N_MR1) @TargetApi(Build.VERSION_CODES.N_MR1)
class ShuffleAllShortcutType(context: Context) : BaseShortcutType(context) { class ShuffleAllShortcutType(context: Context) : BaseShortcutType(context) {
override val shortcutInfo: ShortcutInfo override val shortcutInfo: ShortcutInfo
get() = ShortcutInfo.Builder(context, id) get() = ShortcutInfo.Builder(
.setShortLabel(context.getString(R.string.app_shortcut_shuffle_all_short)) context, id
.setLongLabel(context.getString(R.string.app_shortcut_shuffle_all_long)) ).setShortLabel(context.getString(R.string.app_shortcut_shuffle_all_short)).setLongLabel(
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_shuffle_all)) context.getString(R.string.app_shortcut_shuffle_all_long)
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SHUFFLE_ALL)) ).setIcon(
.build() AppShortcutIconGenerator.generateThemedIcon(
context, R.drawable.ic_app_shortcut_shuffle_all
)
).setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SHUFFLE_ALL)).build()
companion object { companion object {
val id: String val id: String
get() = BaseShortcutType.ID_PREFIX + "shuffle_all" get() = BaseShortcutType.ID_PREFIX + "shuffle_all"
} }
} }

View file

@ -19,23 +19,25 @@ import android.content.Context
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.os.Build import android.os.Build
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.appshortcuts.AppShortcutIconGenerator import code.name.monkey.retromusic.appshortcuts.*
import code.name.monkey.retromusic.appshortcuts.AppShortcutLauncherActivity
@TargetApi(Build.VERSION_CODES.N_MR1) @TargetApi(Build.VERSION_CODES.N_MR1)
class TopTracksShortcutType(context: Context) : BaseShortcutType(context) { class TopTracksShortcutType(context: Context) : BaseShortcutType(context) {
override val shortcutInfo: ShortcutInfo override val shortcutInfo: ShortcutInfo
get() = ShortcutInfo.Builder(context, id) get() = ShortcutInfo.Builder(
.setShortLabel(context.getString(R.string.app_shortcut_top_tracks_short)) context, id
.setLongLabel(context.getString(R.string.app_shortcut_top_tracks_long)) ).setShortLabel(context.getString(R.string.app_shortcut_top_tracks_short)).setLongLabel(
.setIcon(AppShortcutIconGenerator.generateThemedIcon(context, R.drawable.ic_app_shortcut_top_tracks)) context.getString(R.string.app_shortcut_top_tracks_long)
.setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_TOP_TRACKS)) ).setIcon(
.build() AppShortcutIconGenerator.generateThemedIcon(
context, R.drawable.ic_app_shortcut_top_tracks
)
).setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_TOP_TRACKS)).build()
companion object { companion object {
val id: String val id: String
get() = BaseShortcutType.ID_PREFIX + "top_tracks" get() = BaseShortcutType.ID_PREFIX + "top_tracks"
} }
} }

View file

@ -15,154 +15,170 @@
package code.name.monkey.retromusic.appwidgets.base package code.name.monkey.retromusic.appwidgets.base
import android.app.PendingIntent import android.app.PendingIntent
import android.appwidget.AppWidgetManager import android.appwidget.*
import android.appwidget.AppWidgetProvider import android.content.*
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.res.Resources import android.content.res.Resources
import android.graphics.* import android.graphics.*
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.*
import android.graphics.drawable.Drawable
import android.os.Build import android.os.Build
import android.text.TextUtils import android.text.TextUtils
import android.widget.RemoteViews import android.widget.RemoteViews
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import code.name.monkey.retromusic.App import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.* import code.name.monkey.retromusic.service.MusicService.*
abstract class BaseAppWidget : AppWidgetProvider() { abstract class BaseAppWidget : AppWidgetProvider() {
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, override fun onUpdate(
appWidgetIds: IntArray) { context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray
defaultAppWidget(context, appWidgetIds) ) {
val updateIntent = Intent(APP_WIDGET_UPDATE) defaultAppWidget(context, appWidgetIds)
updateIntent.putExtra(EXTRA_APP_WIDGET_NAME, NAME) val updateIntent = Intent(APP_WIDGET_UPDATE)
updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds) updateIntent.putExtra(EXTRA_APP_WIDGET_NAME, NAME)
updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY) updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
context.sendBroadcast(updateIntent) updateIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
} context.sendBroadcast(updateIntent)
}
/** /**
* Handle a change notification coming over from [MusicService] * Handle a change notification coming over from [MusicService]
*/ */
fun notifyChange(service: MusicService, what: String) { fun notifyChange(service: MusicService, what: String) {
if (hasInstances(service)) { if (hasInstances(service)) {
if (META_CHANGED == what || PLAY_STATE_CHANGED == what) { if (META_CHANGED == what || PLAY_STATE_CHANGED == what) {
performUpdate(service, null) performUpdate(service, null)
} }
} }
} }
protected fun pushUpdate(context: Context, appWidgetIds: IntArray?, protected fun pushUpdate(
views: RemoteViews) { context: Context, appWidgetIds: IntArray?, views: RemoteViews
val appWidgetManager = AppWidgetManager.getInstance(context) ) {
if (appWidgetIds != null) { val appWidgetManager = AppWidgetManager.getInstance(context)
appWidgetManager.updateAppWidget(appWidgetIds, views) if (appWidgetIds != null) {
} else { appWidgetManager.updateAppWidget(appWidgetIds, views)
appWidgetManager.updateAppWidget(ComponentName(context, javaClass), views) } else {
} appWidgetManager.updateAppWidget(ComponentName(context, javaClass), views)
} }
}
/** /**
* Check against [AppWidgetManager] if there are any instances of this widget. * Check against [AppWidgetManager] if there are any instances of this widget.
*/ */
private fun hasInstances(context: Context): Boolean { private fun hasInstances(context: Context): Boolean {
val appWidgetManager = AppWidgetManager.getInstance(context) val appWidgetManager = AppWidgetManager.getInstance(context)
val mAppWidgetIds = appWidgetManager.getAppWidgetIds(ComponentName(context, val mAppWidgetIds = appWidgetManager.getAppWidgetIds(
javaClass)) ComponentName(
return mAppWidgetIds.isNotEmpty() context, javaClass
} )
)
return mAppWidgetIds.isNotEmpty()
}
protected fun buildPendingIntent(context: Context, action: String, protected fun buildPendingIntent(
serviceName: ComponentName): PendingIntent { context: Context, action: String, serviceName: ComponentName
val intent = Intent(action) ): PendingIntent {
intent.component = serviceName val intent = Intent(action)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { intent.component = serviceName
PendingIntent.getForegroundService(context, 0, intent, 0) return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
} else { PendingIntent.getForegroundService(context, 0, intent, 0)
PendingIntent.getService(context, 0, intent, 0) } else {
} PendingIntent.getService(context, 0, intent, 0)
} }
}
protected abstract fun defaultAppWidget(context: Context, appWidgetIds: IntArray) protected abstract fun defaultAppWidget(context: Context, appWidgetIds: IntArray)
abstract fun performUpdate(service: MusicService, appWidgetIds: IntArray?) abstract fun performUpdate(service: MusicService, appWidgetIds: IntArray?)
protected fun getAlbumArtDrawable(resources: Resources, bitmap: Bitmap?): Drawable { protected fun getAlbumArtDrawable(resources: Resources, bitmap: Bitmap?): Drawable {
return if (bitmap == null) { return if (bitmap == null) {
ContextCompat.getDrawable(App.getContext(), R.drawable.default_album_art)!! ContextCompat.getDrawable(App.getContext(), R.drawable.default_album_art)!!
} else { } else {
BitmapDrawable(resources, bitmap) BitmapDrawable(resources, bitmap)
} }
} }
protected fun getSongArtistAndAlbum(song: Song): String { protected fun getSongArtistAndAlbum(song: Song): String {
val builder = StringBuilder() val builder = StringBuilder()
builder.append(song.artistName) builder.append(song.artistName)
if (!TextUtils.isEmpty(song.artistName) && !TextUtils.isEmpty(song.albumName)) { if (!TextUtils.isEmpty(song.artistName) && !TextUtils.isEmpty(song.albumName)) {
builder.append("") builder.append("")
} }
builder.append(song.albumName) builder.append(song.albumName)
return builder.toString() return builder.toString()
} }
companion object { companion object {
const val NAME: String = "app_widget" const val NAME: String = "app_widget"
fun createRoundedBitmap(
drawable: Drawable?,
width: Int,
height: Int,
tl: Float,
tr: Float,
bl: Float,
br: Float
): Bitmap? {
if (drawable == null) {
return null
}
fun createRoundedBitmap(drawable: Drawable?, width: Int, height: Int, tl: Float, val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
tr: Float, bl: Float, br: Float): Bitmap? { val c = Canvas(bitmap)
if (drawable == null) { drawable.setBounds(0, 0, width, height)
return null drawable.draw(c)
}
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val rounded = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val c = Canvas(bitmap)
drawable.setBounds(0, 0, width, height)
drawable.draw(c)
val rounded = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val canvas = Canvas(rounded)
val paint = Paint()
paint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
paint.isAntiAlias = true
canvas.drawPath(
composeRoundedRectPath(
RectF(0f, 0f, width.toFloat(), height.toFloat()), tl, tr, bl, br
), paint
)
val canvas = Canvas(rounded) return rounded
val paint = Paint() }
paint.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
paint.isAntiAlias = true
canvas.drawPath(composeRoundedRectPath(RectF(0f, 0f, width.toFloat(), height.toFloat()), tl, tr, bl, br), paint)
return rounded fun createBitmap(drawable: Drawable, sizeMultiplier: Float): Bitmap {
} val bitmap = Bitmap.createBitmap(
(drawable.intrinsicWidth * sizeMultiplier).toInt(),
(drawable.intrinsicHeight * sizeMultiplier).toInt(),
Bitmap.Config.ARGB_8888
)
val c = Canvas(bitmap)
drawable.setBounds(0, 0, c.width, c.height)
drawable.draw(c)
return bitmap
}
fun createBitmap(drawable: Drawable, sizeMultiplier: Float): Bitmap { protected fun composeRoundedRectPath(
val bitmap = Bitmap.createBitmap((drawable.intrinsicWidth * sizeMultiplier).toInt(), rect: RectF, tl: Float, tr: Float, bl: Float, br: Float
(drawable.intrinsicHeight * sizeMultiplier).toInt(), Bitmap.Config.ARGB_8888) ): Path {
val c = Canvas(bitmap) val path = Path()
drawable.setBounds(0, 0, c.width, c.height) path.moveTo(rect.left + tl, rect.top)
drawable.draw(c) path.lineTo(rect.right - tr, rect.top)
return bitmap path.quadTo(rect.right, rect.top, rect.right, rect.top + tr)
} path.lineTo(rect.right, rect.bottom - br)
path.quadTo(rect.right, rect.bottom, rect.right - br, rect.bottom)
path.lineTo(rect.left + bl, rect.bottom)
path.quadTo(rect.left, rect.bottom, rect.left, rect.bottom - bl)
path.lineTo(rect.left, rect.top + tl)
path.quadTo(rect.left, rect.top, rect.left + tl, rect.top)
path.close()
protected fun composeRoundedRectPath(rect: RectF, tl: Float, tr: Float, bl: Float, br: Float): Path { return path
val path = Path() }
path.moveTo(rect.left + tl, rect.top) }
path.lineTo(rect.right - tr, rect.top)
path.quadTo(rect.right, rect.top, rect.right, rect.top + tr)
path.lineTo(rect.right, rect.bottom - br)
path.quadTo(rect.right, rect.bottom, rect.right - br, rect.bottom)
path.lineTo(rect.left + bl, rect.bottom)
path.quadTo(rect.left, rect.bottom, rect.left, rect.bottom - bl)
path.lineTo(rect.left, rect.top + tl)
path.quadTo(rect.left, rect.top, rect.left + tl, rect.top)
path.close()
return path
}
}
} }

View file

@ -4,19 +4,13 @@ import android.animation.ValueAnimator
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.*
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.palette.graphics.Palette import androidx.palette.graphics.Palette
import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.*
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.*
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
@ -27,160 +21,169 @@ import kotlinx.android.synthetic.main.fragment_color_player.*
class ColorFragment : AbsPlayerFragment() { class ColorFragment : AbsPlayerFragment() {
private var lastColor: Int = 0 private var lastColor: Int = 0
private var backgroundColor: Int = 0 private var backgroundColor: Int = 0
private var playbackControlsFragment: ColorPlaybackControlsFragment? = null private var playbackControlsFragment: ColorPlaybackControlsFragment? = null
private var valueAnimator: ValueAnimator? = null private var valueAnimator: ValueAnimator? = null
override fun playerToolbar(): Toolbar { override fun playerToolbar(): Toolbar {
return playerToolbar return playerToolbar
} }
override val paletteColor: Int override val paletteColor: Int
get() = backgroundColor get() = backgroundColor
override fun onColorChanged(color: Int) { override fun onColorChanged(color: Int) {
} }
override fun onFavoriteToggled() { override fun onFavoriteToggled() {
} }
override fun onShow() { override fun onShow() {
playbackControlsFragment!!.show() playbackControlsFragment!!.show()
} }
override fun onHide() { override fun onHide() {
playbackControlsFragment!!.hide() playbackControlsFragment!!.hide()
onBackPressed() onBackPressed()
} }
override fun onBackPressed(): Boolean { override fun onBackPressed(): Boolean {
return false return false
} }
override fun toolbarIconColor(): Int { override fun toolbarIconColor(): Int {
return lastColor return lastColor
} }
override fun toggleFavorite(song: Song) { override fun toggleFavorite(song: Song) {
super.toggleFavorite(song) super.toggleFavorite(song)
if (song.id == MusicPlayerRemote.currentSong.id) { if (song.id == MusicPlayerRemote.currentSong.id) {
updateIsFavorite() updateIsFavorite()
} }
} }
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
if (valueAnimator != null) { if (valueAnimator != null) {
valueAnimator!!.cancel() valueAnimator!!.cancel()
valueAnimator = null valueAnimator = null
} }
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(
savedInstanceState: Bundle?): View? { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_color_player, container, false) return inflater.inflate(R.layout.fragment_color_player, container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setUpSubFragments() setUpSubFragments()
setUpPlayerToolbar() setUpPlayerToolbar()
} }
private fun setUpSubFragments() { private fun setUpSubFragments() {
playbackControlsFragment = childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as ColorPlaybackControlsFragment? playbackControlsFragment = childFragmentManager.findFragmentById(
R.id.playbackControlsFragment
) as ColorPlaybackControlsFragment?
} }
private fun setUpPlayerToolbar() { private fun setUpPlayerToolbar() {
playerToolbar.apply { playerToolbar.apply {
inflateMenu(R.menu.menu_player) inflateMenu(R.menu.menu_player)
setNavigationOnClickListener { requireActivity().onBackPressed() } setNavigationOnClickListener { requireActivity().onBackPressed() }
setOnMenuItemClickListener(this@ColorFragment) setOnMenuItemClickListener(this@ColorFragment)
ToolbarContentTintHelper.colorizeToolbar(this, ATHUtil.resolveColor(context, R.attr.iconColor), activity) ToolbarContentTintHelper.colorizeToolbar(
} this, ATHUtil.resolveColor(
} context, R.attr.iconColor
), activity
)
}
}
override fun onPlayingMetaChanged() { override fun onPlayingMetaChanged() {
super.onPlayingMetaChanged() super.onPlayingMetaChanged()
updateSong() updateSong()
} }
override fun onServiceConnected() { override fun onServiceConnected() {
super.onServiceConnected() super.onServiceConnected()
updateSong() updateSong()
} }
private fun updateSong() { private fun updateSong() {
SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong) SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong)
.checkIgnoreMediaStore(requireContext()) .checkIgnoreMediaStore(requireContext()).generatePalette(requireContext()).build()
.generatePalette(requireContext()) .into(object : RetroMusicColoredTarget(playerImage) {
.build() override fun onColorReady(color: Int) {
.into(object : RetroMusicColoredTarget(playerImage) {
override fun onColorReady(color: Int) {
} }
override fun onResourceReady(resource: BitmapPaletteWrapper?, glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?) { override fun onResourceReady(
super.onResourceReady(resource, glideAnimation) resource: BitmapPaletteWrapper?,
resource?.let { glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?
val background = resource.palette.getColor() ) {
super.onResourceReady(resource, glideAnimation)
resource?.let {
val background = resource.palette.getColor()
val palette = resource.palette val palette = resource.palette
val swatch = RetroColorUtil.getSwatch(palette) val swatch = RetroColorUtil.getSwatch(palette)
val textColor = RetroColorUtil.getTextColor(palette) val textColor = RetroColorUtil.getTextColor(palette)
val backgroundColor = swatch.rgb val backgroundColor = swatch.rgb
setColors(backgroundColor, textColor) setColors(backgroundColor, textColor)
} }
} }
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) { override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
super.onLoadFailed(e, errorDrawable) super.onLoadFailed(e, errorDrawable)
val backgroundColor = defaultFooterColor val backgroundColor = defaultFooterColor
val textColor = if (ColorUtil.isColorLight(defaultFooterColor)) val textColor = if (ColorUtil.isColorLight(defaultFooterColor)) MaterialValueHelper.getPrimaryTextColor(
MaterialValueHelper.getPrimaryTextColor(context, true) context,
else true
MaterialValueHelper.getPrimaryTextColor(context, false) )
else MaterialValueHelper.getPrimaryTextColor(context, false)
setColors(backgroundColor, textColor) setColors(backgroundColor, textColor)
} }
}) })
} }
private fun setColors(backgroundColor: Int, textColor: Int) { private fun setColors(
playbackControlsFragment!!.setDark(textColor, backgroundColor) backgroundColor: Int, textColor: Int
colorGradientBackground?.setBackgroundColor(backgroundColor) ) {
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, textColor, activity) playbackControlsFragment?.setDark(textColor, backgroundColor)
lastColor = textColor colorGradientBackground?.setBackgroundColor(backgroundColor)
this.backgroundColor = backgroundColor ToolbarContentTintHelper.colorizeToolbar(playerToolbar, textColor, activity)
playerActivity?.setLightNavigationBar(ColorUtil.isColorLight(backgroundColor)) lastColor = textColor
callbacks?.onPaletteColorChanged() this.backgroundColor = backgroundColor
} playerActivity?.setLightNavigationBar(ColorUtil.isColorLight(backgroundColor))
callbacks?.onPaletteColorChanged()
}
companion object { companion object {
fun newInstance(): ColorFragment {
fun newInstance(): ColorFragment { val args = Bundle()
val args = Bundle() val fragment = ColorFragment()
val fragment = ColorFragment() fragment.arguments = args
fragment.arguments = args return fragment
return fragment }
} }
}
} }
fun Palette.getColor(): Int { fun Palette.getColor(): Int {
return when { return when {
darkMutedSwatch != null -> darkMutedSwatch!!.rgb darkMutedSwatch != null -> darkMutedSwatch!!.rgb
mutedSwatch != null -> mutedSwatch!!.rgb mutedSwatch != null -> mutedSwatch!!.rgb
lightMutedSwatch != null -> lightMutedSwatch!!.rgb lightMutedSwatch != null -> lightMutedSwatch!!.rgb
else -> Palette.Swatch(Color.BLACK, 1).rgb else -> Palette.Swatch(Color.BLACK, 1).rgb
} }
} }

View file

@ -1,53 +0,0 @@
/*
* 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.helper
import android.content.Intent
import androidx.core.app.ActivityCompat
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.activities.bugreport.ErrorHandlerActivity
class TopExceptionHandler() : Thread.UncaughtExceptionHandler {
private val defaultUEH: Thread.UncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
override fun uncaughtException(t: Thread, e: Throwable) {
var arr = e.stackTrace
var report = e.toString() + "\n\n"
report += "--------- Stack trace ---------\n\n"
for (i in arr.indices) {
report += " " + arr[i].toString() + "\n"
}
report += "-------------------------------\n\n"
// If the exception was thrown in a background thread inside
// AsyncTask, then the actual exception can be found with getCause
report += "--------- Cause ---------\n\n"
val cause = e.cause
if (cause != null) {
report += cause.toString() + "\n\n"
arr = cause.stackTrace
for (i in arr.indices) {
report += " " + arr[i].toString() + "\n"
}
}
report += "-------------------------------\n\n"
ActivityCompat.startActivity(App.getContext(), Intent(App.getContext(), ErrorHandlerActivity::class.java)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra("error", report), null)
defaultUEH.uncaughtException(t, e)
}
}

View file

@ -14,7 +14,9 @@
package code.name.monkey.retromusic.util; package code.name.monkey.retromusic.util;
import android.text.TextUtils;
import android.util.Base64; import android.util.Base64;
import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -78,35 +80,38 @@ public class LyricUtil {
@NonNull @NonNull
public static File getLocalLyricFile(@NonNull String title, @NonNull String artist) { public static File getLocalLyricFile(@NonNull String title, @NonNull String artist) {
try{ try {
File file = new File(getLrcPath(title, artist)); File file = new File(getLrcPath(title, artist));
File file2 = new File(getLrcPath2(title, artist)); File file2 = new File(getLrcPath2(title, artist));
if (file.exists()) { if (file.exists()) {
return file;
} else if (file2.exists()) {
return file2;
}
else {
return new File("lyric file not exist"); return file;
}} catch (Exception dfs){ } else if (file2.exists()) {
return file2;
} else {
return new File("lyric file not exist");
}
} catch (Exception dfs) {
dfs.printStackTrace(); dfs.printStackTrace();
return new File("lyric file not exist"); return new File("lyric file not exist");
} }
} }
public static String getLrcPath2(String title, String artist) { public static String getLrcPath2(String title, String artist) {
String x2; Log.i("HEM", "getLrcPath2: " + title);
if(title.endsWith(".flac")||title.endsWith(".mogg")||title.endsWith(".alac")||title.endsWith(".aiff")||title.endsWith(".webv")){ if (!TextUtils.isEmpty(title)) {
x2= title.substring(0, title.length() -5 ) + ".lrc"; String x2;
if (title.endsWith(".flac") || title.endsWith(".mogg") || title.endsWith(".alac") || title.endsWith(".aiff") || title.endsWith(".webv")) {
x2 = title.substring(0, title.length() - 5) + ".lrc";
} else {
x2 = title.substring(0, title.length() - 4) + ".lrc";
}
return x2;
} }
else{ return "";
x2= title.substring(0, title.length() -4 ) + ".lrc";}
return x2;
} }
public static String getLrcPath(String title, String artist) { public static String getLrcPath(String title, String artist) {
@ -135,7 +140,7 @@ public class LyricUtil {
File file; File file;
File file2 = new File(getLrcPath(title, artist)); File file2 = new File(getLrcPath(title, artist));
File file3 = new File(getLrcPath2(title, artist)); File file3 = new File(getLrcPath2(title, artist));
if(file2.exists()){ if (file2.exists()) {
file = file2; file = file2;
} else { } else {
file = file3; file = file3;
@ -143,7 +148,7 @@ public class LyricUtil {
FileInputStream fin = new FileInputStream(file); FileInputStream fin = new FileInputStream(file);
String ret = convertStreamToString(fin); String ret = convertStreamToString(fin);
fin.close(); fin.close();
// Log.d("damn2",ret); // Log.d("damn2",ret);
return ret; return ret;
} }

View file

@ -6,4 +6,6 @@ android.useAndroidX=true
android.enabelR8=true android.enabelR8=true
android.enableR8.fullMode=false android.enableR8.fullMode=false
android.enableJetifier=true android.enableJetifier=true
android.debug.obsoleteApi=true android.debug.obsoleteApi=true
android.enableBuildCache=true
android.jetifier.blacklist = butterknife.*\\.jar