Fix banner
This commit is contained in:
parent
ccde2d91ec
commit
a271a180b5
20 changed files with 0 additions and 1577 deletions
|
@ -16,8 +16,6 @@ package code.name.monkey.retromusic
|
|||
|
||||
import code.name.monkey.retromusic.providers.RepositoryImpl
|
||||
import code.name.monkey.retromusic.providers.interfaces.Repository
|
||||
import code.name.monkey.retromusic.rest.KogouClient
|
||||
import code.name.monkey.retromusic.rest.service.KuGouApiService
|
||||
import code.name.monkey.retromusic.util.schedulers.BaseSchedulerProvider
|
||||
import code.name.monkey.retromusic.util.schedulers.SchedulerProvider
|
||||
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
package code.name.monkey.retromusic.adapter
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.glide.GlideApp
|
||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.adapter.CollageSongAdapter.CollageSongViewHolder
|
||||
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
*/
|
||||
class CollageSongAdapter(private val activity: Activity, private val dataSet: ArrayList<Song>) : RecyclerView.Adapter<CollageSongViewHolder>() {
|
||||
|
||||
override fun onBindViewHolder(holder: CollageSongViewHolder, position: Int) {
|
||||
holder.bindSongs()
|
||||
if (dataSet.size > 8) {
|
||||
for (i in 0 until dataSet.subList(0, 8).size) {
|
||||
GlideApp.with(activity)
|
||||
.asBitmapPalette()
|
||||
.load(RetroGlideExtension.getSongModel(dataSet[i]))
|
||||
.transition(RetroGlideExtension.getDefaultTransition())
|
||||
.songOptions(dataSet[i])
|
||||
.into(object : RetroMusicColoredTarget(holder.itemView.findViewById(holder.ids[i]) as ImageView) {
|
||||
override fun onColorReady(color: Int) {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CollageSongViewHolder {
|
||||
return CollageSongViewHolder(LayoutInflater.from(activity).inflate(R.layout.item_collage, parent, false))
|
||||
}
|
||||
|
||||
inner class CollageSongViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
||||
|
||||
val ids = arrayListOf(R.id.image_2, R.id.image_3, R.id.image_4, R.id.image_5, R.id.image_6, R.id.image_7, R.id.image_8, R.id.image_9)
|
||||
private var textView: TextView = itemView.findViewById(R.id.image_1)
|
||||
|
||||
fun bindSongs() {
|
||||
for (i in ids) {
|
||||
val imageView = itemView.findViewById<ImageView>(i)
|
||||
imageView.setOnClickListener {
|
||||
textView.setOnClickListener { MusicPlayerRemote.openQueue(dataSet, 0, true) }
|
||||
}
|
||||
}
|
||||
|
||||
val context = itemView.context
|
||||
val color = ThemeStore.accentColor(context);
|
||||
|
||||
textView.setOnClickListener { MusicPlayerRemote.openQueue(dataSet, 0, true) }
|
||||
textView.setBackgroundColor(color);
|
||||
textView.setTextColor(MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(color)))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package code.name.monkey.retromusic.adapter
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import code.name.monkey.retromusic.interfaces.CabHolder
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.adapter.song.SongAdapter
|
||||
import java.util.*
|
||||
|
||||
class SpanSongsAdapter(activity: AppCompatActivity, dataSet: ArrayList<Song>, itemLayoutRes: Int, usePalette: Boolean, cabHolder: CabHolder?) : SongAdapter(activity, dataSet, itemLayoutRes, usePalette, cabHolder) {
|
||||
|
||||
override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) {
|
||||
super.onBindViewHolder(holder, position)
|
||||
if (position == 0) {
|
||||
val params = StaggeredGridLayoutManager.LayoutParams(StaggeredGridLayoutManager.LayoutParams.WRAP_CONTENT, StaggeredGridLayoutManager.LayoutParams.MATCH_PARENT)
|
||||
params.isFullSpan = true
|
||||
holder.itemView.layoutParams = params
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package code.name.monkey.retromusic.fragments.mainactivity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.model.Genre
|
||||
import code.name.monkey.retromusic.mvp.contract.GenreContract
|
||||
import code.name.monkey.retromusic.mvp.presenter.GenrePresenter
|
||||
import code.name.monkey.retromusic.adapter.GenreAdapter
|
||||
import code.name.monkey.retromusic.fragments.base.AbsLibraryPagerRecyclerViewFragment
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import java.util.*
|
||||
|
||||
class GenreFragment : AbsLibraryPagerRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(), GenreContract.GenreView {
|
||||
|
||||
private var mPresenter: GenrePresenter? = null
|
||||
|
||||
override val emptyMessage: Int
|
||||
get() = R.string.no_genres
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
mPresenter = GenrePresenter(this)
|
||||
}
|
||||
|
||||
override fun setMenuVisibility(menuVisible: Boolean) {
|
||||
super.setMenuVisibility(menuVisible)
|
||||
if (menuVisible) {
|
||||
libraryFragment.setTitle(if (PreferenceUtil.getInstance().tabTitles()) R.string.library else R.string.genres)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
libraryFragment.setTitle(if (PreferenceUtil.getInstance().tabTitles()) R.string.library else R.string.genres)
|
||||
if (adapter!!.dataSet.isEmpty()) {
|
||||
mPresenter!!.subscribe()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mPresenter!!.unsubscribe()
|
||||
}
|
||||
|
||||
override fun createLayoutManager(): LinearLayoutManager {
|
||||
return LinearLayoutManager(activity)
|
||||
}
|
||||
|
||||
override fun createAdapter(): GenreAdapter {
|
||||
val dataSet = adapter!!.dataSet
|
||||
return GenreAdapter(libraryFragment.mainActivity, dataSet, R.layout.item_list)
|
||||
}
|
||||
|
||||
override fun loading() {
|
||||
|
||||
}
|
||||
|
||||
override fun showData(list: ArrayList<Genre>) {
|
||||
adapter!!.swapDataSet(list)
|
||||
}
|
||||
|
||||
override fun showEmptyView() {
|
||||
adapter!!.swapDataSet(ArrayList())
|
||||
}
|
||||
|
||||
override fun completed() {
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
menu.removeItem(R.id.action_sort_order)
|
||||
menu.removeItem(R.id.action_grid_size)
|
||||
menu.removeItem(R.id.action_new_playlist)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(): GenreFragment {
|
||||
val args = Bundle()
|
||||
val fragment = GenreFragment()
|
||||
fragment.arguments = args
|
||||
return fragment
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,332 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.fragments.player.slide
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.graphics.Color
|
||||
import android.graphics.PorterDuff
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.widget.SeekBar
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.LinearSmoothScroller
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.*
|
||||
import code.name.monkey.retromusic.R
|
||||
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.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
|
||||
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
|
||||
import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.service.MusicService
|
||||
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
|
||||
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
|
||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
|
||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.ViewUtil
|
||||
import kotlinx.android.synthetic.main.fragment_slide_player.*
|
||||
|
||||
/**
|
||||
* Created by hemanths on 3/15/19
|
||||
*/
|
||||
class SlidePlayerFragment : AbsPlayerFragment(), MusicProgressViewUpdateHelper.Callback {
|
||||
private var lastColor: Int = 0
|
||||
override val paletteColor: Int
|
||||
get() = lastColor
|
||||
|
||||
override fun playerToolbar(): Toolbar {
|
||||
return playerToolbar
|
||||
}
|
||||
|
||||
override fun onShow() {
|
||||
|
||||
}
|
||||
|
||||
override fun onHide() {
|
||||
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun toolbarIconColor(): Int {
|
||||
return Color.WHITE
|
||||
}
|
||||
|
||||
override fun onColorChanged(color: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onFavoriteToggled() {
|
||||
toggleFavorite(MusicPlayerRemote.currentSong)
|
||||
}
|
||||
|
||||
override fun toggleFavorite(song: Song) {
|
||||
super.toggleFavorite(song)
|
||||
if (song.id == MusicPlayerRemote.currentSong.id) {
|
||||
updateIsFavorite()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_slide_player, container, false)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
progressViewUpdateHelper.start()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
progressViewUpdateHelper.stop()
|
||||
}
|
||||
|
||||
|
||||
override fun onPlayingMetaChanged() {
|
||||
super.onPlayingMetaChanged()
|
||||
updateSong()
|
||||
updateIsFavorite()
|
||||
}
|
||||
|
||||
override fun onQueueChanged() {
|
||||
super.onQueueChanged()
|
||||
updateQueue()
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {
|
||||
updatePlayPauseDrawableState()
|
||||
updateRepeatState()
|
||||
updateShuffleState()
|
||||
updateSong()
|
||||
updateIsFavorite()
|
||||
updateQueue()
|
||||
}
|
||||
|
||||
private fun updateQueue() {
|
||||
songAdapter.swapDataSet(MusicPlayerRemote.playingQueue)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private fun updatePlayPauseDrawableState() {
|
||||
if (MusicPlayerRemote.isPlaying) {
|
||||
albumCoverContainer.cardElevation = 24.0f
|
||||
playPauseButton.setImageResource(R.drawable.ic_pause_white_24dp)
|
||||
} else {
|
||||
albumCoverContainer.cardElevation = 0.0f
|
||||
playPauseButton.setImageResource(R.drawable.ic_play_arrow_white_24dp)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateRepeatState() {
|
||||
when (MusicPlayerRemote.repeatMode) {
|
||||
MusicService.REPEAT_MODE_NONE -> {
|
||||
repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp)
|
||||
repeatButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
MusicService.REPEAT_MODE_ALL -> {
|
||||
repeatButton.setImageResource(R.drawable.ic_repeat_white_24dp)
|
||||
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
MusicService.REPEAT_MODE_THIS -> {
|
||||
repeatButton.setImageResource(R.drawable.ic_repeat_one_white_24dp)
|
||||
repeatButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateShuffleState() {
|
||||
when (MusicPlayerRemote.shuffleMode) {
|
||||
MusicService.SHUFFLE_MODE_SHUFFLE -> shuffleButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
|
||||
else -> shuffleButton.setColorFilter(lastDisabledPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun updateSong() {
|
||||
val song = MusicPlayerRemote.currentSong
|
||||
title.text = song.title
|
||||
text.text = song.artistName
|
||||
|
||||
GlideApp.with(activity!!).asBitmapPalette()
|
||||
.load(RetroGlideExtension.getSongModel(song))
|
||||
.songOptions(song)
|
||||
.transition(RetroGlideExtension.getDefaultTransition())
|
||||
.into(object : RetroMusicColoredTarget(playerImage) {
|
||||
override fun onColorReady(color: Int) {
|
||||
setColor(color)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setColor(color: Int) {
|
||||
lastColor = color
|
||||
val colorBg = ATHUtil.resolveColor(context!!, android.R.attr.colorBackground)
|
||||
if (ColorUtil.isColorLight(colorBg)) {
|
||||
lastPlaybackControlsColor = MaterialValueHelper.getSecondaryTextColor(context!!, true)
|
||||
lastDisabledPlaybackControlsColor = MaterialValueHelper.getSecondaryDisabledTextColor(context!!, true)
|
||||
} else {
|
||||
lastPlaybackControlsColor = MaterialValueHelper.getPrimaryTextColor(context!!, false)
|
||||
lastDisabledPlaybackControlsColor = MaterialValueHelper.getPrimaryDisabledTextColor(context!!, false)
|
||||
}
|
||||
|
||||
val colorFinal = if (PreferenceUtil.getInstance().adaptiveColor) {
|
||||
color
|
||||
} else {
|
||||
ThemeStore.accentColor(context!!)
|
||||
}
|
||||
|
||||
|
||||
text.setTextColor(colorFinal)
|
||||
playerQueueSubHeader.setTextColor(colorFinal)
|
||||
TintHelper.setTintAuto(playPauseButton, lastPlaybackControlsColor, false)
|
||||
ViewUtil.setProgressDrawable(progressSlider, colorFinal)
|
||||
|
||||
updateRepeatState()
|
||||
updateShuffleState()
|
||||
updatePrevNextColor()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setUpMusicControllers()
|
||||
setUpPlayerToolbar()
|
||||
(activity as AbsSlidingMusicPanelActivity).setAntiDragView(recyclerView)
|
||||
playerQueueSubHeader.setTextColor(ThemeStore.accentColor(context!!))
|
||||
}
|
||||
|
||||
private fun setUpMusicControllers() {
|
||||
setUpPlayPauseFab()
|
||||
setUpPrevNext()
|
||||
setUpRepeatButton()
|
||||
setUpShuffleButton()
|
||||
setUpProgressSlider()
|
||||
setUpRecyclerView()
|
||||
}
|
||||
|
||||
private lateinit var songAdapter: SimpleSongAdapter
|
||||
|
||||
private fun setUpRecyclerView() {
|
||||
songAdapter = SimpleSongAdapter(context = activity as AppCompatActivity,
|
||||
songs = ArrayList(), i = R.layout.item_song, useNumbers = true)
|
||||
recyclerView.apply {
|
||||
adapter = songAdapter
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUpProgressSlider() {
|
||||
progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
MusicPlayerRemote.seekTo(progress)
|
||||
onUpdateProgressViews(MusicPlayerRemote.songProgressMillis, MusicPlayerRemote.songDurationMillis)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onUpdateProgressViews(progress: Int, total: Int) {
|
||||
progressSlider.max = total
|
||||
|
||||
val animator = ObjectAnimator.ofInt(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())
|
||||
}
|
||||
|
||||
private fun setUpPlayPauseFab() {
|
||||
playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
|
||||
}
|
||||
|
||||
private fun setUpRepeatButton() {
|
||||
repeatButton.setOnClickListener { MusicPlayerRemote.cycleRepeatMode() }
|
||||
}
|
||||
|
||||
private fun setUpShuffleButton() {
|
||||
shuffleButton.setOnClickListener { MusicPlayerRemote.toggleShuffleMode() }
|
||||
}
|
||||
|
||||
private fun setUpPrevNext() {
|
||||
updatePrevNextColor()
|
||||
nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
|
||||
previousButton.setOnClickListener { MusicPlayerRemote.back() }
|
||||
}
|
||||
|
||||
private fun updatePrevNextColor() {
|
||||
nextButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
|
||||
previousButton.setColorFilter(lastPlaybackControlsColor, PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
|
||||
private var lastPlaybackControlsColor: Int = 0
|
||||
private var lastDisabledPlaybackControlsColor: Int = 0
|
||||
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
|
||||
|
||||
override fun onPlayStateChanged() {
|
||||
updatePlayPauseDrawableState()
|
||||
}
|
||||
|
||||
override fun onRepeatModeChanged() {
|
||||
updateRepeatState()
|
||||
}
|
||||
|
||||
override fun onShuffleModeChanged() {
|
||||
updateShuffleState()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
|
||||
}
|
||||
|
||||
private fun setUpPlayerToolbar() {
|
||||
playerToolbar.inflateMenu(R.menu.menu_player)
|
||||
playerToolbar.setNavigationOnClickListener { activity!!.onBackPressed() }
|
||||
playerToolbar.setOnMenuItemClickListener(this)
|
||||
|
||||
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity)
|
||||
}
|
||||
|
||||
fun RecyclerView.smoothSnapToPosition(position: Int, snapMode: Int = LinearSmoothScroller.SNAP_TO_START) {
|
||||
val smoothScroller = object : LinearSmoothScroller(this.context) {
|
||||
override fun getVerticalSnapPreference(): Int {
|
||||
return snapMode
|
||||
}
|
||||
|
||||
override fun getHorizontalSnapPreference(): Int {
|
||||
return snapMode
|
||||
}
|
||||
}
|
||||
smoothScroller.targetPosition = position
|
||||
this.layoutManager?.startSmoothScroll(smoothScroller)
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.misc
|
||||
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
|
||||
object DisposableManager {
|
||||
|
||||
private var compositeDisposable: CompositeDisposable? = null
|
||||
|
||||
fun add(disposable: Disposable) {
|
||||
getCompositeDisposable().add(disposable)
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
getCompositeDisposable().dispose()
|
||||
}
|
||||
|
||||
private fun getCompositeDisposable(): CompositeDisposable {
|
||||
if (compositeDisposable == null || compositeDisposable!!.isDisposed) {
|
||||
compositeDisposable = CompositeDisposable()
|
||||
}
|
||||
return compositeDisposable!!
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.misc
|
||||
|
||||
import androidx.annotation.CallSuper
|
||||
import io.reactivex.Observer
|
||||
import io.reactivex.disposables.Disposable
|
||||
|
||||
class DisposingObserver<T> : Observer<T> {
|
||||
@CallSuper
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
DisposableManager.add(d)
|
||||
}
|
||||
|
||||
override fun onNext(next: T) {}
|
||||
|
||||
override fun onError(e: Throwable) {}
|
||||
|
||||
override fun onComplete() {}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.misc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.core.view.ViewCompat;
|
||||
|
||||
/*Don't delete even if its not showing not using*/
|
||||
public class ScrollAwareFABBehavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
|
||||
private static final String TAG = "ScrollingFABBehavior";
|
||||
Handler mHandler;
|
||||
|
||||
public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
|
||||
@NonNull FloatingActionButton child,
|
||||
@NonNull View target) {
|
||||
super.onStopNestedScroll(coordinatorLayout, child, target);
|
||||
|
||||
if (mHandler == null)
|
||||
mHandler = new Handler();
|
||||
|
||||
|
||||
mHandler.postDelayed(() -> {
|
||||
child.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
|
||||
Log.d("FabAnim", "startHandler()");
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
|
||||
@NonNull FloatingActionButton child,
|
||||
@NonNull View target,
|
||||
int dxConsumed,
|
||||
int dyConsumed,
|
||||
int dxUnconsumed,
|
||||
int dyUnconsumed) {
|
||||
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
|
||||
|
||||
//child -> Floating Action Button
|
||||
if (dyConsumed > 0) {
|
||||
Log.d("Scrolling", "Up");
|
||||
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
|
||||
int fab_bottomMargin = layoutParams.bottomMargin;
|
||||
child.animate().translationY(child.getHeight() + fab_bottomMargin).setInterpolator(new LinearInterpolator()).start();
|
||||
} else if (dyConsumed < 0) {
|
||||
Log.d("Scrolling", "down");
|
||||
child.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
|
||||
@NonNull FloatingActionButton child,
|
||||
@NonNull View directTargetChild,
|
||||
@NonNull View target,
|
||||
int nestedScrollAxes) {
|
||||
if (mHandler != null) {
|
||||
mHandler.removeMessages(0);
|
||||
Log.d("Scrolling", "stopHandler()");
|
||||
}
|
||||
return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.misc;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
|
||||
private int space;
|
||||
|
||||
public SpacesItemDecoration(int space) {
|
||||
this.space = space;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view,
|
||||
RecyclerView parent, RecyclerView.State state) {
|
||||
outRect.right = space;
|
||||
outRect.bottom = space;
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.providers
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.database.sqlite.SQLiteOpenHelper
|
||||
import code.name.monkey.retromusic.loaders.SongLoader
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
class NotPlayedStore(val context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, VERSION) {
|
||||
|
||||
private val dataBaseCreate = "CREATE TABLE IF NOT EXISTS $NAME ( $ID LONG PRIMARY KEY )"
|
||||
|
||||
override fun onCreate(db: SQLiteDatabase) {
|
||||
db.execSQL(dataBaseCreate)
|
||||
}
|
||||
|
||||
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
db.execSQL("DROP TABLE IF EXISTS $NAME")
|
||||
}
|
||||
|
||||
fun removeSong(id: Long) {
|
||||
val db = writableDatabase
|
||||
db.apply {
|
||||
beginTransaction()
|
||||
delete(NAME, "$ID = $id", null)
|
||||
setTransactionSuccessful()
|
||||
endTransaction()
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
fun addAllSongs(songs: ArrayList<Song>) {
|
||||
SongLoader.getAllSongs(context)
|
||||
.map {
|
||||
val database = writableDatabase;
|
||||
database.apply {
|
||||
val contentValues = ContentValues()
|
||||
for (song in songs) {
|
||||
contentValues.put(ID, song.id)
|
||||
insert(NAME, null, contentValues)
|
||||
}
|
||||
setTransactionSuccessful()
|
||||
endTransaction()
|
||||
}
|
||||
return@map true
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val NAME = "not_played_songs"
|
||||
const val ID = "song_id"
|
||||
const val DATABASE_NAME = "not_played.db"
|
||||
private const val VERSION = 1
|
||||
private var sInstance: NotPlayedStore? = null
|
||||
|
||||
@Synchronized
|
||||
fun getInstance(context: Context): NotPlayedStore {
|
||||
if (sInstance == null) {
|
||||
sInstance = NotPlayedStore(context.applicationContext)
|
||||
}
|
||||
return sInstance!!
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.rest;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import code.name.monkey.retromusic.App;
|
||||
import code.name.monkey.retromusic.rest.service.KuGouApiService;
|
||||
import okhttp3.Cache;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
import static code.name.monkey.retromusic.Constants.BASE_API_URL_KUGOU;
|
||||
|
||||
/**
|
||||
* Created by hemanths on 23/08/17.
|
||||
*/
|
||||
|
||||
public class KogouClient {
|
||||
|
||||
private static final String BASE_URL = BASE_API_URL_KUGOU;
|
||||
|
||||
private KuGouApiService apiService;
|
||||
|
||||
public KogouClient() {
|
||||
this(createDefaultOkHttpClientBuilder().build());
|
||||
}
|
||||
|
||||
private KogouClient(@NonNull Call.Factory client) {
|
||||
Retrofit restAdapter = new Retrofit.Builder()
|
||||
.baseUrl(BASE_URL)
|
||||
.callFactory(client)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||
.build();
|
||||
|
||||
apiService = restAdapter.create(KuGouApiService.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Cache createDefaultCache(Context context) {
|
||||
File cacheDir = new File(context.getCacheDir().getAbsolutePath(), "/okhttp-lastfm/");
|
||||
if (cacheDir.mkdirs() || cacheDir.isDirectory()) {
|
||||
return new Cache(cacheDir, 1024 * 1024 * 10);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Interceptor createCacheControlInterceptor() {
|
||||
return chain -> {
|
||||
Request modifiedRequest = chain.request().newBuilder()
|
||||
.addHeader("Cache-Control", String.format("max-age=%d, max-stale=%d", 31536000, 31536000))
|
||||
.build();
|
||||
return chain.proceed(modifiedRequest);
|
||||
};
|
||||
}
|
||||
|
||||
private static OkHttpClient.Builder createDefaultOkHttpClientBuilder() {
|
||||
return new OkHttpClient.Builder()
|
||||
.cache(createDefaultCache(App.Companion.getInstance()))
|
||||
.addInterceptor(createCacheControlInterceptor());
|
||||
}
|
||||
|
||||
public KuGouApiService getApiService() {
|
||||
return apiService;
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.rest.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Created by hefuyi on 2017/1/20.
|
||||
*/
|
||||
|
||||
public class KuGouRawLyric {
|
||||
|
||||
private static final String CHARSET = "charset";
|
||||
private static final String CONTENT = "content";
|
||||
private static final String FMT = "fmt";
|
||||
private static final String INFO = "info";
|
||||
private static final String STATUS = "status";
|
||||
|
||||
@SerializedName(CHARSET)
|
||||
public String charset;
|
||||
|
||||
@SerializedName(CONTENT)
|
||||
public String content;
|
||||
|
||||
@SerializedName(FMT)
|
||||
public String fmt;
|
||||
@SerializedName(INFO)
|
||||
public String info;
|
||||
@SerializedName(STATUS)
|
||||
public int status;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KuGouRawLyric{" +
|
||||
"charset='" + charset + '\'' +
|
||||
", content='" + content + '\'' +
|
||||
", fmt='" + fmt + '\'' +
|
||||
", info='" + info + '\'' +
|
||||
", status=" + status +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.rest.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Created by hefuyi on 2017/1/20.
|
||||
*/
|
||||
|
||||
public class KuGouSearchLyricResult {
|
||||
|
||||
private static final String INFO = "info";
|
||||
private static final String STATUS = "status";
|
||||
private static final String PROPOSAL = "proposal";
|
||||
private static final String KEYWORD = "keyword";
|
||||
private static final String CANDIDATES = "candidates";
|
||||
|
||||
@NonNull
|
||||
@SerializedName(INFO)
|
||||
public String info;
|
||||
|
||||
@SerializedName(STATUS)
|
||||
public int status;
|
||||
|
||||
@NonNull
|
||||
@SerializedName(PROPOSAL)
|
||||
public String proposal;
|
||||
|
||||
@NonNull
|
||||
@SerializedName(KEYWORD)
|
||||
public String keyword;
|
||||
|
||||
@NonNull
|
||||
@SerializedName(CANDIDATES)
|
||||
public List<Candidates> candidates;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KuGouSearchLyricResult{" +
|
||||
"info='" + info + '\'' +
|
||||
", status=" + status +
|
||||
", proposal='" + proposal + '\'' +
|
||||
", keyword='" + keyword + '\'' +
|
||||
", candidates=" + candidates +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static class Candidates {
|
||||
private static final String NICKNAME = "nickname";
|
||||
private static final String ACCESSKEY = "accesskey";
|
||||
private static final String SCORE = "score";
|
||||
private static final String DURATION = "duration";
|
||||
private static final String UID = "uid";
|
||||
private static final String SONG = "song";
|
||||
private static final String ID = "id";
|
||||
private static final String SINGER = "singer";
|
||||
private static final String LANGUAGE = "language";
|
||||
@SerializedName(NICKNAME)
|
||||
public String nickname;
|
||||
@SerializedName(ACCESSKEY)
|
||||
public String accesskey;
|
||||
@SerializedName(SCORE)
|
||||
public int score;
|
||||
@SerializedName(DURATION)
|
||||
public long duration;
|
||||
@SerializedName(UID)
|
||||
public String uid;
|
||||
@SerializedName(SONG)
|
||||
public String songName;
|
||||
@SerializedName(ID)
|
||||
public String id;
|
||||
@SerializedName(SINGER)
|
||||
public String singer;
|
||||
@SerializedName(LANGUAGE)
|
||||
public String language;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Candidates{" +
|
||||
"nickname='" + nickname + '\'' +
|
||||
", accesskey='" + accesskey + '\'' +
|
||||
", score=" + score +
|
||||
", duration=" + duration +
|
||||
", uid='" + uid + '\'' +
|
||||
", songName='" + songName + '\'' +
|
||||
", id='" + id + '\'' +
|
||||
", singer='" + singer + '\'' +
|
||||
", language='" + language + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.rest.service;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import code.name.monkey.retromusic.rest.model.KuGouRawLyric;
|
||||
import code.name.monkey.retromusic.rest.model.KuGouSearchLyricResult;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
/**
|
||||
* Created by hemanths on 28/07/17.
|
||||
*/
|
||||
|
||||
public interface KuGouApiService {
|
||||
|
||||
@NonNull
|
||||
@GET("search?ver=1&man=yes&client=pc")
|
||||
Observable<KuGouSearchLyricResult> searchLyric(@Query("keyword") @NonNull String songName, @Query("duration") @NonNull String duration);
|
||||
|
||||
@NonNull
|
||||
@GET("download?ver=1&client=pc&fmt=lrc&charset=utf8")
|
||||
Observable<KuGouRawLyric> getRawLyric(@Query("id") @NonNull String id, @Query("accesskey") @NonNull String accesskey);
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.transform;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
/**
|
||||
* Created by hemanths on 3/9/19
|
||||
*/
|
||||
public class RoundStackTransformer implements ViewPager.PageTransformer {
|
||||
@Override
|
||||
public void transformPage(@NonNull View page, float position) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.transform
|
||||
|
||||
import android.view.View
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
|
||||
class StackPagerTransformer : ViewPager.PageTransformer {
|
||||
|
||||
|
||||
override fun transformPage(view: View, position: Float) {
|
||||
|
||||
if (position < -1f) {
|
||||
view.translationX = view.width * position
|
||||
}
|
||||
|
||||
if (position < 0f) {
|
||||
view.translationX = 0f
|
||||
view.scaleX = 1f
|
||||
view.scaleY = 1f
|
||||
|
||||
} else if (position <= 1f) {
|
||||
|
||||
val scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position))
|
||||
view.pivotY = 0.5f * view.height
|
||||
view.translationX = view.width * -position
|
||||
view.scaleX = scaleFactor
|
||||
view.scaleY = scaleFactor
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val MIN_SCALE = 0.75f
|
||||
}
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import code.name.monkey.retromusic.App;
|
||||
|
||||
public class SystemUtils {
|
||||
|
||||
private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";
|
||||
private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height";
|
||||
private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape";
|
||||
private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width";
|
||||
private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar";
|
||||
private final float mSmallestWidthDp;
|
||||
private final boolean mInPortrait;
|
||||
|
||||
private Activity activity;
|
||||
|
||||
public SystemUtils(Activity activity) {
|
||||
this.activity = activity;
|
||||
Resources resources = activity.getResources();
|
||||
mSmallestWidthDp = getSmallestWidthDp(activity);
|
||||
mInPortrait = (resources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
|
||||
}
|
||||
|
||||
private static boolean hasNavBar(Resources resources) {
|
||||
int id = resources.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android");
|
||||
if (id > 0)
|
||||
return resources.getBoolean(id);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int getNavigationBarHeight() {
|
||||
int result = 0;
|
||||
int resourceId = App.Companion.getContext().getResources().getIdentifier("navigation_bar_height", "dimen", "android");
|
||||
if (resourceId > 0) {
|
||||
result = App.Companion.getContext().getResources().getDimensionPixelSize(resourceId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getComboHeight() {
|
||||
if (isNavigationAtBottom()) {
|
||||
return getNavigationBarWidth();
|
||||
} else {
|
||||
return getNavigationBarHeight();
|
||||
}
|
||||
}
|
||||
|
||||
public int getNavigationBarWidth() {
|
||||
Resources res = activity.getResources();
|
||||
int result = 0;
|
||||
if (hasNavBar(activity.getResources())) {
|
||||
if (!isNavigationAtBottom())
|
||||
return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addPadding(ViewGroup viewGroup) {
|
||||
Context context = viewGroup.getContext();
|
||||
Resources resources = context.getResources();
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) viewGroup.getLayoutParams();
|
||||
if (isNavigationAtBottom()) {
|
||||
params.leftMargin = getNavigationBarWidth();
|
||||
params.rightMargin = getNavigationBarWidth();
|
||||
} else {
|
||||
params.bottomMargin = getNavigationBarHeight();
|
||||
}
|
||||
}
|
||||
|
||||
private int getInternalDimensionSize(Resources res, String key) {
|
||||
int result = 0;
|
||||
int resourceId = res.getIdentifier(key, "dimen", "android");
|
||||
if (resourceId > 0) {
|
||||
result = res.getDimensionPixelSize(resourceId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private float getSmallestWidthDp(Activity activity) {
|
||||
DisplayMetrics metrics = new DisplayMetrics();
|
||||
activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
|
||||
float widthDp = metrics.widthPixels / metrics.density;
|
||||
float heightDp = metrics.heightPixels / metrics.density;
|
||||
return Math.min(widthDp, heightDp);
|
||||
}
|
||||
|
||||
boolean isNavigationAtBottom() {
|
||||
return (mSmallestWidthDp >= 600 || mInPortrait);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.views
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.util.AttributeSet
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
|
||||
class MaterialButtonTextColor @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = -1) : MaterialButton(context, attrs, defStyleAttr) {
|
||||
|
||||
init {
|
||||
setTextColor(MaterialValueHelper.getPrimaryTextColor(getContext(), ColorUtil.isColorLight(ThemeStore.primaryColor(getContext()))))
|
||||
iconTint = ColorStateList.valueOf(ATHUtil.resolveColor(context, R.attr.iconColor))
|
||||
rippleColor = ColorStateList.valueOf(ColorUtil.withAlpha(ThemeStore.accentColor(context), 0.4f))
|
||||
//minHeight = RetroUtil.convertDpToPixel(42f, context).toInt()
|
||||
iconSize = RetroUtil.convertDpToPixel(20f, context).toInt()
|
||||
}
|
||||
}
|
|
@ -1,225 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.views;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.Property;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
|
||||
import code.name.monkey.retromusic.R;
|
||||
|
||||
|
||||
public class PlayPauseDrawable extends Drawable {
|
||||
private static final long PLAY_PAUSE_ANIMATION_DURATION = 250;
|
||||
|
||||
private static final Property<PlayPauseDrawable, Float> PROGRESS =
|
||||
new Property<PlayPauseDrawable, Float>(Float.class, "progress") {
|
||||
@Override
|
||||
public Float get(@NonNull PlayPauseDrawable d) {
|
||||
return d.getProgress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(@NonNull PlayPauseDrawable d, Float value) {
|
||||
d.setProgress(value);
|
||||
}
|
||||
};
|
||||
|
||||
private final Path leftPauseBar = new Path();
|
||||
private final Path rightPauseBar = new Path();
|
||||
private final Paint paint = new Paint();
|
||||
private final float pauseBarWidth;
|
||||
private final float pauseBarHeight;
|
||||
private final float pauseBarDistance;
|
||||
|
||||
private float width;
|
||||
private float height;
|
||||
|
||||
private float progress;
|
||||
private boolean isPlay;
|
||||
private boolean isPlaySet;
|
||||
|
||||
private Animator animator;
|
||||
|
||||
public PlayPauseDrawable(@NonNull Context context) {
|
||||
final Resources res = context.getResources();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
paint.setColor(Color.WHITE);
|
||||
|
||||
pauseBarWidth = res.getDimensionPixelSize(R.dimen.pause_bar_width);
|
||||
pauseBarHeight = res.getDimensionPixelSize(R.dimen.pause_bar_height);
|
||||
pauseBarDistance = res.getDimensionPixelSize(R.dimen.pause_bar_distance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Linear interpolate between a and b with parameter t.
|
||||
*/
|
||||
private static float lerp(float a, float b, float t) {
|
||||
return a + (b - a) * t;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBoundsChange(@NonNull final Rect bounds) {
|
||||
super.onBoundsChange(bounds);
|
||||
if (bounds.width() > 0 && bounds.height() > 0) {
|
||||
width = bounds.width();
|
||||
height = bounds.height();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
leftPauseBar.rewind();
|
||||
rightPauseBar.rewind();
|
||||
|
||||
// The current distance between the two pause bars.
|
||||
final float barDist = lerp(pauseBarDistance, 0f, progress);
|
||||
// The current width of each pause bar.
|
||||
float rawBarWidth = lerp(pauseBarWidth, pauseBarHeight / 1.75f, progress);
|
||||
// We have to round the bar width when finishing the progress to prevent the gap
|
||||
// that might occur onDraw because of a pixel is lost when casting float to int instead of rounding it.
|
||||
final float barWidth = progress == 1f ? Math.round(rawBarWidth) : rawBarWidth;
|
||||
// The current position of the left pause bar's top left coordinate.
|
||||
final float firstBarTopLeft = lerp(0f, barWidth, progress);
|
||||
// The current position of the right pause bar's top right coordinate.
|
||||
final float secondBarTopRight = lerp(2f * barWidth + barDist, barWidth + barDist, progress);
|
||||
|
||||
// Draw the left pause bar. The left pause bar transforms into the
|
||||
// top half of the play button triangle by animating the position of the
|
||||
// rectangle's top left coordinate and expanding its bottom width.
|
||||
leftPauseBar.moveTo(0f, 0f);
|
||||
leftPauseBar.lineTo(firstBarTopLeft, -pauseBarHeight);
|
||||
leftPauseBar.lineTo(barWidth, -pauseBarHeight);
|
||||
leftPauseBar.lineTo(barWidth, 0f);
|
||||
leftPauseBar.close();
|
||||
|
||||
// Draw the right pause bar. The right pause bar transforms into the
|
||||
// bottom half of the play button triangle by animating the position of the
|
||||
// rectangle's top right coordinate and expanding its bottom width.
|
||||
rightPauseBar.moveTo(barWidth + barDist, 0f);
|
||||
rightPauseBar.lineTo(barWidth + barDist, -pauseBarHeight);
|
||||
rightPauseBar.lineTo(secondBarTopRight, -pauseBarHeight);
|
||||
rightPauseBar.lineTo(2 * barWidth + barDist, 0f);
|
||||
rightPauseBar.close();
|
||||
|
||||
final int saveCount = canvas.save();
|
||||
|
||||
// Translate the play button a tiny bit to the right so it looks more centered.
|
||||
canvas.translate(lerp(0f, pauseBarHeight / 8f, progress), 0f);
|
||||
|
||||
// (1) Pause --> Play: rotate 0 to 90 degrees clockwise.
|
||||
// (2) Play --> Pause: rotate 90 to 180 degrees clockwise.
|
||||
final float rotationProgress = isPlay ? 1f - progress : progress;
|
||||
final float startingRotation = isPlay ? 90f : 0f;
|
||||
canvas.rotate(lerp(startingRotation, startingRotation + 90f, rotationProgress), width / 2f, height / 2f);
|
||||
|
||||
// Position the pause/play button in the center of the drawable's bounds.
|
||||
canvas.translate(Math.round(width / 2f - ((2f * barWidth + barDist) / 2f)), Math.round(height / 2f + (pauseBarHeight / 2f)));
|
||||
|
||||
// Draw the two bars that form the animated pause/play button.
|
||||
canvas.drawPath(leftPauseBar, paint);
|
||||
canvas.drawPath(rightPauseBar, paint);
|
||||
|
||||
canvas.restoreToCount(saveCount);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Animator getPausePlayAnimator() {
|
||||
isPlaySet = !isPlaySet;
|
||||
final Animator anim = ObjectAnimator.ofFloat(this, PROGRESS, isPlay ? 1f : 0f, isPlay ? 0f : 1f);
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
isPlay = !isPlay;
|
||||
}
|
||||
});
|
||||
return anim;
|
||||
}
|
||||
|
||||
private float getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
private void setProgress(float progress) {
|
||||
this.progress = progress;
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
paint.setAlpha(alpha);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
paint.setColorFilter(cf);
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
public void setPlay(boolean animate) {
|
||||
if (animate) {
|
||||
if (!isPlaySet) {
|
||||
togglePlayPause();
|
||||
}
|
||||
} else {
|
||||
isPlaySet = true;
|
||||
isPlay = true;
|
||||
setProgress(1f);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPause(boolean animate) {
|
||||
if (animate) {
|
||||
if (isPlaySet) {
|
||||
togglePlayPause();
|
||||
}
|
||||
} else {
|
||||
isPlaySet = false;
|
||||
isPlay = false;
|
||||
setProgress(0f);
|
||||
}
|
||||
}
|
||||
|
||||
public void togglePlayPause() {
|
||||
if (animator != null) {
|
||||
animator.cancel();
|
||||
}
|
||||
|
||||
animator = getPausePlayAnimator();
|
||||
animator.setInterpolator(new DecelerateInterpolator());
|
||||
animator.setDuration(PLAY_PAUSE_ANIMATION_DURATION);
|
||||
animator.start();
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package code.name.monkey.retromusic.views
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
|
||||
class TintIconColorToolbar : Toolbar {
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
||||
|
||||
|
||||
override fun setNavigationIcon(icon: Drawable?) {
|
||||
super.setNavigationIcon(icon)
|
||||
icon?.setColorFilter(ThemeStore.textColorSecondary(context), PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue