Here's a list of changes/features: https://github.com/RetroMusicPlayer/RetroMusicPlayer/releases/tag/v5.0

Internal Changes:
1) Migrated to ViewBinding
2) Migrated to Glide V4
3) Migrated to kotlin version of Material Dialogs
This commit is contained in:
Prathamesh More 2021-09-09 00:00:20 +05:30
parent fc42767031
commit bce6dbfa27
421 changed files with 13285 additions and 5757 deletions

View file

@ -23,10 +23,12 @@ import android.widget.SeekBar
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.databinding.ActivityDriveModeBinding
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.glide.BlurTransformation
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback
@ -35,19 +37,19 @@ import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.activity_drive_mode.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/**
* Created by hemanths on 2020-02-02.
*/
class DriveModeActivity : AbsMusicServiceActivity(), Callback {
private lateinit var binding: ActivityDriveModeBinding
private var lastPlaybackControlsColor: Int = Color.GRAY
private var lastDisabledPlaybackControlsColor: Int = Color.GRAY
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
@ -55,12 +57,13 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_drive_mode)
binding = ActivityDriveModeBinding.inflate(layoutInflater)
setContentView(binding.root)
setUpMusicControllers()
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
lastPlaybackControlsColor = ThemeStore.accentColor(this)
close.setOnClickListener {
binding.close.setOnClickListener {
onBackPressed()
}
}
@ -75,7 +78,7 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
}
private fun setupFavouriteToggle() {
songFavourite.setOnClickListener {
binding.songFavourite.setOnClickListener {
MusicUtil.toggleFavorite(
this@DriveModeActivity,
MusicPlayerRemote.currentSong
@ -88,13 +91,13 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
val isFavourite =
MusicUtil.isFavorite(this@DriveModeActivity, MusicPlayerRemote.currentSong)
withContext(Dispatchers.Main) {
songFavourite.setImageResource(if (isFavourite) R.drawable.ic_favorite else R.drawable.ic_favorite_border)
binding.songFavourite.setImageResource(if (isFavourite) R.drawable.ic_favorite else R.drawable.ic_favorite_border)
}
}
}
private fun setUpProgressSlider() {
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
@ -119,20 +122,20 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
private fun setUpPrevNext() {
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
previousButton.setOnClickListener { MusicPlayerRemote.back() }
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
private fun setUpShuffleButton() {
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
binding.shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
}
private fun setUpRepeatButton() {
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
binding.repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
}
private fun setUpPlayPauseFab() {
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
}
override fun onRepeatModeChanged() {
@ -161,19 +164,19 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
private fun updatePlayPauseDrawableState() {
if (MusicPlayerRemote.isPlaying) {
playPauseButton.setImageResource(R.drawable.ic_pause)
binding.playPauseButton.setImageResource(R.drawable.ic_pause)
} else {
playPauseButton.setImageResource(R.drawable.ic_play_arrow)
binding.playPauseButton.setImageResource(R.drawable.ic_play_arrow)
}
}
fun updateShuffleState() {
when (MusicPlayerRemote.shuffleMode) {
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(
MusicService.SHUFFLE_MODE_SHUFFLE -> binding.shuffleButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
else -> shuffleButton.setColorFilter(
else -> binding.shuffleButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
@ -183,19 +186,25 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
private fun updateRepeatState() {
when (MusicPlayerRemote.repeatMode) {
MusicService.REPEAT_MODE_NONE -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastDisabledPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_ALL -> {
repeatButton.setImageResource(R.drawable.ic_repeat)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
MusicService.REPEAT_MODE_THIS -> {
repeatButton.setImageResource(R.drawable.ic_repeat_one)
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
binding.repeatButton.setImageResource(R.drawable.ic_repeat_one)
binding.repeatButton.setColorFilter(
lastPlaybackControlsColor,
PorterDuff.Mode.SRC_IN
)
}
}
}
@ -209,29 +218,29 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
private fun updateSong() {
val song = MusicPlayerRemote.currentSong
songTitle.text = song.title
songText.text = song.artistName
binding.songTitle.text = song.title
binding.songText.text = song.artistName
SongGlideRequest.Builder.from(Glide.with(this), song)
.checkIgnoreMediaStore(this)
.generatePalette(this)
.build()
GlideApp.with(this)
.asBitmapPalette()
.songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song))
.transform(BlurTransformation.Builder(this).build())
.into(object : RetroMusicColoredTarget(image) {
.into(object : RetroMusicColoredTarget(binding.image) {
override fun onColorReady(colors: MediaNotificationProcessor) {
}
})
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider.max = total
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(progressSlider, "progress", progress)
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
}

View file

@ -18,19 +18,23 @@ import android.graphics.Color;
import android.os.Bundle;
import android.view.MenuItem;
import android.webkit.WebView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedReader;
import java.io.InputStream;
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;
import code.name.monkey.retromusic.activities.base.AbsBaseActivity;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import org.jetbrains.annotations.Nullable;
/** Created by hemanths on 2019-09-27. */
public class LicenseActivity extends AbsBaseActivity {

View file

@ -23,27 +23,29 @@ import android.view.WindowManager
import androidx.core.view.ViewCompat
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.databinding.ActivityLockScreenBinding
import code.name.monkey.retromusic.extensions.whichFragment
import code.name.monkey.retromusic.fragments.player.lockscreen.LockScreenControlsFragment
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
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 kotlinx.android.synthetic.main.activity_lock_screen.*
class LockScreenActivity : AbsMusicServiceActivity() {
private lateinit var binding: ActivityLockScreenBinding
private var fragment: LockScreenControlsFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
lockScreenInit()
setContentView(R.layout.activity_lock_screen)
binding = ActivityLockScreenBinding.inflate(layoutInflater)
setContentView(binding.root)
hideStatusBar()
setStatusbarColorAuto()
setNavigationbarColorAuto()
@ -107,9 +109,12 @@ class LockScreenActivity : AbsMusicServiceActivity() {
private fun updateSongs() {
val song = MusicPlayerRemote.currentSong
SongGlideRequest.Builder.from(Glide.with(this), song).checkIgnoreMediaStore(this)
.generatePalette(this).build().dontAnimate()
.into(object : RetroMusicColoredTarget(image) {
GlideApp.with(this)
.asBitmapPalette()
.songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song))
.dontAnimate()
.into(object : RetroMusicColoredTarget(binding.image) {
override fun onColorReady(colors: MediaNotificationProcessor) {
fragment?.setColor(colors)
}

View file

@ -15,38 +15,64 @@
package code.name.monkey.retromusic.activities
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.WindowManager
import android.text.InputType
import android.view.*
import androidx.core.view.ViewCompat
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.activities.tageditor.WriteTagsAsyncTask
import code.name.monkey.retromusic.databinding.ActivityLyricsBinding
import code.name.monkey.retromusic.databinding.FragmentNormalLyricsBinding
import code.name.monkey.retromusic.databinding.FragmentSyncedLyricsBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.extensions.textColorSecondary
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.lyrics.LrcView
import code.name.monkey.retromusic.model.LoadingInfo
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.LyricUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.afollestad.materialdialogs.LayoutMode
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.input.input
import com.google.android.material.color.MaterialColors
import com.google.android.material.transition.platform.MaterialArcMotion
import com.google.android.material.tabs.TabLayoutMediator
import com.google.android.material.transition.platform.MaterialContainerTransform
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
import kotlinx.android.synthetic.main.activity_lyrics.*
import kotlinx.coroutines.*
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.tag.FieldKey
import java.io.File
import java.util.*
class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.Callback {
private lateinit var updateHelper: MusicProgressViewUpdateHelper
class LyricsActivity : AbsMusicServiceActivity() {
private lateinit var binding: ActivityLyricsBinding
private lateinit var song: Song
private val lyricsSectionsAdapter = LyricsSectionsAdapter(this)
private val googleSearchLrcUrl: String
get() {
var baseUrl = "http://www.google.com/search?"
var query = song.title + "+" + song.artistName
query = "q=" + query.replace(" ", "+") + " .lrc"
query = "q=" + query.replace(" ", "+") + " lyrics"
baseUrl += query
return baseUrl
}
private val syairSearchLrcUrl: String
get() {
var baseUrl = "https://www.syair.info/search?"
var query = song.title + "+" + song.artistName
query = "q=" + query.replace(" ", "+")
baseUrl += query
return baseUrl
}
@ -63,75 +89,55 @@ class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_lyrics)
ViewCompat.setTransitionName(container, "lyrics")
binding = ActivityLyricsBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setTransitionName(binding.container, "lyrics")
setStatusbarColorAuto()
setTaskDescriptionColorAuto()
setNavigationbarColorAuto()
setupWakelock()
toolbar.setBackgroundColor(surfaceColor())
ToolbarContentTintHelper.colorBackButton(toolbar)
setSupportActionBar(toolbar)
binding.toolbar.setBackgroundColor(surfaceColor())
binding.tabLyrics.setBackgroundColor(surfaceColor())
binding.container.setBackgroundColor(surfaceColor())
ToolbarContentTintHelper.colorBackButton(binding.toolbar)
setSupportActionBar(binding.toolbar)
setupViews()
updateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
setupLyricsView()
}
private fun setupLyricsView() {
lyricsView.apply {
setCurrentColor(ThemeStore.accentColor(context))
setTimeTextColor(ThemeStore.accentColor(context))
setTimelineColor(ThemeStore.accentColor(context))
setTimelineTextColor(ThemeStore.accentColor(context))
setDraggable(true, LrcView.OnPlayClickListener {
MusicPlayerRemote.seekTo(it.toInt())
return@OnPlayClickListener true
})
}
private fun setupViews() {
binding.lyricsPager.adapter = lyricsSectionsAdapter
TabLayoutMediator(binding.tabLyrics, binding.lyricsPager) { tab, position ->
tab.text = when (position) {
0 -> "Synced Lyrics"
1 -> "Normal Lyrics"
else -> ""
}
}.attach()
// lyricsPager.isUserInputEnabled = false
binding.tabLyrics.setSelectedTabIndicatorColor(ThemeStore.accentColor(this))
binding.tabLyrics.setTabTextColors(textColorSecondary(), accentColor())
}
override fun onResume() {
super.onResume()
updateHelper.start()
}
override fun onPause() {
super.onPause()
updateHelper.stop()
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
lyricsView.updateTime(progress.toLong())
}
private fun loadLRCLyrics() {
lyricsView.setLabel("Empty")
val song = MusicPlayerRemote.currentSong
if (LyricUtil.isLrcOriginalFileExist(song.data)) {
lyricsView.loadLrc(LyricUtil.getLocalLyricOriginalFile(song.data))
} else if (LyricUtil.isLrcFileExist(song.title, song.artistName)) {
lyricsView.loadLrc(LyricUtil.getLocalLyricFile(song.title, song.artistName))
}
}
override fun onPlayingMetaChanged() {
super.onPlayingMetaChanged()
updateTitleSong()
loadLRCLyrics()
}
override fun onServiceConnected() {
super.onServiceConnected()
updateTitleSong()
loadLRCLyrics()
}
private fun updateTitleSong() {
song = MusicPlayerRemote.currentSong
toolbar.title = song.title
toolbar.subtitle = song.artistName
binding.toolbar.title = song.title
binding.toolbar.subtitle = song.artistName
}
private fun setupWakelock() {
@ -149,8 +155,206 @@ class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.
return true
}
if (item.itemId == R.id.action_search) {
RetroUtil.openUrl(this, googleSearchLrcUrl)
RetroUtil.openUrl(
this, when (binding.lyricsPager.currentItem) {
0 -> syairSearchLrcUrl
1 -> googleSearchLrcUrl
else -> googleSearchLrcUrl
}
)
} else if (item.itemId == R.id.action_edit) {
when (binding.lyricsPager.currentItem) {
0 -> {
editSyncedLyrics()
}
1 -> {
editNormalLyrics()
}
}
}
return super.onOptionsItemSelected(item)
}
private fun editNormalLyrics() {
var content = ""
val file = File(MusicPlayerRemote.currentSong.data)
try {
content = AudioFileIO.read(file).tagOrCreateDefault.getFirst(FieldKey.LYRICS)
} catch (e: Exception) {
e.printStackTrace()
}
MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(res = R.string.edit_normal_lyrics)
input(
hintRes = R.string.paste_lyrics_here,
prefill = content,
inputType = InputType.TYPE_TEXT_FLAG_MULTI_LINE or InputType.TYPE_CLASS_TEXT
) { _, input ->
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.LYRICS] = input.toString()
WriteTagsAsyncTask(this@LyricsActivity).execute(
LoadingInfo(
listOf(song.data), fieldKeyValueMap, null
)
)
}
positiveButton(res = R.string.save) {
(lyricsSectionsAdapter.fragments[1].first as NormalLyrics).loadNormalLyrics()
}
negativeButton(res = android.R.string.cancel)
}
}
private fun editSyncedLyrics() {
var lrcFile: File? = null
if (LyricUtil.isLrcOriginalFileExist(song.data)) {
lrcFile = LyricUtil.getLocalLyricOriginalFile(song.data)
} else if (LyricUtil.isLrcFileExist(song.title, song.artistName)) {
lrcFile = LyricUtil.getLocalLyricFile(song.title, song.artistName)
}
val content: String = LyricUtil.getStringFromLrc(lrcFile)
MaterialDialog(this, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
title(res = R.string.edit_synced_lyrics)
input(
hintRes = R.string.paste_timeframe_lyrics_here,
prefill = content,
inputType = InputType.TYPE_TEXT_FLAG_MULTI_LINE or InputType.TYPE_CLASS_TEXT
) { _, input ->
LyricUtil.writeLrc(song, input.toString())
}
positiveButton(res = R.string.save) {
(lyricsSectionsAdapter.fragments[0].first as SyncedLyrics).loadLRCLyrics()
}
negativeButton(res = android.R.string.cancel)
}
}
class LyricsSectionsAdapter(fragmentActivity: FragmentActivity) :
FragmentStateAdapter(fragmentActivity) {
val fragments = listOf(
Pair(SyncedLyrics(), R.string.synced_lyrics),
Pair(NormalLyrics(), R.string.normal_lyrics)
)
override fun getItemCount(): Int {
return fragments.size
}
override fun createFragment(position: Int): Fragment {
return fragments[position].first
}
}
class NormalLyrics : AbsMusicServiceFragment(R.layout.fragment_normal_lyrics) {
private var _binding: FragmentNormalLyricsBinding? = null
private val binding get() = _binding!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
_binding = FragmentNormalLyricsBinding.bind(view)
loadNormalLyrics()
super.onViewCreated(view, savedInstanceState)
}
fun loadNormalLyrics() {
var lyrics: String? = null
val file = File(MusicPlayerRemote.currentSong.data)
try {
lyrics = AudioFileIO.read(file).tagOrCreateDefault.getFirst(FieldKey.LYRICS)
} catch (e: Exception) {
e.printStackTrace()
}
if (lyrics.isNullOrEmpty()) {
binding.noLyricsFound.visibility = View.VISIBLE
} else {
binding.noLyricsFound.visibility = View.GONE
}
binding.normalLyrics.text = lyrics
}
override fun onPlayingMetaChanged() {
super.onPlayingMetaChanged()
loadNormalLyrics()
}
override fun onServiceConnected() {
super.onServiceConnected()
loadNormalLyrics()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
class SyncedLyrics : AbsMusicServiceFragment(R.layout.fragment_synced_lyrics),
MusicProgressViewUpdateHelper.Callback {
private var _binding: FragmentSyncedLyricsBinding? = null
private val binding get() = _binding!!
private lateinit var updateHelper: MusicProgressViewUpdateHelper
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
updateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
_binding = FragmentSyncedLyricsBinding.bind(view)
setupLyricsView()
loadLRCLyrics()
super.onViewCreated(view, savedInstanceState)
}
fun loadLRCLyrics() {
binding.lyricsView.setLabel("Empty")
val song = MusicPlayerRemote.currentSong
if (LyricUtil.isLrcOriginalFileExist(song.data)) {
binding.lyricsView.loadLrc(LyricUtil.getLocalLyricOriginalFile(song.data))
} else if (LyricUtil.isLrcFileExist(song.title, song.artistName)) {
binding.lyricsView.loadLrc(LyricUtil.getLocalLyricFile(song.title, song.artistName))
}
}
private fun setupLyricsView() {
binding.lyricsView.apply {
setCurrentColor(ThemeStore.accentColor(context))
setTimeTextColor(ThemeStore.accentColor(context))
setTimelineColor(ThemeStore.accentColor(context))
setTimelineTextColor(ThemeStore.accentColor(context))
setDraggable(true, LrcView.OnPlayClickListener {
MusicPlayerRemote.seekTo(it.toInt())
return@OnPlayClickListener true
})
}
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
binding.lyricsView.updateTime(progress.toLong())
}
override fun onPlayingMetaChanged() {
super.onPlayingMetaChanged()
loadLRCLyrics()
}
override fun onServiceConnected() {
super.onServiceConnected()
loadLRCLyrics()
}
override fun onResume() {
super.onResume()
updateHelper.start()
}
override fun onPause() {
super.onPause()
updateHelper.stop()
}
}
}

View file

@ -20,38 +20,15 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.view.View
import androidx.lifecycle.lifecycleScope
import androidx.navigation.ui.NavigationUI
import code.name.monkey.retromusic.ADAPTIVE_COLOR_APP
import code.name.monkey.retromusic.ALBUM_COVER_STYLE
import code.name.monkey.retromusic.ALBUM_COVER_TRANSFORM
import code.name.monkey.retromusic.BANNER_IMAGE_PATH
import code.name.monkey.retromusic.BLACK_THEME
import code.name.monkey.retromusic.CAROUSEL_EFFECT
import code.name.monkey.retromusic.CIRCULAR_ALBUM_ART
import code.name.monkey.retromusic.DESATURATED_COLOR
import code.name.monkey.retromusic.EXTRA_SONG_INFO
import code.name.monkey.retromusic.GENERAL_THEME
import code.name.monkey.retromusic.HOME_ARTIST_GRID_STYLE
import code.name.monkey.retromusic.KEEP_SCREEN_ON
import code.name.monkey.retromusic.LANGUAGE_NAME
import code.name.monkey.retromusic.LIBRARY_CATEGORIES
import code.name.monkey.retromusic.NOW_PLAYING_SCREEN_ID
import code.name.monkey.retromusic.PROFILE_IMAGE_PATH
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.ROUND_CORNERS
import code.name.monkey.retromusic.TAB_TEXT_MODE
import code.name.monkey.retromusic.TOGGLE_ADD_CONTROLS
import code.name.monkey.retromusic.TOGGLE_FULL_SCREEN
import code.name.monkey.retromusic.TOGGLE_GENRE
import code.name.monkey.retromusic.TYPE_HOME_BANNER
import code.name.monkey.retromusic.TOGGLE_SEPARATE_LINE
import code.name.monkey.retromusic.TOGGLE_VOLUME
import code.name.monkey.retromusic.USER_NAME
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import androidx.navigation.ui.setupWithNavController
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.activities.base.AbsCastActivity
import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding
import code.name.monkey.retromusic.extensions.extra
import code.name.monkey.retromusic.extensions.findNavController
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
import code.name.monkey.retromusic.fragments.home.HomeFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs
import code.name.monkey.retromusic.model.CategoryInfo
@ -64,13 +41,13 @@ import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import org.koin.android.ext.android.get
class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener {
class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
companion object {
const val TAG = "MainActivity"
const val EXPAND_PANEL = "expand_panel"
}
override fun createContentView(): View {
override fun createContentView(): SlidingMusicPanelLayoutBinding {
return wrapSlidingMusicPanel()
}
@ -98,10 +75,50 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
val categoryInfo: CategoryInfo = PreferenceUtil.libraryCategory.first { it.visible }
if (categoryInfo.visible) {
navGraph.startDestination = categoryInfo.category.id
navGraph.setStartDestination(
if (PreferenceUtil.rememberLastTab) {
PreferenceUtil.lastTab.let {
if (it == 0) {
categoryInfo.category.id
} else {
it
}
}
} else categoryInfo.category.id
)
}
navController.graph = navGraph
NavigationUI.setupWithNavController(getBottomNavigationView(), navController)
getBottomNavigationView().setupWithNavController(navController)
// Scroll Fragment to top
getBottomNavigationView().setOnItemReselectedListener {
supportFragmentManager.findFragmentById(R.id.fragment_container)?.childFragmentManager?.fragments?.get(0)
.also {
if (it is AbsRecyclerViewFragment<*, *>) {
it.scrollToTop()
}
if (it is HomeFragment) {
it.scrollToTop()
}
}
}
navController.addOnDestinationChangedListener { _, destination, _ ->
when (destination.id) {
R.id.action_home, R.id.action_song, R.id.action_album, R.id.action_artist, R.id.action_folder, R.id.action_playlist, R.id.action_genre -> {
// Save the last tab
if (PreferenceUtil.rememberLastTab) {
saveTab(destination.id)
}
// Show Bottom Navigation Bar
setBottomBarVisibility(true)
}
else -> setBottomBarVisibility(false) // Hide Bottom Navigation Bar
}
}
}
private fun saveTab(id: Int) {
PreferenceUtil.lastTab = id
}
override fun onSupportNavigateUp(): Boolean =
@ -112,6 +129,8 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
val expand = extra<Boolean>(EXPAND_PANEL).value ?: false
if (expand && PreferenceUtil.isExpandPanel) {
setBottomBarVisibility(false)
fromNotification = true
expandPanel()
intent.removeExtra(EXPAND_PANEL)
}
@ -123,7 +142,7 @@ class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeLis
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (key == GENERAL_THEME || key == BLACK_THEME || key == ADAPTIVE_COLOR_APP || key == USER_NAME || key == TOGGLE_FULL_SCREEN || key == TOGGLE_VOLUME || key == ROUND_CORNERS || key == CAROUSEL_EFFECT || key == NOW_PLAYING_SCREEN_ID || key == TOGGLE_GENRE || key == BANNER_IMAGE_PATH || key == PROFILE_IMAGE_PATH || key == CIRCULAR_ALBUM_ART || key == KEEP_SCREEN_ON || key == TOGGLE_SEPARATE_LINE || key == TYPE_HOME_BANNER || key == TOGGLE_ADD_CONTROLS || key == ALBUM_COVER_STYLE || key == HOME_ARTIST_GRID_STYLE || key == ALBUM_COVER_TRANSFORM || key == DESATURATED_COLOR || key == EXTRA_SONG_INFO || key == TAB_TEXT_MODE || key == LANGUAGE_NAME || key == LIBRARY_CATEGORIES) {
if (key == GENERAL_THEME || key == BLACK_THEME || key == ADAPTIVE_COLOR_APP || key == USER_NAME || key == TOGGLE_FULL_SCREEN || key == TOGGLE_VOLUME || key == ROUND_CORNERS || key == CAROUSEL_EFFECT || key == NOW_PLAYING_SCREEN_ID || key == TOGGLE_GENRE || key == BANNER_IMAGE_PATH || key == PROFILE_IMAGE_PATH || key == CIRCULAR_ALBUM_ART || key == KEEP_SCREEN_ON || key == TOGGLE_SEPARATE_LINE || key == TOGGLE_HOME_BANNER || key == TOGGLE_ADD_CONTROLS || key == ALBUM_COVER_STYLE || key == HOME_ARTIST_GRID_STYLE || key == ALBUM_COVER_TRANSFORM || key == DESATURATED_COLOR || key == EXTRA_SONG_INFO || key == TAB_TEXT_MODE || key == LANGUAGE_NAME || key == LIBRARY_CATEGORIES) {
postRecreate()
}
}

View file

@ -14,44 +14,51 @@
*/
package code.name.monkey.retromusic.activities
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.ColorStateList
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.View
import androidx.annotation.RequiresApi
import androidx.core.text.HtmlCompat
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.databinding.ActivityPermissionBinding
import code.name.monkey.retromusic.extensions.accentBackgroundColor
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.util.RingtoneManager
import kotlinx.android.synthetic.main.activity_permission.*
import kotlinx.android.synthetic.main.fragment_library.appNameText
class PermissionActivity : AbsMusicServiceActivity() {
private lateinit var binding: ActivityPermissionBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView((R.layout.activity_permission))
binding = ActivityPermissionBinding.inflate(layoutInflater)
setContentView(binding.root)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setLightNavigationBar(true)
setTaskDescriptionColorAuto()
setupTitle()
storagePermission.setButtonClick {
binding.storagePermission.setButtonClick {
requestPermissions()
}
if (VersionUtils.hasMarshmallow()) audioPermission.show()
audioPermission.setButtonClick {
if (VersionUtils.hasMarshmallow()) binding.audioPermission.show()
binding.audioPermission.setButtonClick {
if (RingtoneManager.requiresDialog(this@PermissionActivity)) {
val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS)
intent.data = Uri.parse("package:" + applicationContext.packageName)
startActivity(intent)
}
}
finish.accentBackgroundColor()
finish.setOnClickListener {
binding.finish.accentBackgroundColor()
binding.finish.setOnClickListener {
if (hasPermissions()) {
startActivity(
Intent(this, MainActivity::class.java).addFlags(
@ -71,6 +78,32 @@ class PermissionActivity : AbsMusicServiceActivity() {
"Hello there! <br>Welcome to <b>Retro <span style='color:$hexColor';>Music</span></b>",
HtmlCompat.FROM_HTML_MODE_COMPACT
)
appNameText.text = appName
binding.appNameText.text = appName
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onResume() {
if (hasStoragePermission()) {
binding.storagePermission.checkImage.visibility = View.VISIBLE
binding.storagePermission.checkImage.imageTintList =
ColorStateList.valueOf(ThemeStore.accentColor(this))
}
if (hasAudioPermission()) {
binding.audioPermission.checkImage.visibility = View.VISIBLE
binding.audioPermission.checkImage.imageTintList =
ColorStateList.valueOf(ThemeStore.accentColor(this))
}
super.onResume()
}
@RequiresApi(Build.VERSION_CODES.M)
private fun hasStoragePermission(): Boolean {
return checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
}
@RequiresApi(Build.VERSION_CODES.M)
private fun hasAudioPermission(): Boolean {
return Settings.System.canWrite(this)
}
}

View file

@ -24,6 +24,7 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
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.databinding.ActivityPlayingQueueBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -34,10 +35,10 @@ import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropM
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
import kotlinx.android.synthetic.main.activity_playing_queue.*
open class PlayingQueueActivity : AbsMusicServiceActivity() {
private lateinit var binding: ActivityPlayingQueueBinding
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
private var recyclerViewSwipeManager: RecyclerViewSwipeManager? = null
@ -56,7 +57,8 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_playing_queue)
binding = ActivityPlayingQueueBinding.inflate(layoutInflater)
setContentView(binding.root)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
@ -65,7 +67,7 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
setupToolbar()
setUpRecyclerView()
clearQueue.setOnClickListener {
binding.clearQueue.setOnClickListener {
MusicPlayerRemote.clearQueue()
}
checkForPadding()
@ -100,25 +102,25 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
linearLayoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = linearLayoutManager
recyclerView.adapter = wrappedAdapter
recyclerView.itemAnimator = animator
recyclerViewTouchActionGuardManager?.attachRecyclerView(recyclerView)
recyclerViewDragDropManager?.attachRecyclerView(recyclerView)
recyclerViewSwipeManager?.attachRecyclerView(recyclerView)
binding.recyclerView.layoutManager = linearLayoutManager
binding.recyclerView.adapter = wrappedAdapter
binding.recyclerView.itemAnimator = animator
recyclerViewTouchActionGuardManager?.attachRecyclerView(binding.recyclerView)
recyclerViewDragDropManager?.attachRecyclerView(binding.recyclerView)
recyclerViewSwipeManager?.attachRecyclerView(binding.recyclerView)
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy > 0) {
clearQueue.shrink()
binding.clearQueue.shrink()
} else if (dy < 0) {
clearQueue.extend()
binding.clearQueue.extend()
}
}
})
ThemedFastScroller.create(recyclerView)
ThemedFastScroller.create(binding.recyclerView)
}
private fun checkForPadding() {
@ -140,7 +142,7 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
}
private fun updateCurrentSong() {
toolbar.subtitle = getUpNextAndQueueTime()
binding.toolbar.subtitle = getUpNextAndQueueTime()
}
override fun onPlayingMetaChanged() {
@ -150,7 +152,7 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
private fun updateQueuePosition() {
playingQueueAdapter?.setCurrent(MusicPlayerRemote.position)
resetToCurrentPosition()
toolbar.subtitle = getUpNextAndQueueTime()
binding.toolbar.subtitle = getUpNextAndQueueTime()
}
private fun updateQueue() {
@ -159,7 +161,7 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
}
private fun resetToCurrentPosition() {
recyclerView.stopScroll()
binding.recyclerView.stopScroll()
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}
@ -188,15 +190,15 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
}
private fun setupToolbar() {
toolbar.subtitle = getUpNextAndQueueTime()
toolbar.setBackgroundColor(surfaceColor())
setSupportActionBar(toolbar)
clearQueue.backgroundTintList = ColorStateList.valueOf(accentColor())
binding.toolbar.subtitle = getUpNextAndQueueTime()
binding.toolbar.setBackgroundColor(surfaceColor())
setSupportActionBar(binding.toolbar)
binding.clearQueue.backgroundTintList = ColorStateList.valueOf(accentColor())
ColorStateList.valueOf(
MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(accentColor()))
).apply {
clearQueue.setTextColor(this)
clearQueue.iconTint = this
binding.clearQueue.setTextColor(this)
binding.clearQueue.iconTint = this
}
}
}

View file

@ -29,43 +29,45 @@ import code.name.monkey.retromusic.BuildConfig
import code.name.monkey.retromusic.Constants.PRO_VERSION_PRODUCT_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.databinding.ActivityProVersionBinding
import com.anjlab.android.iab.v3.BillingProcessor
import com.anjlab.android.iab.v3.TransactionDetails
import java.lang.ref.WeakReference
import kotlinx.android.synthetic.main.activity_pro_version.*
class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
private lateinit var binding: ActivityProVersionBinding
private lateinit var billingProcessor: BillingProcessor
private var restorePurchaseAsyncTask: AsyncTask<*, *, *>? = null
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pro_version)
binding = ActivityProVersionBinding.inflate(layoutInflater)
setContentView(binding.root)
setStatusbarColor(Color.TRANSPARENT)
setLightStatusbar(false)
setNavigationbarColor(Color.BLACK)
setLightNavigationBar(false)
toolbar.navigationIcon?.setTint(Color.WHITE)
toolbar.setNavigationOnClickListener { onBackPressed() }
binding.toolbar.navigationIcon?.setTint(Color.WHITE)
binding.toolbar.setNavigationOnClickListener { onBackPressed() }
restoreButton.isEnabled = false
purchaseButton.isEnabled = false
binding.restoreButton.isEnabled = false
binding.purchaseButton.isEnabled = false
billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this)
MaterialUtil.setTint(purchaseButton, true)
MaterialUtil.setTint(binding.purchaseButton, true)
restoreButton.setOnClickListener {
binding.restoreButton.setOnClickListener {
if (restorePurchaseAsyncTask == null || restorePurchaseAsyncTask!!.status != AsyncTask.Status.RUNNING) {
restorePurchase()
}
}
purchaseButton.setOnClickListener {
binding.purchaseButton.setOnClickListener {
billingProcessor.purchase(this@PurchaseActivity, PRO_VERSION_PRODUCT_ID)
}
bannerContainer.backgroundTintList =
binding.bannerContainer.backgroundTintList =
ColorStateList.valueOf(ThemeStore.accentColor(this))
}
@ -99,8 +101,8 @@ class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
}
override fun onBillingInitialized() {
restoreButton.isEnabled = true
purchaseButton.isEnabled = true
binding.restoreButton.isEnabled = true
binding.purchaseButton.isEnabled = true
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

View file

@ -23,16 +23,19 @@ import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.databinding.ActivitySettingsBinding
import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.extensions.findNavController
import com.afollestad.materialdialogs.color.ColorChooserDialog
import kotlinx.android.synthetic.main.activity_settings.*
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.color.ColorCallback
class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
class SettingsActivity : AbsBaseActivity(), ColorCallback {
private lateinit var binding: ActivitySettingsBinding
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding.root)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setLightNavigationBar(true)
@ -41,10 +44,11 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
private fun setupToolbar() {
setTitle(R.string.action_settings)
applyToolbar(toolbar)
applyToolbar(binding.toolbar)
val navController: NavController = findNavController(R.id.contentFrame)
navController.addOnDestinationChangedListener { _, _, _ ->
toolbar.title = navController.currentDestination?.let { getStringFromDestination(it) }
binding.toolbar.title =
navController.currentDestination?.let { getStringFromDestination(it) }
}
}
@ -68,24 +72,18 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
return findNavController(R.id.contentFrame).navigateUp() || super.onSupportNavigateUp()
}
override fun onColorSelection(dialog: ColorChooserDialog, selectedColor: Int) {
when (dialog.title) {
R.string.accent_color -> {
ThemeStore.editTheme(this).accentColor(selectedColor).commit()
if (VersionUtils.hasNougatMR())
DynamicShortcutManager(this).updateDynamicShortcuts()
}
}
recreate()
}
override fun onColorChooserDismissed(dialog: ColorChooserDialog) {
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
}
return super.onOptionsItemSelected(item)
}
override fun invoke(dialog: MaterialDialog, color: Int) {
ThemeStore.editTheme(this).accentColor(color).commit()
if (VersionUtils.hasNougatMR())
DynamicShortcutManager(this).updateDynamicShortcuts()
recreate()
}
}

View file

@ -26,15 +26,14 @@ import androidx.core.view.drawToBitmap
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.databinding.ActivityShareInstagramBinding
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.Share
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.activity_share_instagram.*
/**
* Created by hemanths on 2020-02-02.
@ -42,6 +41,8 @@ import kotlinx.android.synthetic.main.activity_share_instagram.*
class ShareInstagramStory : AbsBaseActivity() {
private lateinit var binding: ActivityShareInstagramBinding
companion object {
const val EXTRA_SONG = "extra_song"
}
@ -57,32 +58,33 @@ class ShareInstagramStory : AbsBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_share_instagram)
binding = ActivityShareInstagramBinding.inflate(layoutInflater)
setContentView(binding.root)
setStatusbarColor(Color.TRANSPARENT)
setNavigationbarColor(Color.BLACK)
toolbar.setBackgroundColor(Color.TRANSPARENT)
setSupportActionBar(toolbar)
binding.toolbar.setBackgroundColor(Color.TRANSPARENT)
setSupportActionBar(binding.toolbar)
val song = intent.extras?.getParcelable<Song>(EXTRA_SONG)
song?.let { songFinal ->
SongGlideRequest.Builder.from(Glide.with(this), songFinal)
.checkIgnoreMediaStore(this@ShareInstagramStory)
.generatePalette(this@ShareInstagramStory)
.build()
.into(object : RetroMusicColoredTarget(image) {
GlideApp.with(this)
.asBitmapPalette()
.songCoverOptions(songFinal)
.load(RetroGlideExtension.getSongModel(songFinal))
.into(object : RetroMusicColoredTarget(binding.image) {
override fun onColorReady(colors: MediaNotificationProcessor) {
val isColorLight = ColorUtil.isColorLight(colors.backgroundColor)
setColors(isColorLight, colors.backgroundColor)
}
})
shareTitle.text = songFinal.title
shareText.text = songFinal.artistName
shareButton.setOnClickListener {
binding.shareTitle.text = songFinal.title
binding.shareText.text = songFinal.artistName
binding.shareButton.setOnClickListener {
val path: String = Media.insertImage(
contentResolver,
mainContent.drawToBitmap(Bitmap.Config.ARGB_8888),
binding.mainContent.drawToBitmap(Bitmap.Config.ARGB_8888),
"Design", null
)
val uri = Uri.parse(path)
@ -92,24 +94,25 @@ class ShareInstagramStory : AbsBaseActivity() {
)
}
}
shareButton.setTextColor(
binding.shareButton.setTextColor(
MaterialValueHelper.getPrimaryTextColor(
this,
ColorUtil.isColorLight(ThemeStore.accentColor(this))
)
)
shareButton.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
binding.shareButton.backgroundTintList =
ColorStateList.valueOf(ThemeStore.accentColor(this))
}
private fun setColors(colorLight: Boolean, color: Int) {
setLightStatusbar(colorLight)
toolbar.setTitleTextColor(
binding.toolbar.setTitleTextColor(
MaterialValueHelper.getPrimaryTextColor(
this@ShareInstagramStory,
colorLight
)
)
toolbar.navigationIcon?.setTintList(
binding.toolbar.navigationIcon?.setTintList(
ColorStateList.valueOf(
MaterialValueHelper.getPrimaryTextColor(
this@ShareInstagramStory,
@ -117,7 +120,7 @@ class ShareInstagramStory : AbsBaseActivity() {
)
)
)
mainContent.background =
binding.mainContent.background =
GradientDrawable(
GradientDrawable.Orientation.TOP_BOTTOM,
intArrayOf(color, Color.BLACK)

View file

@ -37,6 +37,7 @@ import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
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.databinding.ActivityDonationBinding
import code.name.monkey.retromusic.extensions.textColorPrimary
import code.name.monkey.retromusic.extensions.textColorSecondary
import com.anjlab.android.iab.v3.BillingProcessor
@ -44,10 +45,11 @@ import com.anjlab.android.iab.v3.SkuDetails
import com.anjlab.android.iab.v3.TransactionDetails
import java.lang.ref.WeakReference
import java.util.*
import kotlinx.android.synthetic.main.activity_donation.*
class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
lateinit var binding: ActivityDonationBinding
companion object {
val TAG: String = SupportDevelopmentActivity::class.java.simpleName
const val DONATION_PRODUCT_IDS = R.array.donation_ids
@ -72,6 +74,7 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDonationBinding.inflate(layoutInflater)
setContentView(R.layout.activity_donation)
setStatusbarColorAuto()
@ -82,15 +85,15 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
setupToolbar()
billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this)
TintHelper.setTint(progress, ThemeStore.accentColor(this))
donation.setTextColor(ThemeStore.accentColor(this))
TintHelper.setTint(binding.progress, ThemeStore.accentColor(this))
binding.donation.setTextColor(ThemeStore.accentColor(this))
}
private fun setupToolbar() {
val toolbarColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
toolbar.setBackgroundColor(toolbarColor)
ToolbarContentTintHelper.colorBackButton(toolbar)
setSupportActionBar(toolbar)
binding.toolbar.setBackgroundColor(toolbarColor)
ToolbarContentTintHelper.colorBackButton(binding.toolbar)
setSupportActionBar(binding.toolbar)
}
override fun onBillingInitialized() {
@ -146,8 +149,8 @@ private class SkuDetailsLoadAsyncTask(supportDevelopmentActivity: SupportDevelop
super.onPreExecute()
val supportDevelopmentActivity = weakReference.get() ?: return
supportDevelopmentActivity.progressContainer.visibility = View.VISIBLE
supportDevelopmentActivity.recyclerView.visibility = View.GONE
supportDevelopmentActivity.binding.progressContainer.visibility = View.VISIBLE
supportDevelopmentActivity.binding.recyclerView.visibility = View.GONE
}
override fun doInBackground(vararg params: Void): List<SkuDetails>? {
@ -166,15 +169,17 @@ private class SkuDetailsLoadAsyncTask(supportDevelopmentActivity: SupportDevelop
val dialog = weakReference.get() ?: return
if (skuDetails == null || skuDetails.isEmpty()) {
dialog.progressContainer.visibility = View.GONE
dialog.binding.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.binding.progressContainer.visibility = View.GONE
dialog.binding.recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = GridLayoutManager(dialog, 2)
adapter = SkuDetailsAdapter(dialog, skuDetails)
visibility = View.VISIBLE
}
}
}

View file

@ -27,54 +27,58 @@ import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
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.databinding.ActivityUserInfoBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.glide.ProfileBannerGlideRequest
import code.name.monkey.retromusic.glide.UserProfileGlideRequest
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.github.dhaval2404.imagepicker.ImagePicker
import com.github.dhaval2404.imagepicker.constant.ImageProvider
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import kotlinx.android.synthetic.main.activity_user_info.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
class UserInfoActivity : AbsBaseActivity() {
private lateinit var binding: ActivityUserInfoBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user_info)
binding = ActivityUserInfoBinding.inflate(layoutInflater)
setContentView(binding.root)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
applyToolbar(toolbar)
applyToolbar(binding.toolbar)
nameContainer.accentColor()
name.setText(PreferenceUtil.userName)
binding.nameContainer.accentColor()
binding.name.setText(PreferenceUtil.userName)
userImage.setOnClickListener {
binding.userImage.setOnClickListener {
pickNewPhoto()
}
bannerImage.setOnClickListener {
binding.bannerImage.setOnClickListener {
selectBannerImage()
}
next.setOnClickListener {
val nameString = name.text.toString().trim { it <= ' ' }
binding.next.setOnClickListener {
val nameString = binding.name.text.toString().trim { it <= ' ' }
if (TextUtils.isEmpty(nameString)) {
Toast.makeText(this, "Umm you're name can't be empty!", Toast.LENGTH_SHORT).show()
return@setOnClickListener
@ -86,23 +90,24 @@ class UserInfoActivity : AbsBaseActivity() {
val textColor =
MaterialValueHelper.getPrimaryTextColor(this, ColorUtil.isColorLight(accentColor()))
next.backgroundTintList = ColorStateList.valueOf(accentColor())
next.iconTint = ColorStateList.valueOf(textColor)
next.setTextColor(textColor)
binding.next.backgroundTintList = ColorStateList.valueOf(accentColor())
binding.next.iconTint = ColorStateList.valueOf(textColor)
binding.next.setTextColor(textColor)
loadProfile()
}
private fun loadProfile() {
bannerImage?.let {
ProfileBannerGlideRequest.Builder.from(
Glide.with(this),
ProfileBannerGlideRequest.getBannerModel()
).build().into(it)
binding.bannerImage.let {
GlideApp.with(this)
.asBitmap()
.load(RetroGlideExtension.getBannerModel())
.profileBannerOptions(RetroGlideExtension.getBannerModel())
.into(it)
}
UserProfileGlideRequest.Builder.from(
Glide.with(this),
UserProfileGlideRequest.getUserModel()
).build().into(userImage)
GlideApp.with(this).asBitmap()
.load(RetroGlideExtension.getUserModel())
.userProfileOptions(RetroGlideExtension.getUserModel())
.into(binding.userImage)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -145,31 +150,31 @@ class UserInfoActivity : AbsBaseActivity() {
private fun setAndSaveBannerImage(fileUri: Uri) {
Glide.with(this)
.load(fileUri)
.asBitmap()
.load(fileUri)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.listener(object : RequestListener<Any, Bitmap> {
override fun onException(
e: java.lang.Exception?,
model: Any?,
target: Target<Bitmap>?,
isFirstResource: Boolean
): Boolean {
return false
}
.listener(object : RequestListener<Bitmap> {
override fun onResourceReady(
resource: Bitmap?,
model: Any?,
target: Target<Bitmap>?,
isFromMemoryCache: Boolean,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
resource?.let { saveImage(it, USER_BANNER) }
return false
}
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Bitmap>?,
isFirstResource: Boolean
): Boolean {
return false
}
})
.into(bannerImage)
.into(binding.bannerImage)
}
private fun saveImage(bitmap: Bitmap, fileName: String) {
@ -195,31 +200,31 @@ class UserInfoActivity : AbsBaseActivity() {
private fun setAndSaveUserImage(fileUri: Uri) {
Glide.with(this)
.load(fileUri)
.asBitmap()
.load(fileUri)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.listener(object : RequestListener<Any, Bitmap> {
override fun onException(
e: java.lang.Exception?,
model: Any?,
target: Target<Bitmap>?,
isFirstResource: Boolean
): Boolean {
return false
}
.listener(object : RequestListener<Bitmap> {
override fun onResourceReady(
resource: Bitmap?,
model: Any?,
target: Target<Bitmap>?,
isFromMemoryCache: Boolean,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
resource?.let { saveImage(it, USER_PROFILE) }
return false
}
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Bitmap>?,
isFirstResource: Boolean
): Boolean {
return false
}
})
.into(userImage)
.into(binding.userImage)
}
companion object {

View file

@ -5,34 +5,40 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.webkit.WebView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
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.ToolbarContentTintHelper;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.activities.base.AbsBaseActivity;
import code.name.monkey.retromusic.util.PreferenceUtil;
import androidx.core.widget.NestedScrollView;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
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.ToolbarContentTintHelper;
import code.name.monkey.retromusic.Constants;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.activities.base.AbsBaseActivity;
import code.name.monkey.retromusic.databinding.ActivityWhatsNewBinding;
import code.name.monkey.retromusic.extensions.ColorExtKt;
import code.name.monkey.retromusic.util.PreferenceUtil;
import code.name.monkey.retromusic.util.RetroUtil;
public class WhatsNewActivity extends AbsBaseActivity {
private static String colorToCSS(int color) {
return String.format(
Locale.getDefault(),
"rgba(%d, %d, %d, %d)",
Color.red(color),
Color.green(color),
Color.blue(color),
Color.alpha(color)); // on API 29, WebView doesn't load with hex colors
Locale.getDefault(),
"rgba(%d, %d, %d, %d)",
Color.red(color),
Color.green(color),
Color.blue(color),
Color.alpha(color)); // on API 29, WebView doesn't load with hex colors
}
private static void setChangelogRead(@NonNull Context context) {
@ -49,16 +55,15 @@ public class WhatsNewActivity extends AbsBaseActivity {
protected void onCreate(@Nullable Bundle savedInstanceState) {
setDrawUnderStatusBar();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_whats_new);
ActivityWhatsNewBinding binding = ActivityWhatsNewBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setStatusbarColorAuto();
setNavigationbarColorAuto();
setTaskDescriptionColorAuto();
WebView webView = findViewById(R.id.webView);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setBackgroundColor(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface));
toolbar.setNavigationOnClickListener(v -> onBackPressed());
ToolbarContentTintHelper.colorBackButton(toolbar);
binding.toolbar.setBackgroundColor(ATHUtil.INSTANCE.resolveColor(this, R.attr.colorSurface));
binding.toolbar.setNavigationOnClickListener(v -> onBackPressed());
ToolbarContentTintHelper.colorBackButton(binding.toolbar);
try {
StringBuilder buf = new StringBuilder();
@ -74,38 +79,50 @@ public class WhatsNewActivity extends AbsBaseActivity {
final boolean isDark = ATHUtil.INSTANCE.isWindowBackgroundDark(this);
final int accentColor = ThemeStore.Companion.accentColor(this);
final String backgroundColor =
colorToCSS(
ATHUtil.INSTANCE.resolveColor(
this, R.attr.colorSurface, Color.parseColor(isDark ? "#424242" : "#ffffff")));
colorToCSS(
ATHUtil.INSTANCE.resolveColor(
this, R.attr.colorSurface, Color.parseColor(isDark ? "#424242" : "#ffffff")));
final String contentColor = colorToCSS(Color.parseColor(isDark ? "#ffffff" : "#000000"));
final String textColor = colorToCSS(Color.parseColor(isDark ? "#60FFFFFF" : "#80000000"));
final String accentColorString = colorToCSS(ThemeStore.Companion.accentColor(this));
final String cardBackgroundColor = colorToCSS(Color.parseColor(isDark ? "#353535" : "#ffffff"));
final String accentTextColor =
colorToCSS(
MaterialValueHelper.getPrimaryTextColor(
this, ColorUtil.INSTANCE.isColorLight(accentColor)));
colorToCSS(
MaterialValueHelper.getPrimaryTextColor(
this, ColorUtil.INSTANCE.isColorLight(accentColor)));
final String changeLog =
buf.toString()
.replace(
"{style-placeholder}",
String.format(
"body { background-color: %s; color: %s; } li {color: %s;} .colorHeader {background-color: %s; color: %s;} .tag {color: %s;}",
backgroundColor,
contentColor,
textColor,
accentColorString,
accentTextColor,
accentColorString))
.replace("{link-color}", colorToCSS(ThemeStore.Companion.accentColor(this)))
.replace(
"{link-color-active}",
colorToCSS(
ColorUtil.INSTANCE.lightenColor(ThemeStore.Companion.accentColor(this))));
webView.loadData(changeLog, "text/html", "UTF-8");
buf.toString()
.replace(
"{style-placeholder}",
String.format(
"body { background-color: %s; color: %s; } li {color: %s;} h3 {color: %s;} .tag {color: %s;} div{background-color: %s;}",
backgroundColor,
contentColor,
textColor,
accentColorString,
accentColorString,
cardBackgroundColor))
.replace("{link-color}", colorToCSS(ThemeStore.Companion.accentColor(this)))
.replace(
"{link-color-active}",
colorToCSS(
ColorUtil.INSTANCE.lightenColor(ThemeStore.Companion.accentColor(this))));
binding.webView.loadData(changeLog, "text/html", "UTF-8");
} catch (Throwable e) {
webView.loadData(
"<h1>Unable to load</h1><p>" + e.getLocalizedMessage() + "</p>", "text/html", "UTF-8");
binding.webView.loadData(
"<h1>Unable to load</h1><p>" + e.getLocalizedMessage() + "</p>", "text/html", "UTF-8");
}
setChangelogRead(this);
binding.tgFab.setOnClickListener(v -> RetroUtil.openUrl(this, Constants.TELEGRAM_CHANGE_LOG));
ColorExtKt.accentColor(binding.tgFab);
binding.tgFab.shrink();
binding.container.setOnScrollChangeListener((NestedScrollView.OnScrollChangeListener) (v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
int dy = scrollY - oldScrollY;
if (dy > 0) {
binding.tgFab.shrink();
} else if (dy < 0) {
binding.tgFab.extend();
}
});
}
}

View file

@ -0,0 +1,141 @@
package code.name.monkey.retromusic.activities.base
import android.os.Bundle
import android.view.ViewStub
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.cast.CastHelper
import code.name.monkey.retromusic.cast.RetroSessionManager
import code.name.monkey.retromusic.cast.RetroWebServer
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import com.google.android.gms.cast.framework.CastContext
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import java.util.*
abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
private var mCastSession: CastSession? = null
private lateinit var castContext: CastContext
private var webServer: RetroWebServer? = null
private var playServicesAvailable: Boolean = false
private val sessionManagerListener by lazy {
object : RetroSessionManager {
override fun onSessionStarting(castSession: CastSession) {
invalidateOptionsMenu()
webServer = RetroWebServer.getInstance(this@AbsCastActivity)
webServer?.start()
}
override fun onSessionStarted(castSession: CastSession, p1: String) {
invalidateOptionsMenu()
mCastSession = castSession
loadCastQueue(MusicPlayerRemote.position)
inflateCastController()
MusicPlayerRemote.isCasting = true
setAllowDragging(false)
collapsePanel()
}
override fun onSessionEnding(p0: CastSession) {
invalidateOptionsMenu()
webServer?.stop()
}
override fun onSessionEnded(castSession: CastSession, p1: Int) {
invalidateOptionsMenu()
if (mCastSession == castSession) {
mCastSession = null
}
MusicPlayerRemote.isCasting = false
setAllowDragging(true)
}
override fun onSessionResumed(castSession: CastSession, p1: Boolean) {
invalidateOptionsMenu()
mCastSession = castSession
loadCastQueue(MusicPlayerRemote.position)
inflateCastController()
MusicPlayerRemote.isCasting = true
setAllowDragging(false)
collapsePanel()
}
override fun onSessionSuspended(castSession: CastSession, p1: Int) {
invalidateOptionsMenu()
if (mCastSession == castSession) {
mCastSession = null
}
MusicPlayerRemote.isCasting = false
setAllowDragging(true)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
playServicesAvailable = try {
GoogleApiAvailability
.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS
} catch (e: Exception) {
false
}
if (playServicesAvailable) {
setupCast()
}
}
private fun setupCast() {
castContext = CastContext.getSharedInstance(this)
}
override fun onResume() {
if (playServicesAvailable) {
castContext.sessionManager.addSessionManagerListener(
sessionManagerListener,
CastSession::class.java
)
if (mCastSession == null) {
mCastSession = castContext.sessionManager.currentCastSession
}
}
super.onResume()
}
override fun onStop() {
super.onStop()
mCastSession = null
}
private fun songChanged(position: Int) {
loadCastQueue(position)
}
fun loadCastQueue(position: Int) {
if (!MusicPlayerRemote.playingQueue.isNullOrEmpty()) {
mCastSession?.let {
CastHelper.castQueue(
it,
MusicPlayerRemote.playingQueue,
position,
MusicPlayerRemote.songProgressMillis.toLong()
)
}
} else {
mCastSession?.let { CastHelper.castSong(it, MusicPlayerRemote.currentSong) }
}
}
override fun onPlayingMetaChanged() {
super.onPlayingMetaChanged()
if (playServicesAvailable) {
songChanged(MusicPlayerRemote.position)
}
}
fun inflateCastController() {
findViewById<ViewStub>(R.id.cast_stub)?.inflate()
}
}

View file

@ -15,12 +15,7 @@
package code.name.monkey.retromusic.activities.base
import android.Manifest
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.ServiceConnection
import android.content.*
import android.os.Bundle
import android.os.IBinder
import androidx.lifecycle.lifecycleScope
@ -30,11 +25,11 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.service.MusicService.*
import java.lang.ref.WeakReference
import java.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import java.lang.ref.WeakReference
import java.util.*
abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventListener {
@ -166,6 +161,12 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventLi
}
}
override fun onFavoriteStateChanged() {
for (listener in mMusicServiceEventListeners) {
listener.onFavoriteStateChanged()
}
}
override fun onHasPermissionsChanged(hasPermissions: Boolean) {
super.onHasPermissionsChanged(hasPermissions)
val intent = Intent(MEDIA_STORE_CHANGED)
@ -194,7 +195,8 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventLi
val activity = reference.get()
if (activity != null && action != null) {
when (action) {
FAVORITE_STATE_CHANGED, META_CHANGED -> activity.onPlayingMetaChanged()
FAVORITE_STATE_CHANGED -> activity.onFavoriteStateChanged()
META_CHANGED -> activity.onPlayingMetaChanged()
QUEUE_CHANGED -> activity.onQueueChanged()
PLAY_STATE_CHANGED -> activity.onPlayStateChanged()
REPEAT_MODE_CHANGED -> activity.onRepeatModeChanged()

View file

@ -14,7 +14,6 @@
*/
package code.name.monkey.retromusic.activities.base
import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Bundle
import android.view.View
@ -29,6 +28,8 @@ import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.RetroBottomSheetBehavior
import code.name.monkey.retromusic.databinding.ActivityMainContentBinding
import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.MiniPlayerFragment
@ -57,12 +58,12 @@ import code.name.monkey.retromusic.model.CategoryInfo
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.views.BottomNavigationBarTinted
import com.google.android.material.bottomsheet.BottomSheetBehavior.*
import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
import org.koin.androidx.viewmodel.ext.android.viewModel
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
companion object {
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
var fromNotification: Boolean = false
}
protected val libraryViewModel by viewModel<LibraryViewModel>()
@ -75,16 +76,17 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
private var lightStatusBar: Boolean = false
private var lightNavigationBar: Boolean = false
private var paletteColor: Int = Color.WHITE
protected abstract fun createContentView(): View
protected abstract fun createContentView(): SlidingMusicPanelLayoutBinding
private val panelState: Int
get() = bottomSheetBehavior.state
private lateinit var binding: SlidingMusicPanelLayoutBinding
private val bottomSheetCallbackList = object : BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
setMiniPlayerAlphaProgress(slideOffset)
dimBackground.show()
dimBackground.alpha = slideOffset
binding.dimBackground.show()
binding.dimBackground.alpha = slideOffset
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
@ -94,9 +96,17 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}
STATE_COLLAPSED -> {
onPanelCollapsed()
dimBackground.hide()
binding.dimBackground.hide()
if (fromNotification) {
hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
fromNotification = false
}
}
STATE_SETTLING, STATE_DRAGGING -> {
if (fromNotification) {
getBottomNavigationView().isVisible = true
}
}
else -> {
println("Do something")
}
@ -108,23 +118,25 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(createContentView())
binding = createContentView()
setContentView(binding.root)
chooseFragmentForTheme()
setupSlidingUpPanel()
setupBottomSheet()
updateColor()
val themeColor = resolveColor(android.R.attr.windowBackground, Color.GRAY)
dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
dimBackground.setOnClickListener {
binding.dimBackground.setBackgroundColor(ColorUtil.withAlpha(themeColor, 0.5f))
binding.dimBackground.setOnClickListener {
println("dimBackground")
collapsePanel()
}
}
private fun setupBottomSheet() {
bottomSheetBehavior = from(slidingPanel) as RetroBottomSheetBehavior
bottomSheetBehavior = from(binding.slidingPanel) as RetroBottomSheetBehavior
bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
bottomSheetBehavior.maxWidth = resources.displayMetrics.widthPixels
}
override fun onResume() {
@ -142,14 +154,13 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList)
}
@SuppressLint("InflateParams")
protected fun wrapSlidingMusicPanel(): View {
val slidingMusicPanelLayout =
layoutInflater.inflate(R.layout.sliding_music_panel_layout, null)
protected fun wrapSlidingMusicPanel(): SlidingMusicPanelLayoutBinding {
val slidingMusicPanelLayoutBinding =
SlidingMusicPanelLayoutBinding.inflate(layoutInflater)
val contentContainer: ViewGroup =
slidingMusicPanelLayout.findViewById(R.id.mainContentFrame)
layoutInflater.inflate(R.layout.activity_main_content, contentContainer)
return slidingMusicPanelLayout
slidingMusicPanelLayoutBinding.mainContentFrame
ActivityMainContentBinding.inflate(layoutInflater, contentContainer, true)
return slidingMusicPanelLayoutBinding
}
fun collapsePanel() {
@ -166,8 +177,8 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
val alpha = 1 - progress
miniPlayerFragment?.view?.alpha = alpha
miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE
bottomNavigationView.translationY = progress * 500
bottomNavigationView.alpha = alpha
binding.bottomNavigationView.translationY = progress * 500
binding.bottomNavigationView.alpha = alpha
}
open fun onPanelCollapsed() {
@ -183,14 +194,14 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}
private fun setupSlidingUpPanel() {
slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object :
binding.slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
binding.slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
if (nowPlayingScreen != Peak) {
val params = slidingPanel.layoutParams as ViewGroup.LayoutParams
val params = binding.slidingPanel.layoutParams as ViewGroup.LayoutParams
params.height = ViewGroup.LayoutParams.MATCH_PARENT
slidingPanel.layoutParams = params
binding.slidingPanel.layoutParams = params
}
when (panelState) {
STATE_EXPANDED -> onPanelExpanded()
@ -204,16 +215,16 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}
fun getBottomNavigationView(): BottomNavigationBarTinted {
return bottomNavigationView
return binding.bottomNavigationView
}
override fun onServiceConnected() {
super.onServiceConnected()
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object :
binding.slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
binding.slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
hideBottomBar(false)
}
})
@ -305,16 +316,17 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}
fun updateTabs() {
bottomNavigationView.menu.clear()
binding.bottomNavigationView.menu.clear()
val currentTabs: List<CategoryInfo> = PreferenceUtil.libraryCategory
for (tab in currentTabs) {
if (tab.visible) {
val menu = tab.category
bottomNavigationView.menu.add(0, menu.id, 0, menu.stringRes).setIcon(menu.icon)
binding.bottomNavigationView.menu.add(0, menu.id, 0, menu.stringRes)
.setIcon(menu.icon)
}
}
if (bottomNavigationView.menu.size() == 1) {
bottomNavigationView.hide()
if (binding.bottomNavigationView.menu.size() == 1) {
binding.bottomNavigationView.hide()
}
}
@ -326,28 +338,34 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}
fun setBottomBarVisibility(visible: Boolean) {
bottomNavigationView.isVisible = visible
binding.bottomNavigationView.isVisible = visible
hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
}
private fun hideBottomBar(hide: Boolean) {
val heightOfBar = dip(R.dimen.mini_player_height)
val heightOfBarWithTabs = heightOfBar * 2
val isVisible = bottomNavigationView.isVisible
val heightOfBar =
if (MusicPlayerRemote.isCasting) dip(R.dimen.cast_mini_player_height) else dip(R.dimen.mini_player_height)
val heightOfBarWithTabs =
if (MusicPlayerRemote.isCasting) dip(R.dimen.mini_cast_player_height_expanded) else dip(
R.dimen.mini_player_height_expanded
)
val isVisible = binding.bottomNavigationView.isVisible
if (hide) {
bottomSheetBehavior.isHideable = true
bottomSheetBehavior.peekHeight = 0
ViewCompat.setElevation(slidingPanel, 0f)
ViewCompat.setElevation(bottomNavigationView, 10f)
ViewCompat.setElevation(binding.slidingPanel, 0f)
ViewCompat.setElevation(binding.bottomNavigationView, 10f)
collapsePanel()
} else {
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
bottomSheetBehavior.isHideable = false
ViewCompat.setElevation(slidingPanel, 10f)
ViewCompat.setElevation(bottomNavigationView, 10f)
ViewCompat.setElevation(binding.slidingPanel, 10f)
ViewCompat.setElevation(binding.bottomNavigationView, 10f)
if (isVisible) {
println("List")
bottomSheetBehavior.peekHeight = heightOfBarWithTabs - 22
if (bottomSheetBehavior.state != STATE_EXPANDED)
getBottomNavigationView().translateYAnimate(0F)
bottomSheetBehavior.peekHeightAnimate(heightOfBarWithTabs)
} else {
println("Details")
bottomSheetBehavior.peekHeight = heightOfBar
@ -356,6 +374,11 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}
}
fun setAllowDragging(allowDragging: Boolean) {
bottomSheetBehavior.setAllowDragging(allowDragging)
hideBottomBar(false)
}
private fun chooseFragmentForTheme() {
nowPlayingScreen = PreferenceUtil.nowPlayingScreen

View file

@ -15,6 +15,7 @@
package code.name.monkey.retromusic.activities.base
import android.content.Context
import android.content.res.Resources
import android.graphics.Color
import android.os.Bundle
import android.os.Handler
@ -23,12 +24,12 @@ import android.view.View
import android.view.WindowManager
import androidx.annotation.ColorInt
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
import androidx.core.os.ConfigurationCompat
import code.name.monkey.appthemehelper.ATH
import code.name.monkey.appthemehelper.ThemeStore
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.MaterialDialogsUtil
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.LanguageContextWrapper
import code.name.monkey.retromusic.R
@ -48,7 +49,7 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
setImmersiveFullscreen()
registerSystemUiVisibility()
toggleScreenOn()
MaterialDialogsUtil.updateMaterialDialogsThemeSingleton(this)
//MaterialDialogsUtil.updateMaterialDialogsThemeSingleton(this)
}
private fun updateTheme() {
@ -213,8 +214,12 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
override fun attachBaseContext(newBase: Context?) {
val code = PreferenceUtil.languageCode
if (code != "auto") {
super.attachBaseContext(LanguageContextWrapper.wrap(newBase, Locale(code)))
} else super.attachBaseContext(newBase)
val locale = if (code == "auto") {
// Get the device default locale
ConfigurationCompat.getLocales(Resources.getSystem().configuration)[0]
} else {
Locale.forLanguageTag(code)
}
super.attachBaseContext(LanguageContextWrapper.wrap(newBase, locale))
}
}

View file

@ -41,18 +41,16 @@ 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.databinding.ActivityBugReportBinding
import code.name.monkey.retromusic.misc.DialogAsyncTask
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.textfield.TextInputLayout
import java.io.IOException
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.service.IssueService
import java.io.IOException
private const val RESULT_SUCCESS = "RESULT_OK"
private const val RESULT_BAD_CREDENTIALS = "RESULT_BAD_CREDENTIALS"
@ -72,12 +70,14 @@ private annotation class Result
open class BugReportActivity : AbsThemeActivity() {
private lateinit var binding: ActivityBugReportBinding
private var deviceInfo: DeviceInfo? = null
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bug_report)
binding = ActivityBugReportBinding.inflate(layoutInflater)
setContentView(binding.root)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
@ -87,50 +87,50 @@ open class BugReportActivity : AbsThemeActivity() {
if (TextUtils.isEmpty(title)) setTitle(R.string.report_an_issue)
deviceInfo = DeviceInfo(this)
airTextDeviceInfo.text = deviceInfo.toString()
binding.cardDeviceInfo.airTextDeviceInfo.text = deviceInfo.toString()
}
private fun initViews() {
val accentColor = ThemeStore.accentColor(this)
val primaryColor = ATHUtil.resolveColor(this, R.attr.colorSurface)
toolbar.setBackgroundColor(primaryColor)
setSupportActionBar(toolbar)
ToolbarContentTintHelper.colorBackButton(toolbar)
binding.toolbar.setBackgroundColor(primaryColor)
setSupportActionBar(binding.toolbar)
ToolbarContentTintHelper.colorBackButton(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
TintHelper.setTintAuto(optionUseAccount, accentColor, false)
optionUseAccount?.setOnClickListener {
inputTitle.isEnabled = true
inputDescription.isEnabled = true
inputUsername.isEnabled = true
inputPassword.isEnabled = true
TintHelper.setTintAuto(binding.cardReport.optionUseAccount, accentColor, false)
binding.cardReport.optionUseAccount.setOnClickListener {
binding.cardReport.inputTitle.isEnabled = true
binding.cardReport.inputDescription.isEnabled = true
binding.cardReport.inputUsername.isEnabled = true
binding.cardReport.inputPassword.isEnabled = true
optionAnonymous.isChecked = false
sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
binding.cardReport.optionAnonymous.isChecked = false
binding.sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab)
sendFab.setImageResource(R.drawable.ic_send)
sendFab.show()
binding.sendFab.setImageResource(R.drawable.ic_send)
binding.sendFab.show()
}
})
}
TintHelper.setTintAuto(optionAnonymous, accentColor, false)
optionAnonymous.setOnClickListener {
inputTitle.isEnabled = false
inputDescription.isEnabled = false
inputUsername.isEnabled = false
inputPassword.isEnabled = false
TintHelper.setTintAuto(binding.cardReport.optionAnonymous, accentColor, false)
binding.cardReport.optionAnonymous.setOnClickListener {
binding.cardReport.inputTitle.isEnabled = false
binding.cardReport.inputDescription.isEnabled = false
binding.cardReport.inputUsername.isEnabled = false
binding.cardReport.inputPassword.isEnabled = false
optionUseAccount.isChecked = false
sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
binding.cardReport.optionUseAccount.isChecked = false
binding.sendFab.hide(object : FloatingActionButton.OnVisibilityChangedListener() {
override fun onHidden(fab: FloatingActionButton?) {
super.onHidden(fab)
sendFab.setImageResource(R.drawable.ic_open_in_browser)
sendFab.show()
binding.sendFab.setImageResource(R.drawable.ic_open_in_browser)
binding.sendFab.show()
}
})
}
inputPassword.setOnEditorActionListener { _, actionId, _ ->
binding.cardReport.inputPassword.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEND) {
reportIssue()
return@setOnEditorActionListener true
@ -138,22 +138,22 @@ open class BugReportActivity : AbsThemeActivity() {
false
}
airTextDeviceInfo.setOnClickListener { copyDeviceInfoToClipBoard() }
binding.cardDeviceInfo.airTextDeviceInfo.setOnClickListener { copyDeviceInfoToClipBoard() }
TintHelper.setTintAuto(sendFab, accentColor, true)
sendFab.setOnClickListener { reportIssue() }
TintHelper.setTintAuto(binding.sendFab, accentColor, true)
binding.sendFab.setOnClickListener { reportIssue() }
MaterialUtil.setTint(inputLayoutTitle, false)
MaterialUtil.setTint(inputLayoutDescription, false)
MaterialUtil.setTint(inputLayoutUsername, false)
MaterialUtil.setTint(inputLayoutPassword, false)
MaterialUtil.setTint(binding.cardReport.inputLayoutTitle, false)
MaterialUtil.setTint(binding.cardReport.inputLayoutDescription, false)
MaterialUtil.setTint(binding.cardReport.inputLayoutUsername, false)
MaterialUtil.setTint(binding.cardReport.inputLayoutPassword, false)
}
private fun reportIssue() {
if (optionUseAccount.isChecked) {
if (binding.cardReport.optionUseAccount.isChecked) {
if (!validateInput()) return
val username = inputUsername.text.toString()
val password = inputPassword.text.toString()
val username = binding.cardReport.inputUsername.text.toString()
val password = binding.cardReport.inputPassword.text.toString()
sendBugReport(GithubLogin(username, password))
} else {
copyDeviceInfoToClipBoard()
@ -179,34 +179,34 @@ open class BugReportActivity : AbsThemeActivity() {
private fun validateInput(): Boolean {
var hasErrors = false
if (optionUseAccount.isChecked) {
if (TextUtils.isEmpty(inputUsername.text)) {
setError(inputLayoutUsername, R.string.bug_report_no_username)
if (binding.cardReport.optionUseAccount.isChecked) {
if (TextUtils.isEmpty(binding.cardReport.inputUsername.text)) {
setError(binding.cardReport.inputLayoutUsername, R.string.bug_report_no_username)
hasErrors = true
} else {
removeError(inputLayoutUsername)
removeError(binding.cardReport.inputLayoutUsername)
}
if (TextUtils.isEmpty(inputPassword.text)) {
setError(inputLayoutPassword, R.string.bug_report_no_password)
if (TextUtils.isEmpty(binding.cardReport.inputPassword.text)) {
setError(binding.cardReport.inputLayoutPassword, R.string.bug_report_no_password)
hasErrors = true
} else {
removeError(inputLayoutPassword)
removeError(binding.cardReport.inputLayoutPassword)
}
}
if (TextUtils.isEmpty(inputTitle.text)) {
setError(inputLayoutTitle, R.string.bug_report_no_title)
if (TextUtils.isEmpty(binding.cardReport.inputTitle.text)) {
setError(binding.cardReport.inputLayoutTitle, R.string.bug_report_no_title)
hasErrors = true
} else {
removeError(inputLayoutTitle)
removeError(binding.cardReport.inputLayoutTitle)
}
if (TextUtils.isEmpty(inputDescription.text)) {
setError(inputLayoutDescription, R.string.bug_report_no_description)
if (TextUtils.isEmpty(binding.cardReport.inputDescription.text)) {
setError(binding.cardReport.inputLayoutDescription, R.string.bug_report_no_description)
hasErrors = true
} else {
removeError(inputLayoutDescription)
removeError(binding.cardReport.inputLayoutDescription)
}
return !hasErrors
@ -223,8 +223,8 @@ open class BugReportActivity : AbsThemeActivity() {
private fun sendBugReport(login: GithubLogin) {
if (!validateInput()) return
val bugTitle = inputTitle.text.toString()
val bugDescription = inputDescription.text.toString()
val bugTitle = binding.cardReport.inputTitle.text.toString()
val bugDescription = binding.cardReport.inputDescription.text.toString()
val extraInfo = ExtraInfo()
onSaveExtraInfo()

View file

@ -5,11 +5,14 @@ import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.annotation.IntRange;
import code.name.monkey.retromusic.util.PreferenceUtil;
import java.util.Arrays;
import java.util.Locale;
import code.name.monkey.retromusic.util.PreferenceUtil;
public class DeviceInfo {
@SuppressLint("NewApi")

View file

@ -16,11 +16,14 @@ package code.name.monkey.retromusic.activities.saf;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.Nullable;
import code.name.monkey.retromusic.R;
import com.heinrichreimersoftware.materialintro.app.IntroActivity;
import com.heinrichreimersoftware.materialintro.slide.SimpleSlide;
import code.name.monkey.retromusic.R;
/** Created by hemanths on 2019-07-31. */
public class SAFGuideActivity extends IntroActivity {

View file

@ -22,10 +22,12 @@ import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.animation.OvershootInterpolator
import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
import androidx.viewbinding.ViewBinding
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.TintHelper
@ -41,7 +43,6 @@ import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.SAFUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import org.jaudiotagger.audio.AudioFile
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.tag.FieldKey
@ -49,7 +50,8 @@ import org.koin.android.ext.android.inject
import java.io.File
import java.util.*
abstract class AbsTagEditorActivity : AbsBaseActivity() {
abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
abstract val editorImage: ImageView?
val repository by inject<Repository>()
lateinit var saveFab: MaterialButton
@ -62,7 +64,11 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
private val currentSongPath: String? = null
private var savedTags: Map<FieldKey, String>? = null
private var savedArtworkInfo: ArtworkInfo? = null
protected abstract val contentViewLayout: Int
private var _binding: VB? = null
protected val binding: VB get() = _binding!!
abstract val bindingInflater: (LayoutInflater) -> VB
protected abstract fun loadImageFromFile(selectedFile: Uri?)
protected val show: AlertDialog
@ -187,7 +193,8 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(contentViewLayout)
_binding = bindingInflater.invoke(layoutInflater)
setContentView(binding.root)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
@ -284,10 +291,6 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
protected fun setNoImageMode() {
isInNoImageMode = true
imageContainer?.visibility = View.GONE
editorImage?.visibility = View.GONE
editorImage?.isEnabled = false
setColors(
intent.getIntExtra(
EXTRA_PALETTE,
@ -296,6 +299,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
)
}
protected fun dataChanged() {
showFab()
}
@ -314,9 +318,9 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) {
if (bitmap == null) {
editorImage.setImageResource(drawable.default_audio_art)
editorImage?.setImageResource(drawable.default_audio_art)
} else {
editorImage.setImageBitmap(bitmap)
editorImage?.setImageBitmap(bitmap)
}
setColors(bgColor)
}

View file

@ -25,30 +25,31 @@ import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.transition.Slide
import android.view.LayoutInflater
import android.widget.ImageView
import android.widget.Toast
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding
import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTranscoder
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.ArtworkInfo
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette
import code.name.monkey.retromusic.util.RetroColorUtil.getColor
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.animation.GlideAnimation
import com.bumptech.glide.request.target.SimpleTarget
import java.util.*
import kotlinx.android.synthetic.main.activity_album_tag_editor.*
import com.bumptech.glide.request.target.ImageViewTarget
import com.bumptech.glide.request.transition.Transition
import org.jaudiotagger.tag.FieldKey
import java.util.*
class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBinding>(), TextWatcher {
override val contentViewLayout: Int
get() = R.layout.activity_album_tag_editor
override val bindingInflater: (LayoutInflater) -> ActivityAlbumTagEditorBinding =
ActivityAlbumTagEditorBinding::inflate
private fun windowEnterTransition() {
val slide = Slide()
@ -62,20 +63,20 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
override fun loadImageFromFile(selectedFile: Uri?) {
Glide.with(this@AlbumTagEditorActivity).load(selectedFile).asBitmap()
.transcode(BitmapPaletteTranscoder(this), BitmapPaletteWrapper::class.java)
GlideApp.with(this@AlbumTagEditorActivity).asBitmapPalette().load(selectedFile)
.diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true)
.into(object : SimpleTarget<BitmapPaletteWrapper>() {
.into(object : ImageViewTarget<BitmapPaletteWrapper>(binding.editorImage) {
override fun onResourceReady(
resource: BitmapPaletteWrapper?,
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
) {
getColor(resource?.palette, Color.TRANSPARENT)
albumArtBitmap = resource?.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
getColor(resource.palette, Color.TRANSPARENT)
albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) }
setImageBitmap(
albumArtBitmap,
getColor(
resource?.palette,
resource.palette,
ATHUtil.resolveColor(
this@AlbumTagEditorActivity,
R.attr.defaultFooterColor
@ -87,11 +88,13 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
setResult(Activity.RESULT_OK)
}
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
super.onLoadFailed(e, errorDrawable)
Toast.makeText(this@AlbumTagEditorActivity, e.toString(), Toast.LENGTH_LONG)
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
Toast.makeText(this@AlbumTagEditorActivity, "Load Failed", Toast.LENGTH_LONG)
.show()
}
override fun setResource(resource: BitmapPaletteWrapper?) {}
})
}
@ -99,15 +102,15 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
private var deleteAlbumArt: Boolean = false
private fun setupToolbar() {
toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
setSupportActionBar(toolbar)
binding.toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
setSupportActionBar(binding.toolbar)
}
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
window.sharedElementsUseOverlay = true
imageContainer?.transitionName = getString(R.string.transition_album_art)
binding.imageContainer.transitionName = getString(R.string.transition_album_art)
windowEnterTransition()
setUpViews()
setupToolbar()
@ -116,22 +119,23 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
private fun setUpViews() {
fillViewsWithFileTags()
MaterialUtil.setTint(yearContainer, false)
MaterialUtil.setTint(genreContainer, false)
MaterialUtil.setTint(albumTitleContainer, false)
MaterialUtil.setTint(albumArtistContainer, false)
MaterialUtil.setTint(binding.yearContainer, false)
MaterialUtil.setTint(binding.genreContainer, false)
MaterialUtil.setTint(binding.albumTitleContainer, false)
MaterialUtil.setTint(binding.albumArtistContainer, false)
albumText.appHandleColor().addTextChangedListener(this)
albumArtistText.appHandleColor().addTextChangedListener(this)
genreTitle.appHandleColor().addTextChangedListener(this)
yearTitle.appHandleColor().addTextChangedListener(this)
binding.albumText.appHandleColor().addTextChangedListener(this)
binding.albumArtistText.appHandleColor().addTextChangedListener(this)
binding.genreTitle.appHandleColor().addTextChangedListener(this)
binding.yearTitle.appHandleColor().addTextChangedListener(this)
}
private fun fillViewsWithFileTags() {
albumText.setText(albumTitle)
albumArtistText.setText(albumArtistName)
genreTitle.setText(genreName)
yearTitle.setText(songYear)
binding.albumText.setText(albumTitle)
binding.albumArtistText.setText(albumArtistName)
binding.genreTitle.setText(genreName)
binding.yearTitle.setText(songYear)
println(albumTitle + albumArtistName)
}
override fun loadCurrentImage() {
@ -155,7 +159,7 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
}
override fun searchImageOnWeb() {
searchWebFor(albumText.text.toString(), albumArtistText.text.toString())
searchWebFor(binding.albumText.text.toString(), binding.albumArtistText.text.toString())
}
override fun deleteImage() {
@ -169,12 +173,12 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
override fun save() {
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
fieldKeyValueMap[FieldKey.ALBUM] = albumText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM] = binding.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()
fieldKeyValueMap[FieldKey.ARTIST] = binding.albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = binding.albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.GENRE] = binding.genreTitle.text.toString()
fieldKeyValueMap[FieldKey.YEAR] = binding.yearTitle.text.toString()
writeValuesToFiles(
fieldKeyValueMap,
@ -206,6 +210,10 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
saveFab.backgroundTintList = ColorStateList.valueOf(color)
}
override val editorImage: ImageView
get() = binding.editorImage
companion object {
val TAG: String = AlbumTagEditorActivity::class.java.simpleName

View file

@ -14,91 +14,98 @@
*/
package code.name.monkey.retromusic.activities.tageditor
import android.annotation.SuppressLint
import android.net.Uri
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.widget.ImageView
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.ActivitySongTagEditorBinding
import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.repository.SongRepository
import kotlinx.android.synthetic.main.activity_song_tag_editor.*
import org.jaudiotagger.tag.FieldKey
import org.koin.android.ext.android.inject
import java.util.*
class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>(), TextWatcher {
override val bindingInflater: (LayoutInflater) -> ActivitySongTagEditorBinding =
ActivitySongTagEditorBinding::inflate
override val contentViewLayout: Int
get() = R.layout.activity_song_tag_editor
private val songRepository by inject<SongRepository>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setNoImageMode()
setUpViews()
toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
setSupportActionBar(toolbar)
setNoImageMode()
binding.toolbar.setBackgroundColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
setSupportActionBar(binding.toolbar)
}
@SuppressLint("ClickableViewAccessibility")
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)
MaterialUtil.setTint(binding.songTextContainer, false)
MaterialUtil.setTint(binding.composerContainer, false)
MaterialUtil.setTint(binding.albumTextContainer, false)
MaterialUtil.setTint(binding.artistContainer, false)
MaterialUtil.setTint(binding.albumArtistContainer, false)
MaterialUtil.setTint(binding.yearContainer, false)
MaterialUtil.setTint(binding.genreContainer, false)
MaterialUtil.setTint(binding.trackNumberContainer, false)
MaterialUtil.setTint(binding.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)
binding.songText.appHandleColor().addTextChangedListener(this)
binding.albumText.appHandleColor().addTextChangedListener(this)
binding.albumArtistText.appHandleColor().addTextChangedListener(this)
binding.artistText.appHandleColor().addTextChangedListener(this)
binding.genreText.appHandleColor().addTextChangedListener(this)
binding.yearText.appHandleColor().addTextChangedListener(this)
binding.trackNumberText.appHandleColor().addTextChangedListener(this)
binding.lyricsText.appHandleColor().addTextChangedListener(this)
binding.songComposerText.appHandleColor().addTextChangedListener(this)
binding.lyricsText.setOnTouchListener { view, _ ->
view.parent.requestDisallowInterceptTouchEvent(true)
return@setOnTouchListener false
}
}
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)
binding.songText.setText(songTitle)
binding.albumArtistText.setText(albumArtist)
binding.albumText.setText(albumTitle)
binding.artistText.setText(artistName)
binding.genreText.setText(genreName)
binding.yearText.setText(songYear)
binding.trackNumberText.setText(trackNumber)
binding.lyricsText.setText(lyrics)
binding.songComposerText.setText(composer)
println(songTitle + songYear)
}
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()
fieldKeyValueMap[FieldKey.TITLE] = binding.songText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM] = binding.albumText.text.toString()
fieldKeyValueMap[FieldKey.ARTIST] = binding.artistText.text.toString()
fieldKeyValueMap[FieldKey.GENRE] = binding.genreText.text.toString()
fieldKeyValueMap[FieldKey.YEAR] = binding.yearText.text.toString()
fieldKeyValueMap[FieldKey.TRACK] = binding.trackNumberText.text.toString()
fieldKeyValueMap[FieldKey.LYRICS] = binding.lyricsText.text.toString()
fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = binding.albumArtistText.text.toString()
fieldKeyValueMap[FieldKey.COMPOSER] = binding.songComposerText.text.toString()
writeValuesToFiles(fieldKeyValueMap, null)
}
@ -120,4 +127,7 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
companion object {
val TAG: String = SongTagEditorActivity::class.java.simpleName
}
override val editorImage: ImageView?
get() = null
}

View file

@ -10,7 +10,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import com.afollestad.materialdialogs.MaterialDialog;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
@ -136,17 +136,17 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<LoadingInfo, Integer, Li
@Override
protected Dialog createDialog(@NonNull Context context) {
return new MaterialDialog.Builder(context)
.title(R.string.saving_changes)
.cancelable(false)
.progress(false, 0)
.build();
return new MaterialAlertDialogBuilder(context)
.setTitle(R.string.saving_changes)
.setCancelable(false)
.setView(R.layout.loading)
.create();
}
@Override
protected void onProgressUpdate(@NonNull Dialog dialog, Integer... values) {
super.onProgressUpdate(dialog, values);
((MaterialDialog) dialog).setMaxProgress(values[1]);
((MaterialDialog) dialog).setProgress(values[0]);
// ((MaterialDialog) dialog).setMaxProgress(values[1]);
// ((MaterialDialog) dialog).setProgress(values[0]);
}
}