Working towards single activity design

This commit is contained in:
Hemanth S 2020-08-11 23:59:44 +05:30
parent 31534769a8
commit 3ebf777d7b
87 changed files with 1908 additions and 2423 deletions

View file

@ -34,7 +34,7 @@ android {
}
signingConfigs {
release {
Properties properties = getProperties('/Users/h4h13/Documents/Github/retro.properties')
Properties properties = getProperties('/Users/apple/Documents/Github/retro.properties')
storeFile file(getProperty(properties, 'storeFile'))
keyAlias getProperty(properties, 'keyAlias')
storePassword getProperty(properties, 'storePassword')
@ -120,6 +120,7 @@ dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.google.android.material:material:1.3.0-alpha01'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
def retrofit_version = '2.9.0'
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
@ -160,7 +161,8 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
implementation 'com.google.android.play:core:1.7.3'
def playcore_version = "1.8.1"
implementation "com.google.android.play:core-ktx:$playcore_version"
implementation 'me.jorgecastillo:androidcolorx:0.2.0'
debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'
implementation 'com.github.dhaval2404:imagepicker:1.7.1'
@ -176,5 +178,4 @@ dependencies {
def nav_version = "2.3.0"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}

View file

@ -12,7 +12,7 @@
"filters": [],
"properties": [],
"versionCode": 10438,
"versionName": "10438",
"versionName": "3.5.650_0810",
"enabled": true,
"outputFile": "app-release.apk"
}

View file

@ -21,12 +21,12 @@
<application
android:name=".App"
android:allowBackup="true"
android:configChanges="locale|layoutDirection"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:configChanges="locale|layoutDirection"
android:theme="@style/Theme.RetroMusic.FollowSystem"
android:usesCleartextTraffic="false"
tools:ignore="AllowBackup,GoogleAppIndexingWarning"
@ -105,18 +105,13 @@
<data android:mimeType="vnd.android.cursor.dir/audio" />
</intent-filter>
</activity>
<activity android:name=".activities.albums.AlbumDetailsActivity" />
<activity android:name=".activities.artists.ArtistDetailActivity" />
<activity android:name=".activities.playlist.PlaylistDetailActivity" />
<activity android:name=".activities.PlayingQueueActivity" />
<activity android:name=".activities.AboutActivity" />
<activity android:name="code.name.monkey.retromusic.fragments.about.AboutActivity" />
<activity android:name=".activities.tageditor.AlbumTagEditorActivity" />
<activity android:name=".activities.tageditor.SongTagEditorActivity" />
<activity android:name=".activities.SettingsActivity" />
<activity android:name=".activities.LyricsActivity" />
<activity android:name=".activities.UserInfoActivity" />
<activity android:name=".activities.SupportDevelopmentActivity" />
<activity android:name=".activities.genre.GenreDetailsActivity" />
<activity android:name=".activities.LicenseActivity" />
<activity android:name=".activities.PurchaseActivity" />
<activity android:name=".activities.WhatsNewActivity" />

View file

@ -48,13 +48,16 @@ object Constants {
MediaStore.Audio.AudioColumns.ALBUM, // 8
MediaStore.Audio.AudioColumns.ARTIST_ID, // 9
MediaStore.Audio.AudioColumns.ARTIST,// 10
MediaStore.Audio.AudioColumns.COMPOSER// 11
MediaStore.Audio.AudioColumns.COMPOSER,// 11
"album_artist"//12
)
const val NUMBER_OF_TOP_TRACKS = 99
}
const val EXTRA_GENRE = "extra_genre"
const val EXTRA_PLAYLIST = "extra_playlist"
const val EXTRA_ALBUM_ID = "extra_album_id"
const val EXTRA_ARTIST_ID = "extra_artist_id"
const val EXTRA_SONG = "extra_songs"
const val EXTRA_PLAYLIST = "extra_list"
const val LIBRARY_CATEGORIES = "library_categories"
const val EXTRA_SONG_INFO = "extra_song_info"
const val DESATURATED_COLOR = "desaturated_color"

View file

@ -1,9 +1,9 @@
package code.name.monkey.retromusic
import code.name.monkey.retromusic.activities.albums.AlbumDetailsViewModel
import code.name.monkey.retromusic.activities.artists.ArtistDetailsViewModel
import code.name.monkey.retromusic.activities.genre.GenreDetailsViewModel
import code.name.monkey.retromusic.activities.playlist.PlaylistDetailsViewModel
import code.name.monkey.retromusic.fragments.albums.AlbumDetailsViewModel
import code.name.monkey.retromusic.fragments.artists.ArtistDetailsViewModel
import code.name.monkey.retromusic.fragments.genres.GenreDetailsViewModel
import code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsViewModel
import code.name.monkey.retromusic.activities.search.SearchViewModel
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.model.Genre
@ -28,19 +28,31 @@ private val viewModules = module {
}
viewModel { (albumId: Int) ->
AlbumDetailsViewModel(get(), albumId)
AlbumDetailsViewModel(
get(),
albumId
)
}
viewModel { (artistId: Int) ->
ArtistDetailsViewModel(get(), artistId)
ArtistDetailsViewModel(
get(),
artistId
)
}
viewModel { (playlist: Playlist) ->
PlaylistDetailsViewModel(get(), playlist)
PlaylistDetailsViewModel(
get(),
playlist
)
}
viewModel { (genre: Genre) ->
GenreDetailsViewModel(get(), genre)
GenreDetailsViewModel(
get(),
genre
)
}
viewModel {

View file

@ -1,113 +1,51 @@
package code.name.monkey.retromusic.activities
import android.app.ActivityOptions
import android.content.*
import android.content.IntentSender.SendIntentException
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.SubMenu
import android.view.View
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog.Companion.create
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.extensions.findNavController
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.albums.AlbumsFragment
import code.name.monkey.retromusic.fragments.artists.ArtistsFragment
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
import code.name.monkey.retromusic.fragments.folder.FoldersFragment
import code.name.monkey.retromusic.fragments.genres.GenresFragment
import code.name.monkey.retromusic.fragments.home.BannerHomeFragment
import code.name.monkey.retromusic.fragments.playlists.PlaylistsFragment
import code.name.monkey.retromusic.fragments.queue.PlayingQueueFragment
import code.name.monkey.retromusic.fragments.songs.SongsFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote.isPlaying
import code.name.monkey.retromusic.helper.MusicPlayerRemote.openAndShuffleQueue
import code.name.monkey.retromusic.helper.MusicPlayerRemote.openQueue
import code.name.monkey.retromusic.helper.MusicPlayerRemote.playFromUri
import code.name.monkey.retromusic.helper.MusicPlayerRemote.shuffleMode
import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs
import code.name.monkey.retromusic.helper.SortOrder.*
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
import code.name.monkey.retromusic.loaders.AlbumLoader.getAlbum
import code.name.monkey.retromusic.loaders.ArtistLoader.getArtist
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader.getPlaylistSongList
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.AppRater.appLaunched
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.afollestad.materialcab.MaterialCab
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.snackbar.Snackbar
import com.google.android.play.core.appupdate.AppUpdateInfo
import com.google.android.play.core.appupdate.AppUpdateManager
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.install.InstallState
import com.google.android.play.core.install.InstallStateUpdatedListener
import com.google.android.play.core.install.model.AppUpdateType
import com.google.android.play.core.install.model.InstallStatus.DOWNLOADED
import com.google.android.play.core.install.model.InstallStatus.INSTALLED
import com.google.android.play.core.install.model.UpdateAvailability
import com.google.android.play.core.tasks.Task
import kotlinx.android.synthetic.main.activity_main_content.*
import com.afollestad.materialdialogs.color.ColorChooserDialog
import org.koin.android.ext.android.inject
import java.util.*
class MainActivity : AbsSlidingMusicPanelActivity(),
SharedPreferences.OnSharedPreferenceChangeListener, CabHolder {
SharedPreferences.OnSharedPreferenceChangeListener, CabHolder,
ColorChooserDialog.ColorCallback {
companion object {
const val TAG = "MainActivity"
const val EXPAND_PANEL = "expand_panel"
const val APP_UPDATE_REQUEST_CODE = 9002
}
private val libraryViewModel: LibraryViewModel by inject()
private var cab: MaterialCab? = null
private val intentFilter = IntentFilter(Intent.ACTION_SCREEN_OFF)
private lateinit var currentFragment: MainActivityFragmentCallbacks
private var appUpdateManager: AppUpdateManager? = null
private var blockRequestPermissions = false
private val listener = object : InstallStateUpdatedListener {
override fun onStateUpdate(state: InstallState) {
when {
state.installStatus() == DOWNLOADED -> {
popupSnackBarForCompleteUpdate()
}
state.installStatus() == INSTALLED -> {
appUpdateManager?.unregisterListener(this)
}
else -> {
Log.i(TAG, "InstallStateUpdatedListener: state: " + state.installStatus())
}
}
}
}
private val broadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (action != null && action == Intent.ACTION_SCREEN_OFF) {
if (PreferenceUtil.isLockScreen && isPlaying) {
val activity = Intent(context, LockScreenActivity::class.java)
activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
ActivityCompat.startActivity(context, activity, null)
}
}
}
}
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_main_content)
@ -122,29 +60,16 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
setTaskDescriptionColorAuto()
hideStatusBar()
setBottomBarVisibility(View.VISIBLE)
addMusicServiceEventListener(libraryViewModel)
if (savedInstanceState == null) {
selectedFragment(PreferenceUtil.lastPage)
} else {
restoreCurrentFragment()
}
appLaunched(this)
setupToolbar()
checkUpdate()
addMusicServiceEventListener(libraryViewModel)
updateTabs()
getBottomNavigationView().selectedItemId = PreferenceUtil.lastPage
getBottomNavigationView().setOnNavigationItemSelectedListener {
PreferenceUtil.lastPage = it.itemId
selectedFragment(it.itemId)
true
}
}
override fun onSupportNavigateUp(): Boolean =
findNavController(R.id.fragment_container).navigateUp()
override fun onResume() {
super.onResume()
registerReceiver(broadcastReceiver, intentFilter)
PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
if (intent.hasExtra(EXPAND_PANEL) &&
intent.getBooleanExtra(EXPAND_PANEL, false) &&
@ -153,411 +78,13 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
expandPanel()
intent.removeExtra(EXPAND_PANEL)
}
appUpdateManager?.appUpdateInfo
?.addOnSuccessListener { appUpdateInfo: AppUpdateInfo ->
if (appUpdateInfo.installStatus() == DOWNLOADED) {
popupSnackBarForCompleteUpdate()
}
try {
if (appUpdateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
appUpdateManager!!.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.IMMEDIATE,
this,
APP_UPDATE_REQUEST_CODE
)
}
} catch (e: SendIntentException) {
e.printStackTrace()
}
}
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(broadcastReceiver)
PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this)
}
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(this, toolbar)
return super.onPrepareOptionsMenu(menu)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
menu ?: return super.onCreateOptionsMenu(menu)
if (isPlaylistPage()) {
menu.add(0, R.id.action_new_playlist, 1, R.string.new_playlist_title)
.setIcon(R.drawable.ic_playlist_add)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM)
}
if (isHomePage()) {
menu.add(0, R.id.action_mic, 1, getString(R.string.action_search))
.setIcon(R.drawable.ic_mic)
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM)
}
if (isFolderPage()) {
menu.add(0, R.id.action_scan, 0, R.string.scan_media)
.setIcon(R.drawable.ic_scanner)
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM)
menu.add(0, R.id.action_go_to_start_directory, 1, R.string.action_go_to_start_directory)
.setIcon(R.drawable.ic_bookmark_music)
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM)
}
val fragment: Fragment? = getCurrentFragment()
if (fragment != null && fragment is AbsRecyclerViewCustomGridSizeFragment<*, *>) {
val gridSizeItem: MenuItem = menu.findItem(R.id.action_grid_size)
if (RetroUtil.isLandscape()) {
gridSizeItem.setTitle(R.string.action_grid_size_land)
}
setUpGridSizeMenu(fragment, gridSizeItem.subMenu)
setupLayoutMenu(fragment, menu.findItem(R.id.action_layout_type).subMenu)
setUpSortOrderMenu(fragment, menu.findItem(R.id.action_sort_order).subMenu)
} else {
menu.removeItem(R.id.action_layout_type)
menu.removeItem(R.id.action_grid_size)
menu.removeItem(R.id.action_sort_order)
}
menu.add(0, R.id.action_settings, 6, getString(R.string.action_settings))
.setIcon(R.drawable.ic_settings)
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM)
menu.add(0, R.id.action_search, 0, getString(R.string.action_search))
.setIcon(R.drawable.ic_search)
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS)
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
this,
toolbar,
menu,
getToolbarBackgroundColor(toolbar)
)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val fragment = getCurrentFragment()
if (fragment is AbsRecyclerViewCustomGridSizeFragment<*, *>) {
if (handleGridSizeMenuItem(fragment, item)) {
return true
}
if (handleLayoutResType(fragment, item)) {
return true
}
if (handleSortOrderMenuItem(fragment, item)) {
return true
}
}
when (item.itemId) {
R.id.action_search -> NavigationUtil.goToSearch(this)
R.id.action_new_playlist -> {
create().show(supportFragmentManager, "CREATE_PLAYLIST")
return true
}
R.id.action_mic -> {
val options = ActivityOptions.makeSceneTransitionAnimation(
this, toolbar,
getString(R.string.transition_toolbar)
)
NavigationUtil.goToSearch(this, true, options)
return true
}
R.id.action_settings -> {
NavigationUtil.goToSettings(this)
return true
}
}
return super.onOptionsItemSelected(item)
}
private fun handleSortOrderMenuItem(
fragment: AbsRecyclerViewCustomGridSizeFragment<*, *>,
item: MenuItem
): Boolean {
var sortOrder: String? = null
when (fragment) {
is AlbumsFragment -> {
when (item.itemId) {
R.id.action_album_sort_order_asc -> sortOrder = AlbumSortOrder.ALBUM_A_Z
R.id.action_album_sort_order_desc -> sortOrder = AlbumSortOrder.ALBUM_Z_A
R.id.action_album_sort_order_artist -> sortOrder = AlbumSortOrder.ALBUM_ARTIST
R.id.action_album_sort_order_year -> sortOrder = AlbumSortOrder.ALBUM_YEAR
}
}
is ArtistsFragment -> {
when (item.itemId) {
R.id.action_artist_sort_order_asc -> sortOrder = ArtistSortOrder.ARTIST_A_Z
R.id.action_artist_sort_order_desc -> sortOrder = ArtistSortOrder.ARTIST_Z_A
}
}
is SongsFragment -> {
when (item.itemId) {
R.id.action_song_sort_order_asc -> sortOrder = SongSortOrder.SONG_A_Z
R.id.action_song_sort_order_desc -> sortOrder = SongSortOrder.SONG_Z_A
R.id.action_song_sort_order_artist -> sortOrder = SongSortOrder.SONG_ARTIST
R.id.action_song_sort_order_album -> sortOrder = SongSortOrder.SONG_ALBUM
R.id.action_song_sort_order_year -> sortOrder = SongSortOrder.SONG_YEAR
R.id.action_song_sort_order_date -> sortOrder = SongSortOrder.SONG_DATE
R.id.action_song_sort_order_composer -> sortOrder = SongSortOrder.COMPOSER
R.id.action_song_sort_order_date_modified ->
sortOrder = SongSortOrder.SONG_DATE_MODIFIED
}
}
}
if (sortOrder != null) {
item.isChecked = true
fragment.setAndSaveSortOrder(sortOrder)
return true
}
return false
}
private fun handleLayoutResType(
fragment: AbsRecyclerViewCustomGridSizeFragment<*, *>,
item: MenuItem
): Boolean {
var layoutRes = -1
when (item.itemId) {
R.id.action_layout_normal -> layoutRes = R.layout.item_grid
R.id.action_layout_card -> layoutRes = R.layout.item_card
R.id.action_layout_colored_card -> layoutRes = R.layout.item_card_color
R.id.action_layout_circular -> layoutRes = R.layout.item_grid_circle
R.id.action_layout_image -> layoutRes = R.layout.image
R.id.action_layout_gradient_image -> layoutRes = R.layout.item_image_gradient
}
if (layoutRes != -1) {
item.isChecked = true
fragment.setAndSaveLayoutRes(layoutRes)
return true
}
return false
}
private fun handleGridSizeMenuItem(
fragment: AbsRecyclerViewCustomGridSizeFragment<*, *>,
item: MenuItem
): Boolean {
var gridSize = 0
when (item.itemId) {
R.id.action_grid_size_1 -> gridSize = 1
R.id.action_grid_size_2 -> gridSize = 2
R.id.action_grid_size_3 -> gridSize = 3
R.id.action_grid_size_4 -> gridSize = 4
R.id.action_grid_size_5 -> gridSize = 5
R.id.action_grid_size_6 -> gridSize = 6
R.id.action_grid_size_7 -> gridSize = 7
R.id.action_grid_size_8 -> gridSize = 8
}
if (gridSize > 0) {
item.isChecked = true
fragment.setAndSaveGridSize(gridSize)
return true
}
return false
}
private fun setUpGridSizeMenu(
fragment: AbsRecyclerViewCustomGridSizeFragment<*, *>,
gridSizeMenu: SubMenu
) {
when (fragment.getGridSize()) {
1 -> gridSizeMenu.findItem(R.id.action_grid_size_1).isChecked = true
2 -> gridSizeMenu.findItem(R.id.action_grid_size_2).isChecked = true
3 -> gridSizeMenu.findItem(R.id.action_grid_size_3).isChecked = true
4 -> gridSizeMenu.findItem(R.id.action_grid_size_4).isChecked = true
5 -> gridSizeMenu.findItem(R.id.action_grid_size_5).isChecked = true
6 -> gridSizeMenu.findItem(R.id.action_grid_size_6).isChecked = true
7 -> gridSizeMenu.findItem(R.id.action_grid_size_7).isChecked = true
8 -> gridSizeMenu.findItem(R.id.action_grid_size_8).isChecked = true
}
val maxGridSize = fragment.maxGridSize
if (maxGridSize < 8) {
gridSizeMenu.findItem(R.id.action_grid_size_8).isVisible = false
}
if (maxGridSize < 7) {
gridSizeMenu.findItem(R.id.action_grid_size_7).isVisible = false
}
if (maxGridSize < 6) {
gridSizeMenu.findItem(R.id.action_grid_size_6).isVisible = false
}
if (maxGridSize < 5) {
gridSizeMenu.findItem(R.id.action_grid_size_5).isVisible = false
}
if (maxGridSize < 4) {
gridSizeMenu.findItem(R.id.action_grid_size_4).isVisible = false
}
if (maxGridSize < 3) {
gridSizeMenu.findItem(R.id.action_grid_size_3).isVisible = false
}
}
private fun setupLayoutMenu(
fragment: AbsRecyclerViewCustomGridSizeFragment<*, *>,
subMenu: SubMenu
) {
when (fragment.itemLayoutRes()) {
R.layout.item_card ->
subMenu.findItem(R.id.action_layout_card).isChecked = true
R.layout.item_card_color ->
subMenu.findItem(R.id.action_layout_colored_card).isChecked = true
R.layout.item_grid_circle ->
subMenu.findItem(R.id.action_layout_circular).isChecked = true
R.layout.image ->
subMenu.findItem(R.id.action_layout_image).isChecked = true
R.layout.item_image_gradient ->
subMenu.findItem(R.id.action_layout_gradient_image).isChecked = true
R.layout.item_grid ->
subMenu.findItem(R.id.action_layout_normal).isChecked = true
else ->
subMenu.findItem(R.id.action_layout_normal).isChecked = true
}
}
private fun setUpSortOrderMenu(
fragment: AbsRecyclerViewCustomGridSizeFragment<*, *>,
sortOrderMenu: SubMenu
) {
val currentSortOrder = fragment.getSortOrder()
sortOrderMenu.clear()
when (fragment) {
is AlbumsFragment -> {
sortOrderMenu.add(
0,
R.id.action_album_sort_order_asc,
0,
R.string.sort_order_a_z
).isChecked = currentSortOrder == AlbumSortOrder.ALBUM_A_Z
sortOrderMenu.add(
0,
R.id.action_album_sort_order_desc,
1,
R.string.sort_order_z_a
).isChecked =
currentSortOrder == AlbumSortOrder.ALBUM_Z_A
sortOrderMenu.add(
0,
R.id.action_album_sort_order_artist,
2,
R.string.sort_order_artist
).isChecked =
currentSortOrder == AlbumSortOrder.ALBUM_ARTIST
sortOrderMenu.add(
0,
R.id.action_album_sort_order_year,
3,
R.string.sort_order_year
).isChecked =
currentSortOrder == AlbumSortOrder.ALBUM_YEAR
}
is ArtistsFragment -> {
sortOrderMenu.add(
0,
R.id.action_artist_sort_order_asc,
0,
R.string.sort_order_a_z
).isChecked =
currentSortOrder == ArtistSortOrder.ARTIST_A_Z
sortOrderMenu.add(
0,
R.id.action_artist_sort_order_desc,
1,
R.string.sort_order_z_a
).isChecked =
currentSortOrder == ArtistSortOrder.ARTIST_Z_A
}
is SongsFragment -> {
sortOrderMenu.add(
0,
R.id.action_song_sort_order_asc,
0,
R.string.sort_order_a_z
).isChecked =
currentSortOrder == SongSortOrder.SONG_A_Z
sortOrderMenu.add(
0,
R.id.action_song_sort_order_desc,
1,
R.string.sort_order_z_a
).isChecked =
currentSortOrder == SongSortOrder.SONG_Z_A
sortOrderMenu.add(
0,
R.id.action_song_sort_order_artist,
2,
R.string.sort_order_artist
).isChecked =
currentSortOrder == SongSortOrder.SONG_ARTIST
sortOrderMenu.add(
0,
R.id.action_song_sort_order_album,
3,
R.string.sort_order_album
).isChecked =
currentSortOrder == SongSortOrder.SONG_ALBUM
sortOrderMenu.add(
0,
R.id.action_song_sort_order_year,
4,
R.string.sort_order_year
).isChecked =
currentSortOrder == SongSortOrder.SONG_YEAR
sortOrderMenu.add(
0,
R.id.action_song_sort_order_date,
5,
R.string.sort_order_date
).isChecked =
currentSortOrder == SongSortOrder.SONG_DATE
sortOrderMenu.add(
0,
R.id.action_song_sort_order_date_modified,
6,
R.string.sort_order_date_modified
).isChecked = currentSortOrder == SongSortOrder.SONG_DATE_MODIFIED
sortOrderMenu.add(
0,
R.id.action_song_sort_order_composer,
7,
R.string.sort_order_composer
).isChecked = currentSortOrder == SongSortOrder.COMPOSER
}
}
sortOrderMenu.setGroupCheckable(0, true, true)
}
private fun getCurrentFragment(): Fragment? {
return supportFragmentManager.findFragmentById(R.id.fragment_container)
}
private fun isFolderPage(): Boolean {
return supportFragmentManager.findFragmentByTag(FoldersFragment.TAG) is FoldersFragment
}
private fun isHomePage(): Boolean {
return supportFragmentManager.findFragmentByTag(BannerHomeFragment.TAG) is BannerHomeFragment
}
private fun isPlaylistPage(): Boolean {
return supportFragmentManager.findFragmentByTag(PlaylistsFragment.TAG) is PlaylistsFragment
}
fun addOnAppBarOffsetChangedListener(
changedListener: AppBarLayout.OnOffsetChangedListener
) {
appBarLayout.addOnOffsetChangedListener(changedListener)
}
fun removeOnAppBarOffsetChangedListener(
changedListener: AppBarLayout.OnOffsetChangedListener
) {
appBarLayout.removeOnOffsetChangedListener(changedListener)
}
fun getTotalAppBarScrollingRange(): Int {
return appBarLayout.totalScrollRange
}
override fun requestPermissions() {
if (!blockRequestPermissions) {
@ -572,115 +99,6 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
}
}
private fun setupToolbar() {
toolbar.setBackgroundColor(resolveColor(this, R.attr.colorSurface))
appBarLayout.setBackgroundColor(resolveColor(this, R.attr.colorSurface))
setSupportActionBar(toolbar)
}
private fun checkUpdate() {
appUpdateManager = AppUpdateManagerFactory.create(this)
appUpdateManager?.registerListener(listener)
val appUpdateInfoTask: Task<AppUpdateInfo>? = appUpdateManager?.appUpdateInfo
appUpdateInfoTask?.addOnSuccessListener { appUpdateInfo ->
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
) {
try {
appUpdateManager?.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.IMMEDIATE,
this,
APP_UPDATE_REQUEST_CODE
)
} catch (e: SendIntentException) {
e.printStackTrace()
}
}
}
}
private fun popupSnackBarForCompleteUpdate() {
val snackBar =
Snackbar.make(
findViewById(R.id.mainContent),
"New app is ready!",
Snackbar.LENGTH_INDEFINITE
)
snackBar.setAction(
"Install"
) {
appUpdateManager?.completeUpdate()
}
snackBar.setActionTextColor(accentColor(this))
snackBar.show()
}
private fun setCurrentFragment(
fragment: Fragment,
tag: String
) {
supportFragmentManager.commit {
setCustomAnimations(
R.anim.retro_fragment_open_enter,
R.anim.retro_fragment_open_exit,
R.anim.retro_fragment_fade_enter,
R.anim.retro_fragment_fade_exit
)
replace(R.id.fragment_container, fragment, tag)
}
currentFragment = fragment as MainActivityFragmentCallbacks
}
private fun selectedFragment(itemId: Int) {
when (itemId) {
R.id.action_album -> setCurrentFragment(
AlbumsFragment.newInstance(),
AlbumsFragment.TAG
)
R.id.action_artist -> setCurrentFragment(
ArtistsFragment.newInstance(),
ArtistsFragment.TAG
)
R.id.action_playlist -> setCurrentFragment(
PlaylistsFragment.newInstance(),
PlaylistsFragment.TAG
)
R.id.action_genre -> setCurrentFragment(
GenresFragment.newInstance(),
GenresFragment.TAG
)
R.id.action_playing_queue -> setCurrentFragment(
PlayingQueueFragment.newInstance(),
PlayingQueueFragment.TAG
)
R.id.action_song -> setCurrentFragment(
SongsFragment.newInstance(),
SongsFragment.TAG
)
R.id.action_folder -> setCurrentFragment(
FoldersFragment.newInstance(this),
FoldersFragment.TAG
)
R.id.action_home -> setCurrentFragment(
BannerHomeFragment.newInstance(),
BannerHomeFragment.TAG
)
else -> setCurrentFragment(
BannerHomeFragment.newInstance(),
BannerHomeFragment.TAG
)
}
}
private fun restoreCurrentFragment() {
val fragment = supportFragmentManager.findFragmentById(R.id.fragment_container)
if (fragment != null) {
currentFragment = fragment as MainActivityFragmentCallbacks
}
}
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 == 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
) {
@ -762,11 +180,12 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
}
override fun handleBackPress(): Boolean {
getBottomNavigationView().menu.getItem(0).isChecked = true
if (cab != null && cab!!.isActive) {
cab?.finish()
return true
}
return super.handleBackPress() || currentFragment.handleBackPress()
return super.handleBackPress()
}
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
@ -787,4 +206,19 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
.start(callback)
return cab as MaterialCab
}
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) {
}
}

View file

@ -1,104 +0,0 @@
package code.name.monkey.retromusic.activities
import android.os.Bundle
import android.view.MenuItem
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.AppBarConfiguration
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.AbsBaseActivity
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.extensions.applyToolbar
import com.afollestad.materialdialogs.color.ColorChooserDialog
import kotlinx.android.synthetic.main.activity_settings.*
class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
private val fragmentManager = supportFragmentManager
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setLightNavigationBar(true)
setupToolbar()
}
private fun setupToolbar() {
setTitle(R.string.action_settings)
applyToolbar(toolbar)
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.contentFrame) as NavHostFragment
val navController: NavController = navHostFragment.navController
navController.addOnDestinationChangedListener { _, _, _ ->
toolbar.title = navController.currentDestination?.label
}
//It removes the back button
//appBarConfiguration = AppBarConfiguration(navController.graph)
//setupActionBarWithNavController(navController, appBarConfiguration)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
fun setupFragment(fragment: Fragment, @StringRes titleName: Int) {
val fragmentTransaction = fragmentManager
.beginTransaction()
.setCustomAnimations(
R.anim.sliding_in_left,
R.anim.sliding_out_right,
android.R.anim.slide_in_left,
android.R.anim.slide_out_right
)
fragmentTransaction.replace(R.id.contentFrame, fragment, fragment.tag)
fragmentTransaction.addToBackStack(null)
fragmentTransaction.commit()
setTitle(titleName)
}
override fun onBackPressed() {
if (fragmentManager.backStackEntryCount == 0) {
super.onBackPressed()
} else {
setTitle(R.string.action_settings)
fragmentManager.popBackStack()
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
return true
}
return super.onOptionsItemSelected(item)
}
companion object {
const val TAG: String = "SettingsActivity"
}
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) {
}
}

View file

@ -1,399 +0,0 @@
package code.name.monkey.retromusic.activities.albums
import android.app.ActivityOptions
import android.content.Intent
import android.os.Bundle
import android.transition.Slide
import android.view.Menu
import android.view.MenuItem
import android.view.SubMenu
import android.view.View
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
import code.name.monkey.retromusic.activities.tageditor.AlbumTagEditorActivity
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.dialogs.DeleteSongsDialog
import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SortOrder.AlbumSongSortOrder
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.network.model.LastFmAlbum
import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.afollestad.materialcab.MaterialCab
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.activity_album.*
import kotlinx.android.synthetic.main.activity_album_content.*
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import java.util.*
import android.util.Pair as UtilPair
class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
cab?.let {
if (it.isActive) it.finish()
}
cab = MaterialCab(this, R.id.cab_stub)
.setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close)
.setBackgroundColor(
RetroColorUtil.shiftBackgroundColorForLightText(
ATHUtil.resolveColor(
this,
R.attr.colorSurface
)
)
)
.start(callback)
return cab as MaterialCab
}
private val detailsViewModel by viewModel<AlbumDetailsViewModel> {
parametersOf(extraNotNull<Int>(EXTRA_ALBUM_ID).value)
}
private lateinit var simpleSongAdapter: SimpleSongAdapter
private lateinit var album: Album
private var cab: MaterialCab? = null
private val savedSortOrder: String
get() = PreferenceUtil.albumDetailSongSortOrder
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_album)
}
private fun windowEnterTransition() {
val slide = Slide()
slide.excludeTarget(R.id.appBarLayout, true)
slide.excludeTarget(R.id.status_bar, true)
slide.excludeTarget(android.R.id.statusBarBackground, true)
slide.excludeTarget(android.R.id.navigationBarBackground, true)
window.enterTransition = slide
}
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setBottomBarVisibility(View.GONE)
window.sharedElementsUseOverlay = true
windowEnterTransition()
toolbar.setBackgroundColor(surfaceColor())
addMusicServiceEventListener(detailsViewModel)
ActivityCompat.postponeEnterTransition(this)
detailsViewModel.getAlbum().observe(this, androidx.lifecycle.Observer {
ActivityCompat.startPostponedEnterTransition(this@AlbumDetailsActivity)
showAlbum(it)
})
detailsViewModel.getArtist().observe(this, androidx.lifecycle.Observer {
loadArtistImage(it)
})
detailsViewModel.getMoreAlbums().observe(this, androidx.lifecycle.Observer {
moreAlbums(it)
})
detailsViewModel.getAlbumInfo().observe(this, androidx.lifecycle.Observer {
aboutAlbum(it)
})
setupRecyclerView()
artistImage.setOnClickListener {
val artistPairs = ActivityOptions.makeSceneTransitionAnimation(
this,
UtilPair.create(
artistImage,
getString(R.string.transition_artist_image)
)
)
NavigationUtil.goToArtistOptions(this, album.artistId, artistPairs)
}
playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
}
shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album.songs!!, true) }
}
aboutAlbumText.setOnClickListener {
if (aboutAlbumText.maxLines == 4) {
aboutAlbumText.maxLines = Integer.MAX_VALUE
} else {
aboutAlbumText.maxLines = 4
}
}
}
private fun setupRecyclerView() {
simpleSongAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song, this)
recyclerView.apply {
layoutManager = LinearLayoutManager(this@AlbumDetailsActivity)
itemAnimator = DefaultItemAnimator()
isNestedScrollingEnabled = false
adapter = simpleSongAdapter
}
}
private fun showAlbum(album: Album) {
if (album.songs!!.isEmpty()) {
finish()
return
}
this.album = album
albumTitle.text = album.title
val songText =
resources.getQuantityString(
R.plurals.albumSongs,
album.songCount,
album.songCount
)
songTitle.text = songText
if (MusicUtil.getYearString(album.year) == "-") {
albumText.text = String.format(
"%s • %s",
album.artistName,
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs))
)
} else {
albumText.text = String.format(
"%s • %s • %s",
album.artistName,
MusicUtil.getYearString(album.year),
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs))
)
}
loadAlbumCover()
simpleSongAdapter.swapDataSet(album.songs)
detailsViewModel.loadArtist(album.artistId)
detailsViewModel.loadAlbumInfo(album)
}
private fun moreAlbums(albums: List<Album>) {
moreTitle.show()
moreRecyclerView.show()
moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName)
val albumAdapter = HorizontalAlbumAdapter(this, albums, null)
moreRecyclerView.layoutManager = GridLayoutManager(
this,
1,
GridLayoutManager.HORIZONTAL,
false
)
moreRecyclerView.adapter = albumAdapter
}
private fun aboutAlbum(lastFmAlbum: LastFmAlbum) {
if (lastFmAlbum.album != null) {
if (lastFmAlbum.album.wiki != null) {
aboutAlbumText.show()
aboutAlbumTitle.show()
aboutAlbumTitle.text =
String.format(getString(R.string.about_album_label), lastFmAlbum.album.name)
aboutAlbumText.text = lastFmAlbum.album.wiki.content
}
if (lastFmAlbum.album.listeners.isNotEmpty()) {
listeners.show()
listenersLabel.show()
scrobbles.show()
scrobblesLabel.show()
listeners.text = RetroUtil.formatValue(lastFmAlbum.album.listeners.toFloat())
scrobbles.text = RetroUtil.formatValue(lastFmAlbum.album.playcount.toFloat())
}
}
}
private fun loadArtistImage(artist: Artist) {
ArtistGlideRequest.Builder.from(Glide.with(this), artist)
.generatePalette(this)
.build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(artistImage) {
override fun onColorReady(colors: MediaNotificationProcessor) {
}
})
}
private fun loadAlbumCover() {
AlbumGlideRequest.Builder.from(Glide.with(this), album.safeGetFirstSong())
.checkIgnoreMediaStore(this)
.ignoreMediaStore(PreferenceUtil.isIgnoreMediaStoreArtwork)
.generatePalette(this)
.build()
.dontAnimate()
.dontTransform()
.into(object : RetroMusicColoredTarget(image) {
override fun onColorReady(colors: MediaNotificationProcessor) {
setColors(colors)
}
})
}
private fun setColors(color: MediaNotificationProcessor) {
MaterialUtil.tintColor(
button = shuffleAction,
textColor = color.primaryTextColor,
backgroundColor = color.backgroundColor
)
MaterialUtil.tintColor(
button = playAction,
textColor = color.primaryTextColor,
backgroundColor = color.backgroundColor
)
setSupportActionBar(toolbar)
supportActionBar?.title = null
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_album_detail, menu)
val sortOrder = menu.findItem(R.id.action_sort_order)
setUpSortOrderMenu(sortOrder.subMenu)
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
this,
toolbar,
menu,
getToolbarBackgroundColor(toolbar)
)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return handleSortOrderMenuItem(item)
}
private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
var sortOrder: String? = null
val songs = simpleSongAdapter.dataSet
when (item.itemId) {
R.id.action_play_next -> {
MusicPlayerRemote.playNext(songs)
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(songs)
return true
}
R.id.action_add_to_playlist -> {
AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
return true
}
R.id.action_delete_from_device -> {
DeleteSongsDialog.create(songs).show(supportFragmentManager, "DELETE_SONGS")
return true
}
android.R.id.home -> {
super.onBackPressed()
return true
}
R.id.action_tag_editor -> {
val intent = Intent(this, AlbumTagEditorActivity::class.java)
intent.putExtra(AbsTagEditorActivity.EXTRA_ID, album.id)
val options = ActivityOptions.makeSceneTransitionAnimation(
this,
albumCoverContainer,
"${getString(R.string.transition_album_art)}_${album.id}"
)
startActivityForResult(
intent,
TAG_EDITOR_REQUEST, options.toBundle()
)
return true
}
/*Sort*/
R.id.action_sort_order_title -> sortOrder = AlbumSongSortOrder.SONG_A_Z
R.id.action_sort_order_title_desc -> sortOrder = AlbumSongSortOrder.SONG_Z_A
R.id.action_sort_order_track_list -> sortOrder = AlbumSongSortOrder.SONG_TRACK_LIST
R.id.action_sort_order_artist_song_duration ->
sortOrder = AlbumSongSortOrder.SONG_DURATION
}
if (sortOrder != null) {
item.isChecked = true
setSaveSortOrder(sortOrder)
}
return true
}
private fun setUpSortOrderMenu(sortOrder: SubMenu) {
when (savedSortOrder) {
AlbumSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title)
.isChecked = true
AlbumSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc)
.isChecked = true
AlbumSongSortOrder.SONG_TRACK_LIST -> sortOrder.findItem(R.id.action_sort_order_track_list)
.isChecked = true
AlbumSongSortOrder.SONG_DURATION -> sortOrder.findItem(R.id.action_sort_order_artist_song_duration)
.isChecked = true
}
}
private fun setSaveSortOrder(sortOrder: String) {
PreferenceUtil.albumDetailSongSortOrder = sortOrder
when (sortOrder) {
AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs?.sortWith(Comparator { o1, o2 ->
o1.trackNumber.compareTo(
o2.trackNumber
)
})
AlbumSongSortOrder.SONG_A_Z -> album.songs?.sortWith(Comparator { o1, o2 ->
o1.title.compareTo(
o2.title
)
})
AlbumSongSortOrder.SONG_Z_A -> album.songs?.sortWith(Comparator { o1, o2 ->
o2.title.compareTo(
o1.title
)
})
AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 ->
o1.duration.compareTo(
o2.duration
)
})
}
album.songs?.let { simpleSongAdapter.swapDataSet(it) }
}
override fun onBackPressed() {
if (cab != null && cab!!.isActive) {
cab?.finish()
} else {
super.onBackPressed()
}
}
override fun onDestroy() {
super.onDestroy()
removeMusicServiceEventListener(detailsViewModel)
}
companion object {
const val EXTRA_ALBUM_ID = "extra_album_id"
private const val TAG_EDITOR_REQUEST = 2001
}
}

View file

@ -1,324 +0,0 @@
package code.name.monkey.retromusic.activities.artists
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.text.Spanned
import android.transition.Slide
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.text.HtmlCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
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.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.network.model.LastFmArtist
import code.name.monkey.retromusic.util.CustomArtistImageUtil
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.afollestad.materialcab.MaterialCab
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.activity_artist_content.*
import kotlinx.android.synthetic.main.activity_artist_details.*
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import java.util.*
import kotlin.collections.ArrayList
class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
cab?.let {
if (it.isActive) it.finish()
}
cab = MaterialCab(this, R.id.cab_stub)
.setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close)
.setBackgroundColor(
RetroColorUtil.shiftBackgroundColorForLightText(
ATHUtil.resolveColor(
this,
R.attr.colorSurface
)
)
)
.start(callback)
return cab as MaterialCab
}
private var cab: MaterialCab? = null
private var biography: Spanned? = null
private lateinit var artist: Artist
private lateinit var songAdapter: SimpleSongAdapter
private lateinit var albumAdapter: HorizontalAlbumAdapter
private var forceDownload: Boolean = false
private val detailsViewModel: ArtistDetailsViewModel by viewModel {
parametersOf(extraNotNull<Int>(EXTRA_ARTIST_ID).value)
}
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_artist_details)
}
private fun windowEnterTransition() {
val slide = Slide()
slide.excludeTarget(R.id.appBarLayout, true)
slide.excludeTarget(R.id.status_bar, true)
slide.excludeTarget(android.R.id.statusBarBackground, true)
slide.excludeTarget(android.R.id.navigationBarBackground, true)
window.enterTransition = slide
}
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setBottomBarVisibility(View.GONE)
window.sharedElementsUseOverlay = true
windowEnterTransition()
toolbar.setBackgroundColor(surfaceColor())
addMusicServiceEventListener(detailsViewModel)
ActivityCompat.postponeEnterTransition(this)
detailsViewModel.getArtist().observe(this, androidx.lifecycle.Observer {
ActivityCompat.startPostponedEnterTransition(this@ArtistDetailActivity)
artist(it)
})
detailsViewModel.getArtistInfo().observe(this, androidx.lifecycle.Observer {
artistInfo(it)
})
setupRecyclerView()
playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
}
shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
}
biographyText.setOnClickListener {
if (biographyText.maxLines == 4) {
biographyText.maxLines = Integer.MAX_VALUE
} else {
biographyText.maxLines = 4
}
}
}
private fun setupRecyclerView() {
albumAdapter = HorizontalAlbumAdapter(this, ArrayList(), null)
albumRecyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false)
adapter = albumAdapter
}
songAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song, this)
recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(this.context)
adapter = songAdapter
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let {
CustomArtistImageUtil.getInstance(this).setCustomArtistImage(artist, it)
}
}
else -> if (resultCode == Activity.RESULT_OK) {
//reload()
}
}
}
fun artist(artist: Artist) {
if (artist.songs.isEmpty()) {
finish()
}
this.artist = artist
loadArtistImage(artist)
if (RetroUtil.isAllowedToDownloadMetadata(this)) {
loadBiography(artist.name)
}
artistTitle.text = artist.name
text.text = String.format(
"%s • %s",
MusicUtil.getArtistInfoString(this, artist),
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(artist.songs))
)
val songText =
resources.getQuantityString(
R.plurals.albumSongs,
artist.songCount,
artist.songCount
)
val albumText =
resources.getQuantityString(
R.plurals.albums,
artist.songCount,
artist.songCount
)
songTitle.text = songText
albumTitle.text = albumText
songAdapter.swapDataSet(artist.songs)
artist.albums?.let { albumAdapter.swapDataSet(it) }
}
private fun loadBiography(
name: String,
lang: String? = Locale.getDefault().language
) {
biography = null
this.lang = lang
detailsViewModel.loadBiography(name, lang, null)
}
private fun artistInfo(lastFmArtist: LastFmArtist?) {
if (lastFmArtist != null && lastFmArtist.artist != null) {
val bioContent = lastFmArtist.artist.bio.content
if (bioContent != null && bioContent.trim { it <= ' ' }.isNotEmpty()) {
biographyText.visibility = View.VISIBLE
biographyTitle.visibility = View.VISIBLE
biography = HtmlCompat.fromHtml(bioContent, HtmlCompat.FROM_HTML_MODE_LEGACY)
biographyText.text = biography
if (lastFmArtist.artist.stats.listeners.isNotEmpty()) {
listeners.show()
listenersLabel.show()
scrobbles.show()
scrobblesLabel.show()
listeners.text =
RetroUtil.formatValue(lastFmArtist.artist.stats.listeners.toFloat())
scrobbles.text =
RetroUtil.formatValue(lastFmArtist.artist.stats.playcount.toFloat())
}
}
}
// If the "lang" parameter is set and no biography is given, retry with default language
if (biography == null && lang != null) {
loadBiography(artist.name, null)
}
}
private var lang: String? = null
private fun loadArtistImage(artist: Artist) {
ArtistGlideRequest.Builder.from(Glide.with(this), artist)
.generatePalette(this).build()
.dontAnimate().into(object : RetroMusicColoredTarget(image) {
override fun onColorReady(colors: MediaNotificationProcessor) {
setColors(colors)
}
})
}
private fun setColors(color: MediaNotificationProcessor) {
MaterialUtil.tintColor(
button = shuffleAction,
textColor = color.primaryTextColor,
backgroundColor = color.backgroundColor
)
MaterialUtil.tintColor(
button = playAction,
textColor = color.primaryTextColor,
backgroundColor = color.backgroundColor
)
setSupportActionBar(toolbar)
supportActionBar?.title = null
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return handleSortOrderMenuItem(item)
}
private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
val songs = artist.songs
when (item.itemId) {
android.R.id.home -> {
super.onBackPressed()
return true
}
R.id.action_play_next -> {
MusicPlayerRemote.playNext(songs)
return true
}
R.id.action_add_to_current_playing -> {
MusicPlayerRemote.enqueue(songs)
return true
}
R.id.action_add_to_playlist -> {
AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
return true
}
R.id.action_set_artist_image -> {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(
Intent.createChooser(intent, getString(R.string.pick_from_local_storage)),
REQUEST_CODE_SELECT_IMAGE
)
return true
}
R.id.action_reset_artist_image -> {
Toast.makeText(
this@ArtistDetailActivity,
resources.getString(R.string.updating),
Toast.LENGTH_SHORT
)
.show()
CustomArtistImageUtil.getInstance(this@ArtistDetailActivity)
.resetCustomArtistImage(artist)
forceDownload = true
return true
}
}
return true
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_artist_detail, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onBackPressed() {
if (cab != null && cab!!.isActive) {
cab?.finish()
} else {
super.onBackPressed()
}
}
override fun onDestroy() {
super.onDestroy()
removeMusicServiceEventListener(detailsViewModel)
}
companion object {
const val EXTRA_ARTIST_ID = "extra_artist_id"
const val REQUEST_CODE_SELECT_IMAGE = 9003
}
}

View file

@ -12,15 +12,13 @@ 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.extensions.hide
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.MiniPlayerFragment
import code.name.monkey.retromusic.fragments.NowPlayingScreen
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.CategoryInfo
import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.views.BottomNavigationBarTinted
import com.google.android.material.bottomsheet.BottomSheetBehavior
@ -178,19 +176,18 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
}
private fun hideBottomBar(hide: Boolean) {
val heightOfBar = resources.getDimensionPixelSize(R.dimen.mini_player_height)
val heightOfBarWithTabs =
resources.getDimensionPixelSize(R.dimen.mini_player_height_expanded)
val heightOfBar = dimToPixel(R.dimen.mini_player_height)
val heightOfBarWithTabs = dimToPixel(R.dimen.mini_player_height_expanded)
if (hide) {
behavior.isHideable = true
behavior.peekHeight = 0
bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat()
bottomNavigationView.elevation = dipToPix(10f)
collapsePanel()
} else {
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
slidingPanel.elevation = DensityUtil.dip2px(this, 10f).toFloat()
bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat()
slidingPanel.elevation = dipToPix(10f)
bottomNavigationView.elevation = dipToPix(10f)
behavior.isHideable = false
behavior.peekHeight =
if (bottomNavigationView.visibility == View.VISIBLE) {
@ -204,8 +201,7 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
private fun chooseFragmentForTheme() {
cps = PreferenceUtil.nowPlayingScreen
miniPlayerFragment =
supportFragmentManager.findFragmentById(R.id.miniPlayerFragment) as MiniPlayerFragment
miniPlayerFragment = whichFragment<MiniPlayerFragment>(R.id.miniPlayerFragment)
miniPlayerFragment?.view?.setOnClickListener { expandPanel() }
}
@ -232,7 +228,6 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
}
open fun handleBackPress(): Boolean {
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
collapsePanel()
return true
@ -305,6 +300,11 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
}
}
fun hideBottomNavigation() {
behavior.isHideable = true
behavior.state == BottomSheetBehavior.STATE_HIDDEN
}
fun updateTabs() {
bottomNavigationView.menu.clear()
val currentTabs: List<CategoryInfo> = PreferenceUtil.libraryCategory

View file

@ -1,143 +0,0 @@
package code.name.monkey.retromusic.activities.genre
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.adapter.song.ShuffleButtonSongAdapter
import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.helper.menu.GenreMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import com.afollestad.materialcab.MaterialCab
import kotlinx.android.synthetic.main.activity_playlist_detail.*
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import java.util.*
/**
* @author Hemanth S (h4h13).
*/
class GenreDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
private val detailsViewModel: GenreDetailsViewModel by viewModel {
parametersOf(extraNotNull<Genre>(EXTRA_GENRE_ID).value)
}
private lateinit var genre: Genre
private lateinit var songAdapter: ShuffleButtonSongAdapter
private var cab: MaterialCab? = null
private fun getEmojiByUnicode(unicode: Int): String {
return String(Character.toChars(unicode))
}
private fun checkIsEmpty() {
checkForPadding()
emptyEmoji.text = getEmojiByUnicode(0x1F631)
empty?.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE
}
private fun checkForPadding() {
val height = DensityUtil.dip2px(this, 52f)
recyclerView.setPadding(0, 0, 0, (height))
}
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setBottomBarVisibility(View.GONE)
applyToolbar(toolbar)
setupRecyclerView()
detailsViewModel.getSongs().observe(this, androidx.lifecycle.Observer {
songs(it)
})
detailsViewModel.getGenre().observe(this, androidx.lifecycle.Observer {
genre = it
supportActionBar?.title = it.name
})
addMusicServiceEventListener(detailsViewModel)
}
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_playlist_detail)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_genre_detail, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
}
return GenreMenuHelper.handleMenuClick(this, genre, item)
}
private fun setupRecyclerView() {
songAdapter = ShuffleButtonSongAdapter(this, ArrayList(), R.layout.item_list, this)
recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(this@GenreDetailsActivity)
adapter = songAdapter
}
songAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
checkIsEmpty()
}
})
}
fun songs(songs: List<Song>) {
songAdapter.swapDataSet(songs)
}
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
if (cab != null && cab!!.isActive) cab?.finish()
cab = MaterialCab(this, R.id.cab_stub).setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close)
.setBackgroundColor(
RetroColorUtil.shiftBackgroundColorForLightText(
ATHUtil.resolveColor(
this,
R.attr.colorSurface
)
)
).start(callback)
return cab!!
}
override fun onBackPressed() {
if (cab != null && cab!!.isActive) cab!!.finish()
else {
recyclerView!!.stopScroll()
super.onBackPressed()
}
}
companion object {
const val EXTRA_GENRE_ID = "extra_genre_id"
}
}

View file

@ -35,7 +35,7 @@ import kotlin.collections.ArrayList
class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatcher {
private val viewModel: SearchViewModel by inject()
private var searchAdapter: SearchAdapter? = null
private lateinit var searchAdapter: SearchAdapter
private var query: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
@ -87,10 +87,10 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch
private fun setupRecyclerView() {
searchAdapter = SearchAdapter(this, emptyList())
searchAdapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
searchAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
empty.visibility = if (searchAdapter!!.itemCount < 1) View.VISIBLE else View.GONE
empty.visibility = if (searchAdapter.itemCount < 1) View.VISIBLE else View.GONE
}
})
recyclerView.apply {
@ -152,15 +152,11 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch
}
}
private fun showEmptyView() {
searchAdapter?.swapDataSet(ArrayList())
}
private fun showData(data: MutableList<Any>) {
if (data.isNotEmpty()) {
searchAdapter?.swapDataSet(data)
searchAdapter.swapDataSet(data)
} else {
showEmptyView()
searchAdapter.swapDataSet(ArrayList())
}
}
@ -215,7 +211,7 @@ class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatch
const val EXTRA_SHOW_MIC = "extra_show_mic"
const val QUERY: String = "query"
private const val REQ_CODE_SPEECH_INPUT = 9002
const val REQ_CODE_SPEECH_INPUT = 9002
}
}

View file

@ -0,0 +1,134 @@
package code.name.monkey.retromusic.activities.search
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.speech.RecognizerIntent
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat.getSystemService
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.transition.TransitionManager
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.SearchAdapter
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.fragments.MainActivityFragment
import kotlinx.android.synthetic.main.fragment_search.*
import org.koin.android.ext.android.inject
import java.util.*
import kotlin.collections.ArrayList
class SearchFragment : MainActivityFragment(R.layout.fragment_search), TextWatcher {
private val viewModel: SearchViewModel by inject()
private lateinit var searchAdapter: SearchAdapter
private var query: String? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupRecyclerView()
setupSearchView()
mainActivity.setSupportActionBar(toolbar)
mainActivity.setBottomBarVisibility(View.GONE)
voiceSearch.setOnClickListener { startMicSearch() }
clearText.setOnClickListener { searchView.clearText() }
keyboardPopup.setOnClickListener {
val inputManager =
getSystemService<InputMethodManager>(
requireContext(),
InputMethodManager::class.java
)
inputManager?.showSoftInput(searchView, InputMethodManager.SHOW_IMPLICIT)
}
keyboardPopup.accentColor()
if (savedInstanceState != null) {
query = savedInstanceState.getString(SearchActivity.QUERY)
}
viewModel.getSearchResult().observe(viewLifecycleOwner, Observer {
showData(it)
})
}
private fun showData(data: MutableList<Any>) {
if (data.isNotEmpty()) {
searchAdapter.swapDataSet(data)
} else {
searchAdapter.swapDataSet(ArrayList())
}
}
private fun setupRecyclerView() {
searchAdapter = SearchAdapter(requireActivity() as AppCompatActivity, emptyList())
searchAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
empty.visibility = if (searchAdapter.itemCount < 1) View.VISIBLE else View.GONE
}
})
recyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = searchAdapter
addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy > 0) {
keyboardPopup.shrink()
} else if (dy < 0) {
keyboardPopup.extend()
}
}
})
}
}
private fun setupSearchView() {
searchView.addTextChangedListener(this)
}
override fun afterTextChanged(newText: Editable?) {
search(newText.toString())
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
private fun search(query: String) {
this.query = query
TransitionManager.beginDelayedTransition(appBarLayout)
voiceSearch.visibility = if (query.isNotEmpty()) View.GONE else View.VISIBLE
clearText.visibility = if (query.isNotEmpty()) View.VISIBLE else View.GONE
viewModel.search(query)
}
private fun startMicSearch() {
val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
intent.putExtra(
RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
)
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())
intent.putExtra(RecognizerIntent.EXTRA_PROMPT, getString(R.string.speech_prompt))
try {
startActivityForResult(
intent,
SearchActivity.REQ_CODE_SPEECH_INPUT
)
} catch (e: ActivityNotFoundException) {
e.printStackTrace()
showToast(getString(R.string.speech_not_supported))
}
}
}

View file

@ -1,14 +1,16 @@
package code.name.monkey.retromusic.adapter
import android.app.Activity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.EXTRA_GENRE
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.util.NavigationUtil
import java.util.*
/**
@ -16,7 +18,7 @@ import java.util.*
*/
class GenreAdapter(
private val activity: Activity,
private val activity: FragmentActivity,
var dataSet: List<Genre>,
private val mItemLayoutRes: Int
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
@ -48,9 +50,10 @@ class GenreAdapter(
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
override fun onClick(v: View?) {
super.onClick(v)
val genre = dataSet[layoutPosition]
NavigationUtil.goToGenre(activity, genre)
activity.findNavController(R.id.fragment_container).navigate(
R.id.genreDetailsFragment,
bundleOf(EXTRA_GENRE to dataSet[layoutPosition])
)
}
}
}

View file

@ -1,6 +1,5 @@
package code.name.monkey.retromusic.adapter
import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -8,18 +7,24 @@ import android.widget.TextView
import androidx.annotation.IntDef
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.os.bundleOf
import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.HORIZONTAL
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.PeekingLinearLayoutManager
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
import code.name.monkey.retromusic.fragments.artists.ArtistClickListener
import code.name.monkey.retromusic.glide.SongGlideRequest
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
@ -29,8 +34,7 @@ import com.bumptech.glide.Glide
import com.google.android.material.card.MaterialCardView
class HomeAdapter(
private val activity: AppCompatActivity,
private val displayMetrics: DisplayMetrics
private val activity: AppCompatActivity
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var list = listOf<Home>()
@ -143,21 +147,28 @@ class HomeAdapter(
const val GENRES = 6
}
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view), AlbumClickListener {
fun bindView(list: List<Album>, titleRes: Int) {
if (list.isNotEmpty()) {
val albumAdapter = AlbumAdapter(activity, list, R.layout.pager_item, null, this)
recyclerView.apply {
show()
adapter = AlbumAdapter(activity, list, R.layout.pager_item, null)
layoutManager =
PeekingLinearLayoutManager(activity, HORIZONTAL, false)
adapter = albumAdapter
layoutManager = PeekingLinearLayoutManager(activity, HORIZONTAL, false)
}
title.text = activity.getString(titleRes)
}
}
override fun onAlbumClick(albumId: Int) {
activity.findNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to albumId)
)
}
}
inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
private inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view), ArtistClickListener {
fun bindView(list: List<Artist>, titleRes: Int) {
if (list.isNotEmpty()) {
val manager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
@ -165,7 +176,8 @@ class HomeAdapter(
activity,
list,
PreferenceUtil.homeGridStyle,
null
null,
this
)
recyclerView.apply {
show()
@ -175,6 +187,13 @@ class HomeAdapter(
title.text = activity.getString(titleRes)
}
}
override fun onArtist(artistId: Int) {
activity.findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to artistId)
)
}
}
private inner class SuggestionsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

View file

@ -1,13 +1,14 @@
package code.name.monkey.retromusic.adapter
import android.app.ActivityOptions
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.ArtistGlideRequest
@ -17,13 +18,11 @@ import code.name.monkey.retromusic.loaders.PlaylistSongsLoader
import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.NavigationUtil
import com.bumptech.glide.Glide
import android.util.Pair as UtilPair
class SearchAdapter(
private val activity: AppCompatActivity,
private var dataSet: List<Any>?
private val activity: FragmentActivity,
private var dataSet: List<Any>
) : RecyclerView.Adapter<SearchAdapter.ViewHolder>() {
fun swapDataSet(dataSet: MutableList<Any>) {
@ -32,11 +31,11 @@ class SearchAdapter(
}
override fun getItemViewType(position: Int): Int {
if (dataSet!![position] is Album) return ALBUM
if (dataSet!![position] is Artist) return ARTIST
if (dataSet!![position] is Genre) return GENRE
if (dataSet!![position] is Playlist) return PLAYLIST
return if (dataSet!![position] is Song) SONG else HEADER
if (dataSet[position] is Album) return ALBUM
if (dataSet[position] is Artist) return ARTIST
if (dataSet[position] is Genre) return GENRE
if (dataSet[position] is Playlist) return PLAYLIST
return if (dataSet[position] is Song) SONG else HEADER
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@ -57,35 +56,35 @@ class SearchAdapter(
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (getItemViewType(position)) {
ALBUM -> {
val album = dataSet?.get(position) as Album
val album = dataSet.get(position) as Album
holder.title?.text = album.title
holder.text?.text = album.artistName
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
.checkIgnoreMediaStore(activity).build().into(holder.image)
}
ARTIST -> {
val artist = dataSet?.get(position) as Artist
val artist = dataSet.get(position) as Artist
holder.title?.text = artist.name
holder.text?.text = MusicUtil.getArtistInfoString(activity, artist)
ArtistGlideRequest.Builder.from(Glide.with(activity), artist).build()
.into(holder.image)
}
SONG -> {
val song = dataSet?.get(position) as Song
val song = dataSet.get(position) as Song
holder.title?.text = song.title
holder.text?.text = song.albumName
}
GENRE -> {
val genre = dataSet?.get(position) as Genre
val genre = dataSet.get(position) as Genre
holder.title?.text = genre.name
}
PLAYLIST -> {
val playlist = dataSet?.get(position) as Playlist
val playlist = dataSet.get(position) as Playlist
holder.title?.text = playlist.name
holder.text?.text = MusicUtil.getPlaylistInfoString(activity, getSongs(playlist))
}
else -> {
holder.title?.text = dataSet?.get(position).toString()
holder.title?.text = dataSet.get(position).toString()
holder.title?.setTextColor(ThemeStore.accentColor(activity))
}
}
@ -102,7 +101,7 @@ class SearchAdapter(
}
override fun getItemCount(): Int {
return dataSet!!.size
return dataSet.size
}
inner class ViewHolder(itemView: View, itemViewType: Int) : MediaEntryViewHolder(itemView) {
@ -113,7 +112,7 @@ class SearchAdapter(
menu?.visibility = View.VISIBLE
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
override val song: Song
get() = dataSet!![layoutPosition] as Song
get() = dataSet[layoutPosition] as Song
})
} else {
menu?.visibility = View.GONE
@ -130,27 +129,31 @@ class SearchAdapter(
}
override fun onClick(v: View?) {
val item = dataSet!![layoutPosition]
val item = dataSet[layoutPosition]
when (itemViewType) {
ALBUM -> {
val options = ActivityOptions.makeSceneTransitionAnimation(
activity,
UtilPair.create(image, activity.getString(R.string.transition_album_art))
activity.findNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to (item as Album).id)
)
NavigationUtil.goToAlbumOptions(activity, (item as Album).id, options)
}
ARTIST -> {
val options = ActivityOptions.makeSceneTransitionAnimation(
activity,
UtilPair.create(image, activity.getString(R.string.transition_artist_image))
activity.findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to (item as Artist).id)
)
NavigationUtil.goToArtistOptions(activity, (item as Artist).id, options)
}
GENRE -> {
NavigationUtil.goToGenre(activity, item as Genre)
activity.findNavController(R.id.fragment_container).navigate(
R.id.genreDetailsFragment,
bundleOf(EXTRA_GENRE to (item as Genre))
)
}
PLAYLIST -> {
NavigationUtil.goToPlaylistNew(activity, item as Playlist)
activity.findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to (item as Playlist))
)
}
SONG -> {
val playList = ArrayList<Song>()

View file

@ -7,10 +7,11 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -20,17 +21,17 @@ import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import me.zhanghai.android.fastscroll.PopupTextProvider
open class AlbumAdapter(
protected val activity: AppCompatActivity,
protected val activity: FragmentActivity,
var dataSet: List<Album>,
protected var itemLayoutRes: Int,
cabHolder: CabHolder?
cabHolder: CabHolder?,
private val albumClickListener: AlbumClickListener?
) : AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album>(
activity,
cabHolder,
@ -177,11 +178,12 @@ open class AlbumAdapter(
imageContainerCard ?: image,
activity.getString(R.string.transition_album_art)
)
NavigationUtil.goToAlbumOptions(
albumClickListener?.onAlbumClick(dataSet[layoutPosition].id)
/*NavigationUtil.goToAlbumOptions(
activity,
dataSet[layoutPosition].id,
activityOptions
)
)*/
}
}

View file

@ -1,10 +1,10 @@
package code.name.monkey.retromusic.adapter.album
import android.graphics.drawable.Drawable
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.HorizontalAdapterHelper
@ -15,11 +15,12 @@ import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
class HorizontalAlbumAdapter(
activity: AppCompatActivity,
activity: FragmentActivity,
dataSet: List<Album>,
cabHolder: CabHolder?
cabHolder: CabHolder?,
albumClickListener: AlbumClickListener
) : AlbumAdapter(
activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, cabHolder
activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, cabHolder, albumClickListener
) {
override fun createViewHolder(view: View, viewType: Int): ViewHolder {
@ -40,11 +41,6 @@ class HorizontalAlbumAdapter(
.generatePalette(activity)
.build()
.into(object : RetroMusicColoredTarget(holder.image!!) {
override fun onLoadCleared(placeholder: Drawable?) {
super.onLoadCleared(placeholder)
//setColors(albumArtistFooterColor, holder)
}
override fun onColorReady(colors: MediaNotificationProcessor) {
setColors(colors, holder)
}

View file

@ -7,11 +7,12 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.fragments.artists.ArtistClickListener
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
@ -19,17 +20,17 @@ import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import me.zhanghai.android.fastscroll.PopupTextProvider
import java.util.*
class ArtistAdapter(
val activity: AppCompatActivity,
val activity: FragmentActivity,
var dataSet: List<Artist>,
var itemLayoutRes: Int,
cabHolder: CabHolder?
cabHolder: CabHolder?,
private val artistClickListener: ArtistClickListener
) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>(
activity, cabHolder, R.menu.menu_media_selection
), PopupTextProvider {
@ -144,9 +145,10 @@ class ArtistAdapter(
imageContainerCard ?: image,
activity.getString(R.string.transition_artist_image)
)
NavigationUtil.goToArtistOptions(
artistClickListener.onArtist(dataSet[layoutPosition].id)
/*NavigationUtil.goToArtistOptions(
activity, dataSet[layoutPosition].id, activityOptions
)
)*/
}
}

View file

@ -9,11 +9,14 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
import androidx.core.os.bundleOf
import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.EXTRA_PLAYLIST
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
@ -29,12 +32,11 @@ import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist
import code.name.monkey.retromusic.util.AutoGeneratedPlaylistBitmap
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import java.util.*
class PlaylistAdapter(
private val activity: AppCompatActivity,
private val activity: FragmentActivity,
var dataSet: List<Playlist>,
private var itemLayoutRes: Int,
cabHolder: CabHolder?
@ -165,9 +167,7 @@ class PlaylistAdapter(
val popupMenu = PopupMenu(activity, view)
popupMenu.inflate(R.menu.menu_item_playlist)
popupMenu.setOnMenuItemClickListener { item ->
PlaylistMenuHelper.handleMenuClick(
activity, dataSet[layoutPosition], item
)
PlaylistMenuHelper.handleMenuClick(activity, dataSet[layoutPosition], item)
}
popupMenu.show()
}
@ -182,8 +182,10 @@ class PlaylistAdapter(
if (isInQuickSelectMode) {
toggleChecked(layoutPosition)
} else {
val playlist = dataSet[layoutPosition]
NavigationUtil.goToPlaylistNew(activity, playlist)
activity.findNavController(R.id.fragment_container).navigate(
R.id.playlistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to dataSet[layoutPosition])
)
}
}

View file

@ -2,7 +2,7 @@ package code.name.monkey.retromusic.adapter.song
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.R.menu
import code.name.monkey.retromusic.dialogs.RemoveFromPlaylistDialog
@ -16,13 +16,16 @@ import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
class OrderablePlaylistSongAdapter(
activity: AppCompatActivity,
activity: FragmentActivity,
dataSet: ArrayList<Song>,
itemLayoutRes: Int,
cabHolder: CabHolder?,
private val onMoveItemListener: OnMoveItemListener?
) : PlaylistSongAdapter(
activity, dataSet, itemLayoutRes, cabHolder
) : SongAdapter(
activity,
dataSet,
itemLayoutRes,
cabHolder
), DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> {
init {
@ -91,7 +94,7 @@ class OrderablePlaylistSongAdapter(
fun onMoveItem(fromPosition: Int, toPosition: Int)
}
inner class ViewHolder(itemView: View) : PlaylistSongAdapter.ViewHolder(itemView),
inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView),
DraggableItemViewHolder {
@DraggableItemStateFlags
private var mDragStateFlags: Int = 0
@ -132,8 +135,4 @@ class OrderablePlaylistSongAdapter(
mDragStateFlags = flags
}
}
companion object {
val TAG: String = OrderablePlaylistSongAdapter::class.java.simpleName
}
}

View file

@ -3,6 +3,7 @@ package code.name.monkey.retromusic.adapter.song
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicPlayerRemote.isPlaying
@ -192,7 +193,7 @@ class PlayingQueueAdapter(
internal class SwipedResultActionRemoveItem(
private val adapter: PlayingQueueAdapter,
private val position: Int,
private val activity: AppCompatActivity
private val activity: FragmentActivity
) : SwipeResultActionRemoveItem() {
private var songToRemove: Song? = null

View file

@ -1,14 +1,15 @@
package code.name.monkey.retromusic.adapter.song
import android.app.ActivityOptions
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import androidx.navigation.findNavController
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.NavigationUtil
import com.google.android.material.button.MaterialButton
open class PlaylistSongAdapter(
@ -57,19 +58,14 @@ open class PlaylistSongAdapter(
override fun onSongMenuItemClick(item: MenuItem): Boolean {
if (item.itemId == R.id.action_go_to_album) {
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
activity,
imageContainerCard ?: image,
activity.getString(R.string.transition_album_art)
)
NavigationUtil.goToAlbumOptions(activity, song.albumId, activityOptions)
activity.findNavController(R.id.fragment_container)
.navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to song.albumId)
)
return true
}
return super.onSongMenuItemClick(item)
}
}
companion object {
val TAG: String = PlaylistSongAdapter::class.java.simpleName
}
}

View file

@ -2,14 +2,14 @@ package code.name.monkey.retromusic.adapter.song
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import java.util.*
class SimpleSongAdapter(
context: AppCompatActivity,
context: FragmentActivity,
songs: ArrayList<Song>,
layoutRes: Int,
cabHolder: CabHolder?

View file

@ -1,13 +1,15 @@
package code.name.monkey.retromusic.adapter.song
import android.app.ActivityOptions
import android.content.res.ColorStateList
import android.content.res.Resources
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
@ -22,7 +24,6 @@ import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.afollestad.materialcab.MaterialCab
@ -34,7 +35,7 @@ import me.zhanghai.android.fastscroll.PopupTextProvider
*/
open class SongAdapter(
protected val activity: AppCompatActivity,
protected val activity: FragmentActivity,
var dataSet: MutableList<Song>,
protected var itemLayoutRes: Int,
cabHolder: CabHolder?,
@ -175,12 +176,11 @@ open class SongAdapter(
if (image != null && image!!.visibility == View.VISIBLE) {
when (item.itemId) {
R.id.action_go_to_album -> {
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
activity,
imageContainerCard ?: image,
activity.getString(R.string.transition_album_art)
)
NavigationUtil.goToAlbumOptions(activity, song.albumId, activityOptions)
activity.findNavController(R.id.fragment_container)
.navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to song.albumId)
)
return true
}
}

View file

@ -22,13 +22,16 @@ import android.widget.Button
import android.widget.CheckBox
import android.widget.SeekBar
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
fun Int.ripAlpha(): Int {
return ColorUtil.stripAlpha(this)
@ -83,4 +86,20 @@ fun SeekBar.addAccentColor() {
fun Button.accentTextColor() {
setTextColor(ThemeStore.accentColor(App.getContext()))
}
fun SeekBar.applyColor(@ColorInt color: Int) {
thumbTintList = ColorStateList.valueOf(color)
progressTintList = ColorStateList.valueOf(color)
progressBackgroundTintList = ColorStateList.valueOf(color)
}
fun ExtendedFloatingActionButton.accentColor() {
val color = ThemeStore.accentColor(context)
val textColor = MaterialValueHelper.getPrimaryTextColor(context, ColorUtil.isColorLight(color))
val colorStateList = ColorStateList.valueOf(color)
val textColorStateList = ColorStateList.valueOf(textColor)
backgroundTintList = colorStateList
setTextColor(textColorStateList)
iconTint = textColorStateList
}

View file

@ -0,0 +1,20 @@
package code.name.monkey.retromusic.extensions
import android.app.Activity
import androidx.annotation.DimenRes
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
fun AppCompatActivity.dimToPixel(@DimenRes dimenRes: Int): Int {
return resources.getDimensionPixelSize(dimenRes)
}
fun Activity.dipToPix(dpInFloat: Float): Float {
val scale = resources.displayMetrics.density
return dpInFloat * scale + 0.5f
}
fun Fragment.dipToPix(dpInFloat: Float): Float {
val scale = resources.displayMetrics.density
return dpInFloat * scale + 0.5f
}

View file

@ -3,7 +3,10 @@ package code.name.monkey.retromusic.extensions
import android.content.Context
import android.content.res.Configuration
import android.os.PowerManager
import android.widget.Toast
import androidx.annotation.IdRes
import androidx.annotation.IntegerRes
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
@ -53,3 +56,17 @@ fun AppCompatActivity.currentFragment(navHostId: Int): Fragment? {
navHostFragment.targetFragment
return navHostFragment?.childFragmentManager?.fragments?.first()
}
@Suppress("UNCHECKED_CAST")
fun <T> AppCompatActivity.whichFragment(@IdRes id: Int): T {
return supportFragmentManager.findFragmentById(id) as T
}
fun Fragment.showToast(@StringRes stringRes: Int) {
showToast(getString(stringRes))
}
fun Fragment.showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}

View file

@ -4,17 +4,22 @@ import androidx.annotation.IdRes
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.findNavController
fun Fragment.navigate(@IdRes id: Int) = findNavController().navigate(id)
fun Fragment.navController(@IdRes id: Int): NavController {
fun Fragment.findNavController(@IdRes id: Int): NavController {
val fragment = childFragmentManager.findFragmentById(id) as NavHostFragment
return fragment.navController
}
fun AppCompatActivity.navController(@IdRes id: Int): NavController {
fun Fragment.findActivityNavController(@IdRes id: Int): NavController {
return requireActivity().findNavController(id)
}
fun AppCompatActivity.findNavController(@IdRes id: Int): NavController {
val fragment = supportFragmentManager.findFragmentById(id) as NavHostFragment
return fragment.navController
}

View file

@ -48,9 +48,3 @@ fun EditText.appHandleColor(): EditText {
TintHelper.colorHandles(this, ThemeStore.accentColor(context))
return this
}
fun SeekBar.applyColor(@ColorInt color: Int) {
thumbTintList = ColorStateList.valueOf(color)
progressTintList = ColorStateList.valueOf(color)
progressBackgroundTintList = ColorStateList.valueOf(color)
}

View file

@ -0,0 +1,11 @@
package code.name.monkey.retromusic.fragments
import androidx.annotation.LayoutRes
import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
open class MainActivityFragment(@LayoutRes layoutRes: Int) : AbsMusicServiceFragment(layoutRes) {
val mainActivity by lazy {
requireActivity() as MainActivity
}
}

View file

@ -1,4 +1,4 @@
package code.name.monkey.retromusic.activities
package code.name.monkey.retromusic.fragments.about
import android.content.Intent
import android.content.pm.PackageManager

View file

@ -0,0 +1,128 @@
package code.name.monkey.retromusic.fragments.about
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.view.View
import androidx.core.app.ShareCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.Constants
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.ContributorAdapter
import code.name.monkey.retromusic.fragments.MainActivityFragment
import code.name.monkey.retromusic.model.Contributor
import code.name.monkey.retromusic.util.NavigationUtil
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kotlinx.android.synthetic.main.activity_about.*
import kotlinx.android.synthetic.main.card_credit.*
import kotlinx.android.synthetic.main.card_other.*
import kotlinx.android.synthetic.main.card_retro_info.*
import kotlinx.android.synthetic.main.card_social.*
import java.io.IOException
import java.nio.charset.StandardCharsets
class AboutFragment : MainActivityFragment(R.layout.fragment_about), View.OnClickListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainActivity.setSupportActionBar(toolbar)
version.setSummary(getAppVersion())
setUpView()
loadContributors()
}
private val contributorsJson: String?
get() {
val json: String
try {
val inputStream = requireActivity().assets.open("contributors.json")
val size = inputStream.available()
val buffer = ByteArray(size)
inputStream.read(buffer)
inputStream.close()
json = String(buffer, StandardCharsets.UTF_8)
} catch (ex: IOException) {
ex.printStackTrace()
return null
}
return json
}
private fun openUrl(url: String) {
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(url)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(i)
}
private fun setUpView() {
appGithub.setOnClickListener(this)
faqLink.setOnClickListener(this)
telegramLink.setOnClickListener(this)
appRate.setOnClickListener(this)
appTranslation.setOnClickListener(this)
appShare.setOnClickListener(this)
donateLink.setOnClickListener(this)
instagramLink.setOnClickListener(this)
twitterLink.setOnClickListener(this)
changelog.setOnClickListener(this)
openSource.setOnClickListener(this)
pinterestLink.setOnClickListener(this)
bugReportLink.setOnClickListener(this)
}
override fun onClick(view: View) {
when (view.id) {
R.id.pinterestLink -> openUrl(Constants.PINTEREST)
R.id.faqLink -> openUrl(Constants.FAQ_LINK)
R.id.telegramLink -> openUrl(Constants.APP_TELEGRAM_LINK)
R.id.appGithub -> openUrl(Constants.GITHUB_PROJECT)
R.id.appTranslation -> openUrl(Constants.TRANSLATE)
R.id.appRate -> openUrl(Constants.RATE_ON_GOOGLE_PLAY)
R.id.appShare -> shareApp()
R.id.donateLink -> NavigationUtil.goToSupportDevelopment(requireActivity())
R.id.instagramLink -> openUrl(Constants.APP_INSTAGRAM_LINK)
R.id.twitterLink -> openUrl(Constants.APP_TWITTER_LINK)
R.id.changelog -> openUrl(Constants.TELEGRAM_CHANGE_LOG)
R.id.openSource -> NavigationUtil.goToOpenSource(requireActivity())
R.id.bugReportLink -> NavigationUtil.bugReport(requireActivity())
}
}
private fun getAppVersion(): String {
return try {
val isPro = if (App.isProVersion()) "Pro" else "Free"
val packageInfo =
requireActivity().packageManager.getPackageInfo(requireActivity().packageName, 0)
"${packageInfo.versionName} $isPro"
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
"0.0.0"
}
}
private fun shareApp() {
ShareCompat.IntentBuilder.from(requireActivity()).setType("text/plain")
.setChooserTitle(R.string.share_app)
.setText(String.format(getString(R.string.app_share), requireActivity().packageName))
.startChooser()
}
private fun loadContributors() {
val type = object : TypeToken<List<Contributor>>() {
}.type
val contributors = Gson().fromJson<List<Contributor>>(contributorsJson, type)
val contributorAdapter = ContributorAdapter(contributors)
recyclerView.apply {
layoutManager = LinearLayoutManager(requireContext())
itemAnimator = DefaultItemAnimator()
adapter = contributorAdapter
}
}
}

View file

@ -1,23 +1,25 @@
package code.name.monkey.retromusic.activities.albums
package code.name.monkey.retromusic.fragments.albums
import android.app.ActivityOptions
import android.os.Bundle
import android.transition.TransitionInflater
import android.util.Pair
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
import code.name.monkey.retromusic.fragments.MainActivityFragment
import code.name.monkey.retromusic.glide.AlbumGlideRequest
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
@ -26,60 +28,56 @@ import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.network.model.LastFmAlbum
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.activity_album.*
import kotlinx.android.synthetic.main.activity_album_content.*
import kotlinx.android.synthetic.main.activity_album_details.*
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import java.util.*
class AlbumDetailsFragment : AbsMusicServiceFragment(R.layout.fragment_album_details) {
class AlbumDetailsFragment : MainActivityFragment(R.layout.fragment_album_details),
AlbumClickListener {
private lateinit var simpleSongAdapter: SimpleSongAdapter
private lateinit var album: Album
private val savedSortOrder: String
get() = PreferenceUtil.albumDetailSongSortOrder
private val detailsViewModel by viewModel<AlbumDetailsViewModel> {
parametersOf(extraNotNull<Int>(AlbumDetailsActivity.EXTRA_ALBUM_ID).value)
}
private fun setSharedElementTransitionOnEnter() {
sharedElementEnterTransition = TransitionInflater.from(context)
.inflateTransition(R.transition.change_bounds)
private val detailsViewModel by viewModel<AlbumDetailsViewModel> {
parametersOf(extraNotNull<Int>(EXTRA_ALBUM_ID).value)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setSharedElementTransitionOnEnter()
mainActivity.setSupportActionBar(toolbar)
mainActivity.setBottomBarVisibility(View.GONE)
toolbar.title = null
postponeEnterTransition()
playerActivity?.addMusicServiceEventListener(detailsViewModel)
detailsViewModel.getAlbum().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer {
startPostponedEnterTransition()
showAlbum(it)
})
detailsViewModel.getArtist().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
loadArtistImage(it)
})
detailsViewModel.getMoreAlbums().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
detailsViewModel.getMoreAlbums().observe(viewLifecycleOwner, Observer {
moreAlbums(it)
})
detailsViewModel.getAlbumInfo().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
detailsViewModel.getAlbumInfo().observe(viewLifecycleOwner, Observer {
aboutAlbum(it)
})
setupRecyclerView()
artistImage.setOnClickListener {
val artistPairs = ActivityOptions.makeSceneTransitionAnimation(
requireActivity(),
Pair.create(
artistImage,
getString(R.string.transition_artist_image)
requireActivity().findNavController(R.id.fragment_container)
.navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to album.artistId)
)
)
NavigationUtil.goToArtistOptions(requireActivity(), album.artistId, artistPairs)
}
playAction.setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
@ -177,7 +175,7 @@ class AlbumDetailsFragment : AbsMusicServiceFragment(R.layout.fragment_album_det
moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName)
val albumAdapter =
HorizontalAlbumAdapter(requireActivity() as AppCompatActivity, albums, null)
HorizontalAlbumAdapter(requireActivity() as AppCompatActivity, albums, null, this)
moreRecyclerView.layoutManager = GridLayoutManager(
requireContext(),
1,
@ -247,4 +245,11 @@ class AlbumDetailsFragment : AbsMusicServiceFragment(R.layout.fragment_album_det
backgroundColor = color.backgroundColor
)
}
override fun onAlbumClick(albumId: Int) {
findNavController().navigate(
R.id.albumDetailsFragment,
bundleOf("extra_album_id" to albumId)
)
}
}

View file

@ -1,4 +1,4 @@
package code.name.monkey.retromusic.activities.albums
package code.name.monkey.retromusic.fragments.albums
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData

View file

@ -2,22 +2,20 @@ package code.name.monkey.retromusic.fragments.albums
import android.os.Bundle
import android.view.View
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
import code.name.monkey.retromusic.util.PreferenceUtil
class AlbumsFragment :
AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
MainActivityFragmentCallbacks {
override fun handleBackPress(): Boolean {
return false
}
AlbumClickListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -40,10 +38,11 @@ class AlbumsFragment :
override fun createAdapter(): AlbumAdapter {
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
return AlbumAdapter(
mainActivity,
requireActivity(),
dataSet,
itemLayoutRes(),
mainActivity
R.layout.item_grid,
null,
this
)
}
@ -90,12 +89,17 @@ class AlbumsFragment :
companion object {
@JvmField
var TAG: String = AlbumsFragment::class.java.simpleName
@JvmStatic
fun newInstance(): AlbumsFragment {
return AlbumsFragment()
}
}
override fun onAlbumClick(albumId: Int) {
val controller = requireActivity().findNavController(R.id.fragment_container)
controller.navigate(R.id.albumDetailsFragment, bundleOf(EXTRA_ALBUM_ID to albumId))
}
}
interface AlbumClickListener {
fun onAlbumClick(albumId: Int)
}

View file

@ -0,0 +1,194 @@
package code.name.monkey.retromusic.fragments.artists
import android.os.Bundle
import android.text.Spanned
import android.view.View
import androidx.core.os.bundleOf
import androidx.core.text.HtmlCompat
import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.album.HorizontalAlbumAdapter
import code.name.monkey.retromusic.adapter.song.SimpleSongAdapter
import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.MainActivityFragment
import code.name.monkey.retromusic.fragments.albums.AlbumClickListener
import code.name.monkey.retromusic.glide.ArtistGlideRequest
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.network.model.LastFmArtist
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.activity_artist_content.*
import kotlinx.android.synthetic.main.activity_artist_details.*
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import java.util.*
import kotlin.collections.ArrayList
class ArtistDetailsFragment : MainActivityFragment(R.layout.fragment_artist_details),
AlbumClickListener {
private var biography: Spanned? = null
private lateinit var artist: Artist
private lateinit var songAdapter: SimpleSongAdapter
private lateinit var albumAdapter: HorizontalAlbumAdapter
private var forceDownload: Boolean = false
private var lang: String? = null
private val detailsViewModel: ArtistDetailsViewModel by viewModel {
parametersOf(extraNotNull<Int>(EXTRA_ARTIST_ID).value)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainActivity.setSupportActionBar(toolbar)
mainActivity.setBottomBarVisibility(View.GONE)
toolbar.title = null
postponeEnterTransition()
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
startPostponedEnterTransition()
showArtist(it)
})
detailsViewModel.getArtistInfo().observe(viewLifecycleOwner, Observer {
artistInfo(it)
})
setupRecyclerView()
playAction.apply {
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
}
shuffleAction.apply {
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(artist.songs, true) }
}
biographyText.setOnClickListener {
if (biographyText.maxLines == 4) {
biographyText.maxLines = Integer.MAX_VALUE
} else {
biographyText.maxLines = 4
}
}
}
private fun setupRecyclerView() {
albumAdapter = HorizontalAlbumAdapter(requireActivity(), ArrayList(), null, this)
albumRecyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false)
adapter = albumAdapter
}
songAdapter = SimpleSongAdapter(requireActivity(), ArrayList(), R.layout.item_song, null)
recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(this.context)
adapter = songAdapter
}
}
fun showArtist(artist: Artist) {
this.artist = artist
loadArtistImage(artist)
if (RetroUtil.isAllowedToDownloadMetadata(requireContext())) {
loadBiography(artist.name)
}
artistTitle.text = artist.name
text.text = String.format(
"%s • %s",
MusicUtil.getArtistInfoString(requireContext(), artist),
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(artist.songs))
)
val songText =
resources.getQuantityString(
R.plurals.albumSongs,
artist.songCount,
artist.songCount
)
val albumText =
resources.getQuantityString(
R.plurals.albums,
artist.songCount,
artist.songCount
)
songTitle.text = songText
albumTitle.text = albumText
songAdapter.swapDataSet(artist.songs)
artist.albums?.let { albumAdapter.swapDataSet(it) }
}
private fun loadBiography(
name: String,
lang: String? = Locale.getDefault().language
) {
biography = null
this.lang = lang
detailsViewModel.loadBiography(name, lang, null)
}
private fun artistInfo(lastFmArtist: LastFmArtist?) {
if (lastFmArtist != null && lastFmArtist.artist != null) {
val bioContent = lastFmArtist.artist.bio.content
if (bioContent != null && bioContent.trim { it <= ' ' }.isNotEmpty()) {
biographyText.visibility = View.VISIBLE
biographyTitle.visibility = View.VISIBLE
biography = HtmlCompat.fromHtml(bioContent, HtmlCompat.FROM_HTML_MODE_LEGACY)
biographyText.text = biography
if (lastFmArtist.artist.stats.listeners.isNotEmpty()) {
listeners.show()
listenersLabel.show()
scrobbles.show()
scrobblesLabel.show()
listeners.text =
RetroUtil.formatValue(lastFmArtist.artist.stats.listeners.toFloat())
scrobbles.text =
RetroUtil.formatValue(lastFmArtist.artist.stats.playcount.toFloat())
}
}
}
// If the "lang" parameter is set and no biography is given, retry with default language
if (biography == null && lang != null) {
loadBiography(artist.name, null)
}
}
private fun loadArtistImage(artist: Artist) {
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
.generatePalette(requireContext()).build()
.dontAnimate().into(object : RetroMusicColoredTarget(image) {
override fun onColorReady(colors: MediaNotificationProcessor) {
setColors(colors)
}
})
}
private fun setColors(color: MediaNotificationProcessor) {
MaterialUtil.tintColor(
button = shuffleAction,
textColor = color.primaryTextColor,
backgroundColor = color.backgroundColor
)
MaterialUtil.tintColor(
button = playAction,
textColor = color.primaryTextColor,
backgroundColor = color.backgroundColor
)
}
override fun onAlbumClick(albumId: Int) {
findNavController().navigate(
R.id.albumDetailsFragment,
bundleOf("extra_album_id" to albumId)
)
}
}

View file

@ -1,4 +1,4 @@
package code.name.monkey.retromusic.activities.artists
package code.name.monkey.retromusic.fragments.artists
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData

View file

@ -2,10 +2,13 @@ package code.name.monkey.retromusic.fragments.artists
import android.os.Bundle
import android.view.View
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.GridLayoutManager
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
import code.name.monkey.retromusic.extensions.findActivityNavController
import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
@ -13,7 +16,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil
class ArtistsFragment :
AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
MainActivityFragmentCallbacks {
MainActivityFragmentCallbacks, ArtistClickListener {
override fun handleBackPress(): Boolean {
return false
@ -46,10 +49,11 @@ class ArtistsFragment :
override fun createAdapter(): ArtistAdapter {
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
return ArtistAdapter(
mainActivity,
requireActivity(),
dataSet,
itemLayoutRes(),
mainActivity
R.layout.item_grid_circle,
null,
this
)
}
@ -91,12 +95,18 @@ class ArtistsFragment :
}
companion object {
@JvmField
val TAG: String = ArtistsFragment::class.java.simpleName
@JvmStatic
fun newInstance(): ArtistsFragment {
return ArtistsFragment()
}
}
override fun onArtist(artistId: Int) {
val controller = findActivityNavController(R.id.fragment_container)
controller.navigate(R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to artistId))
}
}
interface ArtistClickListener {
fun onArtist(artistId: Int)
}

View file

@ -14,6 +14,10 @@ import android.view.View
import android.widget.Toast
import androidx.annotation.LayoutRes
import androidx.appcompat.widget.Toolbar
import androidx.core.os.bundleOf
import androidx.navigation.findNavController
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity
@ -86,11 +90,17 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
return true
}
R.id.action_go_to_album -> {
NavigationUtil.goToAlbum(requireActivity(), song.albumId)
requireActivity().findNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to song.albumId)
)
return true
}
R.id.action_go_to_artist -> {
NavigationUtil.goToArtist(requireActivity(), song.artistId)
requireActivity().findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to song.artistId)
)
return true
}
R.id.now_playing -> {

View file

@ -7,7 +7,6 @@ import androidx.annotation.NonNull
import androidx.annotation.StringRes
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.DensityUtil
@ -24,8 +23,7 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
AppBarLayout.OnOffsetChangedListener {
val libraryViewModel: LibraryViewModel by sharedViewModel()
val mainActivity: MainActivity
get() = requireActivity() as MainActivity
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
@ -38,7 +36,6 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainActivity.addOnAppBarOffsetChangedListener(this)
initLayoutManager()
initAdapter()
setUpRecyclerView()
@ -112,7 +109,7 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
container.paddingLeft,
container.paddingTop,
container.paddingRight,
mainActivity.getTotalAppBarScrollingRange() + i
i
)
}
@ -137,11 +134,6 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
recyclerView.adapter = adapter
}
override fun onDestroyView() {
super.onDestroyView()
mainActivity.removeOnAppBarOffsetChangedListener(this)
}
fun recyclerView(): RecyclerView {
return recyclerView
}

View file

@ -0,0 +1,76 @@
package code.name.monkey.retromusic.fragments.genres
import android.os.Bundle
import android.view.View
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.EXTRA_GENRE
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.extensions.dipToPix
import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.fragments.MainActivityFragment
import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.model.Song
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import java.util.*
class GenreDetailsFragment : MainActivityFragment(R.layout.fragment_playlist_detail) {
private val detailsViewModel: GenreDetailsViewModel by viewModel {
parametersOf(extraNotNull<Genre>(EXTRA_GENRE).value)
}
private lateinit var genre: Genre
private lateinit var songAdapter: SongAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainActivity.addMusicServiceEventListener(detailsViewModel)
mainActivity.setSupportActionBar(toolbar)
setupRecyclerView()
detailsViewModel.getSongs().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
songs(it)
})
detailsViewModel.getGenre().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
genre = it
toolbar?.title = it.name
})
}
private fun setupRecyclerView() {
songAdapter = SongAdapter(requireActivity(), ArrayList(), R.layout.item_list, null)
recyclerView.apply {
itemAnimator = DefaultItemAnimator()
layoutManager = LinearLayoutManager(requireContext())
adapter = songAdapter
}
songAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
super.onChanged()
checkIsEmpty()
}
})
}
fun songs(songs: List<Song>) {
songAdapter.swapDataSet(songs)
}
private fun getEmojiByUnicode(unicode: Int): String {
return String(Character.toChars(unicode))
}
private fun checkIsEmpty() {
checkForPadding()
emptyEmoji.text = getEmojiByUnicode(0x1F631)
empty?.visibility = if (songAdapter.itemCount == 0) View.VISIBLE else View.GONE
}
private fun checkForPadding() {
val height = dipToPix(52f).toInt()
recyclerView.setPadding(0, 0, 0, height)
}
}

View file

@ -1,4 +1,4 @@
package code.name.monkey.retromusic.activities.genre
package code.name.monkey.retromusic.fragments.genres
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData

View file

@ -49,7 +49,7 @@ class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager
override fun createAdapter(): GenreAdapter {
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
return GenreAdapter(mainActivity, dataSet, R.layout.item_list_no_image)
return GenreAdapter(requireActivity(), dataSet, R.layout.item_list_no_image)
}
override val emptyMessage: Int

View file

@ -18,8 +18,11 @@ import android.app.ActivityOptions
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.View
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import androidx.navigation.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.retromusic.EXTRA_PLAYLIST
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.HomeAdapter
import code.name.monkey.retromusic.fragments.LibraryViewModel
@ -40,7 +43,7 @@ import kotlinx.android.synthetic.main.fragment_banner_home.*
import kotlinx.android.synthetic.main.home_content.*
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class BannerHomeFragment :
class HomeFragment :
AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home),
MainActivityFragmentCallbacks {
@ -73,13 +76,16 @@ class BannerHomeFragment :
}
lastAdded.setOnClickListener {
NavigationUtil.goToPlaylistNew(requireActivity(), LastAddedPlaylist(requireActivity()))
requireActivity().findNavController(R.id.fragment_container).navigate(
R.id.playlistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to LastAddedPlaylist(requireActivity()))
)
}
topPlayed.setOnClickListener {
NavigationUtil.goToPlaylistNew(
requireActivity(),
MyTopTracksPlaylist(requireActivity())
requireActivity().findNavController(R.id.fragment_container).navigate(
R.id.playlistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to MyTopTracksPlaylist(requireActivity()))
)
}
@ -88,7 +94,10 @@ class BannerHomeFragment :
}
history.setOnClickListener {
NavigationUtil.goToPlaylistNew(requireActivity(), HistoryPlaylist(requireActivity()))
requireActivity().findNavController(R.id.fragment_container).navigate(
R.id.playlistDetailsFragment,
bundleOf(EXTRA_PLAYLIST to HistoryPlaylist(requireActivity()))
)
}
userImage.setOnClickListener {
@ -101,7 +110,7 @@ class BannerHomeFragment :
}
titleWelcome?.text = String.format("%s", PreferenceUtil.userName)
val homeAdapter = HomeAdapter(mainActivity, displayMetrics)
val homeAdapter = HomeAdapter(mainActivity)
recyclerView.apply {
layoutManager = LinearLayoutManager(mainActivity)
adapter = homeAdapter
@ -133,8 +142,8 @@ class BannerHomeFragment :
const val TAG: String = "BannerHomeFragment"
@JvmStatic
fun newInstance(): BannerHomeFragment {
return BannerHomeFragment()
fun newInstance(): HomeFragment {
return HomeFragment()
}
}
}

View file

@ -0,0 +1,130 @@
package code.name.monkey.retromusic.fragments.library
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.navigation.fragment.findNavController
import androidx.navigation.navOptions
import androidx.navigation.ui.AppBarConfiguration
import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.findNavController
import code.name.monkey.retromusic.fragments.MainActivityFragment
import code.name.monkey.retromusic.fragments.folder.FoldersFragment
import code.name.monkey.retromusic.util.PreferenceUtil
import com.google.android.material.appbar.AppBarLayout
import kotlinx.android.synthetic.main.fragment_library.*
class LibraryFragment : MainActivityFragment(R.layout.fragment_library) {
private val navOptions by lazy {
navOptions {
launchSingleTop = true
anim {
enter = R.anim.retro_fragment_open_enter
exit = R.anim.retro_fragment_open_exit
popEnter = R.anim.retro_fragment_close_enter
popExit = R.anim.retro_fragment_close_exit
}
}
}
private val appBarConfiguration by lazy {
AppBarConfiguration(
setOf(
R.id.libraryFragment,
R.id.settingsFragment,
R.id.searchFragment
)
)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
mainActivity.setBottomBarVisibility(View.VISIBLE)
mainActivity.setSupportActionBar(toolbar)
setupNavigationController()
}
private fun setupNavigationController() {
val navController = findNavController(R.id.fragment_container)
val navOptions = navOptions {
launchSingleTop = true
anim {
enter = R.anim.retro_fragment_open_enter
exit = R.anim.retro_fragment_open_exit
popEnter = R.anim.retro_fragment_close_enter
popExit = R.anim.retro_fragment_close_exit
}
popUpTo(navController.graph.startDestination) {
inclusive = true
}
}
mainActivity.getBottomNavigationView().setOnNavigationItemSelectedListener {
var handled = false
if (navController.graph.findNode(it.itemId) != null) {
navController.navigate(it.itemId, null, navOptions)
handled = true
}
when (it.itemId) {
R.id.action_folder -> navController.navigate(
R.id.action_folder,
Bundle().apply {
putSerializable(
FoldersFragment.PATH,
PreferenceUtil.startDirectory
)
},
navOptions
)
}
return@setOnNavigationItemSelectedListener handled
}
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), toolbar)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.menu_main, menu)
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(),
toolbar,
menu,
getToolbarBackgroundColor(toolbar)
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_search -> findNavController().navigate(
R.id.searchFragment,
null,
navOptions
)
R.id.action_settings -> findNavController().navigate(
R.id.settingsFragment,
null,
navOptions
)
}
return super.onOptionsItemSelected(item)
}
fun addOnAppBarOffsetChangedListener(changedListener: AppBarLayout.OnOffsetChangedListener) {
appBarLayout.addOnOffsetChangedListener(changedListener)
}
fun removeOnAppBarOffsetChangedListener(changedListener: AppBarLayout.OnOffsetChangedListener) {
appBarLayout.removeOnOffsetChangedListener(changedListener)
}
fun getTotalAppBarScrollingRange(): Int {
return 0
}
}

View file

@ -4,7 +4,7 @@ import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.navigation.NavController
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.navController
import code.name.monkey.retromusic.extensions.findNavController
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
import code.name.monkey.retromusic.util.PreferenceUtil
@ -15,7 +15,7 @@ class NowPlayingPlayerFragment : Fragment(R.layout.fragment_now_playing_player)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val navController = navController(R.id.playerFragmentContainer)
val navController = findNavController(R.id.playerFragmentContainer)
updateNowPlaying(navController)
}

View file

@ -1,6 +1,5 @@
package code.name.monkey.retromusic.fragments.player.full
import android.app.ActivityOptions
import android.content.res.ColorStateList
import android.graphics.Color
import android.os.Bundle
@ -8,7 +7,10 @@ import android.view.View
import android.widget.FrameLayout
import android.widget.TextView
import androidx.appcompat.widget.Toolbar
import androidx.core.os.bundleOf
import androidx.navigation.findNavController
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
@ -22,7 +24,6 @@ import code.name.monkey.retromusic.loaders.ArtistLoader
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics
import code.name.monkey.retromusic.model.lyrics.Lyrics
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.fragment_full.*
@ -150,19 +151,11 @@ class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
private fun setupArtist() {
artistImage.setOnClickListener {
val transitionName =
"${getString(R.string.transition_artist_image)}_${MusicPlayerRemote.currentSong.artistId}"
val activityOptions =
ActivityOptions.makeSceneTransitionAnimation(
requireActivity(),
artistImage,
transitionName
requireActivity().findNavController(R.id.fragment_container)
.navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to MusicPlayerRemote.currentSong.artistId)
)
NavigationUtil.goToArtistOptions(
requireActivity(),
MusicPlayerRemote.currentSong.artistId,
activityOptions
)
}
}

View file

@ -1,29 +1,23 @@
package code.name.monkey.retromusic.activities.playlist
package code.name.monkey.retromusic.fragments.playlists
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.MenuInflater
import android.view.View
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.EXTRA_PLAYLIST
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsSlidingMusicPanelActivity
import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter
import code.name.monkey.retromusic.adapter.song.PlaylistSongAdapter
import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.extensions.dipToPix
import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
import code.name.monkey.retromusic.interfaces.CabHolder
import code.name.monkey.retromusic.fragments.MainActivityFragment
import code.name.monkey.retromusic.model.AbsCustomPlaylist
import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.PlaylistsUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import com.afollestad.materialcab.MaterialCab
import com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
@ -31,63 +25,52 @@ import kotlinx.android.synthetic.main.activity_playlist_detail.*
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
class PlaylistDetailsFragment : MainActivityFragment(R.layout.fragment_playlist_detail) {
private val viewModel: PlaylistDetailsViewModel by viewModel {
parametersOf(extraNotNull<Playlist>(EXTRA_PLAYLIST).value)
}
private lateinit var playlist: Playlist
private var cab: MaterialCab? = null
private lateinit var adapter: SongAdapter
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
setDrawUnderStatusBar()
super.onCreate(savedInstanceState)
setStatusbarColorAuto()
setNavigationbarColorAuto()
setTaskDescriptionColorAuto()
setLightNavigationBar(true)
setBottomBarVisibility(View.GONE)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainActivity.addMusicServiceEventListener(viewModel)
mainActivity.setSupportActionBar(toolbar)
playlist = extraNotNull<Playlist>(EXTRA_PLAYLIST).value
setUpToolBar()
setUpRecyclerView()
viewModel.getSongs().observe(this, Observer {
viewModel.getSongs().observe(viewLifecycleOwner, Observer {
songs(it)
})
viewModel.getPlaylist().observe(this, Observer {
viewModel.getPlaylist().observe(viewLifecycleOwner, Observer {
playlist = it
supportActionBar?.title = it.name
toolbar.title = it.name
})
addMusicServiceEventListener(viewModel)
}
override fun createContentView(): View {
return wrapSlidingMusicPanel(R.layout.activity_playlist_detail)
}
private fun setUpRecyclerView() {
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = LinearLayoutManager(requireContext())
if (playlist is AbsCustomPlaylist) {
adapter = PlaylistSongAdapter(this, ArrayList(), R.layout.item_list, this)
adapter = SongAdapter(requireActivity(), ArrayList(), R.layout.item_list, null)
recyclerView.adapter = adapter
} else {
recyclerViewDragDropManager = RecyclerViewDragDropManager()
val animator = RefactoredDefaultItemAnimator()
adapter = OrderablePlaylistSongAdapter(this,
adapter = OrderablePlaylistSongAdapter(requireActivity(),
ArrayList(),
R.layout.item_list,
this,
null,
object : OrderablePlaylistSongAdapter.OnMoveItemListener {
override fun onMoveItem(fromPosition: Int, toPosition: Int) {
if (PlaylistsUtil.moveItem(
this@PlaylistDetailActivity,
requireContext(),
playlist.id,
fromPosition,
toPosition
@ -114,58 +97,18 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
})
}
private fun setUpToolBar() {
applyToolbar(toolbar)
title = playlist.name
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(
if (playlist is AbsCustomPlaylist) R.menu.menu_smart_playlist_detail
else R.menu.menu_playlist_detail, menu
)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
onBackPressed()
return true
}
}
return PlaylistMenuHelper.handleMenuClick(this, playlist, item)
}
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
if (cab != null && cab!!.isActive) {
cab!!.finish()
}
cab = MaterialCab(this, R.id.cab_stub).setMenu(menuRes)
.setCloseDrawableRes(R.drawable.ic_close)
.setBackgroundColor(
RetroColorUtil.shiftBackgroundColorForLightText(
ATHUtil.resolveColor(
this,
R.attr.colorSurface
)
)
).start(callback)
return cab!!
}
override fun onBackPressed() {
if (cab != null && cab!!.isActive) {
cab!!.finish()
} else {
recyclerView!!.stopScroll()
super.onBackPressed()
}
}
private fun checkForPadding() {
val height = DensityUtil.dip2px(this, 52f)
recyclerView.setPadding(0, 0, 0, (height))
val height = dipToPix(52f)
recyclerView.setPadding(0, 0, 0, height.toInt())
}
private fun checkIsEmpty() {
@ -216,8 +159,4 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
showEmptyView()
}
}
companion object {
var EXTRA_PLAYLIST = "extra_playlist"
}
}
}

View file

@ -1,4 +1,4 @@
package code.name.monkey.retromusic.activities.playlist
package code.name.monkey.retromusic.fragments.playlists
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData

View file

@ -1,8 +1,6 @@
package code.name.monkey.retromusic.fragments.playlists
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.View
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.GridLayoutManager
@ -12,7 +10,7 @@ import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
import code.name.monkey.retromusic.interfaces.MainActivityFragmentCallbacks
class PlaylistsFragment :
AbsRecyclerViewFragment<PlaylistAdapter, GridLayoutManager>() ,
AbsRecyclerViewFragment<PlaylistAdapter, GridLayoutManager>(),
MainActivityFragmentCallbacks {
override fun handleBackPress(): Boolean {
@ -39,26 +37,14 @@ class PlaylistsFragment :
override fun createAdapter(): PlaylistAdapter {
return PlaylistAdapter(
mainActivity,
requireActivity(),
ArrayList(),
R.layout.item_list,
mainActivity
null
)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
menu.apply {
removeItem(R.id.action_sort_order)
removeItem(R.id.action_grid_size)
}
}
companion object {
@JvmField
val TAG: String = PlaylistsFragment::class.java.simpleName
@JvmStatic
fun newInstance(): PlaylistsFragment {
return PlaylistsFragment()
}

View file

@ -19,13 +19,11 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.SettingsActivity
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.util.NavigationUtil
@ -78,12 +76,4 @@ class MainSettingsFragment : Fragment(), View.OnClickListener {
diamondIcon.imageTintList = ColorStateList.valueOf(it)
}
}
companion object {
}
private fun inflateFragment(fragment: Fragment, @StringRes title: Int) {
(requireActivity() as SettingsActivity).setupFragment(fragment, title)
}
}

View file

@ -0,0 +1,23 @@
package code.name.monkey.retromusic.fragments.settings
import android.os.Bundle
import android.view.View
import androidx.navigation.NavController
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.findNavController
import code.name.monkey.retromusic.fragments.MainActivityFragment
import kotlinx.android.synthetic.main.fragment_settings.*
class SettingsFragment : MainActivityFragment(R.layout.fragment_settings) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainActivity.setSupportActionBar(toolbar)
mainActivity.hideBottomNavigation()
mainActivity.setBottomBarVisibility(View.GONE)
val navController: NavController = findNavController(R.id.contentFrame)
navController.addOnDestinationChangedListener { _, _, _ ->
toolbar.title = navController.currentDestination?.label
}
}
}

View file

@ -1,12 +1,11 @@
package code.name.monkey.retromusic.fragments.songs
import android.os.Bundle
import android.view.*
import android.view.View
import androidx.annotation.LayoutRes
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.GridLayoutManager
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.song.ShuffleButtonSongAdapter
import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
@ -36,26 +35,16 @@ class SongsFragment :
get() = R.string.no_songs
override fun createLayoutManager(): GridLayoutManager {
return GridLayoutManager(requireActivity(), getGridSize()).apply {
spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return if (position == 0) {
getGridSize()
} else {
1
}
}
}
}
return GridLayoutManager(requireActivity(), getGridSize())
}
override fun createAdapter(): SongAdapter {
val dataSet = if (adapter == null) mutableListOf() else adapter!!.dataSet
return ShuffleButtonSongAdapter(
mainActivity,
return SongAdapter(
requireActivity(),
dataSet,
itemLayoutRes(),
mainActivity
R.layout.item_list,
null
)
}
@ -109,72 +98,4 @@ class SongsFragment :
return SongsFragment()
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
setUpGridSizeMenu(menu.findItem(R.id.action_grid_size).subMenu)
}
private fun setUpGridSizeMenu(
gridSizeMenu: SubMenu
) {
println(getGridSize())
when (getGridSize()) {
1 -> gridSizeMenu.findItem(R.id.action_grid_size_1).isChecked = true
2 -> gridSizeMenu.findItem(R.id.action_grid_size_2).isChecked = true
3 -> gridSizeMenu.findItem(R.id.action_grid_size_3).isChecked = true
4 -> gridSizeMenu.findItem(R.id.action_grid_size_4).isChecked = true
5 -> gridSizeMenu.findItem(R.id.action_grid_size_5).isChecked = true
6 -> gridSizeMenu.findItem(R.id.action_grid_size_6).isChecked = true
7 -> gridSizeMenu.findItem(R.id.action_grid_size_7).isChecked = true
8 -> gridSizeMenu.findItem(R.id.action_grid_size_8).isChecked = true
}
val maxGridSize = maxGridSize
if (maxGridSize < 8) {
gridSizeMenu.findItem(R.id.action_grid_size_8).isVisible = false
}
if (maxGridSize < 7) {
gridSizeMenu.findItem(R.id.action_grid_size_7).isVisible = false
}
if (maxGridSize < 6) {
gridSizeMenu.findItem(R.id.action_grid_size_6).isVisible = false
}
if (maxGridSize < 5) {
gridSizeMenu.findItem(R.id.action_grid_size_5).isVisible = false
}
if (maxGridSize < 4) {
gridSizeMenu.findItem(R.id.action_grid_size_4).isVisible = false
}
if (maxGridSize < 3) {
gridSizeMenu.findItem(R.id.action_grid_size_3).isVisible = false
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (handleGridSizeMenuItem(item)) return true
return super.onOptionsItemSelected(item)
}
fun handleGridSizeMenuItem(
item: MenuItem
): Boolean {
var gridSize = 0
when (item.itemId) {
R.id.action_grid_size_1 -> gridSize = 1
R.id.action_grid_size_2 -> gridSize = 2
R.id.action_grid_size_3 -> gridSize = 3
R.id.action_grid_size_4 -> gridSize = 4
R.id.action_grid_size_5 -> gridSize = 5
R.id.action_grid_size_6 -> gridSize = 6
R.id.action_grid_size_7 -> gridSize = 7
R.id.action_grid_size_8 -> gridSize = 8
}
if (gridSize > 0) {
item.isChecked = true
setAndSaveGridSize(gridSize)
return true
}
return false
}
}

View file

@ -19,7 +19,7 @@ import android.app.Activity
import android.content.Context
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentActivity
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.dialogs.AddToPlaylistDialog
@ -38,7 +38,7 @@ import java.util.*
object PlaylistMenuHelper {
fun handleMenuClick(
activity: AppCompatActivity,
activity: FragmentActivity,
playlist: Playlist, item: MenuItem
): Boolean {
when (item.itemId) {

View file

@ -18,8 +18,11 @@ import android.content.Intent
import android.view.MenuItem
import android.view.View
import android.widget.PopupMenu
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.tageditor.AbsTagEditorActivity
import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity
@ -30,7 +33,6 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.PaletteColorHolder
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.RingtoneManager
object SongMenuHelper {
@ -89,18 +91,24 @@ object SongMenuHelper {
return true
}
R.id.action_go_to_album -> {
NavigationUtil.goToAlbum(activity, song.albumId)
activity.findNavController(R.id.fragment_container).navigate(
R.id.albumDetailsFragment,
bundleOf(EXTRA_ALBUM_ID to song.albumId)
)
return true
}
R.id.action_go_to_artist -> {
NavigationUtil.goToArtist(activity, song.artistId)
activity.findNavController(R.id.fragment_container).navigate(
R.id.artistDetailsFragment,
bundleOf(EXTRA_ARTIST_ID to song.artistId)
)
return true
}
}
return false
}
abstract class OnClickSongMenu protected constructor(private val activity: AppCompatActivity) :
abstract class OnClickSongMenu(private val activity: FragmentActivity) :
View.OnClickListener, PopupMenu.OnMenuItemClickListener {
open val menuRes: Int

View file

@ -67,7 +67,7 @@ object PlaylistSongsLoader {
val artistName = cursor.getString(10)
val idInPlaylist = cursor.getInt(11)
val composer = cursor.getString(12)
val albumArtist = cursor.getString(13)
return PlaylistSong(
id,
title,
@ -82,7 +82,8 @@ object PlaylistSongsLoader {
artistName,
playlistId,
idInPlaylist,
composer
composer,
albumArtist
)
}
@ -103,10 +104,9 @@ object PlaylistSongsLoader {
AudioColumns.ARTIST_ID, // 9
AudioColumns.ARTIST, // 10
MediaStore.Audio.Playlists.Members._ID,//11
AudioColumns.COMPOSER
)// 12
, IS_MUSIC, null,
MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER
AudioColumns.COMPOSER,//12
"album_artist"//13
), IS_MUSIC, null, MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER
)
} catch (e: SecurityException) {
return null

View file

@ -95,10 +95,21 @@ object SongLoader {
val artistId = cursor.getInt(9)
val artistName = cursor.getString(10)
val composer = cursor.getString(11)
val albumArtist = cursor.getString(12)
return Song(
id, title, trackNumber, year, duration, data, dateModified, albumId,
albumName ?: "", artistId, artistName, composer ?: ""
id,
title,
trackNumber,
year,
duration,
data,
dateModified,
albumId,
albumName ?: "",
artistId,
artistName ?: "",
composer ?: "",
albumArtist ?: ""
)
}
@ -123,13 +134,13 @@ object SongLoader {
selectionFinal = generateBlacklistSelection(selectionFinal, paths.size)
selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths)
}
selectionFinal =
selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " + (PreferenceUtil.filterLength * 1000)
try {
return context.contentResolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
baseProjection,
selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " +
(PreferenceUtil.filterLength * 1000),
selectionFinal,
selectionValuesFinal,
sortOrder
)

View file

@ -59,9 +59,9 @@ public class CategoryInfo implements Parcelable {
}
public enum Category {
Home(R.id.action_home, R.string.home, R.drawable.asld_home),
Songs(R.id.action_song, R.string.songs, R.drawable.asld_music_note),
Albums(R.id.action_album, R.string.albums, R.drawable.asld_album),
Home(R.id.action_home, R.string.for_you, R.drawable.ic_baseline),
Songs(R.id.action_song, R.string.songs, R.drawable.ic_audiotrack),
Albums(R.id.action_album, R.string.albums, R.drawable.ic_album),
Artists(R.id.action_artist, R.string.artists, R.drawable.ic_artist),
Playlists(R.id.action_playlist, R.string.playlists, R.drawable.ic_playlist_play),
Genres(R.id.action_genre, R.string.genres, R.drawable.ic_guitar),

View file

@ -41,9 +41,9 @@ public class PlaylistSong extends Song {
@NotNull String artistName,
int playlistId,
int idInPlayList,
@NotNull String composer) {
super(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, artistId, artistName,
composer);
@NotNull String composer,
String albumArtist) {
super(id, title, trackNumber, year, duration, data, dateModified, albumId, albumName, artistId, artistName, composer, albumArtist);
this.playlistId = playlistId;
this.idInPlayList = idInPlayList;
}

View file

@ -29,7 +29,8 @@ open class Song(
val albumName: String,
val artistId: Int,
val artistName: String,
val composer: String?
val composer: String?,
val albumArtist: String?
) : Parcelable {
@ -48,6 +49,7 @@ open class Song(
"",
-1,
"",
"",
""
)
}

View file

@ -43,7 +43,7 @@ public class MusicPlaybackQueueStore extends SQLiteOpenHelper {
public static final String ORIGINAL_PLAYING_QUEUE_TABLE_NAME = "original_playing_queue";
private static final int VERSION = 10;
private static final int VERSION = 12;
@Nullable
private static MusicPlaybackQueueStore sInstance = null;
@ -148,6 +148,9 @@ public class MusicPlaybackQueueStore extends SQLiteOpenHelper {
builder.append(" STRING NOT NULL,");
builder.append(AudioColumns.COMPOSER);
builder.append(" STRING,");
builder.append("album_artist");
builder.append(" STRING);");
db.execSQL(builder.toString());

View file

@ -14,12 +14,15 @@
package code.name.monkey.retromusic.util
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.widget.Toast
import code.name.monkey.retromusic.R
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.play.core.review.ReviewManagerFactory
object AppRater {
private const val DO_NOT_SHOW_AGAIN = "do_not_show_again"// Package Name
@ -53,13 +56,29 @@ object AppRater {
// Wait at least n days before opening
if (launchCount >= LAUNCHES_UNTIL_PROMPT) {
if (System.currentTimeMillis() >= dateFirstLaunch + DAYS_UNTIL_PROMPT * 24 * 60 * 60 * 1000) {
showRateDialog(context, editor)
//showRateDialog(context, editor)
showPlayStoreReviewDialog(context)
}
}
editor.commit()
}
private fun showPlayStoreReviewDialog(context: Context) {
val manager = ReviewManagerFactory.create(context)
manager.requestReviewFlow().addOnCompleteListener { request ->
if (request.isSuccessful) {
val reviewInfo = request.result
manager.launchReviewFlow(context as Activity, reviewInfo).addOnCompleteListener {
if (it.isSuccessful) {
Toast.makeText(context, "Thanks for the feedback", Toast.LENGTH_SHORT)
.show()
}
}
}
}
}
private fun showRateDialog(context: Context, editor: SharedPreferences.Editor) {
MaterialAlertDialogBuilder(context)
.setTitle("Rate this App")

View file

@ -28,28 +28,16 @@ import androidx.core.app.ActivityCompat;
import org.jetbrains.annotations.NotNull;
import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.activities.AboutActivity;
import code.name.monkey.retromusic.activities.DriveModeActivity;
import code.name.monkey.retromusic.activities.genre.GenreDetailsActivity;
import code.name.monkey.retromusic.activities.LicenseActivity;
import code.name.monkey.retromusic.activities.LyricsActivity;
import code.name.monkey.retromusic.activities.PlayingQueueActivity;
import code.name.monkey.retromusic.activities.playlist.PlaylistDetailActivity;
import code.name.monkey.retromusic.activities.PurchaseActivity;
import code.name.monkey.retromusic.activities.search.SearchActivity;
import code.name.monkey.retromusic.activities.SettingsActivity;
import code.name.monkey.retromusic.activities.SupportDevelopmentActivity;
import code.name.monkey.retromusic.activities.UserInfoActivity;
import code.name.monkey.retromusic.activities.WhatsNewActivity;
import code.name.monkey.retromusic.activities.albums.AlbumDetailsActivity;
import code.name.monkey.retromusic.activities.artists.ArtistDetailActivity;
import code.name.monkey.retromusic.activities.bugreport.BugReportActivity;
import code.name.monkey.retromusic.helper.MusicPlayerRemote;
import code.name.monkey.retromusic.model.Genre;
import code.name.monkey.retromusic.model.Playlist;
import static code.name.monkey.retromusic.Constants.RATE_ON_GOOGLE_PLAY;
import static code.name.monkey.retromusic.util.RetroUtil.openUrl;
public class NavigationUtil {
@ -58,45 +46,6 @@ public class NavigationUtil {
ActivityCompat.startActivity(activity, new Intent(activity, BugReportActivity.class), null);
}
public static void goToAbout(@NonNull Activity activity) {
ActivityCompat.startActivity(activity, new Intent(activity, AboutActivity.class), null);
}
public static void goToAlbum(@NonNull Activity activity, int albumId) {
Intent intent = new Intent(activity, AlbumDetailsActivity.class);
intent.putExtra(AlbumDetailsActivity.EXTRA_ALBUM_ID, albumId);
ActivityCompat.startActivity(activity, intent, null);
}
public static void goToAlbumOptions(@NonNull Activity activity,
int albumId,
@NonNull ActivityOptions options) {
Intent intent = new Intent(activity, AlbumDetailsActivity.class);
intent.putExtra(AlbumDetailsActivity.EXTRA_ALBUM_ID, albumId);
ActivityCompat.startActivity(activity, intent, options.toBundle());
}
public static void goToArtist(@NonNull Activity activity, int i) {
Intent intent = new Intent(activity, ArtistDetailActivity.class);
intent.putExtra(ArtistDetailActivity.EXTRA_ARTIST_ID, i);
ActivityCompat.startActivity(activity, intent, null);
}
public static void goToArtistOptions(@NotNull Activity activity,
int artistId,
@NonNull ActivityOptions options) {
Intent intent = new Intent(activity, ArtistDetailActivity.class);
intent.putExtra(ArtistDetailActivity.EXTRA_ARTIST_ID, artistId);
ActivityCompat.startActivity(activity, intent, options.toBundle());
}
public static void goToGenre(@NonNull Activity activity, @NonNull Genre genre) {
Intent intent = new Intent(activity, GenreDetailsActivity.class);
intent.putExtra(GenreDetailsActivity.EXTRA_GENRE_ID, genre);
ActivityCompat.startActivity(activity, intent, null);
}
public static void goToLyrics(@NonNull Activity activity) {
Intent intent = new Intent(activity, LyricsActivity.class);
ActivityCompat.startActivity(activity, intent, null);
@ -106,47 +55,15 @@ public class NavigationUtil {
ActivityCompat.startActivity(activity, new Intent(activity, LicenseActivity.class), null);
}
public static void goToPlayStore(@NonNull Activity activity) {
openUrl(activity, RATE_ON_GOOGLE_PLAY);
}
public static void goToPlayingQueue(@NonNull Activity activity) {
Intent intent = new Intent(activity, PlayingQueueActivity.class);
ActivityCompat.startActivity(activity, intent, null);
}
public static void goToPlaylistNew(@NonNull Activity activity, @NonNull Playlist playlist) {
Intent intent = new Intent(activity, PlaylistDetailActivity.class);
intent.putExtra(PlaylistDetailActivity.Companion.getEXTRA_PLAYLIST(), playlist);
ActivityCompat.startActivity(activity, intent, null);
}
public static void goToProVersion(@NonNull Context context) {
ActivityCompat.startActivity(context, new Intent(context, PurchaseActivity.class), null);
}
public static void goToSearch(@NonNull Activity activity,
@NonNull ActivityOptions activityOptions) {
ActivityCompat.startActivity(activity, new Intent(activity, SearchActivity.class),
activityOptions.toBundle());
}
public static void goToSearch(@NonNull Activity activity) {
ActivityCompat.startActivity(activity, new Intent(activity, SearchActivity.class),
null);
}
public static void goToSearch(@NonNull Activity activity, boolean isMicOpen,
@NonNull ActivityOptions activityOptions) {
ActivityCompat.startActivity(activity, new Intent(activity, SearchActivity.class)
.putExtra(SearchActivity.EXTRA_SHOW_MIC, isMicOpen),
activityOptions.toBundle());
}
public static void goToSettings(@NonNull Activity activity) {
ActivityCompat.startActivity(activity, new Intent(activity, SettingsActivity.class), null);
}
public static void goToSupportDevelopment(@NonNull Activity activity) {
ActivityCompat.startActivity(activity, new Intent(activity, SupportDevelopmentActivity.class), null);
}

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M9,11.75c-0.69,0 -1.25,0.56 -1.25,1.25s0.56,1.25 1.25,1.25 1.25,-0.56 1.25,-1.25 -0.56,-1.25 -1.25,-1.25zM15,11.75c-0.69,0 -1.25,0.56 -1.25,1.25s0.56,1.25 1.25,1.25 1.25,-0.56 1.25,-1.25 -0.56,-1.25 -1.25,-1.25zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8 0,-0.29 0.02,-0.58 0.05,-0.86 2.36,-1.05 4.23,-2.98 5.21,-5.37C11.07,8.33 14.05,10 17.42,10c0.78,0 1.53,-0.09 2.25,-0.26 0.21,0.71 0.33,1.47 0.33,2.26 0,4.41 -3.59,8 -8,8z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M4,11h5L9,5L4,5v6zM4,18h5v-6L4,12v6zM10,18h5v-6h-5v6zM16,18h5v-6h-5v6zM10,11h5L15,5h-5v6zM16,5v6h5L21,5h-5z"/>
</vector>

View file

@ -1,61 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fragment_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?colorSurface"
android:orientation="vertical">
app:defaultNavHost="true"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
app:navGraph="@navigation/main_graph" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="0dp"
tools:ignore="UnusedAttribute">
<include layout="@layout/status_bar" />
</FrameLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/mainContent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:liftOnScroll="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
app:popupTheme="?attr/toolbarPopupTheme"
app:title="@string/app_name"
app:titleTextAppearance="@style/ToolbarTextAppearanceNormal.Library"
app:titleTextColor="?attr/colorControlNormal"
tools:ignore="UnusedAttribute" />
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height" />
</FrameLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
tools:layout="@layout/fragment_main_activity_recycler_view" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:overScrollMode="never"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<include layout="@layout/activity_about_content" />
</androidx.core.widget.NestedScrollView>

View file

@ -1,102 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:orientation="vertical"
tools:ignore="UnusedAttribute">
<androidx.core.widget.NestedScrollView
android:id="@+id/container"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
<include layout="@layout/status_bar" />
</FrameLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
app:liftOnScroll="true">
<com.google.android.material.card.MaterialCardView
android:id="@+id/albumCoverContainer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:transitionName="@string/transition_album_art"
app:cardCornerRadius="24dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image"
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:background="?attr/colorSurface"
app:navigationIcon="@drawable/ic_keyboard_backspace_black" />
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:srcCompat="@tools:sample/backgrounds/scenic[5]" />
android:layout_height="48dp" />
</FrameLayout>
</com.google.android.material.card.MaterialCardView>
</com.google.android.material.appbar.AppBarLayout>
<code.name.monkey.retromusic.views.RetroShapeableImageView
android:id="@+id/artistImage"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_marginStart="16dp"
android:layout_marginTop="28dp"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/albumCoverContainer"
app:retroCornerSize="26dp"
tools:srcCompat="@tools:sample/backgrounds/scenic[11]" />
<androidx.core.widget.NestedScrollView
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<code.name.monkey.retromusic.views.BaselineGridTextView
android:id="@+id/albumTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:maxLines="3"
android:textAppearance="@style/TextViewHeadline5"
android:textColor="?android:attr/textColorPrimary"
android:textStyle="bold"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/artistImage"
app:layout_constraintTop_toTopOf="@id/artistImage"
tools:ignore="MissingPrefix"
tools:text="@tools:sample/lorem/random" />
<code.name.monkey.retromusic.views.BaselineGridTextView
android:id="@+id/albumText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:singleLine="true"
android:textAppearance="@style/TextViewSubtitle2"
android:textColor="?android:attr/textColorSecondary"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/artistImage"
app:layout_constraintTop_toBottomOf="@id/albumTitle"
app:lineHeightHint="24sp"
tools:ignore="MissingPrefix"
tools:text="@tools:sample/lorem/random" />
<include
layout="@layout/activity_album_content"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/albumText" />
android:orientation="vertical">
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/albumCoverContainer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:transitionName="@string/transition_album_art"
app:cardCornerRadius="24dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:srcCompat="@tools:sample/backgrounds/scenic[5]" />
</com.google.android.material.card.MaterialCardView>
<code.name.monkey.retromusic.views.RetroShapeableImageView
android:id="@+id/artistImage"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_marginStart="16dp"
android:layout_marginTop="28dp"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/albumCoverContainer"
app:retroCornerSize="26dp"
tools:srcCompat="@tools:sample/backgrounds/scenic[11]" />
<code.name.monkey.retromusic.views.BaselineGridTextView
android:id="@+id/albumTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:maxLines="3"
android:textAppearance="@style/TextViewHeadline5"
android:textColor="?android:attr/textColorPrimary"
android:textStyle="bold"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/artistImage"
app:layout_constraintTop_toTopOf="@id/artistImage"
tools:ignore="MissingPrefix"
tools:text="@tools:sample/lorem/random" />
<code.name.monkey.retromusic.views.BaselineGridTextView
android:id="@+id/albumText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:singleLine="true"
android:textAppearance="@style/TextViewSubtitle2"
android:textColor="?android:attr/textColorSecondary"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/artistImage"
app:layout_constraintTop_toBottomOf="@id/albumTitle"
app:lineHeightHint="24sp"
tools:ignore="MissingPrefix"
tools:text="@tools:sample/lorem/random" />
<include
layout="@layout/activity_album_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/albumText" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>

View file

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:orientation="vertical"
tools:ignore="UnusedAttribute">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/status_bar" />
</FrameLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:liftOnScroll="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:background="?attr/colorSurface"
app:navigationIcon="@drawable/ic_keyboard_backspace_black" />
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="48dp" />
</FrameLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:id="@+id/artistCoverContainer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:transitionName="@string/transition_artist_image"
app:cardCornerRadius="24dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:srcCompat="@tools:sample/backgrounds/scenic" />
</com.google.android.material.card.MaterialCardView>
<code.name.monkey.retromusic.views.BaselineGridTextView
android:id="@+id/artistTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:maxLines="2"
android:textAppearance="@style/TextViewHeadline5"
android:textColor="?android:attr/textColorPrimary"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/artistCoverContainer"
tools:ignore="MissingPrefix"
tools:text="@tools:sample/full_names" />
<code.name.monkey.retromusic.views.BaselineGridTextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:textAppearance="@style/TextViewSubtitle2"
android:textColor="?android:attr/textColorSecondary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/artistTitle"
tools:ignore="MissingPrefix"
tools:text="@tools:sample/full_names" />
<include
layout="@layout/activity_artist_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>

View file

@ -1,17 +1,4 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ 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.
-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
@ -31,6 +18,7 @@
</FrameLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/mainContent"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -38,47 +26,38 @@
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:elevation="0dp"
app:elevation="0dp"
app:liftOnScroll="true">
<com.google.android.material.card.MaterialCardView
android:id="@+id/toolbarContainer"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="8dp"
app:cardUseCompatPadding="true"
app:layout_scrollFlags="scroll|enterAlways">
<FrameLayout
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
app:popupTheme="?attr/toolbarPopupTheme"
app:title="@string/app_name"
app:titleTextAppearance="@style/ToolbarTextAppearanceNormal.Library"
app:titleTextColor="?attr/colorControlNormal"
tools:ignore="UnusedAttribute" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
android:background="?colorSurface"
app:popupTheme="?attr/toolbarPopupTheme"
app:title="@string/action_search"
app:titleTextAppearance="@style/TextViewHeadline6"
app:titleTextColor="?android:attr/textColorSecondary"
tools:ignore="UnusedAttribute" />
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height" />
</FrameLayout>
</com.google.android.material.card.MaterialCardView>
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height" />
</FrameLayout>
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:id="@+id/fragmentContainer"
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
app:defaultNavHost="true"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
app:navGraph="@navigation/library_graph" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>
</LinearLayout>

View file

@ -58,6 +58,6 @@
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
app:navGraph="@navigation/retro_graph" />
app:navGraph="@navigation/main_graph" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>

View file

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:orientation="vertical"
tools:ignore="UnusedAttribute">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/status_bar" />
</FrameLayout>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:liftOnScroll="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
app:navigationIcon="@drawable/ic_keyboard_backspace_black"
app:titleTextAppearance="@style/ToolbarTextAppearanceNormal" />
<ViewStub
android:id="@+id/cab_stub"
android:layout_width="match_parent"
android:layout_height="48dp" />
</FrameLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:overScrollMode="never"
android:scrollbars="none"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
<LinearLayout
android:id="@android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/emptyEmoji"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/empty_text_emoji"
android:textAppearance="@style/TextViewHeadline3" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/emptyText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/no_songs"
android:textAppearance="@style/TextViewHeadline5"
android:textColor="?android:attr/textColorSecondary"
tools:visibility="visible" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>

View file

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<code.name.monkey.retromusic.views.StatusBarView
android:id="@+id/status_bar"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="?attr/colorSurface"
tools:ignore="UnusedAttribute" />
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
app:liftOnScroll="true">
<com.google.android.material.appbar.MaterialToolbar
android:layout_width="match_parent"
android:id="@+id/toolbar"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/searchView"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
android:layout_weight="1"
android:background="@null"
android:hint="@string/action_search"
android:inputType="text|textAutoComplete"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textAppearance="@style/TextViewSubtitle1">
<requestFocus />
</com.google.android.material.textfield.TextInputEditText>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/voiceSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?roundSelector"
android:padding="12dp"
app:srcCompat="@drawable/ic_mic"
app:tint="?attr/colorControlNormal"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/clearText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?roundSelector"
android:padding="12dp"
android:visibility="gone"
app:srcCompat="@drawable/ic_close"
app:tint="?attr/colorControlNormal"
tools:visibility="visible" />
</FrameLayout>
</LinearLayout>
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.textview.MaterialTextView
android:id="@android:id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="@string/no_results"
android:textAppearance="@style/TextViewHeadline6"
android:visibility="gone"
tools:visibility="visible" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:overScrollMode="never"
android:scrollbarStyle="outsideOverlay"
android:scrollbars="vertical"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/keyboardPopup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_marginEnd="16dp"
android:layout_marginBottom="62dp"
android:text="@string/keyboard"
android:textAppearance="@style/TextViewHeadline6"
app:icon="@drawable/ic_keyboard" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>

View file

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<code.name.monkey.retromusic.views.StatusBarView
android:id="@+id/status_bar"
android:layout_width="match_parent"
android:layout_height="0dp"
tools:ignore="UnusedAttribute" />
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<androidx.core.widget.NestedScrollView
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/contentFrame"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:defaultNavHost="true"
app:navGraph="@navigation/settings_graph" />
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
app:liftOnScroll="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
app:layout_collapseMode="pin"
app:navigationIcon="@drawable/ic_keyboard_backspace_black"
app:titleTextAppearance="@style/ToolbarTextAppearanceNormal"
tools:title="@string/action_settings" />
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>

View file

@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="1dp"
android:background="?attr/rectSelector"
android:clickable="true"
android:focusable="true">
@ -11,7 +12,7 @@
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="6dp"
android:layout_margin="5dp"
app:cardCornerRadius="8dp"
tools:ignore="MissingPrefix">

View file

@ -4,15 +4,15 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_margin="1dp"
android:background="?attr/rectSelector"
android:clickable="true"
android:focusable="true"
tools:ignore="MissingPrefix">
android:focusable="true">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
app:cardCornerRadius="8dp"
tools:ignore="MissingPrefix">
@ -33,7 +33,6 @@
tools:ignore="ContentDescription"
tools:src="@tools:sample/avatars" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View file

@ -16,7 +16,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:gravity="center_vertical|end"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
@ -27,6 +27,7 @@
android:layout_marginEnd="4dp"
android:layout_weight="1"
android:text="@string/action_play_all"
android:visibility="gone"
app:backgroundTint="?attr/colorSurface"
app:icon="@drawable/ic_play_arrow" />
@ -38,7 +39,35 @@
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:text="@string/shuffle"
android:visibility="gone"
app:backgroundTint="?attr/colorSurface"
app:icon="@drawable/ic_shuffle" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/songsMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:padding="16dp"
app:srcCompat="@drawable/ic_sort"
app:tint="?attr/colorControlNormal" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/gridMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:padding="16dp"
app:srcCompat="@drawable/ic_grid_size"
app:tint="?attr/colorControlNormal" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:padding="16dp"
app:srcCompat="@drawable/ic_layout"
app:tint="?attr/colorControlNormal" />
</LinearLayout>

View file

@ -30,11 +30,11 @@
<androidx.fragment.app.FragmentContainerView
android:id="@+id/playerFragmentContainer"
android:layout_width="match_parent"
android:name="code.name.monkey.retromusic.fragments.player.NowPlayingPlayerFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<androidx.fragment.app.FragmentContainerView
<fragment
android:id="@+id/miniPlayerFragment"
android:name="code.name.monkey.retromusic.fragments.MiniPlayerFragment"
android:layout_width="match_parent"

View file

@ -16,84 +16,15 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".DrawerActivity">
<item
android:id="@+id/action_search"
android:icon="@drawable/ic_search"
android:title="@string/action_search"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_grid_size"
android:icon="@drawable/ic_grid_size"
android:orderInCategory="5"
android:title="@string/action_grid_size"
app:showAsAction="ifRoom">
<menu>
<group
android:id="@+id/group_grid_size"
android:checkableBehavior="single">
<item
android:id="@+id/action_grid_size_1"
android:title="@string/grid_size_1" />
<item
android:id="@+id/action_grid_size_2"
android:title="@string/grid_size_2" />
<item
android:id="@+id/action_grid_size_3"
android:title="@string/grid_size_3" />
<item
android:id="@+id/action_grid_size_4"
android:title="@string/grid_size_4" />
<item
android:id="@+id/action_grid_size_5"
android:title="@string/grid_size_5" />
<item
android:id="@+id/action_grid_size_6"
android:title="@string/grid_size_6" />
<item
android:id="@+id/action_grid_size_7"
android:title="@string/grid_size_7" />
<item
android:id="@+id/action_grid_size_8"
android:title="@string/grid_size_8" />
</group>
</menu>
</item>
<item
android:id="@+id/action_layout_type"
android:icon="@drawable/ic_dashboard"
android:orderInCategory="6"
android:title="@string/grid_style_label"
app:showAsAction="ifRoom">
<menu>
<group
android:id="@+id/group_layout_type"
android:checkableBehavior="single">
<item
android:id="@+id/action_layout_normal"
android:checked="true"
android:title="@string/normal" />
<item
android:id="@+id/action_layout_card"
android:title="@string/card" />
<item
android:id="@+id/action_layout_colored_card"
android:title="@string/card_color_style" />
<item
android:id="@+id/action_layout_circular"
android:title="@string/circular" />
<item
android:id="@+id/action_layout_image"
android:title="@string/image" />
<item
android:id="@+id/action_layout_gradient_image"
android:title="@string/image_gradient" />
</group>
</menu>
</item>
<item
android:id="@+id/action_sort_order"
android:icon="@drawable/ic_sort"
android:orderInCategory="2"
android:title="@string/action_sort_order"
app:showAsAction="ifRoom">
<menu></menu>
</item>
android:id="@+id/action_settings"
android:icon="@drawable/ic_settings"
android:title="@string/action_settings"
app:showAsAction="ifRoom" />
</menu>

View file

@ -1,51 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/retro_graph"
app:startDestination="@id/action_song">
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/library_graph"
app:startDestination="@id/action_home">
<fragment
android:id="@+id/action_album"
android:name="code.name.monkey.retromusic.fragments.albums.AlbumsFragment"
android:label="AlbumsFragment" />
tools:layout="@layout/fragment_main_activity_recycler_view" />
<fragment
android:id="@+id/action_artist"
android:name="code.name.monkey.retromusic.fragments.artists.ArtistsFragment"
android:label="ArtistsFragment" />
tools:layout="@layout/fragment_main_activity_recycler_view" />
<fragment
android:id="@+id/action_song"
android:name="code.name.monkey.retromusic.fragments.songs.SongsFragment"
android:label="SongsFragment" />
tools:layout="@layout/fragment_main_activity_recycler_view" />
<fragment
android:id="@+id/action_genre"
android:name="code.name.monkey.retromusic.fragments.genres.GenresFragment"
android:label="GenresFragment" />
tools:layout="@layout/fragment_main_activity_recycler_view" />
<fragment
android:id="@+id/action_playlist"
android:name="code.name.monkey.retromusic.fragments.playlists.PlaylistsFragment"
android:label="PlaylistsFragment" />
tools:layout="@layout/fragment_main_activity_recycler_view" />
<fragment
android:id="@+id/action_playing_queue"
android:name="code.name.monkey.retromusic.fragments.queue.PlayingQueueFragment"
android:label="PlayingQueueFragment" />
tools:layout="@layout/fragment_main_activity_recycler_view" />
<fragment
android:id="@+id/action_folder"
android:name="code.name.monkey.retromusic.fragments.folder.FoldersFragment"
android:label="FoldersFragment" />
tools:layout="@layout/fragment_folder" />
<fragment
android:id="@+id/action_home"
android:name="code.name.monkey.retromusic.fragments.home.BannerHomeFragment"
android:label="BannerHomeFragment" />
<fragment
android:id="@+id/albumDetailsFragment"
android:name="code.name.monkey.retromusic.activities.albums.AlbumDetailsFragment"
android:label="AlbumDetailsFragment" />
android:name="code.name.monkey.retromusic.fragments.home.HomeFragment"
tools:layout="@layout/fragment_banner_home" />
</navigation>

View file

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/retro_graph"
app:startDestination="@id/libraryFragment">
<include app:graph="@navigation/settings_graph" />
<include app:graph="@navigation/library_graph" />
<fragment
android:id="@+id/genreDetailsFragment"
android:name="code.name.monkey.retromusic.fragments.genres.GenreDetailsFragment"
android:label="GenreDetailsFragment"
tools:layout="@layout/fragment_playlist_detail">
<argument
android:name="extra_genre"
app:argType="code.name.monkey.retromusic.model.Genre" />
</fragment>
<fragment
android:id="@+id/playlistDetailsFragment"
android:name="code.name.monkey.retromusic.fragments.playlists.PlaylistDetailsFragment"
android:label="PlaylistDetailsFragment"
tools:layout="@layout/fragment_playlist_detail">
<argument
android:name="extra_playlist"
app:argType="code.name.monkey.retromusic.model.Playlist" />
</fragment>
<fragment
android:id="@+id/albumDetailsFragment"
android:name="code.name.monkey.retromusic.fragments.albums.AlbumDetailsFragment"
android:label="AlbumDetailsFragment"
tools:layout="@layout/activity_album_details">
<argument
android:name="extra_album_id"
app:argType="integer" />
</fragment>
<fragment
android:id="@+id/artistDetailsFragment"
android:name="code.name.monkey.retromusic.fragments.artists.ArtistDetailsFragment"
android:label="ArtistDetailsFragment"
tools:layout="@layout/fragment_artist_details">
<argument
android:name="extra_artist_id"
app:argType="integer" />
</fragment>
<activity
android:id="@+id/action_search"
android:name="code.name.monkey.retromusic.activities.search.SearchActivity"
android:label="Search"
tools:layout="@layout/activity_search" />
<fragment
android:id="@+id/libraryFragment"
android:name="code.name.monkey.retromusic.fragments.library.LibraryFragment"
android:label="LibraryFragment"
tools:layout="@layout/fragment_library">
<action
android:id="@+id/action_main_to_library"
app:destination="@id/library_graph" />
<action
android:id="@+id/action_main_to_settings"
app:destination="@id/settings_graph" />
</fragment>
<fragment
android:id="@+id/searchFragment"
android:name="code.name.monkey.retromusic.activities.search.SearchFragment"
android:label="SearchFragment"
tools:layout="@layout/fragment_search" />
<fragment
android:id="@+id/settingsFragment"
android:name="code.name.monkey.retromusic.fragments.settings.SettingsFragment"
android:label="SettingsFragment"
tools:layout="@layout/fragment_settings" />
</navigation>

View file

@ -18,6 +18,7 @@
app:exitAnim="@anim/retro_fragment_open_exit"
app:popEnterAnim="@anim/retro_fragment_close_enter"
app:popExitAnim="@anim/retro_fragment_close_exit" />
<action
android:id="@+id/action_mainSettingsFragment_to_imageSettingFragment"
app:destination="@id/imageSettingFragment"
@ -25,6 +26,7 @@
app:exitAnim="@anim/retro_fragment_open_exit"
app:popEnterAnim="@anim/retro_fragment_close_enter"
app:popExitAnim="@anim/retro_fragment_close_exit" />
<action
android:id="@+id/action_mainSettingsFragment_to_nowPlayingSettingsFragment"
app:destination="@id/nowPlayingSettingsFragment"
@ -32,6 +34,7 @@
app:exitAnim="@anim/retro_fragment_open_exit"
app:popEnterAnim="@anim/retro_fragment_close_enter"
app:popExitAnim="@anim/retro_fragment_close_exit" />
<action
android:id="@+id/action_mainSettingsFragment_to_audioSettings"
app:destination="@id/audioSettings"
@ -39,6 +42,7 @@
app:exitAnim="@anim/retro_fragment_open_exit"
app:popEnterAnim="@anim/retro_fragment_close_enter"
app:popExitAnim="@anim/retro_fragment_close_exit" />
<action
android:id="@+id/action_mainSettingsFragment_to_otherSettingsFragment"
app:destination="@id/otherSettingsFragment"
@ -46,13 +50,15 @@
app:exitAnim="@anim/retro_fragment_open_exit"
app:popEnterAnim="@anim/retro_fragment_close_enter"
app:popExitAnim="@anim/retro_fragment_close_exit" />
<action
android:id="@+id/action_mainSettingsFragment_to_personalizeSettingsFragment"
app:destination="@id/personalizeSettingsFragment"
app:enterAnim="@anim/retro_fragment_open_enter"
app:exitAnim="@anim/retro_fragment_open_exit"
app:popEnterAnim="@anim/retro_fragment_close_enter"
app:popExitAnim="@anim/retro_fragment_close_exit"
app:destination="@id/personalizeSettingsFragment" />
app:popExitAnim="@anim/retro_fragment_close_exit" />
<action
android:id="@+id/action_mainSettingsFragment_to_notificationSettingsFragment"
app:destination="@id/notificationSettingsFragment"
@ -101,9 +107,9 @@
android:name="code.name.monkey.retromusic.fragments.settings.ThemeSettingsFragment"
android:label="Look &amp; Feel" />
<activity
<fragment
android:id="@+id/aboutActivity"
android:name="code.name.monkey.retromusic.activities.AboutActivity"
android:label="AboutActivity" />
android:name="code.name.monkey.retromusic.fragments.about.AboutFragment"
android:label="About" />
</navigation>

View file

@ -126,7 +126,7 @@
</string-array>
<array name="pref_album_details_style_layout">
<item>@layout/activity_album</item>
<item>@layout/activity_album_details</item>
</array>
<string-array name="pref_language_names">
<item>System default</item>

View file

@ -880,4 +880,6 @@
<item quantity="one">%d Artist</item>
<item quantity="other">%d Artists</item>
</plurals>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
</resources>