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

@ -4,13 +4,10 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.view.*
import androidx.core.app.ShareCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import androidx.recyclerview.widget.*
import code.name.monkey.appthemehelper.util.*
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_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.adapter.ContributorAdapter
import code.name.monkey.retromusic.model.Contributor
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import code.name.monkey.retromusic.util.*
import com.afollestad.materialdialogs.*
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.list.listItems
import com.google.gson.Gson
@ -42,136 +37,132 @@ import java.nio.charset.StandardCharsets
class AboutActivity : AbsBaseActivity(), View.OnClickListener {
private val assetJsonData: String?
get() {
val json: String
try {
val inputStream = assets.open("contributors.json")
val size = inputStream.available()
val buffer = ByteArray(size)
inputStream.read(buffer)
inputStream.close()
json = String(buffer, StandardCharsets.UTF_8)
} catch (ex: IOException) {
ex.printStackTrace()
return null
}
private val assetJsonData: String?
get() {
val json: String
try {
val inputStream = assets.open("contributors.json")
val size = inputStream.available()
val buffer = ByteArray(size)
inputStream.read(buffer)
inputStream.close()
json = String(buffer, StandardCharsets.UTF_8)
} catch (ex: IOException) {
ex.printStackTrace()
return null
}
return json
}
return json
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_about)
setStatusbarColorAuto()
setNavigationBarColorPrimary()
setLightNavigationBar(true)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_about)
setStatusbarColorAuto()
setNavigationBarColorPrimary()
setLightNavigationBar(true)
loadContributors()
setSupportActionBar(toolbar)
toolbar.apply {
setTitleTextColor(ATHUtil.resolveColor(this@AboutActivity, R.attr.colorOnPrimary))
setBackgroundColor(ATHUtil.resolveColor(this@AboutActivity, R.attr.colorPrimary))
setNavigationOnClickListener { onBackPressed() }
ToolbarContentTintHelper.colorBackButton(toolbar)
}
version.setSummary(getAppVersion())
setUpView()
}
loadContributors()
setSupportActionBar(toolbar)
toolbar.apply {
setTitleTextColor(ATHUtil.resolveColor(this@AboutActivity, R.attr.colorOnPrimary))
setBackgroundColor(ATHUtil.resolveColor(this@AboutActivity, R.attr.colorPrimary))
setNavigationOnClickListener { onBackPressed() }
ToolbarContentTintHelper.colorBackButton(toolbar)
}
version.setSummary(getAppVersion())
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 {
if (item.itemId == android.R.id.home) {
onBackPressed()
return true
}
return super.onOptionsItemSelected(item)
}
private fun openUrl(url: String) {
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(url)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(i)
}
private fun openUrl(url: String) {
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(url)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(i)
}
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)
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) {
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)
}
}
private fun showChangeLogOptions() {
MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
cornerRadius(PreferenceUtil.getInstance(this@AboutActivity).dialogCorner)
listItems(items = listOf("Telegram Channel", "App")) { _, position, _ ->
if (position == 0) {
openUrl(TELEGRAM_CHANGE_LOG)
} else {
NavigationUtil.gotoWhatNews(this@AboutActivity)
}
}
}
}
private fun showChangeLogOptions() {
MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT))
.show {
cornerRadius(PreferenceUtil.getInstance(this@AboutActivity).dialogCorner)
listItems(items = listOf("Telegram Channel", "App")) { _, position, _ ->
if (position == 0) {
openUrl(TELEGRAM_CHANGE_LOG)
} else {
NavigationUtil.gotoWhatNews(this@AboutActivity)
}
}
}
}
private fun getAppVersion(): String {
return try {
val packageInfo = packageManager.getPackageInfo(packageName, 0)
packageInfo.versionName
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
"0.0.0"
}
}
private fun getAppVersion(): String {
return try {
val packageInfo = packageManager.getPackageInfo(packageName, 0)
packageInfo.versionName
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
"0.0.0"
}
}
private fun shareApp() {
ShareCompat.IntentBuilder.from(this).setType("text/plain")
.setChooserTitle(R.string.share_app)
.setText(String.format(getString(R.string.app_share), packageName)).startChooser()
}
private fun shareApp() {
ShareCompat.IntentBuilder.from(this)
.setType("text/plain")
.setChooserTitle(R.string.share_app)
.setText(String.format(getString(R.string.app_share), packageName))
.startChooser()
}
private fun loadContributors() {
val data = assetJsonData
val type = object : TypeToken<List<Contributor>>() {
private fun loadContributors() {
val data = assetJsonData
val type = object : TypeToken<List<Contributor>>() {
}.type
val contributors = Gson().fromJson<List<Contributor>>(data, type)
}.type
val contributors = Gson().fromJson<List<Contributor>>(data, type)
val contributorAdapter = ContributorAdapter(contributors)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.itemAnimator = DefaultItemAnimator()
recyclerView.adapter = contributorAdapter
}
val contributorAdapter = ContributorAdapter(contributors)
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.graphics.Color
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.SubMenu
import android.view.View
import android.view.*
import android.widget.ImageView
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.*
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.MaterialUtil
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.appthemehelper.util.*
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
import code.name.monkey.retromusic.activities.tageditor.AlbumTagEditorActivity
import code.name.monkey.retromusic.activities.tageditor.*
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
import code.name.monkey.retromusic.dialogs.*
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.glide.*
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.mvp.presenter.AlbumDetailsPresenter
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 code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.mvp.presenter.*
import code.name.monkey.retromusic.util.*
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.activity_album.*
import kotlinx.android.synthetic.main.activity_album_content.*
@ -46,236 +30,263 @@ import java.util.*
import javax.inject.Inject
import android.util.Pair as UtilPair
class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView {
private lateinit var simpleSongAdapter: SimpleSongAdapter
private lateinit var album: Album
private lateinit var artistImage: ImageView
private val savedSortOrder: String
get() = PreferenceUtil.getInstance(this).albumDetailSongSortOrder
private lateinit var simpleSongAdapter: SimpleSongAdapter
private lateinit var album: Album
private lateinit var artistImage: ImageView
private val savedSortOrder: String
get() = PreferenceUtil.getInstance(this).albumDetailSongSortOrder
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_album)
}
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_album)
}
@Inject
lateinit var albumDetailsPresenter: AlbumDetailsPresenter
@Inject
lateinit var albumDetailsPresenter: AlbumDetailsPresenter
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
toggleBottomNavigationView(true)
setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
toggleBottomNavigationView(true)
setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
ActivityCompat.postponeEnterTransition(this)
ActivityCompat.postponeEnterTransition(this)
App.musicComponent.inject(this)
artistImage = findViewById(R.id.artistImage)
App.musicComponent.inject(this)
artistImage = findViewById(R.id.artistImage)
setupRecyclerView()
setupRecyclerView()
artistImage.setOnClickListener {
val artistPairs = ActivityOptions.makeSceneTransitionAnimation(this, UtilPair.create(artistImage, getString(R.string.transition_artist_image)))
NavigationUtil.goToArtistOptions(this, album.artistId, artistPairs)
}
playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
}
shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album.songs!!, true) }
}
artistImage.setOnClickListener {
val artistPairs = ActivityOptions.makeSceneTransitionAnimation(
this,
UtilPair.create(
artistImage,
getString(R.string.transition_artist_image)
)
)
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)) {
intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) }
} else {
finish()
}
}
if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) }
} else {
finish()
}
}
private fun setupRecyclerView() {
simpleSongAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song)
recyclerView.apply {
layoutManager = LinearLayoutManager(this@AlbumDetailsActivity)
itemAnimator = DefaultItemAnimator()
isNestedScrollingEnabled = false
adapter = simpleSongAdapter
}
}
private fun setupRecyclerView() {
simpleSongAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song)
recyclerView.apply {
layoutManager = LinearLayoutManager(this@AlbumDetailsActivity)
itemAnimator = DefaultItemAnimator()
isNestedScrollingEnabled = false
adapter = simpleSongAdapter
}
}
override fun onDestroy() {
super.onDestroy()
albumDetailsPresenter.detachView()
}
override fun onDestroy() {
super.onDestroy()
albumDetailsPresenter.detachView()
}
override fun complete() {
ActivityCompat.startPostponedEnterTransition(this)
}
override fun complete() {
ActivityCompat.startPostponedEnterTransition(this)
}
override fun album(album: Album) {
override fun album(album: Album) {
if (album.songs!!.isEmpty()) {
finish()
return
}
this.album = album
if (album.songs!!.isEmpty()) {
finish()
return
}
this.album = album
albumTitle.text = album.title
if (MusicUtil.getYearString(album.year) == "-") {
albumText.text = String.format("%s • %s", album.artistName, MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, 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)
}
albumTitle.text = album.title
if (MusicUtil.getYearString(album.year) == "-") {
albumText.text = String.format(
"%s • %s",
album.artistName,
MusicUtil.getReadableDurationString(
MusicUtil.getTotalDuration(
this,
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>) {
moreTitle.show()
moreRecyclerView.show()
moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName)
val albumAdapter = HorizontalAlbumAdapter(this, albums, false, null)
moreRecyclerView.layoutManager = GridLayoutManager(
this,
1,
GridLayoutManager.HORIZONTAL,
false
)
moreRecyclerView.adapter = albumAdapter
}
val albumAdapter = HorizontalAlbumAdapter(this, albums, false, null)
moreRecyclerView.layoutManager = GridLayoutManager(this, 1, GridLayoutManager.HORIZONTAL, false)
moreRecyclerView.adapter = albumAdapter
}
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) {
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() {
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 setColors(color: Int) {
val themeColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
else ThemeStore.accentColor(this)
private fun setColors(color: Int) {
val themeColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
else ThemeStore.accentColor(this)
songTitle.setTextColor(themeColor)
moreTitle.setTextColor(themeColor)
songTitle.setTextColor(themeColor)
moreTitle.setTextColor(themeColor)
val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
else ATHUtil.resolveColor(this, R.attr.cardBackgroundColor)
val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
else ATHUtil.resolveColor(this, R.attr.cardBackgroundColor)
MaterialUtil.setTint(button = shuffleAction, color = buttonColor)
MaterialUtil.setTint(button = playAction, color = buttonColor)
MaterialUtil.setTint(button = shuffleAction, color = buttonColor)
MaterialUtil.setTint(button = playAction, color = buttonColor)
toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
setSupportActionBar(toolbar)
supportActionBar?.title = null
}
toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
setSupportActionBar(toolbar)
supportActionBar?.title = null
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_album_detail, menu)
val sortOrder = menu.findItem(R.id.action_sort_order)
setUpSortOrderMenu(sortOrder.subMenu)
return super.onCreateOptionsMenu(menu)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_album_detail, menu)
val sortOrder = menu.findItem(R.id.action_sort_order)
setUpSortOrderMenu(sortOrder.subMenu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return handleSortOrderMenuItem(item)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return handleSortOrderMenuItem(item)
}
private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
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 {
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 setUpSortOrderMenu(sortOrder: SubMenu) {
when (savedSortOrder) {
AlbumSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title)
.isChecked = true
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 setUpSortOrderMenu(sortOrder: SubMenu) {
when (savedSortOrder) {
AlbumSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title).isChecked = true
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?) {
PreferenceUtil.getInstance(this).albumDetailSongSortOrder = sortOrder
reload()
}
private fun setSaveSortOrder(sortOrder: String?) {
PreferenceUtil.getInstance(this).albumDetailSongSortOrder = sortOrder
reload()
}
override fun onMediaStoreChanged() {
super.onMediaStoreChanged()
reload()
}
override fun onMediaStoreChanged() {
super.onMediaStoreChanged()
reload()
}
private fun reload() {
if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) }
} else {
finish()
}
}
private fun reload() {
if (intent.extras!!.containsKey(EXTRA_ALBUM_ID)) {
intent.extras?.getInt(EXTRA_ALBUM_ID)?.let { albumDetailsPresenter.loadAlbum(it) }
} else {
finish()
}
}
companion object {
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.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.text.Html
import android.text.Spanned
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.os.*
import android.text.*
import android.view.*
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.*
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.MaterialUtil
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.appthemehelper.util.*
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.album.*
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.*
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsPresenter
import code.name.monkey.retromusic.mvp.presenter.ArtistDetailsView
import code.name.monkey.retromusic.mvp.presenter.*
import code.name.monkey.retromusic.rest.LastFMRestClient
import code.name.monkey.retromusic.rest.model.LastFmArtist
import code.name.monkey.retromusic.util.*
@ -44,257 +32,267 @@ import kotlin.collections.ArrayList
class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView {
private var biography: Spanned? = null
private lateinit var artist: Artist
private var lastFMRestClient: LastFMRestClient? = null
private lateinit var songAdapter: SimpleSongAdapter
private lateinit var albumAdapter: AlbumAdapter
private var forceDownload: Boolean = false
private var biography: Spanned? = null
private lateinit var artist: Artist
private var lastFMRestClient: LastFMRestClient? = null
private lateinit var songAdapter: SimpleSongAdapter
private lateinit var albumAdapter: AlbumAdapter
private var forceDownload: Boolean = false
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_artist_details)
}
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_artist_details)
}
@Inject
lateinit var artistDetailsPresenter: ArtistDetailsPresenter
@Inject
lateinit var artistDetailsPresenter: ArtistDetailsPresenter
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
toggleBottomNavigationView(true)
setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
toggleBottomNavigationView(true)
setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
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 {
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
}
shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
}
playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
}
shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
}
biographyText.setOnClickListener {
if (biographyText.maxLines == 4) {
biographyText.maxLines = Integer.MAX_VALUE
} else {
biographyText.maxLines = 4
}
}
biographyText.setOnClickListener {
if (biographyText.maxLines == 4) {
biographyText.maxLines = Integer.MAX_VALUE
} else {
biographyText.maxLines = 4
}
}
App.musicComponent.inject(this)
artistDetailsPresenter.attachView(this)
App.musicComponent.inject(this)
artistDetailsPresenter.attachView(this)
if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) }
} else {
finish()
}
}
if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) }
} else {
finish()
}
}
override fun onDestroy() {
super.onDestroy()
artistDetailsPresenter.detachView()
}
override fun onDestroy() {
super.onDestroy()
artistDetailsPresenter.detachView()
}
private fun setUpViews() {
setupRecyclerView()
setupContainerHeight()
}
private fun setUpViews() {
setupRecyclerView()
setupContainerHeight()
}
private fun setupContainerHeight() {
imageContainer?.let {
val params = it.layoutParams
params.width = DensityUtil.getScreenHeight(this) / 2
it.layoutParams = params
}
}
private fun setupContainerHeight() {
imageContainer?.let {
val params = it.layoutParams
params.width = DensityUtil.getScreenHeight(this) / 2
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() {
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
}
}
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 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() {
ActivityCompat.startPostponedEnterTransition(this)
}
if (RetroUtil.isAllowedToDownloadMetadata(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) {
if (artist.songCount <= 0) {
finish()
}
this.artist = artist
loadArtistImage()
songAdapter.swapDataSet(artist.songs)
albumAdapter.swapDataSet(artist.albums!!)
}
if (RetroUtil.isAllowedToDownloadMetadata(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)))
private fun loadBiography(
name: String, lang: String? = Locale.getDefault().language
) {
biography = null
this.lang = lang
artistDetailsPresenter.loadBiography(name, lang, null)
}
songAdapter.swapDataSet(artist.songs)
albumAdapter.swapDataSet(artist.albums!!)
}
override fun artistInfo(lastFmArtist: LastFmArtist?) {
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,
lang: String? = Locale.getDefault().language) {
biography = null
this.lang = lang
artistDetailsPresenter.loadBiography(name, lang, null)
}
// If the "lang" parameter is set and no biography is given, retry with default language
if (biography == null && lang != null) {
loadBiography(artist.name, null)
}
}
override fun artistInfo(lastFmArtist: LastFmArtist?) {
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 var lang: String? = null
// If the "lang" parameter is set and no biography is given, retry with default language
if (biography == null && lang != null) {
loadBiography(artist.name, null)
}
}
private fun loadArtistImage() {
ArtistGlideRequest.Builder.from(Glide.with(this), artist).generatePalette(this).build()
.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() {
ArtistGlideRequest.Builder.from(Glide.with(this), artist)
.generatePalette(this).build()
.dontAnimate()
.into(object : RetroMusicColoredTarget(artistImage) {
override fun onColorReady(color: Int) {
setColors(color)
}
})
}
val textColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
else ThemeStore.accentColor(this)
private fun setColors(color: Int) {
albumTitle.setTextColor(textColor)
songTitle.setTextColor(textColor)
biographyTitle.setTextColor(textColor)
val textColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
else ThemeStore.accentColor(this)
val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
else ATHUtil.resolveColor(this, R.attr.cardBackgroundColor)
albumTitle.setTextColor(textColor)
songTitle.setTextColor(textColor)
biographyTitle.setTextColor(textColor)
MaterialUtil.setTint(button = shuffleAction, color = buttonColor)
MaterialUtil.setTint(button = playAction, color = buttonColor)
val buttonColor = if (PreferenceUtil.getInstance(this).adaptiveColor) color
else ATHUtil.resolveColor(this, R.attr.cardBackgroundColor)
toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
setSupportActionBar(toolbar)
supportActionBar?.title = null
}
MaterialUtil.setTint(button = shuffleAction, color = buttonColor)
MaterialUtil.setTint(button = playAction, color = buttonColor)
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return handleSortOrderMenuItem(item)
}
toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
setSupportActionBar(toolbar)
supportActionBar?.title = null
}
private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
val songs = artist.songs
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 {
return handleSortOrderMenuItem(item)
}
override fun onMediaStoreChanged() {
super.onMediaStoreChanged()
reload()
}
private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
val songs = artist.songs
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
}
private fun reload() {
if (intent.extras!!.containsKey(EXTRA_ARTIST_ID)) {
intent.extras?.getInt(EXTRA_ARTIST_ID)?.let { artistDetailsPresenter.loadArtist(it) }
} else {
finish()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_artist_detail, menu)
return super.onCreateOptionsMenu(menu)
}
companion object {
override fun onMediaStoreChanged() {
super.onMediaStoreChanged()
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
}
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.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.recyclerview.widget.DefaultItemAnimator
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 android.view.*
import androidx.recyclerview.widget.*
import code.name.monkey.appthemehelper.util.*
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.adapter.song.ShuffleButtonSongAdapter
import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.helper.menu.GenreMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.mvp.presenter.GenreDetailsPresenter
import code.name.monkey.retromusic.mvp.presenter.GenreDetailsView
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.mvp.presenter.*
import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.ViewUtil
import com.afollestad.materialcab.MaterialCab
import kotlinx.android.synthetic.main.activity_playlist_detail.*
@ -34,124 +26,127 @@ import javax.inject.Inject
class GenreDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder, GenreDetailsView {
@Inject
lateinit var genreDetailsPresenter: GenreDetailsPresenter
@Inject
lateinit var genreDetailsPresenter: GenreDetailsPresenter
private lateinit var genre: Genre
private lateinit var songAdapter: ShuffleButtonSongAdapter
private var cab: MaterialCab? = null
private lateinit var genre: Genre
private lateinit var songAdapter: ShuffleButtonSongAdapter
private var cab: MaterialCab? = null
private fun checkIsEmpty() {
empty?.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE
}
private fun checkIsEmpty() {
empty?.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE
}
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
toggleBottomNavigationView(true)
setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
toggleBottomNavigationView(true)
if (intent.extras != null) {
genre = intent?.extras?.getParcelable(EXTRA_GENRE_ID)!!
} else {
finish()
}
if (intent.extras != null) {
genre = intent?.extras?.getParcelable(EXTRA_GENRE_ID)!!
} else {
finish()
}
setUpToolBar()
setupRecyclerView()
setUpToolBar()
setupRecyclerView()
App.musicComponent.inject(this)
genreDetailsPresenter.attachView(this)
App.musicComponent.inject(this)
genreDetailsPresenter.attachView(this)
}
}
private fun setUpToolBar() {
val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary)
appBarLayout.setBackgroundColor(primaryColor)
applyToolbar(toolbar)
title = genre.name
}
private fun setUpToolBar() {
val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary)
appBarLayout.setBackgroundColor(primaryColor)
applyToolbar(toolbar)
title = genre.name
}
override fun onResume() {
super.onResume()
genreDetailsPresenter.loadGenreSongs(genre.id)
}
override fun onResume() {
super.onResume()
genreDetailsPresenter.loadGenreSongs(genre.id)
}
override fun onDestroy() {
super.onDestroy()
genreDetailsPresenter.detachView()
}
override fun onDestroy() {
super.onDestroy()
genreDetailsPresenter.detachView()
}
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_playlist_detail)
}
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_playlist_detail)
}
override fun showEmptyView() {
override fun showEmptyView() {
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_genre_detail, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_genre_detail, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
}
return GenreMenuHelper.handleMenuClick(this, genre, item)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
}
return GenreMenuHelper.handleMenuClick(this, genre, item)
}
private fun setupRecyclerView() {
ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView )
songAdapter = ShuffleButtonSongAdapter(this, ArrayList(), R.layout.item_list, false, this)
recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(this@GenreDetailsActivity)
adapter = songAdapter
}
songAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
checkIsEmpty()
}
})
}
private fun setupRecyclerView() {
ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
songAdapter = ShuffleButtonSongAdapter(this, ArrayList(), R.layout.item_list, false, this)
recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(this@GenreDetailsActivity)
adapter = songAdapter
}
songAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
checkIsEmpty()
}
})
}
override fun songs(songs: ArrayList<Song>) {
songAdapter.swapDataSet(songs)
}
override fun songs(songs: ArrayList<Song>) {
songAdapter.swapDataSet(songs)
}
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
if (cab != null && cab!!.isActive) cab!!.finish()
cab = MaterialCab(this, R.id.cab_stub)
.setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close_white_24dp)
.setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
.start(callback)
return cab!!
}
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
if (cab != null && cab!!.isActive) cab!!.finish()
cab = MaterialCab(this, R.id.cab_stub).setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close_white_24dp).setBackgroundColor(
RetroColorUtil.shiftBackgroundColorForLightText(
ATHUtil.resolveColor(
this,
R.attr.colorPrimary
)
)
).start(callback)
return cab!!
}
override fun onBackPressed() {
if (cab != null && cab!!.isActive)
cab!!.finish()
else {
recyclerView!!.stopScroll()
super.onBackPressed()
}
}
override fun onBackPressed() {
if (cab != null && cab!!.isActive) cab!!.finish()
else {
recyclerView!!.stopScroll()
super.onBackPressed()
}
}
override fun onMediaStoreChanged() {
super.onMediaStoreChanged()
genreDetailsPresenter.loadGenreSongs(genre.id)
}
override fun onMediaStoreChanged() {
super.onMediaStoreChanged()
genreDetailsPresenter.loadGenreSongs(genre.id)
}
companion object {
const val EXTRA_GENRE_ID = "extra_genre_id"
}
companion object {
const val EXTRA_GENRE_ID = "extra_genre_id"
}
}

View file

@ -30,7 +30,6 @@ import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
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.ToolbarContentTintHelper;
import code.name.monkey.retromusic.R;

View file

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

View file

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

View file

@ -3,182 +3,186 @@ package code.name.monkey.retromusic.activities
import android.content.res.ColorStateList
import android.os.Bundle
import android.view.MenuItem
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.*
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.MaterialValueHelper
import code.name.monkey.appthemehelper.util.*
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
import code.name.monkey.retromusic.extensions.applyToolbar
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 com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
import kotlinx.android.synthetic.main.activity_playing_queue.*
open class PlayingQueueActivity : AbsMusicServiceActivity() {
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
private var playingQueueAdapter: PlayingQueueAdapter? = null
private lateinit var linearLayoutManager: LinearLayoutManager
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
private var playingQueueAdapter: PlayingQueueAdapter? = null
private lateinit var linearLayoutManager: LinearLayoutManager
private fun getUpNextAndQueueTime(): String {
val duration = MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.position)
private fun getUpNextAndQueueTime(): String {
val duration = MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.position)
return MusicUtil.buildInfoString(
resources.getString(R.string.up_next), MusicUtil.getReadableDurationString(duration)
)
}
return MusicUtil.buildInfoString(
resources.getString(R.string.up_next),
MusicUtil.getReadableDurationString(duration)
)
}
override fun onCreate(
savedInstanceState: Bundle?
) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_playing_queue)
override fun onCreate(
savedInstanceState: Bundle?
) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_playing_queue)
setStatusbarColorAuto()
setNavigationBarColorPrimary()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setStatusbarColorAuto()
setNavigationBarColorPrimary()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setupToolbar()
setUpRecyclerView()
setupToolbar()
setUpRecyclerView()
clearQueue.setOnClickListener {
MusicPlayerRemote.clearQueue()
}
checkForPadding()
}
clearQueue.setOnClickListener {
MusicPlayerRemote.clearQueue()
}
checkForPadding()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
onBackPressed()
true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
onBackPressed()
true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun setUpRecyclerView() {
recyclerViewDragDropManager = RecyclerViewDragDropManager()
val animator = RefactoredDefaultItemAnimator()
private fun setUpRecyclerView() {
recyclerViewDragDropManager = RecyclerViewDragDropManager()
val animator = RefactoredDefaultItemAnimator()
playingQueueAdapter = PlayingQueueAdapter(
this,
MusicPlayerRemote.playingQueue,
MusicPlayerRemote.position,
R.layout.item_queue
)
wrappedAdapter = recyclerViewDragDropManager?.createWrappedAdapter(playingQueueAdapter!!)
playingQueueAdapter = PlayingQueueAdapter(
this,
MusicPlayerRemote.playingQueue,
MusicPlayerRemote.position,
R.layout.item_queue)
wrappedAdapter = recyclerViewDragDropManager?.createWrappedAdapter(playingQueueAdapter!!)
linearLayoutManager = LinearLayoutManager(this)
linearLayoutManager = LinearLayoutManager(this)
recyclerView.apply {
layoutManager = linearLayoutManager
adapter = wrappedAdapter
itemAnimator = animator
recyclerViewDragDropManager?.attachRecyclerView(this)
}
recyclerView.apply {
layoutManager = linearLayoutManager
adapter = wrappedAdapter
itemAnimator = animator
recyclerViewDragDropManager?.attachRecyclerView(this)
}
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
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() {
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() {
private fun checkForPadding() {
}
}
override fun onQueueChanged() {
if (MusicPlayerRemote.playingQueue.isEmpty()) {
finish()
return
}
checkForPadding()
updateQueue()
updateCurrentSong()
}
override fun onQueueChanged() {
if (MusicPlayerRemote.playingQueue.isEmpty()) {
finish()
return
}
checkForPadding()
updateQueue()
updateCurrentSong()
}
override fun onMediaStoreChanged() {
updateQueue()
updateCurrentSong()
}
override fun onMediaStoreChanged() {
updateQueue()
updateCurrentSong()
}
private fun updateCurrentSong() {
playerQueueSubHeader.text = getUpNextAndQueueTime()
}
private fun updateCurrentSong() {
playerQueueSubHeader.text = getUpNextAndQueueTime()
}
override fun onPlayingMetaChanged() {
updateQueuePosition()
}
override fun onPlayingMetaChanged() {
updateQueuePosition()
}
private fun updateQueuePosition() {
playingQueueAdapter?.setCurrent(MusicPlayerRemote.position)
resetToCurrentPosition()
playerQueueSubHeader.text = getUpNextAndQueueTime()
}
private fun updateQueuePosition() {
playingQueueAdapter?.setCurrent(MusicPlayerRemote.position)
resetToCurrentPosition()
playerQueueSubHeader.text = getUpNextAndQueueTime()
}
private fun updateQueue() {
playingQueueAdapter?.swapDataSet(MusicPlayerRemote.playingQueue, MusicPlayerRemote.position)
resetToCurrentPosition()
}
private fun updateQueue() {
playingQueueAdapter?.swapDataSet(MusicPlayerRemote.playingQueue, MusicPlayerRemote.position)
resetToCurrentPosition()
}
private fun resetToCurrentPosition() {
recyclerView.stopScroll()
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}
private fun resetToCurrentPosition() {
recyclerView.stopScroll()
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}
override fun onPause() {
if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.cancelDrag()
}
super.onPause()
}
override fun onPause() {
if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.cancelDrag()
}
super.onPause()
}
override fun onDestroy() {
if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.release()
recyclerViewDragDropManager = null
}
override fun onDestroy() {
if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.release()
recyclerViewDragDropManager = null
}
if (wrappedAdapter != null) {
WrapperAdapterUtils.releaseAll(wrappedAdapter)
wrappedAdapter = null
}
playingQueueAdapter = null
super.onDestroy()
}
if (wrappedAdapter != null) {
WrapperAdapterUtils.releaseAll(wrappedAdapter)
wrappedAdapter = null
}
playingQueueAdapter = null
super.onDestroy()
}
private fun setupToolbar() {
playerQueueSubHeader.text = getUpNextAndQueueTime()
playerQueueSubHeader.setTextColor(ThemeStore.accentColor(this))
private fun setupToolbar() {
playerQueueSubHeader.text = getUpNextAndQueueTime()
playerQueueSubHeader.setTextColor(ThemeStore.accentColor(this))
applyToolbar(toolbar)
appBarLayout.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
applyToolbar(toolbar)
appBarLayout.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
clearQueue.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
ColorStateList.valueOf(MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(ThemeStore.accentColor(this)))).apply {
clearQueue.setTextColor(this)
clearQueue.iconTint = this
}
}
clearQueue.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
ColorStateList.valueOf(
MaterialValueHelper.getPrimaryTextColor(
this,
ColorUtil.isColorLight(
ThemeStore.accentColor(
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.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
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 android.view.*
import androidx.recyclerview.widget.*
import code.name.monkey.appthemehelper.util.*
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter
import code.name.monkey.retromusic.adapter.song.PlaylistSongAdapter
import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.adapter.song.*
import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.loaders.PlaylistLoader
import code.name.monkey.retromusic.model.AbsCustomPlaylist
import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsPresenter
import code.name.monkey.retromusic.mvp.presenter.PlaylistSongsView
import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.PlaylistsUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.mvp.presenter.*
import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.ViewUtil
import com.afollestad.materialcab.MaterialCab
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 javax.inject.Inject
class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, PlaylistSongsView {
@Inject
lateinit var playlistSongsPresenter: PlaylistSongsPresenter
@Inject
lateinit var playlistSongsPresenter: PlaylistSongsPresenter
private lateinit var playlist: Playlist
private var cab: MaterialCab? = null
private lateinit var adapter: SongAdapter
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
private lateinit var playlist: Playlist
private var cab: MaterialCab? = null
private lateinit var adapter: SongAdapter
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
App.musicComponent.inject(this)
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
App.musicComponent.inject(this)
playlistSongsPresenter.attachView(this)
playlistSongsPresenter.attachView(this)
setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setLightStatusbar(ColorUtil.isColorLight(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
toggleBottomNavigationView(true)
toggleBottomNavigationView(true)
if (intent.extras != null) {
playlist = intent.extras!!.getParcelable(EXTRA_PLAYLIST)!!
} else {
finish()
}
if (intent.extras != null) {
playlist = intent.extras!!.getParcelable(EXTRA_PLAYLIST)!!
} else {
finish()
}
setUpToolBar()
setUpRecyclerView()
}
setUpToolBar()
setUpRecyclerView()
}
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_playlist_detail)
}
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_playlist_detail)
}
private fun setUpRecyclerView() {
ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
if (playlist is AbsCustomPlaylist) {
adapter = PlaylistSongAdapter(this, ArrayList(), R.layout.item_list, false, this)
recyclerView.adapter = adapter
} else {
recyclerViewDragDropManager = RecyclerViewDragDropManager()
val animator = RefactoredDefaultItemAnimator()
adapter = OrderablePlaylistSongAdapter(this, ArrayList(), R.layout.item_list, false, this,
object : OrderablePlaylistSongAdapter.OnMoveItemListener {
override fun onMoveItem(fromPosition: Int, toPosition: Int) {
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)
private fun setUpRecyclerView() {
ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
if (playlist is AbsCustomPlaylist) {
adapter = PlaylistSongAdapter(this, ArrayList(), R.layout.item_list, false, this)
recyclerView.adapter = adapter
} else {
recyclerViewDragDropManager = RecyclerViewDragDropManager()
val animator = RefactoredDefaultItemAnimator()
adapter = OrderablePlaylistSongAdapter(this,
ArrayList(),
R.layout.item_list,
false,
this,
object : OrderablePlaylistSongAdapter.OnMoveItemListener {
override fun onMoveItem(
fromPosition: Int,
toPosition: Int
) {
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.itemAnimator = animator
recyclerView.adapter = wrappedAdapter
recyclerView.itemAnimator = animator
recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
}
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
checkIsEmpty()
}
})
}
recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
}
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
checkIsEmpty()
}
})
}
override fun onResume() {
super.onResume()
playlistSongsPresenter.loadPlaylistSongs(playlist)
}
override fun onResume() {
super.onResume()
playlistSongsPresenter.loadPlaylistSongs(playlist)
}
private fun setUpToolBar() {
applyToolbar(toolbar)
title = playlist.name
}
private fun setUpToolBar() {
applyToolbar(toolbar)
title = playlist.name
}
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)
return super.onCreateOptionsMenu(menu)
}
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
)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
onBackPressed()
return true
}
}
return PlaylistMenuHelper.handleMenuClick(this, playlist, item)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
onBackPressed()
return true
}
}
return PlaylistMenuHelper.handleMenuClick(this, playlist, item)
}
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
if (cab != null && cab!!.isActive) {
cab!!.finish()
}
cab = MaterialCab(this, R.id.cab_stub)
.setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close_white_24dp)
.setBackgroundColor(
RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.resolveColor(this, R.attr.colorPrimary)))
.start(callback)
return cab!!
}
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
if (cab != null && cab!!.isActive) {
cab!!.finish()
}
cab = MaterialCab(this, R.id.cab_stub).setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close_white_24dp).setBackgroundColor(
RetroColorUtil.shiftBackgroundColorForLightText(
ATHUtil.resolveColor(
this,
R.attr.colorPrimary
)
)
).start(callback)
return cab!!
}
override fun onBackPressed() {
if (cab != null && cab!!.isActive) {
cab!!.finish()
} else {
recyclerView!!.stopScroll()
super.onBackPressed()
}
}
override fun onBackPressed() {
if (cab != null && cab!!.isActive) {
cab!!.finish()
} else {
recyclerView!!.stopScroll()
super.onBackPressed()
}
}
override fun onMediaStoreChanged() {
super.onMediaStoreChanged()
if (playlist !is AbsCustomPlaylist) {
// Playlist deleted
if (!PlaylistsUtil.doesPlaylistExist(this, playlist.id)) {
finish()
return
}
// Playlist renamed
val playlistName = PlaylistsUtil.getNameForPlaylist(this, playlist.id.toLong())
if (playlistName != playlist.name) {
playlist = PlaylistLoader.getPlaylist(this, playlist.id)
setToolbarTitle(playlist.name)
}
}
playlistSongsPresenter.loadPlaylistSongs(playlist)
}
override fun onMediaStoreChanged() {
super.onMediaStoreChanged()
if (playlist !is AbsCustomPlaylist) {
// Playlist deleted
if (!PlaylistsUtil.doesPlaylistExist(this, playlist.id)) {
finish()
return
}
// Playlist renamed
val playlistName = PlaylistsUtil.getNameForPlaylist(this, playlist.id.toLong())
if (playlistName != playlist.name) {
playlist = PlaylistLoader.getPlaylist(this, playlist.id)
setToolbarTitle(playlist.name)
}
}
playlistSongsPresenter.loadPlaylistSongs(playlist)
}
private fun setToolbarTitle(title: String) {
supportActionBar!!.title = title
}
private fun setToolbarTitle(title: String) {
supportActionBar!!.title = title
}
private fun checkForPadding() {
val height = DensityUtil.dip2px(this, 52f)
recyclerView.setPadding(0, 0, 0, (height))
}
private fun checkForPadding() {
val height = DensityUtil.dip2px(this, 52f)
recyclerView.setPadding(0, 0, 0, (height))
}
private fun checkIsEmpty() {
checkForPadding()
empty.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
emptyText.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
}
private fun checkIsEmpty() {
checkForPadding()
empty.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
emptyText.visibility = if (adapter.itemCount == 0) View.VISIBLE else View.GONE
}
public override fun onPause() {
if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.cancelDrag()
}
super.onPause()
}
public override fun onPause() {
if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.cancelDrag()
}
super.onPause()
}
override fun onDestroy() {
if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.release()
recyclerViewDragDropManager = null
}
override fun onDestroy() {
if (recyclerViewDragDropManager != null) {
recyclerViewDragDropManager!!.release()
recyclerViewDragDropManager = null
}
if (recyclerView != null) {
recyclerView!!.itemAnimator = null
recyclerView!!.adapter = null
}
if (recyclerView != null) {
recyclerView!!.itemAnimator = null
recyclerView!!.adapter = null
}
if (wrappedAdapter != null) {
WrapperAdapterUtils.releaseAll(wrappedAdapter)
wrappedAdapter = null
}
super.onDestroy()
playlistSongsPresenter.detachView()
}
if (wrappedAdapter != null) {
WrapperAdapterUtils.releaseAll(wrappedAdapter)
wrappedAdapter = null
}
super.onDestroy()
playlistSongsPresenter.detachView()
}
override fun showEmptyView() {
empty.visibility = View.VISIBLE
emptyText.visibility = View.VISIBLE
}
override fun showEmptyView() {
empty.visibility = View.VISIBLE
emptyText.visibility = View.VISIBLE
}
override fun songs(songs: ArrayList<Song>) {
adapter.swapDataSet(songs)
}
override fun songs(songs: ArrayList<Song>) {
adapter.swapDataSet(songs)
}
companion object {
var EXTRA_PLAYLIST = "extra_playlist"
}
companion object {
var EXTRA_PLAYLIST = "extra_playlist"
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,134 +5,139 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.media.AudioManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.*
import android.provider.Settings
import android.view.KeyEvent
import android.view.View
import android.view.*
import androidx.core.app.ActivityCompat
import code.name.monkey.appthemehelper.ThemeStore
import com.google.android.material.snackbar.Snackbar
abstract class AbsBaseActivity : AbsThemeActivity() {
private var hadPermissions: Boolean = false
private lateinit var permissions: Array<String>
private var permissionDeniedMessage: String? = null
private var hadPermissions: Boolean = false
private lateinit var permissions: Array<String>
private var permissionDeniedMessage: String? = null
open fun getPermissionsToRequest(): Array<String> {
return arrayOf()
}
open fun getPermissionsToRequest(): Array<String> {
return arrayOf()
}
protected fun setPermissionDeniedMessage(message: String) {
permissionDeniedMessage = message
}
protected fun setPermissionDeniedMessage(message: String) {
permissionDeniedMessage = message
}
fun getPermissionDeniedMessage(): String {
return if (permissionDeniedMessage == null) getString(code.name.monkey.retromusic.R.string.permissions_denied) else permissionDeniedMessage!!
}
fun getPermissionDeniedMessage(): String {
return if (permissionDeniedMessage == null) getString(code.name.monkey.retromusic.R.string.permissions_denied) else permissionDeniedMessage!!
}
private val snackBarContainer: View
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
get() = window.decorView
override fun onPostCreate(savedInstanceState: Bundle?) {
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?) {
super.onCreate(savedInstanceState)
volumeControlStream = AudioManager.STREAM_MUSIC
permissions = getPermissionsToRequest()
hadPermissions = hasPermissions()
permissionDeniedMessage = null
}
protected open fun onHasPermissionsChanged(hasPermissions: Boolean) {
// implemented by sub classes
}
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
if (!hasPermissions()) {
requestPermissions()
}
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (event.keyCode == KeyEvent.KEYCODE_MENU && event.action == KeyEvent.ACTION_UP) {
showOverflowMenu()
return true
}
return super.dispatchKeyEvent(event)
}
override fun onResume() {
super.onResume()
val hasPermissions = hasPermissions()
if (hasPermissions != hadPermissions) {
hadPermissions = hasPermissions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
onHasPermissionsChanged(hasPermissions)
}
}
}
protected fun showOverflowMenu() {
protected open fun onHasPermissionsChanged(hasPermissions: Boolean) {
// implemented by sub classes
}
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (event.keyCode == KeyEvent.KEYCODE_MENU && event.action == KeyEvent.ACTION_UP) {
showOverflowMenu()
return true
}
return super.dispatchKeyEvent(event)
}
protected open fun requestPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permissions, PERMISSION_REQUEST)
}
}
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() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
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
}
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.content.*
import android.os.Bundle
import android.os.IBinder
import android.os.*
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote
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.util.*
abstract class AbsMusicServiceActivity : AbsBaseActivity(), MusicServiceEventListener {
private val mMusicServiceEventListeners = ArrayList<MusicServiceEventListener>()
private val mMusicServiceEventListeners = ArrayList<MusicServiceEventListener>()
private var serviceToken: MusicPlayerRemote.ServiceToken? = null
private var musicStateReceiver: MusicStateReceiver? = null
private var receiverRegistered: Boolean = false
private var serviceToken: MusicPlayerRemote.ServiceToken? = null
private var musicStateReceiver: MusicStateReceiver? = null
private var receiverRegistered: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
serviceToken = MusicPlayerRemote.bindToService(this, object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
this@AbsMusicServiceActivity.onServiceConnected()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
serviceToken = MusicPlayerRemote.bindToService(this, object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
this@AbsMusicServiceActivity.onServiceConnected()
}
override fun onServiceDisconnected(name: ComponentName) {
this@AbsMusicServiceActivity.onServiceDisconnected()
}
})
override fun onServiceDisconnected(name: ComponentName) {
this@AbsMusicServiceActivity.onServiceDisconnected()
}
})
setPermissionDeniedMessage(getString(R.string.permission_external_storage_denied));
}
setPermissionDeniedMessage(getString(R.string.permission_external_storage_denied));
}
override fun onDestroy() {
super.onDestroy()
MusicPlayerRemote.unbindFromService(serviceToken)
if (receiverRegistered) {
unregisterReceiver(musicStateReceiver)
receiverRegistered = false
}
}
override fun onDestroy() {
super.onDestroy()
MusicPlayerRemote.unbindFromService(serviceToken)
if (receiverRegistered) {
unregisterReceiver(musicStateReceiver)
receiverRegistered = false
}
}
fun addMusicServiceEventListener(listener: MusicServiceEventListener?) {
if (listener != null) {
mMusicServiceEventListeners.add(listener)
}
}
fun addMusicServiceEventListener(listener: MusicServiceEventListener?) {
if (listener != null) {
mMusicServiceEventListeners.add(listener)
}
}
fun removeMusicServiceEventListener(listener: MusicServiceEventListener?) {
if (listener != null) {
mMusicServiceEventListeners.remove(listener)
}
}
fun removeMusicServiceEventListener(listener: MusicServiceEventListener?) {
if (listener != null) {
mMusicServiceEventListeners.remove(listener)
}
}
override fun onServiceConnected() {
if (!receiverRegistered) {
musicStateReceiver = MusicStateReceiver(this)
override fun onServiceConnected() {
if (!receiverRegistered) {
musicStateReceiver = MusicStateReceiver(this)
val filter = IntentFilter()
filter.addAction(PLAY_STATE_CHANGED)
filter.addAction(SHUFFLE_MODE_CHANGED)
filter.addAction(REPEAT_MODE_CHANGED)
filter.addAction(META_CHANGED)
filter.addAction(QUEUE_CHANGED)
filter.addAction(MEDIA_STORE_CHANGED)
filter.addAction(FAVORITE_STATE_CHANGED)
val filter = IntentFilter()
filter.addAction(PLAY_STATE_CHANGED)
filter.addAction(SHUFFLE_MODE_CHANGED)
filter.addAction(REPEAT_MODE_CHANGED)
filter.addAction(META_CHANGED)
filter.addAction(QUEUE_CHANGED)
filter.addAction(MEDIA_STORE_CHANGED)
filter.addAction(FAVORITE_STATE_CHANGED)
registerReceiver(musicStateReceiver, filter)
registerReceiver(musicStateReceiver, filter)
receiverRegistered = true
}
receiverRegistered = true
}
for (listener in mMusicServiceEventListeners) {
listener.onServiceConnected()
}
}
for (listener in mMusicServiceEventListeners) {
listener.onServiceConnected()
}
}
override fun onServiceDisconnected() {
if (receiverRegistered) {
unregisterReceiver(musicStateReceiver)
receiverRegistered = false
}
override fun onServiceDisconnected() {
if (receiverRegistered) {
unregisterReceiver(musicStateReceiver)
receiverRegistered = false
}
for (listener in mMusicServiceEventListeners) {
listener.onServiceDisconnected()
}
}
for (listener in mMusicServiceEventListeners) {
listener.onServiceDisconnected()
}
}
override fun onPlayingMetaChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onPlayingMetaChanged()
}
}
override fun onPlayingMetaChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onPlayingMetaChanged()
}
}
override fun onQueueChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onQueueChanged()
}
}
override fun onQueueChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onQueueChanged()
}
}
override fun onPlayStateChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onPlayStateChanged()
}
}
override fun onPlayStateChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onPlayStateChanged()
}
}
override fun onMediaStoreChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onMediaStoreChanged()
}
}
override fun onMediaStoreChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onMediaStoreChanged()
}
}
override fun onRepeatModeChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onRepeatModeChanged()
}
}
override fun onRepeatModeChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onRepeatModeChanged()
}
}
override fun onShuffleModeChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onShuffleModeChanged()
}
}
override fun onShuffleModeChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onShuffleModeChanged()
}
}
override fun onHasPermissionsChanged(hasPermissions: Boolean) {
super.onHasPermissionsChanged(hasPermissions)
val intent = Intent(MEDIA_STORE_CHANGED)
intent.putExtra("from_permissions_changed", true) // just in case we need to know this at some point
sendBroadcast(intent)
}
override fun onHasPermissionsChanged(hasPermissions: Boolean) {
super.onHasPermissionsChanged(hasPermissions)
val intent = Intent(MEDIA_STORE_CHANGED)
intent.putExtra(
"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> {
return arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
private class MusicStateReceiver(activity: AbsMusicServiceActivity) : BroadcastReceiver() {
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) {
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()
}
}
}
}
companion object {
val TAG: String = AbsMusicServiceActivity::class.java.simpleName
}
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.annotation.SuppressLint
import android.graphics.Color
import android.graphics.Rect
import android.graphics.*
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.*
import androidx.annotation.LayoutRes
import androidx.fragment.app.Fragment
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.*
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.MiniPlayerFragment
import code.name.monkey.retromusic.fragments.NowPlayingScreen
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.*
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
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.tiny.TinyPlayerFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.views.BottomNavigationBarTinted
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.card.MaterialCardView
import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), AbsPlayerFragment.Callbacks {
companion object {
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
}
companion object {
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
}
private lateinit var bottomSheetBehavior: BottomSheetBehavior<MaterialCardView>
private var miniPlayerFragment: MiniPlayerFragment? = null
private var playerFragment: AbsPlayerFragment? = null
private var currentNowPlayingScreen: NowPlayingScreen? = null
private var navigationBarColor: Int = 0
private var taskColor: Int = 0
private var lightStatusBar: Boolean = false
private var lightNavigationBar: Boolean = false
private var navigationBarColorAnimator: ValueAnimator? = null
protected abstract fun createContentView(): View
private val panelState: Int
get() = bottomSheetBehavior.state
private lateinit var bottomSheetBehavior: BottomSheetBehavior<MaterialCardView>
private var miniPlayerFragment: MiniPlayerFragment? = null
private var playerFragment: AbsPlayerFragment? = null
private var currentNowPlayingScreen: NowPlayingScreen? = null
private var navigationBarColor: Int = 0
private var taskColor: Int = 0
private var lightStatusBar: Boolean = false
private var lightNavigationBar: Boolean = false
private var navigationBarColorAnimator: ValueAnimator? = null
protected abstract fun createContentView(): View
private val panelState: Int
get() = bottomSheetBehavior.state
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
setMiniPlayerAlphaProgress(slideOffset)
dimBackground.show()
dimBackground.alpha = slideOffset
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
setMiniPlayerAlphaProgress(slideOffset)
dimBackground.show()
dimBackground.alpha = slideOffset
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
BottomSheetBehavior.STATE_EXPANDED -> {
onPanelExpanded()
}
BottomSheetBehavior.STATE_COLLAPSED -> {
onPanelCollapsed()
dimBackground.hide()
}
else -> {
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
BottomSheetBehavior.STATE_EXPANDED -> {
onPanelExpanded()
}
BottomSheetBehavior.STATE_COLLAPSED -> {
onPanelCollapsed()
dimBackground.hide()
}
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?) {
super.onCreate(savedInstanceState)
setContentView(createContentView())
playerFragment?.setMenuVisibility(false)
playerFragment?.userVisibleHint = false
playerFragment?.onHide()
}
chooseFragmentForTheme()
setupSlidingUpPanel()
open fun onPanelExpanded() {
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)
dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
}
fun toggleBottomNavigationView(toggle: Boolean) {
bottomNavigationView.visibility = if (toggle) View.GONE else View.VISIBLE
}
override fun onResume() {
super.onResume()
if (currentNowPlayingScreen != PreferenceUtil.getInstance(this).nowPlayingScreen) {
postRecreate()
}
bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
fun getBottomNavigationView(): BottomNavigationBarTinted {
return bottomNavigationView
}
if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) {
setMiniPlayerAlphaProgress(1f)
}
}
private fun hideBottomBar(hide: Boolean) {
val heightOfBar = resources.getDimensionPixelSize(R.dimen.mini_player_height)
val heightOfBarWithTabs = resources.getDimensionPixelSize(R.dimen.mini_player_height_expanded)
override fun onDestroy() {
super.onDestroy()
bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList)
if (navigationBarColorAnimator != null) navigationBarColorAnimator!!.cancel() // just in case
}
if (hide) {
bottomSheetBehavior.isHideable = true
bottomSheetBehavior.peekHeight = 0
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 {
@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 chooseFragmentForTheme() {
currentNowPlayingScreen = PreferenceUtil.getInstance(this).nowPlayingScreen
private fun collapsePanel() {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
val fragment: Fragment = when (currentNowPlayingScreen) {
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() {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
setMiniPlayerAlphaProgress(1f)
}
playerFragment = supportFragmentManager.findFragmentById(R.id.playerFragmentContainer) as AbsPlayerFragment
miniPlayerFragment = supportFragmentManager.findFragmentById(R.id.miniPlayerFragment) as MiniPlayerFragment
miniPlayerFragment?.view?.setOnClickListener { expandPanel() }
}
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
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
}
bottomNavigationView.translationY = progress * 500
bottomNavigationView.alpha = alpha
}
override fun onQueueChanged() {
super.onQueueChanged()
hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
}
open fun onPanelCollapsed() {
// restore values
super.setLightStatusbar(lightStatusBar)
super.setTaskDescriptionColor(taskColor)
super.setNavigationbarColor(navigationBarColor)
super.setLightNavigationBar(lightNavigationBar)
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
}
playerFragment?.setMenuVisibility(false)
playerFragment?.userVisibleHint = false
playerFragment?.onHide()
}
override fun onPaletteColorChanged() {
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
val paletteColor = playerFragment!!.paletteColor
super.setTaskDescriptionColor(paletteColor)
open fun onPanelExpanded() {
val playerFragmentColor = playerFragment!!.paletteColor
super.setTaskDescriptionColor(playerFragmentColor)
val isColorLight = ColorUtil.isColorLight(paletteColor)
playerFragment?.setMenuVisibility(true)
playerFragment?.userVisibleHint = true
playerFragment?.onShow()
onPaletteColorChanged()
}
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)
}
}
}
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()
}
}
})
}
override fun setLightStatusbar(enabled: Boolean) {
lightStatusBar = enabled
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
super.setLightStatusbar(enabled)
}
}
fun toggleBottomNavigationView(toggle: Boolean) {
bottomNavigationView.visibility = if (toggle) View.GONE else View.VISIBLE
}
override fun setLightNavigationBar(enabled: Boolean) {
lightNavigationBar = enabled
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
super.setLightNavigationBar(enabled)
}
}
fun getBottomNavigationView(): BottomNavigationBarTinted {
return bottomNavigationView
}
override fun setNavigationbarColor(color: Int) {
navigationBarColor = color
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
if (navigationBarColorAnimator != null) navigationBarColorAnimator!!.cancel()
super.setNavigationbarColor(color)
}
}
private fun hideBottomBar(hide: Boolean) {
val heightOfBar = resources.getDimensionPixelSize(R.dimen.mini_player_height)
val heightOfBarWithTabs = resources.getDimensionPixelSize(R.dimen.mini_player_height_expanded)
override fun setTaskDescriptionColor(color: Int) {
taskColor = color
if (panelState == BottomSheetBehavior.STATE_COLLAPSED) {
super.setTaskDescriptionColor(color)
}
}
if (hide) {
bottomSheetBehavior.isHideable = true
bottomSheetBehavior.peekHeight = 0
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
}
}
}
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)
}
}
}
fun setBottomBarVisibility(gone: Int) {
bottomNavigationView.visibility = gone
hideBottomBar(false)
}
private fun chooseFragmentForTheme() {
currentNowPlayingScreen = PreferenceUtil.getInstance(this).nowPlayingScreen
val fragment: Fragment = when (currentNowPlayingScreen) {
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()
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)
}
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.drawable.Drawable
import android.os.Bundle
import android.os.Handler
import android.view.KeyEvent
import android.view.View
import android.view.WindowManager
import android.os.*
import android.view.*
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import code.name.monkey.appthemehelper.ATH
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.*
import code.name.monkey.appthemehelper.common.ATHToolbarActivity
import code.name.monkey.appthemehelper.util.ATHUtil
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.appthemehelper.util.*
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.ThemeManager
import code.name.monkey.retromusic.util.*
abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
private val handler = Handler()
private val handler = Handler()
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(ThemeManager.getThemeResValue(this))
hideStatusBar()
super.onCreate(savedInstanceState)
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(ThemeManager.getThemeResValue(this))
hideStatusBar()
super.onCreate(savedInstanceState)
changeBackgroundShape()
setImmersiveFullscreen()
registerSystemUiVisibility()
toggleScreenOn()
}
changeBackgroundShape()
setImmersiveFullscreen()
registerSystemUiVisibility()
toggleScreenOn()
}
private fun toggleScreenOn() {
if (PreferenceUtil.getInstance(this).isScreenOnEnabled) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
private fun toggleScreenOn() {
if (PreferenceUtil.getInstance(this).isScreenOnEnabled) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
hideStatusBar()
handler.removeCallbacks(this)
handler.postDelayed(this, 300)
} else {
handler.removeCallbacks(this)
}
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
hideStatusBar()
handler.removeCallbacks(this)
handler.postDelayed(this, 300)
} else {
handler.removeCallbacks(this)
}
}
fun hideStatusBar() {
hideStatusBar(PreferenceUtil.getInstance(this).fullScreenMode)
}
fun hideStatusBar() {
hideStatusBar(PreferenceUtil.getInstance(this).fullScreenMode)
}
private fun hideStatusBar(fullscreen: Boolean) {
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
if (statusBar != null) {
statusBar.visibility = if (fullscreen) View.GONE else View.VISIBLE
}
}
private fun hideStatusBar(fullscreen: Boolean) {
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
if (statusBar != null) {
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() {
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)
}
fun setDrawUnderStatusBar() {
RetroUtil.setAllowDrawUnderStatusBar(window)
}
fun setDrawUnderStatusBar() {
RetroUtil.setAllowDrawUnderStatusBar(window)
}
fun setDrawUnderNavigationBar() {
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)
}
/**
* 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() {
// we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat
setStatusbarColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
}
fun setStatusbarColorAuto() {
// we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat
setStatusbarColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
}
open fun setTaskDescriptionColor(@ColorInt color: Int) {
ATH.setTaskDescriptionColor(this, color)
}
open fun setTaskDescriptionColor(@ColorInt color: Int) {
ATH.setTaskDescriptionColor(this, color)
}
fun setTaskDescriptionColorAuto() {
setTaskDescriptionColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
}
fun setTaskDescriptionColorAuto() {
setTaskDescriptionColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
}
open fun setNavigationbarColor(color: Int) {
if (ThemeStore.coloredNavigationBar(this)) {
ATH.setNavigationbarColor(this, color)
} else {
ATH.setNavigationbarColor(this, Color.BLACK)
}
}
open fun setNavigationbarColor(color: Int) {
if (ThemeStore.coloredNavigationBar(this)) {
ATH.setNavigationbarColor(this, color)
} else {
ATH.setNavigationbarColor(this, Color.BLACK)
}
}
open fun setNavigationBarColorPrimary() {
ATH.setNavigationbarColor(this, ATHUtil.resolveColor(this, R.attr.colorPrimary))
}
open fun setNavigationBarColorPrimary() {
ATH.setNavigationbarColor(this, ATHUtil.resolveColor(this, R.attr.colorPrimary))
}
fun setNavigationbarColorAuto() {
setNavigationbarColor(ATHUtil.resolveColor(this, R.attr.colorSecondary))
}
fun setNavigationbarColorAuto() {
setNavigationbarColor(ATHUtil.resolveColor(this, R.attr.colorSecondary))
}
open fun setLightStatusbar(enabled: Boolean) {
ATH.setLightStatusbar(this, enabled)
}
open fun setLightStatusbar(enabled: Boolean) {
ATH.setLightStatusbar(this, enabled)
}
fun setLightStatusbarAuto(bgColor: Int) {
setLightStatusbar(ColorUtil.isColorLight(bgColor))
}
fun setLightStatusbarAuto(bgColor: Int) {
setLightStatusbar(ColorUtil.isColorLight(bgColor))
}
open fun setLightNavigationBar(enabled: Boolean) {
if (!ATHUtil.isWindowBackgroundDark(this) and ThemeStore.coloredNavigationBar(this)) {
ATH.setLightNavigationbar(this, enabled)
}
}
open fun setLightNavigationBar(enabled: Boolean) {
if (!ATHUtil.isWindowBackgroundDark(this) and ThemeStore.coloredNavigationBar(this)) {
ATH.setLightNavigationbar(this, enabled)
}
}
private fun registerSystemUiVisibility() {
val decorView = window.decorView
decorView.setOnSystemUiVisibilityChangeListener { visibility ->
if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
setImmersiveFullscreen()
}
}
}
private fun registerSystemUiVisibility() {
val decorView = window.decorView
decorView.setOnSystemUiVisibilityChangeListener { visibility ->
if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
setImmersiveFullscreen()
}
}
}
private fun unregisterSystemUiVisibility() {
val decorView = window.decorView
decorView.setOnSystemUiVisibilityChangeListener(null)
}
private fun unregisterSystemUiVisibility() {
val decorView = window.decorView
decorView.setOnSystemUiVisibilityChangeListener(null)
}
private fun setImmersiveFullscreen() {
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)
private fun setImmersiveFullscreen() {
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)
if (PreferenceUtil.getInstance(this).fullScreenMode) {
window.decorView.systemUiVisibility = flags
}
}
if (PreferenceUtil.getInstance(this).fullScreenMode) {
window.decorView.systemUiVisibility = flags
}
}
private fun exitFullscreen() {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
}
private fun exitFullscreen() {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
}
override fun run() {
setImmersiveFullscreen()
}
override fun run() {
setImmersiveFullscreen()
}
override fun onStop() {
handler.removeCallbacks(this)
super.onStop()
}
override fun onStop() {
handler.removeCallbacks(this)
super.onStop()
}
public override fun onDestroy() {
super.onDestroy()
unregisterSystemUiVisibility()
exitFullscreen()
}
public override fun onDestroy() {
super.onDestroy()
unregisterSystemUiVisibility()
exitFullscreen()
}
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)
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
import android.app.Activity
import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.app.*
import android.content.*
import android.net.Uri
import android.os.Bundle
import android.text.TextUtils
import android.view.MenuItem
import android.view.inputmethod.EditorInfo
import android.widget.Toast
import androidx.annotation.StringDef
import androidx.annotation.StringRes
import androidx.annotation.*
import androidx.appcompat.app.AlertDialog
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil
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.appthemehelper.util.*
import code.name.monkey.retromusic.R
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.Report
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.activities.bugreport.model.*
import code.name.monkey.retromusic.activities.bugreport.model.github.*
import code.name.monkey.retromusic.misc.DialogAsyncTask
import com.afollestad.materialdialogs.MaterialDialog
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_report.*
import org.eclipse.egit.github.core.Issue
import org.eclipse.egit.github.core.client.GitHubClient
import org.eclipse.egit.github.core.client.RequestException
import org.eclipse.egit.github.core.client.*
import org.eclipse.egit.github.core.service.IssueService
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_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)
private annotation class Result
open class BugReportActivity : AbsThemeActivity() {
private var deviceInfo: DeviceInfo? = null
private var deviceInfo: DeviceInfo? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bug_report)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bug_report)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setStatusbarColorAuto()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
initViews()
initViews()
if (TextUtils.isEmpty(title))
setTitle(R.string.report_an_issue)
if (TextUtils.isEmpty(title)) setTitle(R.string.report_an_issue)
deviceInfo = DeviceInfo(this)
airTextDeviceInfo.text = deviceInfo.toString()
}
deviceInfo = DeviceInfo(this)
airTextDeviceInfo.text = deviceInfo.toString()
}
private fun initViews() {
val accentColor = ThemeStore.accentColor(this)
val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary)
toolbar.setBackgroundColor(primaryColor)
setSupportActionBar(toolbar)
ToolbarContentTintHelper.colorBackButton(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
TintHelper.setTintAuto(optionUseAccount, accentColor, false)
optionUseAccount?.setOnClickListener {
inputTitle.isEnabled = true
inputDescription.isEnabled = true
inputUsername.isEnabled = true
inputPassword.isEnabled = true
private fun initViews() {
val accentColor = ThemeStore.accentColor(this)
val primaryColor = ATHUtil.resolveColor(this, R.attr.colorPrimary)
toolbar.setBackgroundColor(primaryColor)
setSupportActionBar(toolbar)
ToolbarContentTintHelper.colorBackButton(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
TintHelper.setTintAuto(optionUseAccount, accentColor, false)
optionUseAccount?.setOnClickListener {
inputTitle.isEnabled = true
inputDescription.isEnabled = true
inputUsername.isEnabled = true
inputPassword.isEnabled = true
optionAnonymous.isChecked = false
sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab)
sendFab.setImageResource(R.drawable.ic_send_white_24dp)
sendFab.show()
}
})
}
TintHelper.setTintAuto(optionAnonymous, accentColor, false)
optionAnonymous.setOnClickListener {
inputTitle.isEnabled = false
inputDescription.isEnabled = false
inputUsername.isEnabled = false
inputPassword.isEnabled = false
optionAnonymous.isChecked = false
sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab)
sendFab.setImageResource(R.drawable.ic_send_white_24dp)
sendFab.show()
}
})
}
TintHelper.setTintAuto(optionAnonymous, accentColor, false)
optionAnonymous.setOnClickListener {
inputTitle.isEnabled = false
inputDescription.isEnabled = false
inputUsername.isEnabled = false
inputPassword.isEnabled = false
optionUseAccount.isChecked = false
sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab)
sendFab.setImageResource(R.drawable.ic_open_in_browser_white_24dp)
sendFab.show()
}
})
}
optionUseAccount.isChecked = false
sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab)
sendFab.setImageResource(R.drawable.ic_open_in_browser_white_24dp)
sendFab.show()
}
})
}
inputPassword.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEND) {
reportIssue()
return@setOnEditorActionListener true
}
false
}
inputPassword.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEND) {
reportIssue()
return@setOnEditorActionListener true
}
false
}
airTextDeviceInfo.setOnClickListener { copyDeviceInfoToClipBoard() }
airTextDeviceInfo.setOnClickListener { copyDeviceInfoToClipBoard() }
TintHelper.setTintAuto(sendFab, accentColor, true)
sendFab.setOnClickListener { reportIssue() }
TintHelper.setTintAuto(sendFab, accentColor, true)
sendFab.setOnClickListener { reportIssue() }
MaterialUtil.setTint(inputLayoutTitle, false)
MaterialUtil.setTint(inputLayoutDescription, false)
MaterialUtil.setTint(inputLayoutUsername, false)
MaterialUtil.setTint(inputLayoutPassword, false)
}
MaterialUtil.setTint(inputLayoutTitle, false)
MaterialUtil.setTint(inputLayoutDescription, false)
MaterialUtil.setTint(inputLayoutUsername, false)
MaterialUtil.setTint(inputLayoutPassword, false)
}
private fun reportIssue() {
if (optionUseAccount.isChecked) {
if (!validateInput()) return
val username = inputUsername.text.toString()
val password = inputPassword.text.toString()
sendBugReport(GithubLogin(username, password))
} else {
copyDeviceInfoToClipBoard()
private fun reportIssue() {
if (optionUseAccount.isChecked) {
if (!validateInput()) return
val username = inputUsername.text.toString()
val password = inputPassword.text.toString()
sendBugReport(GithubLogin(username, password))
} else {
copyDeviceInfoToClipBoard()
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(ISSUE_TRACKER_LINK)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(i)
}
}
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(ISSUE_TRACKER_LINK)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(i)
}
}
private fun copyDeviceInfoToClipBoard() {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.device_info), deviceInfo?.toMarkdown())
clipboard.primaryClip = clip
Toast.makeText(this@BugReportActivity, R.string.copied_device_info_to_clipboard, Toast.LENGTH_LONG).show()
}
private fun copyDeviceInfoToClipBoard() {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.device_info), deviceInfo?.toMarkdown())
clipboard.primaryClip = clip
Toast.makeText(
this@BugReportActivity,
R.string.copied_device_info_to_clipboard,
Toast.LENGTH_LONG
).show()
}
private fun validateInput(): Boolean {
var hasErrors = false
private fun validateInput(): Boolean {
var hasErrors = false
if (optionUseAccount.isChecked) {
if (TextUtils.isEmpty(inputUsername.text)) {
setError(inputLayoutUsername, R.string.bug_report_no_username)
hasErrors = true
} else {
removeError(inputLayoutUsername)
}
if (optionUseAccount.isChecked) {
if (TextUtils.isEmpty(inputUsername.text)) {
setError(inputLayoutUsername, R.string.bug_report_no_username)
hasErrors = true
} else {
removeError(inputLayoutUsername)
}
if (TextUtils.isEmpty(inputPassword.text)) {
setError(inputLayoutPassword, R.string.bug_report_no_password)
hasErrors = true
} else {
removeError(inputLayoutPassword)
}
}
if (TextUtils.isEmpty(inputPassword.text)) {
setError(inputLayoutPassword, R.string.bug_report_no_password)
hasErrors = true
} else {
removeError(inputLayoutPassword)
}
}
if (TextUtils.isEmpty(inputTitle.text)) {
setError(inputLayoutTitle, R.string.bug_report_no_title)
hasErrors = true
} else {
removeError(inputLayoutTitle)
}
if (TextUtils.isEmpty(inputTitle.text)) {
setError(inputLayoutTitle, R.string.bug_report_no_title)
hasErrors = true
} else {
removeError(inputLayoutTitle)
}
if (TextUtils.isEmpty(inputDescription.text)) {
setError(inputLayoutDescription, R.string.bug_report_no_description)
hasErrors = true
} else {
removeError(inputLayoutDescription)
}
if (TextUtils.isEmpty(inputDescription.text)) {
setError(inputLayoutDescription, R.string.bug_report_no_description)
hasErrors = true
} else {
removeError(inputLayoutDescription)
}
return !hasErrors
}
return !hasErrors
}
private fun setError(editTextLayout: TextInputLayout, @StringRes errorRes: Int) {
editTextLayout.error = getString(errorRes)
}
private fun setError(editTextLayout: TextInputLayout, @StringRes errorRes: Int) {
editTextLayout.error = getString(errorRes)
}
private fun removeError(editTextLayout: TextInputLayout) {
editTextLayout.error = null
}
private fun removeError(editTextLayout: TextInputLayout) {
editTextLayout.error = null
}
private fun sendBugReport(login: GithubLogin) {
if (!validateInput()) return
private fun sendBugReport(login: GithubLogin) {
if (!validateInput()) return
val bugTitle = inputTitle.text.toString()
val bugDescription = inputDescription.text.toString()
val bugTitle = inputTitle.text.toString()
val bugDescription = inputDescription.text.toString()
val extraInfo = ExtraInfo()
onSaveExtraInfo()
val extraInfo = ExtraInfo()
onSaveExtraInfo()
val report = Report(bugTitle, bugDescription, deviceInfo, extraInfo)
val target = GithubTarget("h4h13", "RetroMusicPlayer")
val report = Report(bugTitle, bugDescription, deviceInfo, extraInfo)
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 {
if (item.itemId == android.R.id.home) {
onBackPressed()
}
return super.onOptionsItemSelected(item)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
}
return super.onOptionsItemSelected(item)
}
private class ReportIssueAsyncTask private constructor(activity: Activity, private val report: Report, private val target: GithubTarget,
private val login: GithubLogin) : DialogAsyncTask<Void, Void, String>(activity) {
override fun createDialog(context: Context): Dialog {
return AlertDialog.Builder(context)
.show()
}
private class ReportIssueAsyncTask private constructor(
activity: Activity,
private val report: Report,
private val target: GithubTarget,
private val login: GithubLogin
) : DialogAsyncTask<Void, Void, String>(activity) {
override fun createDialog(context: Context): Dialog {
return AlertDialog.Builder(context).show()
}
@Result
override fun doInBackground(vararg params: Void): String {
val client: GitHubClient = if (login.shouldUseApiToken()) {
GitHubClient().setOAuth2Token(login.apiToken)
} else {
GitHubClient().setCredentials(login.username, login.password)
}
@Result
override fun doInBackground(vararg params: Void): String {
val client: GitHubClient = if (login.shouldUseApiToken()) {
GitHubClient().setOAuth2Token(login.apiToken)
} else {
GitHubClient().setCredentials(login.username, login.password)
}
val issue = Issue().setTitle(report.title).setBody(report.description)
try {
IssueService(client).createIssue(target.username, target.repository, issue)
return RESULT_SUCCESS
} catch (e: RequestException) {
return when (e.status) {
STATUS_BAD_CREDENTIALS -> {
if (login.shouldUseApiToken()) RESULT_INVALID_TOKEN else RESULT_BAD_CREDENTIALS
}
STATUS_ISSUES_NOT_ENABLED -> RESULT_ISSUES_NOT_ENABLED
else -> {
e.printStackTrace()
RESULT_UNKNOWN
}
}
} catch (e: IOException) {
e.printStackTrace()
return RESULT_UNKNOWN
}
val issue = Issue().setTitle(report.title).setBody(report.description)
try {
IssueService(client).createIssue(target.username, target.repository, issue)
return RESULT_SUCCESS
} catch (e: RequestException) {
return when (e.status) {
STATUS_BAD_CREDENTIALS -> {
if (login.shouldUseApiToken()) RESULT_INVALID_TOKEN else RESULT_BAD_CREDENTIALS
}
STATUS_ISSUES_NOT_ENABLED -> RESULT_ISSUES_NOT_ENABLED
else -> {
e.printStackTrace()
RESULT_UNKNOWN
}
}
} catch (e: IOException) {
e.printStackTrace()
return RESULT_UNKNOWN
}
}
}
override fun onPostExecute(@Result result: String) {
super.onPostExecute(result)
override fun onPostExecute(@Result result: String) {
super.onPostExecute(result)
val context = context ?: return
val context = context ?: return
when (result) {
RESULT_SUCCESS -> tryToFinishActivity()
RESULT_BAD_CREDENTIALS -> MaterialDialog(context).show {
title(R.string.bug_report_failed)
message(R.string.bug_report_failed_wrong_credentials)
positiveButton(android.R.string.ok)
}
RESULT_INVALID_TOKEN -> MaterialDialog(context).show {
title(R.string.bug_report_failed)
message(R.string.bug_report_failed_invalid_token)
positiveButton(android.R.string.ok)
}
RESULT_ISSUES_NOT_ENABLED -> MaterialDialog(context).show {
title(R.string.bug_report_failed)
message(R.string.bug_report_failed_issues_not_available)
positiveButton(android.R.string.ok)
}
else -> MaterialDialog(context).show {
title(R.string.bug_report_failed)
message(R.string.bug_report_failed_unknown)
positiveButton(android.R.string.ok) { tryToFinishActivity() }
onCancel { tryToFinishActivity() }
}
}
}
when (result) {
RESULT_SUCCESS -> tryToFinishActivity()
RESULT_BAD_CREDENTIALS -> MaterialDialog(context).show {
title(R.string.bug_report_failed)
message(R.string.bug_report_failed_wrong_credentials)
positiveButton(android.R.string.ok)
}
RESULT_INVALID_TOKEN -> MaterialDialog(context).show {
title(R.string.bug_report_failed)
message(R.string.bug_report_failed_invalid_token)
positiveButton(android.R.string.ok)
}
RESULT_ISSUES_NOT_ENABLED -> MaterialDialog(context).show {
title(R.string.bug_report_failed)
message(R.string.bug_report_failed_issues_not_available)
positiveButton(android.R.string.ok)
}
else -> MaterialDialog(context).show {
title(R.string.bug_report_failed)
message(R.string.bug_report_failed_unknown)
positiveButton(android.R.string.ok) { tryToFinishActivity() }
onCancel { tryToFinishActivity() }
}
}
}
private fun tryToFinishActivity() {
val context = context
if (context is Activity && !context.isFinishing) {
context.finish()
}
}
private fun tryToFinishActivity() {
val context = context
if (context is Activity && !context.isFinishing) {
context.finish()
}
}
companion object {
companion object {
fun report(activity: Activity, report: Report, target: GithubTarget, login: GithubLogin) {
ReportIssueAsyncTask(activity, report, target, login).execute()
}
}
}
fun report(
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_ISSUES_NOT_ENABLED = 410
private const val ISSUE_TRACKER_LINK = "https://github.com/h4h13/RetroMusicPlayer"
}
private const val STATUS_BAD_CREDENTIALS = 401
private const val STATUS_ISSUES_NOT_ENABLED = 410
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.os.Build;
import androidx.annotation.IntRange;
import java.util.Arrays;
import androidx.annotation.IntRange;
import code.name.monkey.retromusic.util.PreferenceUtil;
public class DeviceInfo {

View file

@ -1,405 +1,416 @@
package code.name.monkey.retromusic.activities.tageditor
import android.app.Activity
import android.app.SearchManager
import android.app.*
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.*
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.*
import android.util.Log
import android.view.MenuItem
import android.view.View
import android.view.*
import android.view.animation.OvershootInterpolator
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.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.*
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.SAFUtil
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import code.name.monkey.retromusic.util.*
import com.afollestad.materialdialogs.*
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.list.listItems
import com.google.android.material.button.MaterialButton
import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import org.jaudiotagger.audio.AudioFile
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.audio.*
import org.jaudiotagger.tag.FieldKey
import java.io.File
import java.util.*
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 set
private var paletteColorPrimary: Int = 0
private var isInNoImageMode: Boolean = false
private var songPaths: List<String>? = null
lateinit var saveFab: MaterialButton
private var savedSongPaths: List<String>? = null
private val currentSongPath: String? = null
private var savedTags: Map<FieldKey, String>? = null
private var savedArtworkInfo: ArtworkInfo? = null
private var savedSongPaths: List<String>? = null
private val currentSongPath: String? = null
private var savedTags: Map<FieldKey, String>? = null
private var savedArtworkInfo: ArtworkInfo? = null
protected val show: MaterialDialog
get() = MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
cornerRadius(PreferenceUtil.getInstance(this@AbsTagEditorActivity).dialogCorner)
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
get() = MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT))
.show {
cornerRadius(PreferenceUtil.getInstance(this@AbsTagEditorActivity).dialogCorner)
title(R.string.update_image)
listItems(items = items) { _, position, _ ->
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
}
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() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.TITLE)
} catch (ignored: Exception) {
null
}
}
protected val composer: String?
get() {
return try {
getAudioFile(songPaths!![0]).tagOrCreateAndSetDefault.getFirst(FieldKey.COMPOSER)
} 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?
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
}
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
}
}
private fun setUpViews() {
setUpScrollView()
setUpFab()
setUpImageView()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(contentViewLayout)
private fun setUpScrollView() {
//observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks);
}
saveFab = findViewById(R.id.saveTags)
getIntentExtras()
private lateinit var items: List<String>
songPaths = getSongPaths()
if (songPaths!!.isEmpty()) {
finish()
return
}
private fun setUpImageView() {
loadCurrentImage()
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)
)
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()
setTaskDescriptionColorAuto()
}
protected abstract fun searchImageOnWeb()
private fun setUpViews() {
setUpScrollView()
setUpFab()
setUpImageView()
}
protected abstract fun deleteImage()
private fun setUpScrollView() {
//observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks);
}
private fun setUpFab() {
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() {
loadCurrentImage()
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))
editorImage?.setOnClickListener { show }
}
private fun getIntentExtras() {
val intentExtras = intent.extras
if (intentExtras != null) {
id = intentExtras.getInt(EXTRA_ID)
}
}
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 getSongPaths(): List<String>
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() {
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)
}
}
protected fun setNoImageMode() {
isInNoImageMode = true
imageContainer?.visibility = View.GONE
editorImage?.visibility = View.GONE
editorImage?.isEnabled = false
protected abstract fun save()
setColors(
intent.getIntExtra(
EXTRA_PALETTE,
ATHUtil.resolveColor(this, R.attr.colorPrimary)
)
)
}
private fun getIntentExtras() {
val intentExtras = intent.extras
if (intentExtras != null) {
id = intentExtras.getInt(EXTRA_ID)
}
}
protected fun dataChanged() {
showFab()
}
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) {
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)
private fun hideFab() {
saveFab.animate().setDuration(500).setInterpolator(OvershootInterpolator()).scaleX(0.0f)
.scaleY(0.0f).start()
saveFab.isEnabled = false
}
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 {
when (item.itemId) {
android.R.id.home -> {
super.onBackPressed()
return true
}
}
return super.onOptionsItemSelected(item)
}
protected open fun setColors(color: Int) {
paletteColorPrimary = color
}
protected fun setNoImageMode() {
isInNoImageMode = true
imageContainer?.visibility = View.GONE
editorImage?.visibility = View.GONE
editorImage?.isEnabled = false
protected fun writeValuesToFiles(
fieldKeyValueMap: Map<FieldKey, String>, artworkInfo: ArtworkInfo?
) {
RetroUtil.hideSoftKeyboard(this)
setColors(intent.getIntExtra(EXTRA_PALETTE, ATHUtil.resolveColor(this, R.attr.colorPrimary)))
}
hideFab()
protected fun dataChanged() {
showFab()
}
savedSongPaths = getSongPaths()
savedTags = fieldKeyValueMap
savedArtworkInfo = artworkInfo
private fun showFab() {
saveFab.animate()
.setDuration(500)
.setInterpolator(OvershootInterpolator())
.scaleX(1f)
.scaleY(1f)
.start()
saveFab.isEnabled = true
}
if (!SAFUtil.isSAFRequired(savedSongPaths)) {
writeTags(savedSongPaths)
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (SAFUtil.isSDCardAccessGranted(this)) {
writeTags(savedSongPaths)
} else {
startActivityForResult(
Intent(this, SAFGuideActivity::class.java),
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE
)
}
}
}
}
private fun hideFab() {
saveFab.animate()
.setDuration(500)
.setInterpolator(OvershootInterpolator())
.scaleX(0.0f)
.scaleY(0.0f)
.start()
saveFab.isEnabled = false
}
private fun writeTags(paths: List<String>?) {
WriteTagsAsyncTask(this).execute(
WriteTagsAsyncTask.LoadingInfo(
paths,
savedTags,
savedArtworkInfo
)
)
}
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 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 open fun setColors(color: Int) {
paletteColorPrimary = color
}
protected abstract fun loadImageFromFile(selectedFile: Uri?)
protected fun writeValuesToFiles(fieldKeyValueMap: Map<FieldKey, String>,
artworkInfo: ArtworkInfo?) {
RetroUtil.hideSoftKeyboard(this)
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()
}
}
hideFab()
class ArtworkInfo constructor(val albumId: Int, val artwork: Bitmap?)
savedSongPaths = getSongPaths()
savedTags = fieldKeyValueMap
savedArtworkInfo = artworkInfo
companion object {
if (!SAFUtil.isSAFRequired(savedSongPaths)) {
writeTags(savedSongPaths)
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
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
}
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.content.res.ColorStateList
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.*
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.text.Editable
import android.text.TextUtils
import android.text.TextWatcher
import android.text.*
import android.widget.Toast
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.appthemehelper.util.*
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.glide.palette.*
import code.name.monkey.retromusic.loaders.AlbumLoader
import code.name.monkey.retromusic.rest.LastFMRestClient
import code.name.monkey.retromusic.rest.model.LastFmAlbum
import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.LastFMUtil
import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette
import code.name.monkey.retromusic.util.RetroColorUtil.getColor
import com.bumptech.glide.Glide
@ -34,181 +27,224 @@ import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import org.jaudiotagger.tag.FieldKey
import java.util.*
class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
override val contentViewLayout: Int
get() = R.layout.activity_album_tag_editor
override val contentViewLayout: Int
get() = R.layout.activity_album_tag_editor
override fun loadImageFromFile(selectedFileUri: Uri?) {
override fun loadImageFromFile(selectedFileUri: Uri?) {
Glide.with(this@AlbumTagEditorActivity)
.load(selectedFileUri)
.asBitmap()
.transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(object : SimpleTarget<BitmapPaletteWrapper>() {
override fun onResourceReady(resource: BitmapPaletteWrapper?, glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?) {
getColor(resource?.palette, Color.TRANSPARENT)
albumArtBitmap = resource?.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
setImageBitmap(albumArtBitmap, getColor(resource?.palette, ATHUtil.resolveColor(this@AlbumTagEditorActivity, R.attr.defaultFooterColor)))
deleteAlbumArt = false
dataChanged()
setResult(Activity.RESULT_OK)
}
Glide.with(this@AlbumTagEditorActivity).load(selectedFileUri).asBitmap()
.transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java)
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
.into(object : SimpleTarget<BitmapPaletteWrapper>() {
override fun onResourceReady(
resource: BitmapPaletteWrapper?,
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?
) {
getColor(resource?.palette, Color.TRANSPARENT)
albumArtBitmap = resource?.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
setImageBitmap(
albumArtBitmap,
getColor(
resource?.palette,
ATHUtil.resolveColor(
this@AlbumTagEditorActivity,
R.attr.defaultFooterColor
)
)
)
deleteAlbumArt = false
dataChanged()
setResult(Activity.RESULT_OK)
}
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
super.onLoadFailed(e, errorDrawable)
Toast.makeText(this@AlbumTagEditorActivity, e.toString(), Toast.LENGTH_LONG).show()
}
})
}
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
super.onLoadFailed(e, errorDrawable)
Toast.makeText(this@AlbumTagEditorActivity, e.toString(), Toast.LENGTH_LONG)
.show()
}
})
}
private var albumArtBitmap: Bitmap? = null
private var deleteAlbumArt: Boolean = false
private var lastFMRestClient: LastFMRestClient? = null
private val disposable = CompositeDisposable()
private var albumArtBitmap: Bitmap? = null
private var deleteAlbumArt: Boolean = false
private var lastFMRestClient: LastFMRestClient? = null
private val disposable = CompositeDisposable()
private fun setupToolbar() {
toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
setSupportActionBar(toolbar)
supportActionBar?.setDisplayShowHomeEnabled(true)
}
private fun setupToolbar() {
toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
setSupportActionBar(toolbar)
supportActionBar?.setDisplayShowHomeEnabled(true)
}
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
lastFMRestClient = LastFMRestClient(this)
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
lastFMRestClient = LastFMRestClient(this)
setUpViews()
setupToolbar()
}
setUpViews()
setupToolbar()
}
private fun setUpViews() {
fillViewsWithFileTags()
private fun setUpViews() {
fillViewsWithFileTags()
MaterialUtil.setTint(yearContainer, false)
MaterialUtil.setTint(genreContainer, false)
MaterialUtil.setTint(albumTitleContainer, false)
MaterialUtil.setTint(albumArtistContainer, false)
MaterialUtil.setTint(yearContainer, false)
MaterialUtil.setTint(genreContainer, false)
MaterialUtil.setTint(albumTitleContainer, false)
MaterialUtil.setTint(albumArtistContainer, false)
albumText.appHandleColor().addTextChangedListener(this)
albumArtistText.appHandleColor().addTextChangedListener(this)
genreTitle.appHandleColor().addTextChangedListener(this)
yearTitle.appHandleColor().addTextChangedListener(this)
}
albumText.appHandleColor().addTextChangedListener(this)
albumArtistText.appHandleColor().addTextChangedListener(this)
genreTitle.appHandleColor().addTextChangedListener(this)
yearTitle.appHandleColor().addTextChangedListener(this)
}
private fun fillViewsWithFileTags() {
albumText.setText(albumTitle)
albumArtistText.setText(albumArtistName)
genreTitle.setText(genreName)
yearTitle.setText(songYear)
}
private fun fillViewsWithFileTags() {
albumText.setText(albumTitle)
albumArtistText.setText(albumArtistName)
genreTitle.setText(genreName)
yearTitle.setText(songYear)
}
override fun loadCurrentImage() {
val bitmap = albumArt
setImageBitmap(
bitmap,
getColor(
generatePalette(bitmap),
ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
)
)
deleteAlbumArt = false
}
override fun loadCurrentImage() {
val bitmap = albumArt
setImageBitmap(bitmap, getColor(generatePalette(bitmap), ATHUtil.resolveColor(this, R.attr.defaultFooterColor)))
deleteAlbumArt = false
}
override fun onPause() {
super.onPause()
disposable.clear()
}
override fun onPause() {
super.onPause()
disposable.clear()
}
private fun extractDetails(lastFmAlbum: LastFmAlbum) {
if (lastFmAlbum.album != null) {
private fun extractDetails(lastFmAlbum: LastFmAlbum) {
if (lastFmAlbum.album != null) {
val url = LastFMUtil.getLargestAlbumImageUrl(lastFmAlbum.album.image)
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()) {
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()
}
override fun onResourceReady(
resource: BitmapPaletteWrapper?,
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?
) {
albumArtBitmap = resource?.bitmap?.let {
ImageUtil.resizeBitmap(
it,
2048
)
}
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) }
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)
}
}
toastLoadingFailed()
}
}
toastLoadingFailed()
}
private fun toastLoadingFailed() {
Toast.makeText(
this@AlbumTagEditorActivity,
R.string.could_not_download_album_cover,
Toast.LENGTH_SHORT
).show()
}
private fun toastLoadingFailed() {
Toast.makeText(this@AlbumTagEditorActivity, R.string.could_not_download_album_cover, Toast.LENGTH_SHORT).show()
}
override fun searchImageOnWeb() {
searchWebFor(albumText.text.toString(), albumArtistText.text.toString())
}
override fun searchImageOnWeb() {
searchWebFor(albumText.text.toString(), albumArtistText.text.toString())
}
override fun deleteImage() {
setImageBitmap(
BitmapFactory.decodeResource(resources, R.drawable.default_album_art),
ATHUtil.resolveColor(this, R.attr.defaultFooterColor)
)
deleteAlbumArt = true
dataChanged()
}
override fun deleteImage() {
setImageBitmap(BitmapFactory.decodeResource(resources, R.drawable.default_album_art), ATHUtil.resolveColor(this, R.attr.defaultFooterColor))
deleteAlbumArt = true
dataChanged()
}
override fun save() {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
//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() {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
//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)
else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!)
)
}
writeValuesToFiles(fieldKeyValueMap, if (deleteAlbumArt) ArtworkInfo(id, null)
else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!))
}
override fun getSongPaths(): List<String> {
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> {
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 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) {
dataChanged()
}
companion object {
override fun setColors(color: Int) {
super.setColors(color)
saveFab.backgroundTintList = ColorStateList.valueOf(color)
}
companion object {
val TAG: String = AlbumTagEditorActivity::class.java.simpleName
}
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.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.text.*
import androidx.core.content.ContextCompat
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.*
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.appHandleColor
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 java.util.*
class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
override val contentViewLayout: Int
get() = R.layout.activity_song_tag_editor
override val contentViewLayout: Int
get() = R.layout.activity_song_tag_editor
private fun setupToolbar() {
appBarLayout.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
toolbar.apply {
setBackgroundColor(ATHUtil.resolveColor(this@SongTagEditorActivity, R.attr.colorPrimary))
navigationIcon = TintHelper.createTintedDrawable(ContextCompat.getDrawable(context, R.drawable.ic_keyboard_backspace_black_24dp), ThemeStore.textColorPrimary(context))
setNavigationOnClickListener { onBackPressed() }
setSupportActionBar(toolbar)
}
title = null
}
private fun setupToolbar() {
appBarLayout.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorPrimary))
toolbar.apply {
setBackgroundColor(
ATHUtil.resolveColor(
this@SongTagEditorActivity,
R.attr.colorPrimary
)
)
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?) {
super.onCreate(savedInstanceState)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setNoImageMode()
setUpViews()
setupToolbar()
setStatusbarColorAuto()
}
setNoImageMode()
setUpViews()
setupToolbar()
setStatusbarColorAuto()
}
private fun setUpViews() {
fillViewsWithFileTags()
MaterialUtil.setTint(songTextContainer, false)
MaterialUtil.setTint(composerContainer, false)
MaterialUtil.setTint(albumTextContainer, false)
MaterialUtil.setTint(artistContainer, false)
MaterialUtil.setTint(albumArtistContainer, false)
MaterialUtil.setTint(yearContainer, false)
MaterialUtil.setTint(genreContainer, false)
MaterialUtil.setTint(trackNumberContainer, false)
MaterialUtil.setTint(lyricsContainer, false)
private fun setUpViews() {
fillViewsWithFileTags()
MaterialUtil.setTint(songTextContainer, false)
MaterialUtil.setTint(composerContainer, false)
MaterialUtil.setTint(albumTextContainer, false)
MaterialUtil.setTint(artistContainer, false)
MaterialUtil.setTint(albumArtistContainer, false)
MaterialUtil.setTint(yearContainer, false)
MaterialUtil.setTint(genreContainer, false)
MaterialUtil.setTint(trackNumberContainer, false)
MaterialUtil.setTint(lyricsContainer, false)
songText.appHandleColor().addTextChangedListener(this)
albumText.appHandleColor().addTextChangedListener(this)
albumArtistText.appHandleColor().addTextChangedListener(this)
artistText.appHandleColor().addTextChangedListener(this)
genreText.appHandleColor().addTextChangedListener(this)
yearText.appHandleColor().addTextChangedListener(this)
trackNumberText.appHandleColor().addTextChangedListener(this)
lyricsText.appHandleColor().addTextChangedListener(this)
songComposerText.appHandleColor().addTextChangedListener(this)
}
songText.appHandleColor().addTextChangedListener(this)
albumText.appHandleColor().addTextChangedListener(this)
albumArtistText.appHandleColor().addTextChangedListener(this)
artistText.appHandleColor().addTextChangedListener(this)
genreText.appHandleColor().addTextChangedListener(this)
yearText.appHandleColor().addTextChangedListener(this)
trackNumberText.appHandleColor().addTextChangedListener(this)
lyricsText.appHandleColor().addTextChangedListener(this)
songComposerText.appHandleColor().addTextChangedListener(this)
}
private fun fillViewsWithFileTags() {
songText.setText(songTitle)
albumArtistText.setText(albumArtist)
albumText.setText(albumTitle)
artistText.setText(artistName)
genreText.setText(genreName)
yearText.setText(songYear)
trackNumberText.setText(trackNumber)
lyricsText.setText(lyrics)
songComposerText.setText(composer)
}
private fun fillViewsWithFileTags() {
songText.setText(songTitle)
albumArtistText.setText(albumArtist)
albumText.setText(albumTitle)
artistText.setText(artistName)
genreText.setText(genreName)
yearText.setText(songYear)
trackNumberText.setText(trackNumber)
lyricsText.setText(lyrics)
songComposerText.setText(composer)
}
override fun loadCurrentImage() {
override fun loadCurrentImage() {
}
}
override fun searchImageOnWeb() {
override fun searchImageOnWeb() {
}
}
override fun deleteImage() {
override fun deleteImage() {
}
}
override fun save() {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.TITLE] = songText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
fieldKeyValueMap[FieldKey.ARTIST] = artistText.text.toString()
fieldKeyValueMap[FieldKey.GENRE] = genreText.text.toString()
fieldKeyValueMap[FieldKey.YEAR] = yearText.text.toString()
fieldKeyValueMap[FieldKey.TRACK] = trackNumberText.text.toString()
fieldKeyValueMap[FieldKey.LYRICS] = lyricsText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.COMPOSER] = songComposerText.text.toString()
writeValuesToFiles(fieldKeyValueMap, null)
}
override fun save() {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.TITLE] = songText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
fieldKeyValueMap[FieldKey.ARTIST] = artistText.text.toString()
fieldKeyValueMap[FieldKey.GENRE] = genreText.text.toString()
fieldKeyValueMap[FieldKey.YEAR] = yearText.text.toString()
fieldKeyValueMap[FieldKey.TRACK] = trackNumberText.text.toString()
fieldKeyValueMap[FieldKey.LYRICS] = lyricsText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.COMPOSER] = songComposerText.text.toString()
writeValuesToFiles(fieldKeyValueMap, null)
}
override fun getSongPaths(): List<String> {
val paths = ArrayList<String>(1)
paths.add(SongLoader.getSong(this, id).data)
return paths
}
override fun getSongPaths(): List<String> {
val paths = ArrayList<String>(1)
paths.add(SongLoader.getSong(this, id).data)
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) {
dataChanged()
}
override fun afterTextChanged(s: Editable) {
dataChanged()
}
companion object {
val TAG: String = SongTagEditorActivity::class.java.simpleName
}
companion object {
val TAG: String = SongTagEditorActivity::class.java.simpleName
}
}