Merge branch 'dev' of https://github.com/h4h13/RetroMusicPlayer into dev
This commit is contained in:
commit
3c3cbf08a9
226 changed files with 4395 additions and 5422 deletions
|
@ -80,17 +80,18 @@ dependencies {
|
|||
implementation "androidx.gridlayout:gridlayout:1.0.0"
|
||||
implementation "androidx.cardview:cardview:1.0.0"
|
||||
implementation "androidx.viewpager2:viewpager2:1.1.0-alpha01"
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.annotation:annotation:1.1.0'
|
||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||
implementation 'androidx.core:core-ktx:1.3.1'
|
||||
implementation 'androidx.fragment:fragment-ktx:1.2.5'
|
||||
implementation 'androidx.palette:palette-ktx:1.0.0'
|
||||
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta8'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-rc1'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha01'
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha02'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
|
||||
def retrofit_version = '2.9.0'
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||
|
@ -144,5 +145,4 @@ dependencies {
|
|||
def nav_version = "2.3.0"
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
|
||||
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"version": 1,
|
||||
"artifactType": {
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "code.name.monkey.retromusic",
|
||||
"variantName": "release",
|
||||
"elements": [
|
||||
{
|
||||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"properties": [],
|
||||
"versionCode": 10438,
|
||||
"versionName": "10438",
|
||||
"enabled": true,
|
||||
"outputFile": "app-release.apk"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -20,12 +20,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"
|
||||
|
@ -104,25 +104,17 @@
|
|||
<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=".activities.SettingsActivity" />
|
||||
<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.GenreDetailsActivity" />
|
||||
<activity android:name=".activities.LicenseActivity" />
|
||||
<activity android:name=".activities.WhatsNewActivity" />
|
||||
<activity android:name=".activities.bugreport.BugReportActivity" />
|
||||
<activity android:name=".activities.ShareInstagramStory" />
|
||||
<activity android:name=".activities.DriveModeActivity" />
|
||||
<activity
|
||||
android:name=".activities.search.SearchActivity"
|
||||
android:windowSoftInputMode="stateVisible" />
|
||||
|
||||
<activity
|
||||
android:name=".activities.LockScreenActivity"
|
||||
|
@ -263,5 +255,8 @@
|
|||
<meta-data
|
||||
android:name="com.android.vending.splits.required"
|
||||
android:value="true" />
|
||||
<meta-data
|
||||
android:name="preloaded_fonts"
|
||||
android:resource="@array/preloaded_fonts" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 43 KiB |
|
@ -47,13 +47,17 @@ 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"
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package io.github.muntashirakon.music
|
||||
|
||||
import androidx.annotation.IntDef
|
||||
|
||||
@IntDef(
|
||||
RECENT_ALBUMS,
|
||||
TOP_ALBUMS,
|
||||
RECENT_ARTISTS,
|
||||
TOP_ARTISTS,
|
||||
SUGGESTIONS,
|
||||
FAVOURITES,
|
||||
GENRES,
|
||||
PLAYLISTS
|
||||
)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class HomeSection
|
||||
|
||||
const val RECENT_ALBUMS = 3
|
||||
const val TOP_ALBUMS = 1
|
||||
const val RECENT_ARTISTS = 2
|
||||
const val TOP_ARTISTS = 0
|
||||
const val SUGGESTIONS = 5
|
||||
const val FAVOURITES = 4
|
||||
const val GENRES = 6
|
||||
const val PLAYLISTS = 7
|
|
@ -1,24 +1,70 @@
|
|||
package io.github.muntashirakon.music
|
||||
|
||||
import io.github.muntashirakon.music.activities.albums.AlbumDetailsViewModel
|
||||
import io.github.muntashirakon.music.activities.artists.ArtistDetailsViewModel
|
||||
import io.github.muntashirakon.music.activities.genre.GenreDetailsViewModel
|
||||
import io.github.muntashirakon.music.activities.playlist.PlaylistDetailsViewModel
|
||||
import io.github.muntashirakon.music.activities.search.SearchViewModel
|
||||
import io.github.muntashirakon.music.fragments.LibraryViewModel
|
||||
import io.github.muntashirakon.music.fragments.albums.AlbumDetailsViewModel
|
||||
import io.github.muntashirakon.music.fragments.artists.ArtistDetailsViewModel
|
||||
import io.github.muntashirakon.music.fragments.genres.GenreDetailsViewModel
|
||||
import io.github.muntashirakon.music.fragments.playlists.PlaylistDetailsViewModel
|
||||
import io.github.muntashirakon.music.fragments.search.SearchViewModel
|
||||
import io.github.muntashirakon.music.model.Genre
|
||||
import io.github.muntashirakon.music.model.Playlist
|
||||
import io.github.muntashirakon.music.network.networkModule
|
||||
import io.github.muntashirakon.music.providers.RepositoryImpl
|
||||
import org.eclipse.egit.github.core.Repository
|
||||
import io.github.muntashirakon.music.repository.*
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.bind
|
||||
import org.koin.dsl.module
|
||||
|
||||
private val dataModule = module {
|
||||
single {
|
||||
RepositoryImpl(get(), get())
|
||||
RealRepository(get(), get(), get(), get(), get(), get(), get(), get(), get(), get())
|
||||
} bind Repository::class
|
||||
|
||||
single {
|
||||
RealSongRepository(get())
|
||||
} bind SongRepository::class
|
||||
|
||||
single {
|
||||
RealGenreRepository(get(), get())
|
||||
} bind GenreRepository::class
|
||||
|
||||
single {
|
||||
RealAlbumRepository(get())
|
||||
} bind AlbumRepository::class
|
||||
|
||||
single {
|
||||
RealArtistRepository(get(), get())
|
||||
} bind ArtistRepository::class
|
||||
|
||||
single {
|
||||
RealPlaylistRepository(get())
|
||||
} bind PlaylistRepository::class
|
||||
|
||||
single {
|
||||
RealTopPlayedRepository(get(), get(), get(), get())
|
||||
} bind TopPlayedRepository::class
|
||||
|
||||
single {
|
||||
RealLastAddedRepository(
|
||||
get(),
|
||||
get(),
|
||||
get()
|
||||
)
|
||||
} bind LastAddedRepository::class
|
||||
|
||||
single {
|
||||
RealSearchRepository(
|
||||
get(),
|
||||
get(),
|
||||
get(),
|
||||
get(),
|
||||
get()
|
||||
)
|
||||
}
|
||||
|
||||
single {
|
||||
androidContext().contentResolver
|
||||
}
|
||||
}
|
||||
|
||||
private val viewModules = module {
|
||||
|
@ -28,19 +74,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 {
|
||||
|
|
25
app/src/main/java/io/github/muntashirakon/music/Result.kt
Normal file
25
app/src/main/java/io/github/muntashirakon/music/Result.kt
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) 2020 Fatih Giris. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.github.muntashirakon.music
|
||||
|
||||
/**
|
||||
* Generic class that holds the network state
|
||||
*/
|
||||
sealed class Result<out R> {
|
||||
data class Success<out T>(val data: T) : Result<T>()
|
||||
object Loading : Result<Nothing>()
|
||||
object Error : Result<Nothing>()
|
||||
}
|
|
@ -20,7 +20,6 @@ import kotlinx.android.synthetic.main.activity_lyrics.*
|
|||
class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.Callback {
|
||||
private lateinit var updateHelper: MusicProgressViewUpdateHelper
|
||||
|
||||
|
||||
private lateinit var song: Song
|
||||
|
||||
private val googleSearchLrcUrl: String
|
||||
|
|
|
@ -1,83 +1,44 @@
|
|||
package io.github.muntashirakon.music.activities
|
||||
|
||||
import android.app.ActivityOptions
|
||||
import android.content.*
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||
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.util.ATHUtil.resolveColor
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
import io.github.muntashirakon.music.R
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import io.github.muntashirakon.music.*
|
||||
import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
|
||||
import io.github.muntashirakon.music.dialogs.CreatePlaylistDialog.Companion.create
|
||||
import io.github.muntashirakon.music.extensions.findNavController
|
||||
import io.github.muntashirakon.music.fragments.LibraryViewModel
|
||||
import io.github.muntashirakon.music.fragments.albums.AlbumsFragment
|
||||
import io.github.muntashirakon.music.fragments.artists.ArtistsFragment
|
||||
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||
import io.github.muntashirakon.music.fragments.folder.FoldersFragment
|
||||
import io.github.muntashirakon.music.fragments.genres.GenresFragment
|
||||
import io.github.muntashirakon.music.fragments.home.BannerHomeFragment
|
||||
import io.github.muntashirakon.music.fragments.playlists.PlaylistsFragment
|
||||
import io.github.muntashirakon.music.fragments.queue.PlayingQueueFragment
|
||||
import io.github.muntashirakon.music.fragments.songs.SongsFragment
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.isPlaying
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.openAndShuffleQueue
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.openQueue
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.playFromUri
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.shuffleMode
|
||||
import io.github.muntashirakon.music.helper.SearchQueryHelper.getSongs
|
||||
import io.github.muntashirakon.music.helper.SortOrder.*
|
||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
||||
import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
|
||||
import io.github.muntashirakon.music.loaders.AlbumLoader.getAlbum
|
||||
import io.github.muntashirakon.music.loaders.ArtistLoader.getArtist
|
||||
import io.github.muntashirakon.music.loaders.PlaylistSongsLoader.getPlaylistSongList
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.repository.PlaylistSongsLoader.getPlaylistSongList
|
||||
import io.github.muntashirakon.music.repository.Repository
|
||||
import io.github.muntashirakon.music.service.MusicService
|
||||
import io.github.muntashirakon.music.util.AppRater.appLaunched
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||
import io.github.muntashirakon.music.util.RetroColorUtil
|
||||
import io.github.muntashirakon.music.util.RetroUtil
|
||||
import com.afollestad.materialcab.MaterialCab
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import io.github.muntashirakon.music.*
|
||||
import kotlinx.android.synthetic.main.activity_main_content.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.*
|
||||
|
||||
class MainActivity : AbsSlidingMusicPanelActivity(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener, CabHolder {
|
||||
class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener {
|
||||
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 val repository by inject<Repository>()
|
||||
private val libraryViewModel by inject<LibraryViewModel>()
|
||||
|
||||
private var blockRequestPermissions = false
|
||||
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)
|
||||
|
@ -91,29 +52,16 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
|
|||
setLightNavigationBar(true)
|
||||
setTaskDescriptionColorAuto()
|
||||
hideStatusBar()
|
||||
setBottomBarVisibility(View.VISIBLE)
|
||||
|
||||
addMusicServiceEventListener(libraryViewModel)
|
||||
if (savedInstanceState == null) {
|
||||
selectedFragment(PreferenceUtil.lastPage)
|
||||
} else {
|
||||
restoreCurrentFragment()
|
||||
}
|
||||
|
||||
appLaunched(this)
|
||||
setupToolbar()
|
||||
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) &&
|
||||
|
@ -126,389 +74,9 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
|
|||
|
||||
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) {
|
||||
super.requestPermissions()
|
||||
|
@ -522,76 +90,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 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
|
||||
) {
|
||||
|
@ -637,16 +135,20 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
|
|||
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
|
||||
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
|
||||
if (id >= 0) {
|
||||
val position = intent.getIntExtra("position", 0)
|
||||
openQueue(getAlbum(this, id).songs!!, position, true)
|
||||
handled = true
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
val position = intent.getIntExtra("position", 0)
|
||||
openQueue(repository.albumById(id).songs!!, position, true)
|
||||
handled = true
|
||||
}
|
||||
}
|
||||
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
|
||||
val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
|
||||
if (id >= 0) {
|
||||
val position = intent.getIntExtra("position", 0)
|
||||
openQueue(getArtist(this, id).songs, position, true)
|
||||
handled = true
|
||||
lifecycleScope.launch {
|
||||
val position = intent.getIntExtra("position", 0)
|
||||
openQueue(repository.artistById(id).songs, position, true)
|
||||
handled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (handled) {
|
||||
|
@ -671,31 +173,4 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
|
|||
}
|
||||
return id
|
||||
}
|
||||
|
||||
override fun handleBackPress(): Boolean {
|
||||
if (cab != null && cab!!.isActive) {
|
||||
cab?.finish()
|
||||
return true
|
||||
}
|
||||
return super.handleBackPress() || currentFragment.handleBackPress()
|
||||
}
|
||||
|
||||
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(
|
||||
resolveColor(
|
||||
this,
|
||||
R.attr.colorSurface
|
||||
)
|
||||
)
|
||||
)
|
||||
.start(callback)
|
||||
return cab as MaterialCab
|
||||
}
|
||||
}
|
|
@ -7,6 +7,11 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
|
||||
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager
|
||||
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.base.AbsMusicServiceActivity
|
||||
import io.github.muntashirakon.music.adapter.song.PlayingQueueAdapter
|
||||
|
@ -14,11 +19,7 @@ import io.github.muntashirakon.music.extensions.accentColor
|
|||
import io.github.muntashirakon.music.extensions.surfaceColor
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
|
||||
import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchActionGuardManager
|
||||
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
|
||||
import io.github.muntashirakon.music.util.ThemedFastScroller
|
||||
import kotlinx.android.synthetic.main.activity_playing_queue.*
|
||||
|
||||
open class PlayingQueueActivity : AbsMusicServiceActivity() {
|
||||
|
@ -103,7 +104,7 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
|
|||
}
|
||||
}
|
||||
})
|
||||
//ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
|
||||
val fastScroller = ThemedFastScroller.create(recyclerView)
|
||||
}
|
||||
|
||||
private fun checkForPadding() {
|
||||
|
|
67
app/src/main/java/io/github/muntashirakon/music/activities/SettingsActivity.kt
Executable file → Normal file
67
app/src/main/java/io/github/muntashirakon/music/activities/SettingsActivity.kt
Executable file → Normal file
|
@ -2,26 +2,18 @@ package io.github.muntashirakon.music.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 com.afollestad.materialdialogs.color.ColorChooserDialog
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.base.AbsBaseActivity
|
||||
import io.github.muntashirakon.music.appshortcuts.DynamicShortcutManager
|
||||
import io.github.muntashirakon.music.extensions.applyToolbar
|
||||
import com.afollestad.materialdialogs.color.ColorChooserDialog
|
||||
import io.github.muntashirakon.music.extensions.findNavController
|
||||
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)
|
||||
|
@ -35,56 +27,14 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
|
|||
private fun setupToolbar() {
|
||||
setTitle(R.string.action_settings)
|
||||
applyToolbar(toolbar)
|
||||
val navHostFragment =
|
||||
supportFragmentManager.findFragmentById(R.id.contentFrame) as NavHostFragment
|
||||
val navController: NavController = navHostFragment.navController
|
||||
val navController: NavController = findNavController(R.id.contentFrame)
|
||||
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"
|
||||
return findNavController(R.id.contentFrame).navigateUp() || super.onSupportNavigateUp()
|
||||
}
|
||||
|
||||
override fun onColorSelection(dialog: ColorChooserDialog, selectedColor: Int) {
|
||||
|
@ -101,4 +51,11 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
|
|||
override fun onColorChooserDismissed(dialog: ColorChooserDialog) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == android.R.id.home) {
|
||||
onBackPressed()
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
|
@ -10,10 +10,16 @@ import android.text.TextUtils
|
|||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.MaterialUtil
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.request.RequestListener
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.github.dhaval2404.imagepicker.ImagePicker
|
||||
import com.github.dhaval2404.imagepicker.constant.ImageProvider
|
||||
import io.github.muntashirakon.music.Constants.USER_BANNER
|
||||
import io.github.muntashirakon.music.Constants.USER_PROFILE
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.base.AbsBaseActivity
|
||||
import io.github.muntashirakon.music.extensions.accentColor
|
||||
import io.github.muntashirakon.music.extensions.applyToolbar
|
||||
|
@ -21,13 +27,6 @@ import io.github.muntashirakon.music.glide.ProfileBannerGlideRequest
|
|||
import io.github.muntashirakon.music.glide.UserProfileGlideRequest
|
||||
import io.github.muntashirakon.music.util.ImageUtil
|
||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.request.RequestListener
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.github.dhaval2404.imagepicker.ImagePicker
|
||||
import com.github.dhaval2404.imagepicker.constant.ImageProvider
|
||||
import io.github.muntashirakon.music.R
|
||||
import kotlinx.android.synthetic.main.activity_user_info.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -49,7 +48,7 @@ class UserInfoActivity : AbsBaseActivity() {
|
|||
setLightNavigationBar(true)
|
||||
applyToolbar(toolbar)
|
||||
|
||||
MaterialUtil.setTint(nameContainer, false)
|
||||
nameContainer.accentColor()
|
||||
name.setText(PreferenceUtil.userName)
|
||||
|
||||
userImage.setOnClickListener {
|
||||
|
@ -161,7 +160,7 @@ class UserInfoActivity : AbsBaseActivity() {
|
|||
}
|
||||
|
||||
private fun saveImage(bitmap: Bitmap, fileName: String) {
|
||||
CoroutineScope(Dispatchers.IO).launch() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val appDir = applicationContext.filesDir
|
||||
val file = File(appDir, fileName)
|
||||
var successful = false
|
||||
|
|
|
@ -1,250 +0,0 @@
|
|||
package io.github.muntashirakon.music.activities.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.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 io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.album.HorizontalAlbumAdapter
|
||||
import io.github.muntashirakon.music.adapter.song.SimpleSongAdapter
|
||||
import io.github.muntashirakon.music.extensions.extraNotNull
|
||||
import io.github.muntashirakon.music.extensions.show
|
||||
import io.github.muntashirakon.music.fragments.base.AbsMusicServiceFragment
|
||||
import io.github.muntashirakon.music.glide.AlbumGlideRequest
|
||||
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.model.Album
|
||||
import io.github.muntashirakon.music.model.Artist
|
||||
import io.github.muntashirakon.music.network.model.LastFmAlbum
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||
import io.github.muntashirakon.music.util.RetroUtil
|
||||
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
||||
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.*
|
||||
|
||||
class AlbumDetailsFragment : AbsMusicServiceFragment(R.layout.fragment_album_details) {
|
||||
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)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setSharedElementTransitionOnEnter()
|
||||
postponeEnterTransition()
|
||||
playerActivity?.addMusicServiceEventListener(detailsViewModel)
|
||||
|
||||
detailsViewModel.getAlbum().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
|
||||
startPostponedEnterTransition()
|
||||
showAlbum(it)
|
||||
})
|
||||
detailsViewModel.getArtist().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
|
||||
loadArtistImage(it)
|
||||
})
|
||||
detailsViewModel.getMoreAlbums().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
|
||||
moreAlbums(it)
|
||||
})
|
||||
detailsViewModel.getAlbumInfo().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
|
||||
aboutAlbum(it)
|
||||
})
|
||||
setupRecyclerView()
|
||||
artistImage.setOnClickListener {
|
||||
val artistPairs = ActivityOptions.makeSceneTransitionAnimation(
|
||||
requireActivity(),
|
||||
Pair.create(
|
||||
artistImage,
|
||||
getString(R.string.transition_artist_image)
|
||||
)
|
||||
)
|
||||
NavigationUtil.goToArtistOptions(requireActivity(), album.artistId, artistPairs)
|
||||
}
|
||||
playAction.setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
|
||||
|
||||
shuffleAction.setOnClickListener {
|
||||
MusicPlayerRemote.openAndShuffleQueue(
|
||||
album.songs!!,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
aboutAlbumText.setOnClickListener {
|
||||
if (aboutAlbumText.maxLines == 4) {
|
||||
aboutAlbumText.maxLines = Integer.MAX_VALUE
|
||||
} else {
|
||||
aboutAlbumText.maxLines = 4
|
||||
}
|
||||
}
|
||||
image.apply {
|
||||
transitionName = getString(R.string.transition_album_art)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val activity = activity as AppCompatActivity
|
||||
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
playerActivity?.removeMusicServiceEventListener(detailsViewModel)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> findNavController().navigateUp()
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
simpleSongAdapter = SimpleSongAdapter(
|
||||
requireActivity() as AppCompatActivity,
|
||||
ArrayList(),
|
||||
R.layout.item_song,
|
||||
null
|
||||
)
|
||||
recyclerView.apply {
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
itemAnimator = DefaultItemAnimator()
|
||||
isNestedScrollingEnabled = false
|
||||
adapter = simpleSongAdapter
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAlbum(album: Album) {
|
||||
if (album.songs!!.isEmpty()) {
|
||||
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(requireActivity() as AppCompatActivity, albums, null)
|
||||
moreRecyclerView.layoutManager = GridLayoutManager(
|
||||
requireContext(),
|
||||
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(requireContext()), artist)
|
||||
.generatePalette(requireContext())
|
||||
.build()
|
||||
.dontAnimate()
|
||||
.dontTransform()
|
||||
.into(object : RetroMusicColoredTarget(artistImage) {
|
||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun loadAlbumCover() {
|
||||
AlbumGlideRequest.Builder.from(Glide.with(requireContext()), album.safeGetFirstSong())
|
||||
.checkIgnoreMediaStore(requireContext())
|
||||
.ignoreMediaStore(PreferenceUtil.isIgnoreMediaStoreArtwork)
|
||||
.generatePalette(requireContext())
|
||||
.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
|
||||
)
|
||||
}
|
||||
}
|
|
@ -7,27 +7,29 @@ import android.view.ViewGroup
|
|||
import android.view.ViewTreeObserver
|
||||
import android.widget.FrameLayout
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.RetroBottomSheetBehavior
|
||||
import io.github.muntashirakon.music.extensions.hide
|
||||
import io.github.muntashirakon.music.extensions.show
|
||||
import io.github.muntashirakon.music.extensions.whichFragment
|
||||
import io.github.muntashirakon.music.fragments.LibraryViewModel
|
||||
import io.github.muntashirakon.music.fragments.MiniPlayerFragment
|
||||
import io.github.muntashirakon.music.fragments.NowPlayingScreen
|
||||
import io.github.muntashirakon.music.fragments.NowPlayingScreen.*
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.model.CategoryInfo
|
||||
import io.github.muntashirakon.music.util.DensityUtil
|
||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||
import io.github.muntashirakon.music.views.BottomNavigationBarTinted
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
||||
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||
companion object {
|
||||
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
|
||||
}
|
||||
|
@ -120,8 +122,9 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
|||
return slidingMusicPanelLayout
|
||||
}
|
||||
|
||||
private fun collapsePanel() {
|
||||
fun collapsePanel() {
|
||||
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
setMiniPlayerAlphaProgress(0f)
|
||||
}
|
||||
|
||||
fun expandPanel() {
|
||||
|
@ -133,9 +136,7 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
|||
if (miniPlayerFragment?.view == null) return
|
||||
val alpha = 1 - progress
|
||||
miniPlayerFragment?.view?.alpha = alpha
|
||||
// necessary to make the views below clickable
|
||||
miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE
|
||||
|
||||
bottomNavigationView.translationY = progress * 500
|
||||
bottomNavigationView.alpha = alpha
|
||||
}
|
||||
|
@ -172,40 +173,31 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
|||
return bottomNavigationView
|
||||
}
|
||||
|
||||
fun setBottomBarVisibility(visible: Int) {
|
||||
bottomNavigationView.visibility = visible
|
||||
fun hideBottomBarVisibility(visible: Boolean) {
|
||||
bottomNavigationView.isVisible = visible
|
||||
hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
|
||||
}
|
||||
|
||||
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 = bottomNavigationView.height
|
||||
val isBottomBarVisible = bottomNavigationView.isVisible
|
||||
|
||||
if (hide) {
|
||||
behavior.isHideable = true
|
||||
behavior.peekHeight = 0
|
||||
bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat()
|
||||
collapsePanel()
|
||||
ViewCompat.setElevation(bottomNavigationView, 10f)
|
||||
} else {
|
||||
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
|
||||
slidingPanel.elevation = DensityUtil.dip2px(this, 10f).toFloat()
|
||||
bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat()
|
||||
behavior.isHideable = false
|
||||
behavior.peekHeight =
|
||||
if (bottomNavigationView.visibility == View.VISIBLE) {
|
||||
heightOfBarWithTabs
|
||||
} else {
|
||||
heightOfBar
|
||||
}
|
||||
}
|
||||
ViewCompat.setElevation(bottomNavigationView, 10f)
|
||||
ViewCompat.setElevation(slidingPanel, 10f)
|
||||
behavior.isHideable = false
|
||||
behavior.peekHeight = (if (isBottomBarVisible) heightOfBar * 2 else heightOfBar) - 24
|
||||
}
|
||||
}
|
||||
|
||||
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 +224,6 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
|||
}
|
||||
|
||||
open fun handleBackPress(): Boolean {
|
||||
|
||||
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
|
||||
collapsePanel()
|
||||
return true
|
||||
|
@ -305,6 +296,12 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
fun hideBottomNavigation() {
|
||||
behavior.isHideable = true
|
||||
behavior.peekHeight = 0
|
||||
hideBottomBarVisibility(false)
|
||||
}
|
||||
|
||||
fun updateTabs() {
|
||||
bottomNavigationView.menu.clear()
|
||||
val currentTabs: List<CategoryInfo> = PreferenceUtil.libraryCategory
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
package io.github.muntashirakon.music.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 io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
|
||||
import io.github.muntashirakon.music.adapter.song.ShuffleButtonSongAdapter
|
||||
import io.github.muntashirakon.music.extensions.applyToolbar
|
||||
import io.github.muntashirakon.music.extensions.extraNotNull
|
||||
import io.github.muntashirakon.music.helper.menu.GenreMenuHelper
|
||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
||||
import io.github.muntashirakon.music.model.Genre
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.DensityUtil
|
||||
import io.github.muntashirakon.music.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"
|
||||
}
|
||||
}
|
|
@ -1,224 +0,0 @@
|
|||
package io.github.muntashirakon.music.activities.search
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Service
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
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 android.widget.TextView.BufferType
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.widget.SearchView.OnQueryTextListener
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.TransitionManager
|
||||
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 io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.base.AbsMusicServiceActivity
|
||||
import io.github.muntashirakon.music.adapter.SearchAdapter
|
||||
import io.github.muntashirakon.music.extensions.extra
|
||||
import io.github.muntashirakon.music.util.RetroUtil
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import kotlinx.android.synthetic.main.activity_search.*
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class SearchActivity : AbsMusicServiceActivity(), OnQueryTextListener, TextWatcher {
|
||||
|
||||
private val viewModel: SearchViewModel by inject()
|
||||
private var searchAdapter: SearchAdapter? = null
|
||||
private var query: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setDrawUnderStatusBar()
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_search)
|
||||
setStatusbarColorAuto()
|
||||
setNavigationbarColorAuto()
|
||||
setTaskDescriptionColorAuto()
|
||||
setLightNavigationBar(true)
|
||||
|
||||
setupRecyclerView()
|
||||
setUpToolBar()
|
||||
setupSearchView()
|
||||
|
||||
if (extra<Boolean>(EXTRA_SHOW_MIC).value == true) {
|
||||
startMicSearch()
|
||||
}
|
||||
|
||||
back.setOnClickListener { onBackPressed() }
|
||||
voiceSearch.setOnClickListener { startMicSearch() }
|
||||
clearText.setOnClickListener { searchView.clearText() }
|
||||
searchContainer.backgroundTintList =
|
||||
ColorStateList.valueOf(ATHUtil.resolveColor(this, R.attr.colorSurface))
|
||||
|
||||
keyboardPopup.setOnClickListener {
|
||||
val inputManager = getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputManager.showSoftInput(searchView, InputMethodManager.SHOW_IMPLICIT)
|
||||
}
|
||||
|
||||
keyboardPopup.backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(this))
|
||||
ColorStateList.valueOf(
|
||||
MaterialValueHelper.getPrimaryTextColor(
|
||||
this,
|
||||
ColorUtil.isColorLight(ThemeStore.accentColor(this))
|
||||
)
|
||||
).apply {
|
||||
keyboardPopup.setTextColor(this)
|
||||
keyboardPopup.iconTint = this
|
||||
}
|
||||
if (savedInstanceState != null) {
|
||||
query = savedInstanceState.getString(QUERY)
|
||||
}
|
||||
|
||||
viewModel.getSearchResult().observe(this, androidx.lifecycle.Observer {
|
||||
showData(it)
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
searchAdapter = SearchAdapter(this, emptyList())
|
||||
searchAdapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||
override fun onChanged() {
|
||||
super.onChanged()
|
||||
empty.visibility = if (searchAdapter!!.itemCount < 1) View.VISIBLE else View.GONE
|
||||
}
|
||||
})
|
||||
recyclerView.apply {
|
||||
layoutManager = LinearLayoutManager(this@SearchActivity)
|
||||
adapter = searchAdapter
|
||||
}
|
||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
if (dy > 0) {
|
||||
keyboardPopup.shrink()
|
||||
} else if (dy < 0) {
|
||||
keyboardPopup.extend()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupSearchView() {
|
||||
searchView.addTextChangedListener(this)
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putString(QUERY, query)
|
||||
}
|
||||
|
||||
private fun setUpToolBar() {
|
||||
title = null
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
override fun onMediaStoreChanged() {
|
||||
super.onMediaStoreChanged()
|
||||
query?.let { search(it) }
|
||||
}
|
||||
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
hideSoftKeyboard()
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String): Boolean {
|
||||
search(newText)
|
||||
return false
|
||||
}
|
||||
|
||||
private fun hideSoftKeyboard() {
|
||||
RetroUtil.hideSoftKeyboard(this@SearchActivity)
|
||||
if (searchView != null) {
|
||||
searchView.clearFocus()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showEmptyView() {
|
||||
searchAdapter?.swapDataSet(ArrayList())
|
||||
}
|
||||
|
||||
private fun showData(data: MutableList<Any>) {
|
||||
if (data.isNotEmpty()) {
|
||||
searchAdapter?.swapDataSet(data)
|
||||
} else {
|
||||
showEmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
when (requestCode) {
|
||||
REQ_CODE_SPEECH_INPUT -> {
|
||||
if (resultCode == Activity.RESULT_OK && null != data) {
|
||||
val result: ArrayList<String>? =
|
||||
data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
|
||||
query = result?.get(0)
|
||||
searchView.setText(query, BufferType.EDITABLE)
|
||||
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,
|
||||
REQ_CODE_SPEECH_INPUT
|
||||
)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(this, getString(R.string.speech_not_supported), Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
||||
}
|
||||
|
||||
override fun onTextChanged(newText: CharSequence, start: Int, before: Int, count: Int) {
|
||||
search(newText.toString())
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG: String = SearchActivity::class.java.simpleName
|
||||
|
||||
const val EXTRA_SHOW_MIC = "extra_show_mic"
|
||||
const val QUERY: String = "query"
|
||||
|
||||
private const val REQ_CODE_SPEECH_INPUT = 9002
|
||||
}
|
||||
}
|
||||
|
||||
fun TextInputEditText.clearText() {
|
||||
text = null
|
||||
}
|
|
@ -14,35 +14,38 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import android.view.animation.OvershootInterpolator
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.R.drawable
|
||||
import io.github.muntashirakon.music.activities.base.AbsBaseActivity
|
||||
import io.github.muntashirakon.music.activities.saf.SAFGuideActivity
|
||||
import io.github.muntashirakon.music.repository.Repository
|
||||
import io.github.muntashirakon.music.util.RetroUtil
|
||||
import io.github.muntashirakon.music.util.SAFUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.android.synthetic.main.activity_album_tag_editor.*
|
||||
import org.jaudiotagger.audio.AudioFile
|
||||
import org.jaudiotagger.audio.AudioFileIO
|
||||
import org.jaudiotagger.tag.FieldKey
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
||||
val repository by inject<Repository>()
|
||||
|
||||
lateinit var saveFab: MaterialButton
|
||||
protected var id: Int = 0
|
||||
private set
|
||||
private var paletteColorPrimary: Int = 0
|
||||
private var isInNoImageMode: Boolean = false
|
||||
private var songPaths: List<String>? = null
|
||||
lateinit var saveFab: MaterialButton
|
||||
|
||||
private var savedSongPaths: List<String>? = null
|
||||
private val currentSongPath: String? = null
|
||||
private var savedTags: Map<FieldKey, String>? = null
|
||||
|
@ -172,41 +175,35 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(contentViewLayout)
|
||||
setStatusbarColorAuto()
|
||||
setNavigationbarColorAuto()
|
||||
setTaskDescriptionColorAuto()
|
||||
|
||||
saveFab = findViewById(R.id.saveTags)
|
||||
getIntentExtras()
|
||||
|
||||
songPaths = getSongPaths()
|
||||
if (songPaths!!.isEmpty()) {
|
||||
finish()
|
||||
return
|
||||
lifecycleScope.launchWhenCreated {
|
||||
songPaths = getSongPaths()
|
||||
if (songPaths!!.isEmpty()) {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
setUpViews()
|
||||
|
||||
setStatusbarColorAuto()
|
||||
setNavigationbarColorAuto()
|
||||
setTaskDescriptionColorAuto()
|
||||
}
|
||||
|
||||
private fun setUpViews() {
|
||||
setUpScrollView()
|
||||
setUpFab()
|
||||
setUpImageView()
|
||||
}
|
||||
|
||||
private fun setUpScrollView() {
|
||||
//observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks);
|
||||
}
|
||||
|
||||
private lateinit var items: List<String>
|
||||
|
||||
private fun setUpImageView() {
|
||||
loadCurrentImage()
|
||||
items = listOf(
|
||||
getString(R.string.pick_from_local_storage),
|
||||
getString(R.string.web_search),
|
||||
getString(R.string.remove_cover)
|
||||
getString(io.github.muntashirakon.music.R.string.pick_from_local_storage),
|
||||
getString(io.github.muntashirakon.music.R.string.web_search),
|
||||
getString(io.github.muntashirakon.music.R.string.remove_cover)
|
||||
)
|
||||
editorImage?.setOnClickListener { show }
|
||||
}
|
||||
|
@ -217,7 +214,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
|||
startActivityForResult(
|
||||
Intent.createChooser(
|
||||
intent,
|
||||
getString(R.string.pick_from_local_storage)
|
||||
getString(io.github.muntashirakon.music.R.string.pick_from_local_storage)
|
||||
), REQUEST_CODE_SELECT_IMAGE
|
||||
)
|
||||
}
|
||||
|
@ -261,7 +258,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract fun getSongPaths(): List<String>
|
||||
protected abstract suspend fun getSongPaths(): List<String>
|
||||
|
||||
protected fun searchWebFor(vararg keys: String) {
|
||||
val stringBuilder = StringBuilder()
|
||||
|
@ -336,7 +333,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
|||
|
||||
hideFab()
|
||||
|
||||
savedSongPaths = getSongPaths()
|
||||
savedSongPaths = songPaths
|
||||
savedTags = fieldKeyValueMap
|
||||
savedArtworkInfo = artworkInfo
|
||||
|
||||
|
|
|
@ -14,23 +14,23 @@ import android.transition.Slide
|
|||
import android.widget.Toast
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import code.name.monkey.appthemehelper.util.MaterialUtil
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.extensions.appHandleColor
|
||||
import io.github.muntashirakon.music.glide.palette.BitmapPaletteTranscoder
|
||||
import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
|
||||
import io.github.muntashirakon.music.loaders.AlbumLoader
|
||||
import io.github.muntashirakon.music.util.ImageUtil
|
||||
import io.github.muntashirakon.music.util.RetroColorUtil.generatePalette
|
||||
import io.github.muntashirakon.music.util.RetroColorUtil.getColor
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.request.animation.GlideAnimation
|
||||
import com.bumptech.glide.request.target.SimpleTarget
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.extensions.appHandleColor
|
||||
import io.github.muntashirakon.music.glide.palette.BitmapPaletteTranscoder
|
||||
import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
|
||||
import io.github.muntashirakon.music.util.ImageUtil
|
||||
import io.github.muntashirakon.music.util.RetroColorUtil.generatePalette
|
||||
import io.github.muntashirakon.music.util.RetroColorUtil.getColor
|
||||
import kotlinx.android.synthetic.main.activity_album_tag_editor.*
|
||||
import org.jaudiotagger.tag.FieldKey
|
||||
import java.util.*
|
||||
|
||||
class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
||||
|
||||
override val contentViewLayout: Int
|
||||
get() = R.layout.activity_album_tag_editor
|
||||
|
||||
|
@ -162,13 +162,13 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
|||
|
||||
writeValuesToFiles(
|
||||
fieldKeyValueMap,
|
||||
if (deleteAlbumArt) AbsTagEditorActivity.ArtworkInfo(id, null)
|
||||
if (deleteAlbumArt) ArtworkInfo(id, null)
|
||||
else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getSongPaths(): List<String> {
|
||||
val songs = AlbumLoader.getAlbum(this, id).songs
|
||||
override suspend fun getSongPaths(): List<String> {
|
||||
val songs = repository.albumById(id).songs
|
||||
val paths = ArrayList<String>(songs!!.size)
|
||||
for (song in songs) {
|
||||
paths.add(song.data)
|
||||
|
|
|
@ -8,9 +8,10 @@ import code.name.monkey.appthemehelper.util.ATHUtil
|
|||
import code.name.monkey.appthemehelper.util.MaterialUtil
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.extensions.appHandleColor
|
||||
import io.github.muntashirakon.music.loaders.SongLoader
|
||||
import io.github.muntashirakon.music.repository.SongRepository
|
||||
import kotlinx.android.synthetic.main.activity_song_tag_editor.*
|
||||
import org.jaudiotagger.tag.FieldKey
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.*
|
||||
|
||||
class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
||||
|
@ -18,6 +19,8 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
|||
override val contentViewLayout: Int
|
||||
get() = R.layout.activity_song_tag_editor
|
||||
|
||||
private val songRepository by inject<SongRepository>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
|
@ -85,9 +88,9 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
|||
writeValuesToFiles(fieldKeyValueMap, null)
|
||||
}
|
||||
|
||||
override fun getSongPaths(): List<String> {
|
||||
override suspend fun getSongPaths(): List<String> {
|
||||
val paths = ArrayList<String>(1)
|
||||
paths.add(SongLoader.getSong(this, id).data)
|
||||
paths.add(songRepository.song(id).data)
|
||||
return paths
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
|
|||
File albumArtFile = null;
|
||||
if (info.artworkInfo != null && info.artworkInfo.getArtwork() != null) {
|
||||
try {
|
||||
albumArtFile = MusicUtil.createAlbumArtFile().getCanonicalFile();
|
||||
albumArtFile = MusicUtil.INSTANCE.createAlbumArtFile().getCanonicalFile();
|
||||
info.artworkInfo.getArtwork()
|
||||
.compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(albumArtFile));
|
||||
artwork = ArtworkFactory.createArtworkFromFile(albumArtFile);
|
||||
|
@ -120,9 +120,9 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
|
|||
Context context = getContext();
|
||||
if (context != null) {
|
||||
if (wroteArtwork) {
|
||||
MusicUtil.insertAlbumArt(context, info.artworkInfo.getAlbumId(), albumArtFile.getPath());
|
||||
MusicUtil.INSTANCE.insertAlbumArt(context, info.artworkInfo.getAlbumId(), albumArtFile.getPath());
|
||||
} else if (deletedArtwork) {
|
||||
MusicUtil.deleteAlbumArt(context, info.artworkInfo.getAlbumId());
|
||||
MusicUtil.INSTANCE.deleteAlbumArt(context, info.artworkInfo.getAlbumId());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
package io.github.muntashirakon.music.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 io.github.muntashirakon.music.EXTRA_GENRE
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
||||
import io.github.muntashirakon.music.model.Genre
|
||||
import io.github.muntashirakon.music.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])
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,37 @@
|
|||
package io.github.muntashirakon.music.adapter
|
||||
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
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.navigation.fragment.FragmentNavigatorExtras
|
||||
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 io.github.muntashirakon.music.PeekingLinearLayoutManager
|
||||
import io.github.muntashirakon.music.R
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import io.github.muntashirakon.music.*
|
||||
import io.github.muntashirakon.music.adapter.album.AlbumAdapter
|
||||
import io.github.muntashirakon.music.adapter.artist.ArtistAdapter
|
||||
import io.github.muntashirakon.music.adapter.song.SongAdapter
|
||||
import io.github.muntashirakon.music.extensions.show
|
||||
import io.github.muntashirakon.music.extensions.hide
|
||||
import io.github.muntashirakon.music.fragments.albums.AlbumClickListener
|
||||
import io.github.muntashirakon.music.fragments.artists.ArtistClickListener
|
||||
import io.github.muntashirakon.music.glide.SongGlideRequest
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.loaders.PlaylistSongsLoader
|
||||
import io.github.muntashirakon.music.model.*
|
||||
import io.github.muntashirakon.music.model.Playlist
|
||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
|
||||
class HomeAdapter(
|
||||
private val activity: AppCompatActivity,
|
||||
private val displayMetrics: DisplayMetrics
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
private val activity: AppCompatActivity
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), ArtistClickListener, AlbumClickListener {
|
||||
|
||||
private var list = listOf<Home>()
|
||||
|
||||
|
@ -45,14 +44,9 @@ class HomeAdapter(
|
|||
.inflate(R.layout.section_recycler_view, parent, false)
|
||||
return when (viewType) {
|
||||
RECENT_ARTISTS, TOP_ARTISTS -> ArtistViewHolder(layout)
|
||||
TOP_ALBUMS, RECENT_ALBUMS -> {
|
||||
AlbumViewHolder(
|
||||
LayoutInflater.from(activity)
|
||||
.inflate(R.layout.metal_section_recycler_view, parent, false)
|
||||
)
|
||||
}
|
||||
GENRES -> GenreViewHolder(layout)
|
||||
FAVOURITES -> PlaylistViewHolder(layout)
|
||||
TOP_ALBUMS, RECENT_ALBUMS -> AlbumViewHolder(layout)
|
||||
else -> {
|
||||
SuggestionsViewHolder(
|
||||
LayoutInflater.from(activity).inflate(
|
||||
|
@ -66,48 +60,62 @@ class HomeAdapter(
|
|||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val home = list[position]
|
||||
when (getItemViewType(position)) {
|
||||
RECENT_ALBUMS -> {
|
||||
val viewHolder = holder as AlbumViewHolder
|
||||
viewHolder.bindView(
|
||||
list[position].arrayList as List<Album>,
|
||||
R.string.recent_albums
|
||||
)
|
||||
viewHolder.bindView(home.arrayList as List<Album>, R.string.recent_albums)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
bundleOf("type" to RECENT_ALBUMS)
|
||||
)
|
||||
}
|
||||
}
|
||||
TOP_ALBUMS -> {
|
||||
val viewHolder = holder as AlbumViewHolder
|
||||
viewHolder.bindView(
|
||||
list[position].arrayList as List<Album>,
|
||||
R.string.top_albums
|
||||
)
|
||||
viewHolder.bindView(home.arrayList as List<Album>, R.string.top_albums)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
bundleOf("type" to TOP_ALBUMS)
|
||||
)
|
||||
}
|
||||
}
|
||||
RECENT_ARTISTS -> {
|
||||
val viewHolder = holder as ArtistViewHolder
|
||||
viewHolder.bindView(
|
||||
list[position].arrayList as List<Artist>,
|
||||
R.string.recent_artists
|
||||
)
|
||||
viewHolder.bindView(home.arrayList, R.string.recent_artists)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
bundleOf("type" to RECENT_ARTISTS)
|
||||
)
|
||||
}
|
||||
}
|
||||
TOP_ARTISTS -> {
|
||||
val viewHolder = holder as ArtistViewHolder
|
||||
viewHolder.bindView(list[position].arrayList as List<Artist>, R.string.top_artists)
|
||||
viewHolder.bindView(home.arrayList, R.string.top_artists)
|
||||
viewHolder.clickableArea.setOnClickListener {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.detailListFragment,
|
||||
bundleOf("type" to TOP_ARTISTS)
|
||||
)
|
||||
}
|
||||
}
|
||||
SUGGESTIONS -> {
|
||||
val viewHolder = holder as SuggestionsViewHolder
|
||||
viewHolder.bindView(
|
||||
list[position].arrayList as List<Song>
|
||||
)
|
||||
viewHolder.bindView(home.arrayList)
|
||||
}
|
||||
FAVOURITES -> {
|
||||
val viewHolder = holder as PlaylistViewHolder
|
||||
viewHolder.bindView(
|
||||
list[position].arrayList as List<Playlist>,
|
||||
R.string.favorites
|
||||
)
|
||||
viewHolder.bindView(home.arrayList, R.string.favorites)
|
||||
}
|
||||
GENRES -> {
|
||||
val viewHolder = holder as GenreViewHolder
|
||||
viewHolder.bind(list[position].arrayList as List<Genre>, R.string.genres)
|
||||
viewHolder.bind(home.arrayList, R.string.genres)
|
||||
}
|
||||
PLAYLISTS -> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,60 +129,23 @@ class HomeAdapter(
|
|||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@IntDef(
|
||||
RECENT_ALBUMS,
|
||||
TOP_ALBUMS,
|
||||
RECENT_ARTISTS,
|
||||
TOP_ARTISTS,
|
||||
SUGGESTIONS,
|
||||
FAVOURITES,
|
||||
GENRES
|
||||
)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class HomeSection
|
||||
|
||||
const val RECENT_ALBUMS = 3
|
||||
const val TOP_ALBUMS = 1
|
||||
const val RECENT_ARTISTS = 2
|
||||
const val TOP_ARTISTS = 0
|
||||
const val SUGGESTIONS = 5
|
||||
const val FAVOURITES = 4
|
||||
const val GENRES = 6
|
||||
}
|
||||
|
||||
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||
fun bindView(list: List<Album>, titleRes: Int) {
|
||||
if (list.isNotEmpty()) {
|
||||
recyclerView.apply {
|
||||
show()
|
||||
adapter = AlbumAdapter(activity, list, R.layout.pager_item, null)
|
||||
layoutManager =
|
||||
PeekingLinearLayoutManager(activity, HORIZONTAL, false)
|
||||
}
|
||||
title.text = activity.getString(titleRes)
|
||||
fun bindView(albums: List<Album>, titleRes: Int) {
|
||||
title.text = activity.getString(titleRes)
|
||||
recyclerView.apply {
|
||||
adapter = albumAdapter(albums)
|
||||
layoutManager = gridLayoutManager()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||
fun bindView(list: List<Artist>, titleRes: Int) {
|
||||
if (list.isNotEmpty()) {
|
||||
val manager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
|
||||
val artistAdapter = ArtistAdapter(
|
||||
activity,
|
||||
list,
|
||||
PreferenceUtil.homeGridStyle,
|
||||
null
|
||||
)
|
||||
recyclerView.apply {
|
||||
show()
|
||||
layoutManager = manager
|
||||
adapter = artistAdapter
|
||||
}
|
||||
title.text = activity.getString(titleRes)
|
||||
private inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||
fun bindView(artists: List<Any>, titleRes: Int) {
|
||||
recyclerView.apply {
|
||||
layoutManager = linearLayoutManager()
|
||||
adapter = artistsAdapter(artists as List<Artist>)
|
||||
}
|
||||
title.text = activity.getString(titleRes)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,52 +161,50 @@ class HomeAdapter(
|
|||
R.id.image8
|
||||
)
|
||||
|
||||
fun bindView(arrayList: List<Song>) {
|
||||
fun bindView(songs: List<Any>) {
|
||||
songs as List<Song>
|
||||
val color = ThemeStore.accentColor(activity)
|
||||
itemView.findViewById<TextView>(R.id.text).setTextColor(color)
|
||||
itemView.findViewById<TextView>(R.id.message).setTextColor(color)
|
||||
itemView.findViewById<MaterialCardView>(R.id.card6).apply {
|
||||
setCardBackgroundColor(ColorUtil.withAlpha(color, 0.2f))
|
||||
setCardBackgroundColor(ColorUtil.withAlpha(color, 0.12f))
|
||||
}
|
||||
if (arrayList.size > 9)
|
||||
images.forEachIndexed { index, i ->
|
||||
itemView.findViewById<View>(i).setOnClickListener {
|
||||
MusicPlayerRemote.playNext(arrayList[index])
|
||||
}
|
||||
SongGlideRequest.Builder.from(Glide.with(activity), arrayList[index])
|
||||
.asBitmap()
|
||||
.build()
|
||||
.into(itemView.findViewById(i))
|
||||
|
||||
images.forEachIndexed { index, id ->
|
||||
itemView.findViewById<View>(id).setOnClickListener {
|
||||
MusicPlayerRemote.playNext(songs[index])
|
||||
}
|
||||
SongGlideRequest.Builder.from(Glide.with(activity), songs[index])
|
||||
.asBitmap()
|
||||
.build()
|
||||
.into(itemView.findViewById(id))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||
fun bindView(arrayList: List<Playlist>, titleRes: Int) {
|
||||
if (arrayList.isNotEmpty()) {
|
||||
val songs = PlaylistSongsLoader.getPlaylistSongList(activity, arrayList[0])
|
||||
if (songs.isNotEmpty()) {
|
||||
recyclerView.apply {
|
||||
show()
|
||||
val songAdapter =
|
||||
SongAdapter(activity, songs, R.layout.item_album_card, null)
|
||||
layoutManager =
|
||||
GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)
|
||||
adapter = songAdapter
|
||||
}
|
||||
title.text = activity.getString(titleRes)
|
||||
}
|
||||
fun bindView(songs: List<Any>, titleRes: Int) {
|
||||
arrow.hide()
|
||||
recyclerView.apply {
|
||||
val songAdapter = SongAdapter(
|
||||
activity,
|
||||
songs as MutableList<Song>,
|
||||
R.layout.item_album_card, null
|
||||
)
|
||||
layoutManager = linearLayoutManager()
|
||||
adapter = songAdapter
|
||||
}
|
||||
title.text = activity.getString(titleRes)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class GenreViewHolder(itemView: View) : AbsHomeViewItem(itemView) {
|
||||
fun bind(genres: List<Genre>, titleRes: Int) {
|
||||
fun bind(genres: List<Any>, titleRes: Int) {
|
||||
arrow.hide()
|
||||
title.text = activity.getString(titleRes)
|
||||
recyclerView.apply {
|
||||
show()
|
||||
layoutManager = GridLayoutManager(activity, 2, GridLayoutManager.HORIZONTAL, false)
|
||||
val genreAdapter = GenreAdapter(activity, genres, R.layout.item_grid_genre)
|
||||
layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.HORIZONTAL, false)
|
||||
val genreAdapter =
|
||||
GenreAdapter(activity, genres as List<Genre>, R.layout.item_grid_genre)
|
||||
adapter = genreAdapter
|
||||
}
|
||||
}
|
||||
|
@ -244,5 +213,38 @@ class HomeAdapter(
|
|||
open inner class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView)
|
||||
val title: AppCompatTextView = itemView.findViewById(R.id.title)
|
||||
val arrow: ImageView = itemView.findViewById(R.id.arrow)
|
||||
val clickableArea: ViewGroup = itemView.findViewById(R.id.clickable_area)
|
||||
}
|
||||
}
|
||||
|
||||
fun artistsAdapter(artists: List<Artist>) =
|
||||
ArtistAdapter(activity, artists, PreferenceUtil.homeGridStyle, null, this)
|
||||
|
||||
fun albumAdapter(albums: List<Album>) =
|
||||
AlbumAdapter(activity, albums, R.layout.item_image, null, this)
|
||||
|
||||
fun gridLayoutManager() = GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)
|
||||
fun linearLayoutManager() = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
|
||||
|
||||
override fun onArtist(artistId: Int, imageView: ImageView) {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.artistDetailsFragment,
|
||||
bundleOf(EXTRA_ARTIST_ID to artistId),
|
||||
null,
|
||||
FragmentNavigatorExtras(
|
||||
imageView to activity.getString(R.string.transition_album_art)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
activity.findNavController(R.id.fragment_container).navigate(
|
||||
R.id.albumDetailsFragment,
|
||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||
null,
|
||||
FragmentNavigatorExtras(
|
||||
view to activity.getString(R.string.transition_album_art)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,29 +1,28 @@
|
|||
package io.github.muntashirakon.music.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 io.github.muntashirakon.music.R
|
||||
import com.bumptech.glide.Glide
|
||||
import io.github.muntashirakon.music.*
|
||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
||||
import io.github.muntashirakon.music.glide.AlbumGlideRequest
|
||||
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.helper.menu.SongMenuHelper
|
||||
import io.github.muntashirakon.music.loaders.PlaylistSongsLoader
|
||||
import io.github.muntashirakon.music.model.*
|
||||
import io.github.muntashirakon.music.model.smartplaylist.AbsSmartPlaylist
|
||||
import io.github.muntashirakon.music.repository.PlaylistSongsLoader
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.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))
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +93,7 @@ class SearchAdapter(
|
|||
private fun getSongs(playlist: Playlist): java.util.ArrayList<Song> {
|
||||
val songs = java.util.ArrayList<Song>()
|
||||
if (playlist is AbsSmartPlaylist) {
|
||||
songs.addAll(playlist.getSongs(activity))
|
||||
songs.addAll(playlist.getSongs())
|
||||
} else {
|
||||
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
|
||||
}
|
||||
|
@ -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>()
|
||||
|
|
|
@ -22,20 +22,20 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.signature.MediaStoreSignature
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
||||
import io.github.muntashirakon.music.glide.audiocover.AudioFileCover
|
||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
||||
import io.github.muntashirakon.music.interfaces.Callbacks
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.util.RetroUtil
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.signature.MediaStoreSignature
|
||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||
import java.io.File
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
import kotlin.math.log10
|
||||
import kotlin.math.pow
|
||||
|
||||
|
@ -135,9 +135,9 @@ class SongFileAdapter(
|
|||
return getFileTitle(`object`)
|
||||
}
|
||||
|
||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<File>) {
|
||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<File>) {
|
||||
if (callbacks == null) return
|
||||
callbacks.onMultipleItemAction(menuItem, selection)
|
||||
callbacks.onMultipleItemAction(menuItem, selection as ArrayList<File>)
|
||||
}
|
||||
|
||||
override fun getPopupText(position: Int): String {
|
||||
|
@ -148,13 +148,6 @@ class SongFileAdapter(
|
|||
return MusicUtil.getSectionName(dataSet[position].name)
|
||||
}
|
||||
|
||||
interface Callbacks {
|
||||
fun onFileSelected(file: File)
|
||||
|
||||
fun onFileMenuClicked(file: File, view: View)
|
||||
|
||||
fun onMultipleItemAction(item: MenuItem, files: ArrayList<File>)
|
||||
}
|
||||
|
||||
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
||||
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
package io.github.muntashirakon.music.adapter.album
|
||||
|
||||
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.fragment.app.FragmentActivity
|
||||
import com.bumptech.glide.Glide
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
||||
import io.github.muntashirakon.music.fragments.albums.AlbumClickListener
|
||||
import io.github.muntashirakon.music.glide.AlbumGlideRequest
|
||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
|
@ -20,17 +21,16 @@ import io.github.muntashirakon.music.interfaces.CabHolder
|
|||
import io.github.muntashirakon.music.model.Album
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||
import io.github.muntashirakon.music.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,
|
||||
|
@ -129,12 +129,12 @@ open class AlbumAdapter(
|
|||
}
|
||||
|
||||
override fun onMultipleItemAction(
|
||||
menuItem: MenuItem, selection: ArrayList<Album>
|
||||
menuItem: MenuItem, selection: List<Album>
|
||||
) {
|
||||
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
|
||||
}
|
||||
|
||||
private fun getSongList(albums: List<Album>): ArrayList<Song> {
|
||||
private fun getSongList(albums: List<Album>): List<Song> {
|
||||
val songs = ArrayList<Song>()
|
||||
for (album in albums) {
|
||||
songs.addAll(album.songs!!)
|
||||
|
@ -156,7 +156,6 @@ open class AlbumAdapter(
|
|||
dataSet[position].year
|
||||
)
|
||||
}
|
||||
|
||||
return MusicUtil.getSectionName(sectionName)
|
||||
}
|
||||
|
||||
|
@ -172,16 +171,7 @@ open class AlbumAdapter(
|
|||
if (isInQuickSelectMode) {
|
||||
toggleChecked(layoutPosition)
|
||||
} else {
|
||||
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
|
||||
activity,
|
||||
imageContainerCard ?: image,
|
||||
activity.getString(R.string.transition_album_art)
|
||||
)
|
||||
NavigationUtil.goToAlbumOptions(
|
||||
activity,
|
||||
dataSet[layoutPosition].id,
|
||||
activityOptions
|
||||
)
|
||||
image?.let { albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package io.github.muntashirakon.music.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 com.bumptech.glide.Glide
|
||||
import io.github.muntashirakon.music.fragments.albums.AlbumClickListener
|
||||
import io.github.muntashirakon.music.glide.AlbumGlideRequest
|
||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||
import io.github.muntashirakon.music.helper.HorizontalAdapterHelper
|
||||
|
@ -12,14 +13,14 @@ import io.github.muntashirakon.music.interfaces.CabHolder
|
|||
import io.github.muntashirakon.music.model.Album
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.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)
|
||||
}
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
package io.github.muntashirakon.music.adapter.artist
|
||||
|
||||
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.view.ViewCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.bumptech.glide.Glide
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
||||
import io.github.muntashirakon.music.extensions.hide
|
||||
import io.github.muntashirakon.music.fragments.artists.ArtistClickListener
|
||||
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
|
||||
|
@ -19,17 +21,16 @@ import io.github.muntashirakon.music.interfaces.CabHolder
|
|||
import io.github.muntashirakon.music.model.Artist
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import io.github.muntashirakon.music.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 {
|
||||
|
@ -106,12 +107,12 @@ class ArtistAdapter(
|
|||
}
|
||||
|
||||
override fun onMultipleItemAction(
|
||||
menuItem: MenuItem, selection: ArrayList<Artist>
|
||||
menuItem: MenuItem, selection: List<Artist>
|
||||
) {
|
||||
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
|
||||
}
|
||||
|
||||
private fun getSongList(artists: List<Artist>): ArrayList<Song> {
|
||||
private fun getSongList(artists: List<Artist>): List<Song> {
|
||||
val songs = ArrayList<Song>()
|
||||
for (artist in artists) {
|
||||
songs.addAll(artist.songs) // maybe async in future?
|
||||
|
@ -130,7 +131,6 @@ class ArtistAdapter(
|
|||
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
||||
|
||||
init {
|
||||
setImageTransitionName(activity.getString(R.string.transition_artist_image))
|
||||
menu?.visibility = View.GONE
|
||||
}
|
||||
|
||||
|
@ -139,14 +139,13 @@ class ArtistAdapter(
|
|||
if (isInQuickSelectMode) {
|
||||
toggleChecked(layoutPosition)
|
||||
} else {
|
||||
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
|
||||
activity,
|
||||
imageContainerCard ?: image,
|
||||
activity.getString(R.string.transition_artist_image)
|
||||
)
|
||||
NavigationUtil.goToArtistOptions(
|
||||
activity, dataSet[layoutPosition].id, activityOptions
|
||||
)
|
||||
image?.let {
|
||||
ViewCompat.setTransitionName(
|
||||
it,
|
||||
activity.getString(R.string.transition_artist_image)
|
||||
)
|
||||
artistClickListener.onArtist(dataSet[layoutPosition].id, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
import com.afollestad.materialcab.MaterialCab;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.github.muntashirakon.music.R;
|
||||
import io.github.muntashirakon.music.interfaces.CabHolder;
|
||||
|
@ -24,7 +25,7 @@ public abstract class AbsMultiSelectAdapter<V extends RecyclerView.ViewHolder, I
|
|||
private final CabHolder cabHolder;
|
||||
private final Context context;
|
||||
private MaterialCab cab;
|
||||
private ArrayList<I> checked;
|
||||
private List<I> checked;
|
||||
private int menuRes;
|
||||
|
||||
public AbsMultiSelectAdapter(@NonNull Context context, @Nullable CabHolder cabHolder, @MenuRes int menuRes) {
|
||||
|
@ -86,7 +87,7 @@ public abstract class AbsMultiSelectAdapter<V extends RecyclerView.ViewHolder, I
|
|||
return cab != null && cab.isActive();
|
||||
}
|
||||
|
||||
protected abstract void onMultipleItemAction(MenuItem menuItem, ArrayList<I> selection);
|
||||
protected abstract void onMultipleItemAction(MenuItem menuItem, List<I> selection);
|
||||
|
||||
protected void setMultiSelectMenuRes(@MenuRes int menuRes) {
|
||||
this.menuRes = menuRes;
|
||||
|
|
|
@ -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 io.github.muntashirakon.music.EXTRA_PLAYLIST
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
||||
|
@ -22,19 +25,18 @@ import io.github.muntashirakon.music.extensions.show
|
|||
import io.github.muntashirakon.music.helper.menu.PlaylistMenuHelper
|
||||
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
|
||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
||||
import io.github.muntashirakon.music.loaders.PlaylistSongsLoader
|
||||
import io.github.muntashirakon.music.model.AbsCustomPlaylist
|
||||
import io.github.muntashirakon.music.model.Playlist
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.model.smartplaylist.AbsSmartPlaylist
|
||||
import io.github.muntashirakon.music.repository.PlaylistSongsLoader
|
||||
import io.github.muntashirakon.music.util.AutoGeneratedPlaylistBitmap
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import io.github.muntashirakon.music.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?
|
||||
|
@ -120,7 +122,7 @@ class PlaylistAdapter(
|
|||
return playlist.name
|
||||
}
|
||||
|
||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<Playlist>) {
|
||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Playlist>) {
|
||||
when (menuItem.itemId) {
|
||||
else -> SongsMenuHelper.handleMenuClick(
|
||||
activity,
|
||||
|
@ -130,11 +132,11 @@ class PlaylistAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getSongList(playlists: List<Playlist>): ArrayList<Song> {
|
||||
private fun getSongList(playlists: List<Playlist>): List<Song> {
|
||||
val songs = ArrayList<Song>()
|
||||
for (playlist in playlists) {
|
||||
if (playlist is AbsCustomPlaylist) {
|
||||
songs.addAll(playlist.getSongs(activity))
|
||||
songs.addAll(playlist.songs())
|
||||
} else {
|
||||
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
|
||||
}
|
||||
|
@ -142,12 +144,12 @@ class PlaylistAdapter(
|
|||
return songs
|
||||
}
|
||||
|
||||
private fun getSongs(playlist: Playlist): ArrayList<Song> {
|
||||
private fun getSongs(playlist: Playlist): List<Song> {
|
||||
val songs = ArrayList<Song>()
|
||||
if (playlist is AbsSmartPlaylist) {
|
||||
songs.addAll(playlist.getSongs(activity))
|
||||
songs.addAll(playlist.songs())
|
||||
} else {
|
||||
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
|
||||
songs.addAll(playlist.getSongs())
|
||||
}
|
||||
return songs
|
||||
}
|
||||
|
@ -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])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,11 @@ package io.github.muntashirakon.music.adapter.song
|
|||
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.R.menu
|
||||
import io.github.muntashirakon.music.dialogs.RemoveFromPlaylistDialog
|
||||
|
@ -10,19 +14,18 @@ import io.github.muntashirakon.music.interfaces.CabHolder
|
|||
import io.github.muntashirakon.music.model.PlaylistSong
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.ViewUtil
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
|
||||
|
||||
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 {
|
||||
|
@ -48,7 +51,7 @@ class OrderablePlaylistSongAdapter(
|
|||
return long
|
||||
}
|
||||
|
||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<Song>) {
|
||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) {
|
||||
when (menuItem.itemId) {
|
||||
R.id.action_remove_from_playlist -> {
|
||||
RemoveFromPlaylistDialog.create(selection as ArrayList<PlaylistSong>)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,7 @@ package io.github.muntashirakon.music.adapter.song
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.isPlaying
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.playNextSong
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.removeFromQueue
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.util.ViewUtil
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
|
||||
|
@ -20,6 +13,14 @@ import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultAct
|
|||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionDefault
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem
|
||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.annotation.SwipeableItemResults
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.isPlaying
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.playNextSong
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.removeFromQueue
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.util.ViewUtil
|
||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||
|
||||
class PlayingQueueAdapter(
|
||||
|
@ -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
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
package io.github.muntashirakon.music.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 com.google.android.material.button.MaterialButton
|
||||
import io.github.muntashirakon.music.EXTRA_ALBUM_ID
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import com.google.android.material.button.MaterialButton
|
||||
|
||||
open class PlaylistSongAdapter(
|
||||
activity: AppCompatActivity,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
|
@ -2,14 +2,14 @@ package io.github.muntashirakon.music.adapter.song
|
|||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import java.util.*
|
||||
|
||||
class SimpleSongAdapter(
|
||||
context: AppCompatActivity,
|
||||
context: FragmentActivity,
|
||||
songs: ArrayList<Song>,
|
||||
layoutRes: Int,
|
||||
cabHolder: CabHolder?
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
package io.github.muntashirakon.music.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 com.afollestad.materialcab.MaterialCab
|
||||
import com.bumptech.glide.Glide
|
||||
import io.github.muntashirakon.music.EXTRA_ALBUM_ID
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
||||
|
@ -22,11 +26,8 @@ import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
|
|||
import io.github.muntashirakon.music.interfaces.CabHolder
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
||||
import com.afollestad.materialcab.MaterialCab
|
||||
import com.bumptech.glide.Glide
|
||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||
|
||||
/**
|
||||
|
@ -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?,
|
||||
|
@ -132,7 +133,7 @@ open class SongAdapter(
|
|||
return song.title
|
||||
}
|
||||
|
||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<Song>) {
|
||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) {
|
||||
SongsMenuHelper.handleMenuClick(activity, selection, menuItem.itemId)
|
||||
}
|
||||
|
||||
|
@ -147,7 +148,6 @@ open class SongAdapter(
|
|||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
return MusicUtil.getSectionName(sectionName)
|
||||
}
|
||||
|
||||
|
@ -175,12 +175,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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,15 +17,13 @@ package io.github.muntashirakon.music.appshortcuts
|
|||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import io.github.muntashirakon.music.activities.search.SearchActivity
|
||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.LastAddedShortcutType
|
||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.SearchShortCutType
|
||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.ShuffleAllShortcutType
|
||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.TopTracksShortcutType
|
||||
import io.github.muntashirakon.music.model.Playlist
|
||||
import io.github.muntashirakon.music.model.smartplaylist.LastAddedPlaylist
|
||||
import io.github.muntashirakon.music.model.smartplaylist.MyTopTracksPlaylist
|
||||
import io.github.muntashirakon.music.model.smartplaylist.ShuffleAllPlaylist
|
||||
import io.github.muntashirakon.music.model.smartplaylist.TopTracksPlaylist
|
||||
import io.github.muntashirakon.music.service.MusicService
|
||||
import io.github.muntashirakon.music.service.MusicService.*
|
||||
|
||||
|
@ -45,26 +43,22 @@ class AppShortcutLauncherActivity : Activity() {
|
|||
when (shortcutType) {
|
||||
SHORTCUT_TYPE_SHUFFLE_ALL -> {
|
||||
startServiceWithPlaylist(
|
||||
MusicService.SHUFFLE_MODE_SHUFFLE, ShuffleAllPlaylist(applicationContext)
|
||||
SHUFFLE_MODE_SHUFFLE, ShuffleAllPlaylist()
|
||||
)
|
||||
DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.id)
|
||||
}
|
||||
SHORTCUT_TYPE_TOP_TRACKS -> {
|
||||
startServiceWithPlaylist(
|
||||
MusicService.SHUFFLE_MODE_NONE, MyTopTracksPlaylist(applicationContext)
|
||||
SHUFFLE_MODE_NONE, TopTracksPlaylist()
|
||||
)
|
||||
DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.id)
|
||||
}
|
||||
SHORTCUT_TYPE_LAST_ADDED -> {
|
||||
startServiceWithPlaylist(
|
||||
MusicService.SHUFFLE_MODE_NONE, LastAddedPlaylist(applicationContext)
|
||||
SHUFFLE_MODE_NONE, LastAddedPlaylist()
|
||||
)
|
||||
DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.id)
|
||||
}
|
||||
SHORTCUT_TYPE_SEARCH -> {
|
||||
startActivity(Intent(this, SearchActivity::class.java))
|
||||
DynamicShortcutManager.reportShortcutUsed(this, SearchShortCutType.id)
|
||||
}
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
@ -87,7 +81,6 @@ class AppShortcutLauncherActivity : Activity() {
|
|||
const val SHORTCUT_TYPE_SHUFFLE_ALL = 0
|
||||
const val SHORTCUT_TYPE_TOP_TRACKS = 1
|
||||
const val SHORTCUT_TYPE_LAST_ADDED = 2
|
||||
const val SHORTCUT_TYPE_SEARCH = 3
|
||||
const val SHORTCUT_TYPE_NONE = 4
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import android.content.pm.ShortcutManager
|
|||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.LastAddedShortcutType
|
||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.SearchShortCutType
|
||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.ShuffleAllShortcutType
|
||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.TopTracksShortcutType
|
||||
import java.util.*
|
||||
|
@ -34,11 +33,9 @@ class DynamicShortcutManager(private val context: Context) {
|
|||
|
||||
private val defaultShortcuts: List<ShortcutInfo>
|
||||
get() = Arrays.asList(
|
||||
SearchShortCutType(context).shortcutInfo,
|
||||
ShuffleAllShortcutType(context).shortcutInfo,
|
||||
TopTracksShortcutType(context).shortcutInfo,
|
||||
LastAddedShortcutType(context).shortcutInfo
|
||||
|
||||
)
|
||||
|
||||
fun initDynamicShortcuts() {
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package io.github.muntashirakon.music.appshortcuts.shortcuttype
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.os.Build
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.appshortcuts.AppShortcutIconGenerator
|
||||
import io.github.muntashirakon.music.appshortcuts.AppShortcutLauncherActivity
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N_MR1)
|
||||
class SearchShortCutType(context: Context) : BaseShortcutType(context) {
|
||||
companion object {
|
||||
|
||||
val id: String
|
||||
get() = BaseShortcutType.ID_PREFIX + "search"
|
||||
}
|
||||
|
||||
override val shortcutInfo: ShortcutInfo
|
||||
get() = ShortcutInfo.Builder(
|
||||
context,
|
||||
id
|
||||
).setShortLabel(context.getString(R.string.action_search))
|
||||
.setLongLabel(context.getString(R.string.search_hint)).setIcon(
|
||||
AppShortcutIconGenerator.generateThemedIcon(
|
||||
context,
|
||||
R.drawable.ic_app_shortcut_search
|
||||
)
|
||||
).setIntent(getPlaySongsIntent(AppShortcutLauncherActivity.SHORTCUT_TYPE_SEARCH))
|
||||
.build()
|
||||
}
|
|
@ -22,22 +22,22 @@ import io.github.muntashirakon.music.R
|
|||
import io.github.muntashirakon.music.extensions.colorButtons
|
||||
import io.github.muntashirakon.music.extensions.extraNotNull
|
||||
import io.github.muntashirakon.music.extensions.materialDialog
|
||||
import io.github.muntashirakon.music.loaders.PlaylistLoader
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.repository.PlaylistRepository
|
||||
import io.github.muntashirakon.music.util.PlaylistsUtil
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class AddToPlaylistDialog : DialogFragment() {
|
||||
|
||||
private val playlistRepository by inject<PlaylistRepository>()
|
||||
override fun onCreateDialog(
|
||||
savedInstanceState: Bundle?
|
||||
): Dialog {
|
||||
val playlists = PlaylistLoader.getAllPlaylists(requireContext())
|
||||
val playlists = playlistRepository.playlists()
|
||||
val playlistNames = mutableListOf<String>()
|
||||
playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist))
|
||||
for (p in playlists) {
|
||||
playlistNames.add(p.name)
|
||||
}
|
||||
|
||||
return materialDialog(R.string.add_playlist_title)
|
||||
.setItems(playlistNames.toTypedArray()) { _, which ->
|
||||
val songs = extraNotNull<ArrayList<Song>>(EXTRA_SONG).value
|
||||
|
|
|
@ -98,7 +98,9 @@ class DeleteSongsDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
fun deleteSongs(songs: List<Song>, safUris: List<Uri>?) {
|
||||
MusicUtil.deleteTracks(requireActivity(), songs, safUris) { this.dismiss() }
|
||||
MusicUtil.deleteTracks(requireActivity(), songs, safUris, Runnable {
|
||||
dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -22,11 +22,17 @@ 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 com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import io.github.muntashirakon.music.App
|
||||
import io.github.muntashirakon.music.R
|
||||
|
||||
|
@ -83,4 +89,45 @@ 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
|
||||
}
|
||||
|
||||
fun MaterialButton.applyColor(color: Int) {
|
||||
val backgroundColorStateList = ColorStateList.valueOf(color)
|
||||
val textColorColorStateList = ColorStateList.valueOf(
|
||||
MaterialValueHelper.getPrimaryTextColor(
|
||||
context,
|
||||
ColorUtil.isColorLight(color)
|
||||
)
|
||||
)
|
||||
backgroundTintList = backgroundColorStateList
|
||||
setTextColor(textColorColorStateList)
|
||||
iconTint = textColorColorStateList
|
||||
}
|
||||
|
||||
fun TextInputLayout.accentColor() {
|
||||
val accentColor = ThemeStore.accentColor(context)
|
||||
val colorState = ColorStateList.valueOf(accentColor)
|
||||
boxStrokeColor = accentColor
|
||||
defaultHintTextColor = colorState
|
||||
isHintAnimationEnabled = true
|
||||
}
|
||||
|
||||
fun TextInputEditText.accentColor() {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package io.github.muntashirakon.music.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
|
||||
}
|
|
@ -3,7 +3,10 @@ package io.github.muntashirakon.music.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
|
||||
|
@ -51,5 +54,23 @@ fun AppCompatActivity.currentFragment(navHostId: Int): Fragment? {
|
|||
val navHostFragment: NavHostFragment =
|
||||
supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
||||
navHostFragment.targetFragment
|
||||
return navHostFragment?.childFragmentManager?.fragments?.first()
|
||||
return navHostFragment.childFragmentManager.fragments.first()
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> AppCompatActivity.whichFragment(@IdRes id: Int): T {
|
||||
return supportFragmentManager.findFragmentById(id) as T
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> Fragment.whichFragment(@IdRes id: Int): T {
|
||||
return childFragmentManager.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()
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -14,13 +14,10 @@
|
|||
|
||||
package io.github.muntashirakon.music.extensions
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.SeekBar
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.LayoutRes
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
|
@ -48,9 +45,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)
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package io.github.muntashirakon.music.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import io.github.muntashirakon.music.*
|
||||
import io.github.muntashirakon.music.adapter.album.AlbumAdapter
|
||||
import io.github.muntashirakon.music.adapter.artist.ArtistAdapter
|
||||
import io.github.muntashirakon.music.adapter.song.SongAdapter
|
||||
import io.github.muntashirakon.music.fragments.albums.AlbumClickListener
|
||||
import io.github.muntashirakon.music.fragments.artists.ArtistClickListener
|
||||
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
|
||||
import io.github.muntashirakon.music.model.Album
|
||||
import io.github.muntashirakon.music.model.Artist
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.repository.RealRepository
|
||||
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail),
|
||||
ArtistClickListener, AlbumClickListener {
|
||||
private val args by navArgs<DetailListFragmentArgs>()
|
||||
private val repository by inject<RealRepository>()
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
mainActivity.hideBottomBarVisibility(false)
|
||||
when (args.type) {
|
||||
TOP_ARTISTS -> {
|
||||
loadArtists(R.string.top_artists, TOP_ARTISTS)
|
||||
}
|
||||
RECENT_ARTISTS -> {
|
||||
loadArtists(R.string.recent_artists, RECENT_ARTISTS)
|
||||
}
|
||||
TOP_ALBUMS -> {
|
||||
loadAlbums(R.string.top_albums, TOP_ALBUMS)
|
||||
}
|
||||
RECENT_ALBUMS -> {
|
||||
loadAlbums(R.string.recent_albums, RECENT_ALBUMS)
|
||||
}
|
||||
FAVOURITES -> {
|
||||
loadFavorite()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadFavorite() {
|
||||
toolbar.setTitle(R.string.favorites)
|
||||
CoroutineScope(IO).launch {
|
||||
val songs = repository.favoritePlaylistHome()
|
||||
withContext(Main) {
|
||||
recyclerView.apply {
|
||||
adapter = SongAdapter(
|
||||
requireActivity(),
|
||||
songs.arrayList as MutableList<Song>,
|
||||
R.layout.item_list, null
|
||||
)
|
||||
layoutManager = linearLayoutManager()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadArtists(title: Int, type: Int) {
|
||||
toolbar.setTitle(title)
|
||||
CoroutineScope(IO).launch {
|
||||
val artists =
|
||||
if (type == TOP_ARTISTS) repository.topArtists() else repository.recentArtists()
|
||||
withContext(Main) {
|
||||
recyclerView.apply {
|
||||
adapter = artistAdapter(artists)
|
||||
layoutManager = gridLayoutManager()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadAlbums(title: Int, type: Int) {
|
||||
toolbar.setTitle(title)
|
||||
CoroutineScope(IO).launch {
|
||||
val albums =
|
||||
if (type == TOP_ALBUMS) repository.topAlbums() else repository.recentAlbums()
|
||||
withContext(Main) {
|
||||
recyclerView.apply {
|
||||
adapter = albumAdapter(albums)
|
||||
layoutManager = gridLayoutManager()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun artistAdapter(artists: List<Artist>): ArtistAdapter = ArtistAdapter(
|
||||
requireActivity(),
|
||||
artists,
|
||||
R.layout.item_grid_circle,
|
||||
null, this@DetailListFragment
|
||||
)
|
||||
|
||||
private fun albumAdapter(albums: List<Album>): AlbumAdapter = AlbumAdapter(
|
||||
requireActivity(),
|
||||
albums,
|
||||
R.layout.item_grid,
|
||||
null, this@DetailListFragment
|
||||
)
|
||||
|
||||
private fun linearLayoutManager(): LinearLayoutManager =
|
||||
LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
||||
|
||||
private fun gridLayoutManager(): GridLayoutManager =
|
||||
GridLayoutManager(requireContext(), 2, GridLayoutManager.VERTICAL, false)
|
||||
|
||||
|
||||
override fun onArtist(artistId: Int, imageView: ImageView) {
|
||||
|
||||
}
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
|
||||
}
|
||||
}
|
|
@ -4,27 +4,26 @@ import androidx.lifecycle.LiveData
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import io.github.muntashirakon.music.adapter.HomeAdapter
|
||||
import io.github.muntashirakon.music.fragments.ReloadType.*
|
||||
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
||||
import io.github.muntashirakon.music.model.*
|
||||
import io.github.muntashirakon.music.providers.RepositoryImpl
|
||||
import io.github.muntashirakon.music.repository.RealRepository
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class LibraryViewModel(
|
||||
private val repository: RepositoryImpl
|
||||
private val realRepository: RealRepository
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
|
||||
private val paletteColor = MutableLiveData<Int>()
|
||||
private val albums = MutableLiveData<List<Album>>()
|
||||
private val songs = MutableLiveData<List<Song>>()
|
||||
private val artists = MutableLiveData<List<Artist>>()
|
||||
private val playlists = MutableLiveData<List<Playlist>>()
|
||||
private val genres = MutableLiveData<List<Genre>>()
|
||||
private val home = MutableLiveData<List<Home>>()
|
||||
private val paletteColor = MutableLiveData<Int>()
|
||||
|
||||
val paletteColorLiveData: LiveData<Int> = paletteColor
|
||||
val homeLiveData: LiveData<List<Home>> = home
|
||||
|
@ -46,59 +45,36 @@ class LibraryViewModel(
|
|||
artists.value = loadArtists.await()
|
||||
playlists.value = loadPlaylists.await()
|
||||
genres.value = loadGenres.await()
|
||||
loadHomeSections()
|
||||
home.value = loadHome.await()
|
||||
}
|
||||
|
||||
private fun loadHomeSections() = viewModelScope.launch {
|
||||
val list = mutableListOf<Home>()
|
||||
val result = listOf(
|
||||
repository.topArtists(),
|
||||
repository.topAlbums(),
|
||||
repository.recentArtists(),
|
||||
repository.recentAlbums(),
|
||||
repository.suggestions(),
|
||||
repository.favoritePlaylist(),
|
||||
repository.homeGenres()
|
||||
)
|
||||
result.forEach {
|
||||
if (it != null && it.arrayList.isNotEmpty()) {
|
||||
if (it.homeSection == HomeAdapter.SUGGESTIONS) {
|
||||
if (it.arrayList.size > 9) {
|
||||
list.add(it)
|
||||
}
|
||||
} else {
|
||||
list.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
home.value = list
|
||||
}
|
||||
private val loadHome: Deferred<List<Home>>
|
||||
get() = viewModelScope.async { realRepository.homeSections() }
|
||||
|
||||
private val loadSongs: Deferred<List<Song>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
repository.allSongs()
|
||||
}
|
||||
get() = viewModelScope.async(IO) { realRepository.allSongs() }
|
||||
|
||||
private val loadAlbums: Deferred<List<Album>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
repository.allAlbums()
|
||||
realRepository.allAlbums()
|
||||
}
|
||||
|
||||
private val loadArtists: Deferred<List<Artist>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
repository.allArtists()
|
||||
realRepository.albumArtists()
|
||||
}
|
||||
|
||||
private val loadPlaylists: Deferred<List<Playlist>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
repository.allPlaylists()
|
||||
realRepository.allPlaylists()
|
||||
}
|
||||
|
||||
private val loadGenres: Deferred<List<Genre>>
|
||||
get() = viewModelScope.async(IO) {
|
||||
repository.allGenres()
|
||||
realRepository.allGenres()
|
||||
}
|
||||
|
||||
|
||||
fun forceReload(reloadType: ReloadType) = viewModelScope.launch {
|
||||
when (reloadType) {
|
||||
Songs -> songs.value = loadSongs.await()
|
||||
|
@ -114,15 +90,37 @@ class LibraryViewModel(
|
|||
|
||||
override fun onMediaStoreChanged() {
|
||||
loadLibraryContent()
|
||||
println("onMediaStoreChanged")
|
||||
}
|
||||
|
||||
override fun onServiceConnected() {}
|
||||
override fun onServiceDisconnected() {}
|
||||
override fun onQueueChanged() {}
|
||||
override fun onPlayingMetaChanged() {}
|
||||
override fun onPlayStateChanged() {}
|
||||
override fun onRepeatModeChanged() {}
|
||||
override fun onShuffleModeChanged() {}
|
||||
|
||||
override fun onServiceConnected() {
|
||||
println("onServiceConnected")
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected() {
|
||||
println("onServiceDisconnected")
|
||||
}
|
||||
|
||||
override fun onQueueChanged() {
|
||||
println("onQueueChanged")
|
||||
}
|
||||
|
||||
override fun onPlayingMetaChanged() {
|
||||
println("onPlayingMetaChanged")
|
||||
}
|
||||
|
||||
override fun onPlayStateChanged() {
|
||||
println("onPlayStateChanged")
|
||||
}
|
||||
|
||||
override fun onRepeatModeChanged() {
|
||||
println("onRepeatModeChanged")
|
||||
}
|
||||
|
||||
override fun onShuffleModeChanged() {
|
||||
println("onShuffleModeChanged")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,32 +1,21 @@
|
|||
package io.github.muntashirakon.music.activities
|
||||
package io.github.muntashirakon.music.fragments.about
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.core.app.ShareCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import io.github.muntashirakon.music.Constants.APP_INSTAGRAM_LINK
|
||||
import io.github.muntashirakon.music.Constants.APP_TELEGRAM_LINK
|
||||
import io.github.muntashirakon.music.Constants.APP_TWITTER_LINK
|
||||
import io.github.muntashirakon.music.Constants.FAQ_LINK
|
||||
import io.github.muntashirakon.music.Constants.GITHUB_PROJECT
|
||||
import io.github.muntashirakon.music.Constants.PINTEREST
|
||||
import io.github.muntashirakon.music.Constants.RATE_ON_GOOGLE_PLAY
|
||||
import io.github.muntashirakon.music.Constants.TELEGRAM_CHANGE_LOG
|
||||
import io.github.muntashirakon.music.Constants.TRANSLATE
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.base.AbsBaseActivity
|
||||
import io.github.muntashirakon.music.adapter.ContributorAdapter
|
||||
import io.github.muntashirakon.music.extensions.applyToolbar
|
||||
import io.github.muntashirakon.music.model.Contributor
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import kotlinx.android.synthetic.main.activity_about.*
|
||||
import io.github.muntashirakon.music.Constants
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.ContributorAdapter
|
||||
import io.github.muntashirakon.music.model.Contributor
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import kotlinx.android.synthetic.main.card_credit.*
|
||||
import kotlinx.android.synthetic.main.card_other.*
|
||||
import kotlinx.android.synthetic.main.card_retro_info.*
|
||||
|
@ -34,13 +23,19 @@ import kotlinx.android.synthetic.main.card_social.*
|
|||
import java.io.IOException
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
||||
class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
version.setSummary(getAppVersion())
|
||||
setUpView()
|
||||
loadContributors()
|
||||
}
|
||||
|
||||
private val contributorsJson: String?
|
||||
get() {
|
||||
val json: String
|
||||
try {
|
||||
val inputStream = assets.open("contributors.json")
|
||||
val inputStream = requireActivity().assets.open("contributors.json")
|
||||
val size = inputStream.available()
|
||||
val buffer = ByteArray(size)
|
||||
inputStream.read(buffer)
|
||||
|
@ -53,27 +48,6 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
|||
return json
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setDrawUnderStatusBar()
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_about)
|
||||
setStatusbarColorAuto()
|
||||
setNavigationbarColorAuto()
|
||||
setLightNavigationBar(true)
|
||||
|
||||
applyToolbar(toolbar)
|
||||
version.setSummary(getAppVersion())
|
||||
setUpView()
|
||||
loadContributors()
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == android.R.id.home) {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun openUrl(url: String) {
|
||||
val i = Intent(Intent.ACTION_VIEW)
|
||||
|
@ -89,6 +63,7 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
|||
appRate.setOnClickListener(this)
|
||||
appTranslation.setOnClickListener(this)
|
||||
appShare.setOnClickListener(this)
|
||||
donateLink.setOnClickListener(this)
|
||||
instagramLink.setOnClickListener(this)
|
||||
twitterLink.setOnClickListener(this)
|
||||
changelog.setOnClickListener(this)
|
||||
|
@ -99,25 +74,26 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
|||
|
||||
override fun onClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.pinterestLink -> openUrl(PINTEREST)
|
||||
R.id.faqLink -> openUrl(FAQ_LINK)
|
||||
R.id.telegramLink -> openUrl(APP_TELEGRAM_LINK)
|
||||
R.id.appGithub -> openUrl(GITHUB_PROJECT)
|
||||
R.id.appTranslation -> openUrl(TRANSLATE)
|
||||
R.id.appRate -> openUrl(RATE_ON_GOOGLE_PLAY)
|
||||
R.id.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.instagramLink -> openUrl(APP_INSTAGRAM_LINK)
|
||||
R.id.twitterLink -> openUrl(APP_TWITTER_LINK)
|
||||
R.id.changelog -> openUrl(TELEGRAM_CHANGE_LOG)
|
||||
R.id.openSource -> NavigationUtil.goToOpenSource(this)
|
||||
R.id.bugReportLink -> NavigationUtil.bugReport(this)
|
||||
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 = "Pro"
|
||||
val packageInfo = packageManager.getPackageInfo(packageName, 0)
|
||||
val packageInfo =
|
||||
requireActivity().packageManager.getPackageInfo(requireActivity().packageName, 0)
|
||||
"${packageInfo.versionName} $isPro"
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
e.printStackTrace()
|
||||
|
@ -126,9 +102,10 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
|||
}
|
||||
|
||||
private fun shareApp() {
|
||||
ShareCompat.IntentBuilder.from(this).setType("text/plain")
|
||||
ShareCompat.IntentBuilder.from(requireActivity()).setType("text/plain")
|
||||
.setChooserTitle(R.string.share_app)
|
||||
.setText(String.format(getString(R.string.app_share), packageName)).startChooser()
|
||||
.setText(String.format(getString(R.string.app_share), requireActivity().packageName))
|
||||
.startChooser()
|
||||
}
|
||||
|
||||
private fun loadContributors() {
|
||||
|
@ -138,8 +115,10 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
|||
val contributors = Gson().fromJson<List<Contributor>>(contributorsJson, type)
|
||||
|
||||
val contributorAdapter = ContributorAdapter(contributors)
|
||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
recyclerView.itemAnimator = DefaultItemAnimator()
|
||||
recyclerView.adapter = contributorAdapter
|
||||
recyclerView.apply {
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
itemAnimator = DefaultItemAnimator()
|
||||
adapter = contributorAdapter
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,137 +1,103 @@
|
|||
package io.github.muntashirakon.music.activities.albums
|
||||
package io.github.muntashirakon.music.fragments.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 android.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.navigation.fragment.navArgs
|
||||
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.common.ATHToolbarActivity.getToolbarBackgroundColor
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
import com.bumptech.glide.Glide
|
||||
import io.github.muntashirakon.music.EXTRA_ALBUM_ID
|
||||
import io.github.muntashirakon.music.EXTRA_ARTIST_ID
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
|
||||
import io.github.muntashirakon.music.activities.tageditor.AbsTagEditorActivity
|
||||
import io.github.muntashirakon.music.activities.tageditor.AlbumTagEditorActivity
|
||||
import io.github.muntashirakon.music.adapter.album.HorizontalAlbumAdapter
|
||||
import io.github.muntashirakon.music.adapter.song.SimpleSongAdapter
|
||||
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
||||
import io.github.muntashirakon.music.dialogs.DeleteSongsDialog
|
||||
import io.github.muntashirakon.music.extensions.extraNotNull
|
||||
import io.github.muntashirakon.music.extensions.applyColor
|
||||
import io.github.muntashirakon.music.extensions.show
|
||||
import io.github.muntashirakon.music.extensions.surfaceColor
|
||||
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
|
||||
import io.github.muntashirakon.music.glide.AlbumGlideRequest
|
||||
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.helper.SortOrder.AlbumSongSortOrder
|
||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
||||
import io.github.muntashirakon.music.helper.SortOrder
|
||||
import io.github.muntashirakon.music.model.Album
|
||||
import io.github.muntashirakon.music.model.Artist
|
||||
import io.github.muntashirakon.music.network.model.LastFmAlbum
|
||||
import io.github.muntashirakon.music.util.*
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||
import io.github.muntashirakon.music.util.RetroUtil
|
||||
import io.github.muntashirakon.music.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 kotlinx.android.synthetic.main.fragment_album_content.*
|
||||
import kotlinx.android.synthetic.main.fragment_album_details.*
|
||||
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
|
||||
}
|
||||
class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_details),
|
||||
AlbumClickListener {
|
||||
|
||||
private val arguments by navArgs<AlbumDetailsFragmentArgs>()
|
||||
private val detailsViewModel by viewModel<AlbumDetailsViewModel> {
|
||||
parametersOf(extraNotNull<Int>(EXTRA_ALBUM_ID).value)
|
||||
parametersOf(arguments.extraAlbumId)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
mainActivity.hideBottomBarVisibility(false)
|
||||
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
|
||||
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
|
||||
}
|
||||
toolbar.title = null
|
||||
|
||||
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)
|
||||
postponeEnterTransition()
|
||||
detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer {
|
||||
showAlbum(it)
|
||||
startPostponedEnterTransition()
|
||||
})
|
||||
detailsViewModel.getArtist().observe(this, androidx.lifecycle.Observer {
|
||||
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
|
||||
loadArtistImage(it)
|
||||
})
|
||||
detailsViewModel.getMoreAlbums().observe(this, androidx.lifecycle.Observer {
|
||||
detailsViewModel.getMoreAlbums().observe(viewLifecycleOwner, Observer {
|
||||
moreAlbums(it)
|
||||
})
|
||||
detailsViewModel.getAlbumInfo().observe(this, androidx.lifecycle.Observer {
|
||||
detailsViewModel.getAlbumInfo().observe(viewLifecycleOwner, Observer {
|
||||
aboutAlbum(it)
|
||||
})
|
||||
setupRecyclerView()
|
||||
artistImage.setOnClickListener {
|
||||
val artistPairs = ActivityOptions.makeSceneTransitionAnimation(
|
||||
this,
|
||||
UtilPair.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)
|
||||
)
|
||||
}
|
||||
playAction.setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
|
||||
|
||||
shuffleAction.setOnClickListener {
|
||||
MusicPlayerRemote.openAndShuffleQueue(
|
||||
album.songs!!,
|
||||
true
|
||||
)
|
||||
NavigationUtil.goToArtistOptions(this, album.artistId, artistPairs)
|
||||
}
|
||||
playAction.apply {
|
||||
setOnClickListener { MusicPlayerRemote.openQueue(album.songs!!, 0, true) }
|
||||
}
|
||||
shuffleAction.apply {
|
||||
setOnClickListener { MusicPlayerRemote.openAndShuffleQueue(album.songs!!, true) }
|
||||
}
|
||||
|
||||
aboutAlbumText.setOnClickListener {
|
||||
|
@ -141,12 +107,26 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
aboutAlbumText.maxLines = 4
|
||||
}
|
||||
}
|
||||
image.apply {
|
||||
transitionName = getString(R.string.transition_album_art)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
playerActivity?.removeMusicServiceEventListener(detailsViewModel)
|
||||
}
|
||||
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
simpleSongAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song, this)
|
||||
simpleSongAdapter = SimpleSongAdapter(
|
||||
requireActivity() as AppCompatActivity,
|
||||
ArrayList(),
|
||||
R.layout.item_song,
|
||||
null
|
||||
)
|
||||
recyclerView.apply {
|
||||
layoutManager = LinearLayoutManager(this@AlbumDetailsActivity)
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
itemAnimator = DefaultItemAnimator()
|
||||
isNestedScrollingEnabled = false
|
||||
adapter = simpleSongAdapter
|
||||
|
@ -155,7 +135,6 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
|
||||
private fun showAlbum(album: Album) {
|
||||
if (album.songs!!.isEmpty()) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
this.album = album
|
||||
|
@ -194,9 +173,10 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
moreRecyclerView.show()
|
||||
moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName)
|
||||
|
||||
val albumAdapter = HorizontalAlbumAdapter(this, albums, null)
|
||||
val albumAdapter =
|
||||
HorizontalAlbumAdapter(requireActivity() as AppCompatActivity, albums, null, this)
|
||||
moreRecyclerView.layoutManager = GridLayoutManager(
|
||||
this,
|
||||
requireContext(),
|
||||
1,
|
||||
GridLayoutManager.HORIZONTAL,
|
||||
false
|
||||
|
@ -226,8 +206,8 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
}
|
||||
|
||||
private fun loadArtistImage(artist: Artist) {
|
||||
ArtistGlideRequest.Builder.from(Glide.with(this), artist)
|
||||
.generatePalette(this)
|
||||
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
||||
.generatePalette(requireContext())
|
||||
.build()
|
||||
.dontAnimate()
|
||||
.dontTransform()
|
||||
|
@ -238,10 +218,10 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
}
|
||||
|
||||
private fun loadAlbumCover() {
|
||||
AlbumGlideRequest.Builder.from(Glide.with(this), album.safeGetFirstSong())
|
||||
.checkIgnoreMediaStore(this)
|
||||
AlbumGlideRequest.Builder.from(Glide.with(requireContext()), album.safeGetFirstSong())
|
||||
.checkIgnoreMediaStore(requireContext())
|
||||
.ignoreMediaStore(PreferenceUtil.isIgnoreMediaStoreArtwork)
|
||||
.generatePalette(this)
|
||||
.generatePalette(requireContext())
|
||||
.build()
|
||||
.dontAnimate()
|
||||
.dontTransform()
|
||||
|
@ -253,32 +233,28 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
}
|
||||
|
||||
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
|
||||
shuffleAction.applyColor(color.backgroundColor)
|
||||
playAction.applyColor(color.backgroundColor)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_album_detail, menu)
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
findNavController().navigate(
|
||||
R.id.albumDetailsFragment,
|
||||
bundleOf(EXTRA_ALBUM_ID to albumId)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.menu_album_detail, menu)
|
||||
val sortOrder = menu.findItem(R.id.action_sort_order)
|
||||
setUpSortOrderMenu(sortOrder.subMenu)
|
||||
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
|
||||
this,
|
||||
requireContext(),
|
||||
toolbar,
|
||||
menu,
|
||||
getToolbarBackgroundColor(toolbar)
|
||||
)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
@ -289,6 +265,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
var sortOrder: String? = null
|
||||
val songs = simpleSongAdapter.dataSet
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> findNavController().navigateUp()
|
||||
R.id.action_play_next -> {
|
||||
MusicPlayerRemote.playNext(songs)
|
||||
return true
|
||||
|
@ -298,22 +275,18 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
return true
|
||||
}
|
||||
R.id.action_add_to_playlist -> {
|
||||
AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
|
||||
AddToPlaylistDialog.create(songs).show(childFragmentManager, "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()
|
||||
DeleteSongsDialog.create(songs).show(childFragmentManager, "DELETE_SONGS")
|
||||
return true
|
||||
}
|
||||
R.id.action_tag_editor -> {
|
||||
val intent = Intent(this, AlbumTagEditorActivity::class.java)
|
||||
val intent = Intent(requireContext(), AlbumTagEditorActivity::class.java)
|
||||
intent.putExtra(AbsTagEditorActivity.EXTRA_ID, album.id)
|
||||
val options = ActivityOptions.makeSceneTransitionAnimation(
|
||||
this,
|
||||
requireActivity(),
|
||||
albumCoverContainer,
|
||||
"${getString(R.string.transition_album_art)}_${album.id}"
|
||||
)
|
||||
|
@ -324,11 +297,12 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
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_title -> sortOrder = SortOrder.AlbumSongSortOrder.SONG_A_Z
|
||||
R.id.action_sort_order_title_desc -> sortOrder = SortOrder.AlbumSongSortOrder.SONG_Z_A
|
||||
R.id.action_sort_order_track_list -> sortOrder =
|
||||
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST
|
||||
R.id.action_sort_order_artist_song_duration ->
|
||||
sortOrder = AlbumSongSortOrder.SONG_DURATION
|
||||
sortOrder = SortOrder.AlbumSongSortOrder.SONG_DURATION
|
||||
}
|
||||
if (sortOrder != null) {
|
||||
item.isChecked = true
|
||||
|
@ -339,13 +313,13 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
|
||||
private fun setUpSortOrderMenu(sortOrder: SubMenu) {
|
||||
when (savedSortOrder) {
|
||||
AlbumSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title)
|
||||
SortOrder.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)
|
||||
SortOrder.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)
|
||||
SortOrder.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)
|
||||
SortOrder.AlbumSongSortOrder.SONG_DURATION -> sortOrder.findItem(R.id.action_sort_order_artist_song_duration)
|
||||
.isChecked = true
|
||||
}
|
||||
}
|
||||
|
@ -353,22 +327,22 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
private fun setSaveSortOrder(sortOrder: String) {
|
||||
PreferenceUtil.albumDetailSongSortOrder = sortOrder
|
||||
when (sortOrder) {
|
||||
AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
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 ->
|
||||
SortOrder.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 ->
|
||||
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
o2.title.compareTo(
|
||||
o1.title
|
||||
)
|
||||
})
|
||||
AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||
o1.duration.compareTo(
|
||||
o2.duration
|
||||
)
|
||||
|
@ -377,23 +351,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
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
|
||||
const val TAG_EDITOR_REQUEST = 9002
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package io.github.muntashirakon.music.activities.albums
|
||||
package io.github.muntashirakon.music.fragments.albums
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
@ -8,15 +8,14 @@ import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
|||
import io.github.muntashirakon.music.model.Album
|
||||
import io.github.muntashirakon.music.model.Artist
|
||||
import io.github.muntashirakon.music.network.model.LastFmAlbum
|
||||
import io.github.muntashirakon.music.providers.RepositoryImpl
|
||||
import io.github.muntashirakon.music.repository.RealRepository
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.Exception
|
||||
|
||||
class AlbumDetailsViewModel(
|
||||
private val repository: RepositoryImpl,
|
||||
private val realRepository: RealRepository,
|
||||
private val albumId: Int
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
|
||||
|
@ -41,7 +40,7 @@ class AlbumDetailsViewModel(
|
|||
|
||||
fun loadAlbumInfo(album: Album) = viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val lastFmAlbum = repository.albumInfo(
|
||||
val lastFmAlbum = realRepository.albumInfo(
|
||||
album.artistName ?: "-", album.title ?: "-"
|
||||
)
|
||||
_lastFmAlbum.postValue(lastFmAlbum)
|
||||
|
@ -49,7 +48,7 @@ class AlbumDetailsViewModel(
|
|||
}
|
||||
|
||||
fun loadArtist(artistId: Int) = viewModelScope.launch(Dispatchers.IO) {
|
||||
val artist = repository.artistById(artistId)
|
||||
val artist = realRepository.artistById(artistId)
|
||||
_artist.postValue(artist)
|
||||
|
||||
artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
|
||||
|
@ -59,7 +58,7 @@ class AlbumDetailsViewModel(
|
|||
|
||||
private val loadAlbumAsync: Deferred<Album?>
|
||||
get() = viewModelScope.async(Dispatchers.IO) {
|
||||
repository.albumById(albumId)
|
||||
realRepository.albumById(albumId)
|
||||
}
|
||||
|
||||
override fun onMediaStoreChanged() {
|
|
@ -2,32 +2,30 @@ package io.github.muntashirakon.music.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.navigation.fragment.FragmentNavigatorExtras
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import io.github.muntashirakon.music.EXTRA_ALBUM_ID
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.album.AlbumAdapter
|
||||
import io.github.muntashirakon.music.fragments.ReloadType
|
||||
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||
import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
|
||||
import io.github.muntashirakon.music.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)
|
||||
libraryViewModel.albumsLiveData
|
||||
.observe(viewLifecycleOwner, Observer { albums ->
|
||||
if (albums.isNotEmpty())
|
||||
adapter?.swapDataSet(albums)
|
||||
else
|
||||
adapter?.swapDataSet(listOf())
|
||||
})
|
||||
libraryViewModel.albumsLiveData.observe(viewLifecycleOwner, Observer {
|
||||
if (it.isNotEmpty())
|
||||
adapter?.swapDataSet(it)
|
||||
else
|
||||
adapter?.swapDataSet(listOf())
|
||||
})
|
||||
}
|
||||
|
||||
override val emptyMessage: Int
|
||||
|
@ -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,24 @@ class AlbumsFragment :
|
|||
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
var TAG: String = AlbumsFragment::class.java.simpleName
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(): AlbumsFragment {
|
||||
return AlbumsFragment()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
val controller = requireActivity().findNavController(R.id.fragment_container)
|
||||
controller.navigate(
|
||||
R.id.albumDetailsFragment,
|
||||
bundleOf(EXTRA_ALBUM_ID to albumId),
|
||||
null,
|
||||
FragmentNavigatorExtras(
|
||||
view to getString(R.string.transition_album_art)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
interface AlbumClickListener {
|
||||
fun onAlbumClick(albumId: Int, view: View)
|
||||
}
|
|
@ -1,115 +1,79 @@
|
|||
package io.github.muntashirakon.music.activities.artists
|
||||
package io.github.muntashirakon.music.fragments.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.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
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 com.bumptech.glide.Glide
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
|
||||
import io.github.muntashirakon.music.adapter.album.HorizontalAlbumAdapter
|
||||
import io.github.muntashirakon.music.adapter.song.SimpleSongAdapter
|
||||
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
||||
import io.github.muntashirakon.music.extensions.extraNotNull
|
||||
import io.github.muntashirakon.music.extensions.applyColor
|
||||
import io.github.muntashirakon.music.extensions.show
|
||||
import io.github.muntashirakon.music.extensions.surfaceColor
|
||||
import io.github.muntashirakon.music.extensions.showToast
|
||||
import io.github.muntashirakon.music.fragments.albums.AlbumClickListener
|
||||
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
|
||||
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
||||
import io.github.muntashirakon.music.model.Artist
|
||||
import io.github.muntashirakon.music.network.model.LastFmArtist
|
||||
import io.github.muntashirakon.music.util.CustomArtistImageUtil
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.util.RetroColorUtil
|
||||
import io.github.muntashirakon.music.util.RetroUtil
|
||||
import io.github.muntashirakon.music.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 kotlinx.android.synthetic.main.fragment_artist_content.*
|
||||
import kotlinx.android.synthetic.main.fragment_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
|
||||
class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_details),
|
||||
AlbumClickListener {
|
||||
private val arguments by navArgs<ArtistDetailsFragmentArgs>()
|
||||
private val detailsViewModel: ArtistDetailsViewModel by viewModel {
|
||||
parametersOf(arguments.extraArtistId)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
private var lang: String? = null
|
||||
private var biography: Spanned? = null
|
||||
|
||||
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 onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
mainActivity.hideBottomBarVisibility(false)
|
||||
toolbar.title = null
|
||||
setupRecyclerView()
|
||||
postponeEnterTransition()
|
||||
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
|
||||
|
||||
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)
|
||||
showArtist(it)
|
||||
startPostponedEnterTransition()
|
||||
})
|
||||
detailsViewModel.getArtistInfo().observe(this, androidx.lifecycle.Observer {
|
||||
detailsViewModel.getArtistInfo().observe(viewLifecycleOwner, Observer {
|
||||
artistInfo(it)
|
||||
})
|
||||
setupRecyclerView()
|
||||
|
||||
playAction.apply {
|
||||
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
|
||||
}
|
||||
|
@ -127,13 +91,13 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
albumAdapter = HorizontalAlbumAdapter(this, ArrayList(), null)
|
||||
albumAdapter = HorizontalAlbumAdapter(requireActivity(), ArrayList(), null, this)
|
||||
albumRecyclerView.apply {
|
||||
itemAnimator = DefaultItemAnimator()
|
||||
layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false)
|
||||
adapter = albumAdapter
|
||||
}
|
||||
songAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song, this)
|
||||
songAdapter = SimpleSongAdapter(requireActivity(), ArrayList(), R.layout.item_song, null)
|
||||
recyclerView.apply {
|
||||
itemAnimator = DefaultItemAnimator()
|
||||
layoutManager = LinearLayoutManager(this.context)
|
||||
|
@ -141,33 +105,16 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
fun showArtist(artist: Artist) {
|
||||
this.artist = artist
|
||||
loadArtistImage(artist)
|
||||
if (RetroUtil.isAllowedToDownloadMetadata(this)) {
|
||||
if (RetroUtil.isAllowedToDownloadMetadata(requireContext())) {
|
||||
loadBiography(artist.name)
|
||||
}
|
||||
artistTitle.text = artist.name
|
||||
text.text = String.format(
|
||||
"%s • %s",
|
||||
MusicUtil.getArtistInfoString(this, artist),
|
||||
MusicUtil.getArtistInfoString(requireContext(), artist),
|
||||
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(artist.songs))
|
||||
)
|
||||
val songText =
|
||||
|
@ -184,7 +131,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
)
|
||||
songTitle.text = songText
|
||||
albumTitle.text = albumText
|
||||
songAdapter.swapDataSet(artist.songs)
|
||||
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
|
||||
artist.albums?.let { albumAdapter.swapDataSet(it) }
|
||||
}
|
||||
|
||||
|
@ -224,31 +171,32 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
}
|
||||
}
|
||||
|
||||
private var lang: String? = null
|
||||
|
||||
private fun loadArtistImage(artist: Artist) {
|
||||
ArtistGlideRequest.Builder.from(Glide.with(this), artist)
|
||||
.generatePalette(this).build()
|
||||
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
||||
.generatePalette(requireContext()).build()
|
||||
.dontAnimate().into(object : RetroMusicColoredTarget(image) {
|
||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||
startPostponedEnterTransition()
|
||||
setColors(colors)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setColors(color: MediaNotificationProcessor) {
|
||||
MaterialUtil.tintColor(
|
||||
button = shuffleAction,
|
||||
textColor = color.primaryTextColor,
|
||||
backgroundColor = color.backgroundColor
|
||||
shuffleAction.applyColor(color.backgroundColor)
|
||||
playAction.applyColor(color.backgroundColor)
|
||||
}
|
||||
|
||||
override fun onAlbumClick(albumId: Int, view: View) {
|
||||
findNavController().navigate(
|
||||
R.id.albumDetailsFragment,
|
||||
bundleOf("extra_album_id" to albumId),
|
||||
null,
|
||||
FragmentNavigatorExtras(
|
||||
view to getString(R.string.transition_album_art)
|
||||
)
|
||||
)
|
||||
MaterialUtil.tintColor(
|
||||
button = playAction,
|
||||
textColor = color.primaryTextColor,
|
||||
backgroundColor = color.backgroundColor
|
||||
)
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar?.title = null
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
@ -258,10 +206,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
|
||||
val songs = artist.songs
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
super.onBackPressed()
|
||||
return true
|
||||
}
|
||||
android.R.id.home -> findNavController().navigateUp()
|
||||
R.id.action_play_next -> {
|
||||
MusicPlayerRemote.playNext(songs)
|
||||
return true
|
||||
|
@ -271,7 +216,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
return true
|
||||
}
|
||||
R.id.action_add_to_playlist -> {
|
||||
AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
|
||||
AddToPlaylistDialog.create(songs).show(childFragmentManager, "ADD_PLAYLIST")
|
||||
return true
|
||||
}
|
||||
R.id.action_set_artist_image -> {
|
||||
|
@ -284,14 +229,8 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
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)
|
||||
showToast(resources.getString(R.string.updating))
|
||||
CustomArtistImageUtil.getInstance(requireContext()).resetCustomArtistImage(artist)
|
||||
forceDownload = true
|
||||
return true
|
||||
}
|
||||
|
@ -299,26 +238,12 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
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)
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.menu_artist_detail, menu)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_ARTIST_ID = "extra_artist_id"
|
||||
const val REQUEST_CODE_SELECT_IMAGE = 9003
|
||||
const val REQUEST_CODE_SELECT_IMAGE = 9002
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package io.github.muntashirakon.music.activities.artists
|
||||
package io.github.muntashirakon.music.fragments.artists
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
@ -6,21 +6,21 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
||||
import io.github.muntashirakon.music.model.Artist
|
||||
import io.github.muntashirakon.music.providers.RepositoryImpl
|
||||
import io.github.muntashirakon.music.network.model.LastFmArtist
|
||||
import io.github.muntashirakon.music.repository.RealRepository
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ArtistDetailsViewModel(
|
||||
private val repository: RepositoryImpl,
|
||||
private val realRepository: RealRepository,
|
||||
private val artistId: Int
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
|
||||
private val loadArtistDetailsAsync: Deferred<Artist?>
|
||||
get() = viewModelScope.async(Dispatchers.IO) {
|
||||
repository.artistById(artistId)
|
||||
realRepository.artistById(artistId)
|
||||
}
|
||||
|
||||
private val _artist = MutableLiveData<Artist>()
|
||||
|
@ -40,7 +40,7 @@ class ArtistDetailsViewModel(
|
|||
}
|
||||
|
||||
fun loadBiography(name: String, lang: String?, cache: String?) = viewModelScope.launch {
|
||||
val info = repository.artistInfo(name, lang, cache)
|
||||
val info = realRepository.artistInfo(name, lang, cache)
|
||||
_lastFmArtist.postValue(info)
|
||||
}
|
||||
|
|
@ -2,10 +2,14 @@ package io.github.muntashirakon.music.fragments.artists
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import io.github.muntashirakon.music.EXTRA_ARTIST_ID
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.artist.ArtistAdapter
|
||||
import io.github.muntashirakon.music.extensions.findActivityNavController
|
||||
import io.github.muntashirakon.music.fragments.ReloadType
|
||||
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||
import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
|
||||
|
@ -13,7 +17,7 @@ import io.github.muntashirakon.music.util.PreferenceUtil
|
|||
|
||||
class ArtistsFragment :
|
||||
AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
|
||||
MainActivityFragmentCallbacks {
|
||||
MainActivityFragmentCallbacks, ArtistClickListener {
|
||||
|
||||
override fun handleBackPress(): Boolean {
|
||||
return false
|
||||
|
@ -22,14 +26,12 @@ class ArtistsFragment :
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
libraryViewModel.artistsLiveData
|
||||
.observe(viewLifecycleOwner, Observer { artists ->
|
||||
if (artists.isNotEmpty()) {
|
||||
adapter?.swapDataSet(artists)
|
||||
} else {
|
||||
adapter?.swapDataSet(listOf())
|
||||
}
|
||||
})
|
||||
libraryViewModel.artistsLiveData.observe(viewLifecycleOwner, Observer {
|
||||
if (it.isNotEmpty())
|
||||
adapter?.swapDataSet(it)
|
||||
else
|
||||
adapter?.swapDataSet(listOf())
|
||||
})
|
||||
}
|
||||
|
||||
override val emptyMessage: Int
|
||||
|
@ -46,10 +48,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 +94,18 @@ class ArtistsFragment :
|
|||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val TAG: String = ArtistsFragment::class.java.simpleName
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(): ArtistsFragment {
|
||||
return ArtistsFragment()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onArtist(artistId: Int, imageView: ImageView) {
|
||||
val controller = findActivityNavController(R.id.fragment_container)
|
||||
controller.navigate(R.id.artistDetailsFragment, bundleOf(EXTRA_ARTIST_ID to artistId))
|
||||
}
|
||||
}
|
||||
|
||||
interface ArtistClickListener {
|
||||
fun onArtist(artistId: Int, imageView: ImageView)
|
||||
}
|
|
@ -7,6 +7,8 @@ import android.view.View
|
|||
import android.webkit.MimeTypeMap
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.navOptions
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.base.AbsMusicServiceActivity
|
||||
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
|
@ -23,6 +25,21 @@ import java.util.*
|
|||
open class AbsMusicServiceFragment(@LayoutRes layout: Int) : Fragment(layout),
|
||||
MusicServiceEventListener {
|
||||
|
||||
val navOptions by lazy {
|
||||
navOptions {
|
||||
popUpTo(R.id.action_home) {
|
||||
inclusive = false
|
||||
}
|
||||
launchSingleTop = false
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var playerActivity: AbsMusicServiceActivity? = null
|
||||
private set
|
||||
|
||||
|
|
|
@ -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 io.github.muntashirakon.music.EXTRA_ALBUM_ID
|
||||
import io.github.muntashirakon.music.EXTRA_ARTIST_ID
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.tageditor.AbsTagEditorActivity
|
||||
import io.github.muntashirakon.music.activities.tageditor.SongTagEditorActivity
|
||||
|
@ -30,11 +34,8 @@ import kotlinx.android.synthetic.main.shadow_statusbar_toolbar.*
|
|||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
import java.io.FileNotFoundException
|
||||
|
||||
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragment(layout),
|
||||
Toolbar.OnMenuItemClickListener,
|
||||
PaletteColorHolder,
|
||||
PlayerAlbumCoverFragment.Callbacks {
|
||||
|
||||
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragment(layout),
|
||||
Toolbar.OnMenuItemClickListener, PaletteColorHolder, PlayerAlbumCoverFragment.Callbacks {
|
||||
|
||||
private var updateIsFavoriteTask: AsyncTask<*, *, *>? = null
|
||||
private var updateLyricsAsyncTask: AsyncTask<*, *, *>? = null
|
||||
|
@ -86,11 +87,19 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
|
|||
return true
|
||||
}
|
||||
R.id.action_go_to_album -> {
|
||||
NavigationUtil.goToAlbum(requireActivity(), song.albumId)
|
||||
mainActivity.collapsePanel()
|
||||
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)
|
||||
mainActivity.collapsePanel()
|
||||
requireActivity().findNavController(R.id.fragment_container).navigate(
|
||||
R.id.artistDetailsFragment,
|
||||
bundleOf(EXTRA_ARTIST_ID to song.artistId)
|
||||
)
|
||||
return true
|
||||
}
|
||||
R.id.now_playing -> {
|
||||
|
@ -254,11 +263,6 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
|
|||
statusBarShadow?.hide()
|
||||
}
|
||||
|
||||
interface Callbacks {
|
||||
|
||||
fun onPaletteColorChanged()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG: String = AbsPlayerFragment::class.java.simpleName
|
||||
const val VISIBILITY_ANIM_DURATION: Long = 300
|
||||
|
|
|
@ -6,26 +6,24 @@ import android.view.ViewGroup
|
|||
import androidx.annotation.NonNull
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.MainActivity
|
||||
import io.github.muntashirakon.music.fragments.LibraryViewModel
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.util.DensityUtil
|
||||
import io.github.muntashirakon.music.util.ThemedFastScroller.create
|
||||
import io.github.muntashirakon.music.views.ScrollingViewOnApplyWindowInsetsListener
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import kotlinx.android.synthetic.main.fragment_main_activity_recycler_view.*
|
||||
import me.zhanghai.android.fastscroll.FastScroller
|
||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
|
||||
|
||||
abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : RecyclerView.LayoutManager> :
|
||||
AbsMusicServiceFragment(R.layout.fragment_main_activity_recycler_view),
|
||||
AppBarLayout.OnOffsetChangedListener {
|
||||
|
||||
val libraryViewModel: LibraryViewModel by sharedViewModel()
|
||||
val mainActivity: MainActivity
|
||||
get() = requireActivity() as MainActivity
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
@ -38,22 +36,23 @@ 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()
|
||||
}
|
||||
|
||||
private fun setUpRecyclerView() {
|
||||
recyclerView.layoutManager = layoutManager
|
||||
recyclerView.adapter = adapter
|
||||
val fastScroller = create(recyclerView)
|
||||
recyclerView.setOnApplyWindowInsetsListener(
|
||||
ScrollingViewOnApplyWindowInsetsListener(
|
||||
recyclerView,
|
||||
fastScroller
|
||||
recyclerView.apply {
|
||||
layoutManager = this@AbsRecyclerViewFragment.layoutManager
|
||||
adapter = this@AbsRecyclerViewFragment.adapter
|
||||
val fastScroller = create(this)
|
||||
setOnApplyWindowInsetsListener(
|
||||
ScrollingViewOnApplyWindowInsetsListener(
|
||||
recyclerView,
|
||||
fastScroller
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
checkForPadding()
|
||||
}
|
||||
|
||||
|
@ -112,7 +111,7 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
|
|||
container.paddingLeft,
|
||||
container.paddingTop,
|
||||
container.paddingRight,
|
||||
mainActivity.getTotalAppBarScrollingRange() + i
|
||||
i
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -137,11 +136,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
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ import io.github.muntashirakon.music.helper.MusicPlayerRemote;
|
|||
import io.github.muntashirakon.music.helper.menu.SongMenuHelper;
|
||||
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper;
|
||||
import io.github.muntashirakon.music.interfaces.CabHolder;
|
||||
import io.github.muntashirakon.music.interfaces.Callbacks;
|
||||
import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks;
|
||||
import io.github.muntashirakon.music.misc.DialogAsyncTask;
|
||||
import io.github.muntashirakon.music.misc.UpdateToastMediaScannerCompletionListener;
|
||||
|
@ -76,7 +77,9 @@ import me.zhanghai.android.fastscroll.FastScroller;
|
|||
|
||||
public class FoldersFragment extends AbsMainActivityFragment implements
|
||||
MainActivityFragmentCallbacks,
|
||||
CabHolder, BreadCrumbLayout.SelectionCallback, SongFileAdapter.Callbacks,
|
||||
CabHolder,
|
||||
BreadCrumbLayout.SelectionCallback,
|
||||
Callbacks,
|
||||
LoaderManager.LoaderCallbacks<List<File>> {
|
||||
|
||||
public static final String TAG = FoldersFragment.class.getSimpleName();
|
||||
|
@ -84,7 +87,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
|||
FileUtil.fileIsMimeType(file, "audio/*", MimeTypeMap.getSingleton()) ||
|
||||
FileUtil.fileIsMimeType(file, "application/opus", MimeTypeMap.getSingleton()) ||
|
||||
FileUtil.fileIsMimeType(file, "application/ogg", MimeTypeMap.getSingleton()));
|
||||
public static final String PATH = "path";
|
||||
|
||||
private static final String CRUMBS = "crumbs";
|
||||
private static final int LOADER_ID = 5;
|
||||
private SongFileAdapter adapter;
|
||||
|
@ -125,18 +128,6 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
|||
return startFolder;
|
||||
}
|
||||
|
||||
public static FoldersFragment newInstance(File directory) {
|
||||
FoldersFragment frag = new FoldersFragment();
|
||||
Bundle b = new Bundle();
|
||||
b.putSerializable(PATH, directory);
|
||||
frag.setArguments(b);
|
||||
return frag;
|
||||
}
|
||||
|
||||
public static FoldersFragment newInstance(Context context) {
|
||||
return newInstance(PreferenceUtil.INSTANCE.getStartDirectory());
|
||||
}
|
||||
|
||||
private static File tryGetCanonicalFile(File file) {
|
||||
try {
|
||||
return file.getCanonicalFile();
|
||||
|
@ -171,7 +162,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
|||
|
||||
if (savedInstanceState == null) {
|
||||
//noinspection ConstantConditions
|
||||
setCrumb(new BreadCrumbLayout.Crumb(FileUtil.safeGetCanonicalFile((File) requireArguments().getSerializable(PATH))), true);
|
||||
setCrumb(new BreadCrumbLayout.Crumb(FileUtil.safeGetCanonicalFile(PreferenceUtil.INSTANCE.getStartDirectory())), true);
|
||||
} else {
|
||||
breadCrumbs.restoreFromStateWrapper(savedInstanceState.getParcelable(CRUMBS));
|
||||
getLoaderManager().initLoader(LOADER_ID, null, this);
|
||||
|
@ -299,7 +290,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
|||
}
|
||||
}
|
||||
if (startIndex > -1) {
|
||||
MusicPlayerRemote.INSTANCE.openQueue(songs, startIndex, true);
|
||||
MusicPlayerRemote.openQueue(songs, startIndex, true);
|
||||
} else {
|
||||
final File finalFile = file1;
|
||||
Snackbar.make(coordinatorLayout, Html.fromHtml(
|
||||
|
@ -619,7 +610,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
|||
}
|
||||
|
||||
private static class ListSongsAsyncTask
|
||||
extends ListingFilesDialogAsyncTask<ListSongsAsyncTask.LoadingInfo, Void, ArrayList<Song>> {
|
||||
extends ListingFilesDialogAsyncTask<ListSongsAsyncTask.LoadingInfo, Void, List<Song>> {
|
||||
|
||||
private final Object extra;
|
||||
private WeakReference<OnSongsListedCallback> callbackWeakReference;
|
||||
|
@ -633,7 +624,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ArrayList<Song> doInBackground(LoadingInfo... params) {
|
||||
protected List<Song> doInBackground(LoadingInfo... params) {
|
||||
try {
|
||||
LoadingInfo info = params[0];
|
||||
List<File> files = FileUtil.listFilesDeep(info.files, info.fileFilter);
|
||||
|
@ -659,7 +650,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(ArrayList<Song> songs) {
|
||||
protected void onPostExecute(List<Song> songs) {
|
||||
super.onPostExecute(songs);
|
||||
OnSongsListedCallback callback = checkCallbackReference();
|
||||
if (songs != null && callback != null) {
|
||||
|
@ -692,7 +683,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
|||
|
||||
public interface OnSongsListedCallback {
|
||||
|
||||
void onSongsListed(@NonNull ArrayList<Song> songs, Object extra);
|
||||
void onSongsListed(@NonNull List<Song> songs, Object extra);
|
||||
}
|
||||
|
||||
static class LoadingInfo {
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
package io.github.muntashirakon.music.fragments.genres
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.song.SongAdapter
|
||||
import io.github.muntashirakon.music.extensions.dipToPix
|
||||
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
|
||||
import io.github.muntashirakon.music.helper.menu.GenreMenuHelper
|
||||
import io.github.muntashirakon.music.model.Genre
|
||||
import io.github.muntashirakon.music.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 : AbsMainActivityFragment(R.layout.fragment_playlist_detail) {
|
||||
private val arguments by navArgs<GenreDetailsFragmentArgs>()
|
||||
private val detailsViewModel: GenreDetailsViewModel by viewModel {
|
||||
parametersOf(arguments.extraGenre)
|
||||
}
|
||||
|
||||
private lateinit var genre: Genre
|
||||
private lateinit var songAdapter: SongAdapter
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
mainActivity.hideBottomBarVisibility(false)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.menu_genre_detail, menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return GenreMenuHelper.handleMenuClick(requireActivity(), genre, item)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package io.github.muntashirakon.music.activities.genre
|
||||
package io.github.muntashirakon.music.fragments.genres
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
@ -7,13 +7,13 @@ import androidx.lifecycle.viewModelScope
|
|||
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
||||
import io.github.muntashirakon.music.model.Genre
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.providers.RepositoryImpl
|
||||
import io.github.muntashirakon.music.repository.RealRepository
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class GenreDetailsViewModel(
|
||||
private val repository: RepositoryImpl,
|
||||
private val realRepository: RealRepository,
|
||||
private val genre: Genre
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
|
||||
|
@ -31,7 +31,7 @@ class GenreDetailsViewModel(
|
|||
}
|
||||
|
||||
private fun loadGenreSongs(genre: Genre) = viewModelScope.launch {
|
||||
val songs = repository.getGenre(genre.id)
|
||||
val songs = realRepository.getGenre(genre.id)
|
||||
withContext(Main) { _playListSongs.postValue(songs) }
|
||||
}
|
||||
|
|
@ -32,14 +32,12 @@ class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
libraryViewModel.genresLiveData
|
||||
.observe(viewLifecycleOwner, Observer { genres ->
|
||||
if (genres.isNotEmpty()) {
|
||||
adapter?.swapDataSet(genres)
|
||||
} else {
|
||||
adapter?.swapDataSet(listOf())
|
||||
}
|
||||
})
|
||||
libraryViewModel.genresLiveData.observe(viewLifecycleOwner, Observer {
|
||||
if (it.isNotEmpty())
|
||||
adapter?.swapDataSet(it)
|
||||
else
|
||||
adapter?.swapDataSet(listOf())
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,7 +47,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
|
||||
|
|
|
@ -18,36 +18,38 @@ 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.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.bumptech.glide.Glide
|
||||
import io.github.muntashirakon.music.EXTRA_PLAYLIST
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.HomeAdapter
|
||||
import io.github.muntashirakon.music.extensions.findActivityNavController
|
||||
import io.github.muntashirakon.music.fragments.LibraryViewModel
|
||||
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
|
||||
import io.github.muntashirakon.music.glide.ProfileBannerGlideRequest
|
||||
import io.github.muntashirakon.music.glide.UserProfileGlideRequest
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
|
||||
import io.github.muntashirakon.music.loaders.SongLoader
|
||||
import io.github.muntashirakon.music.model.smartplaylist.HistoryPlaylist
|
||||
import io.github.muntashirakon.music.model.smartplaylist.LastAddedPlaylist
|
||||
import io.github.muntashirakon.music.model.smartplaylist.MyTopTracksPlaylist
|
||||
import io.github.muntashirakon.music.model.smartplaylist.TopTracksPlaylist
|
||||
import io.github.muntashirakon.music.repository.Repository
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||
import com.bumptech.glide.Glide
|
||||
import kotlinx.android.synthetic.main.abs_playlists.*
|
||||
import kotlinx.android.synthetic.main.fragment_banner_home.*
|
||||
import kotlinx.android.synthetic.main.home_content.*
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
|
||||
class BannerHomeFragment :
|
||||
AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home),
|
||||
MainActivityFragmentCallbacks {
|
||||
|
||||
override fun handleBackPress(): Boolean {
|
||||
return false
|
||||
}
|
||||
class HomeFragment :
|
||||
AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home) {
|
||||
|
||||
private val repository by inject<Repository>()
|
||||
private val libraryViewModel: LibraryViewModel by sharedViewModel()
|
||||
|
||||
private val displayMetrics: DisplayMetrics
|
||||
|
@ -60,9 +62,7 @@ class BannerHomeFragment :
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
setStatusBarColorAuto(view)
|
||||
|
||||
bannerImage?.setOnClickListener {
|
||||
val options = ActivityOptions.makeSceneTransitionAnimation(
|
||||
mainActivity,
|
||||
|
@ -73,22 +73,33 @@ class BannerHomeFragment :
|
|||
}
|
||||
|
||||
lastAdded.setOnClickListener {
|
||||
NavigationUtil.goToPlaylistNew(requireActivity(), LastAddedPlaylist(requireActivity()))
|
||||
findActivityNavController(R.id.fragment_container).navigate(
|
||||
R.id.playlistDetailsFragment,
|
||||
bundleOf(EXTRA_PLAYLIST to LastAddedPlaylist())
|
||||
)
|
||||
}
|
||||
|
||||
topPlayed.setOnClickListener {
|
||||
NavigationUtil.goToPlaylistNew(
|
||||
requireActivity(),
|
||||
MyTopTracksPlaylist(requireActivity())
|
||||
findActivityNavController(R.id.fragment_container).navigate(
|
||||
R.id.playlistDetailsFragment,
|
||||
bundleOf(EXTRA_PLAYLIST to TopTracksPlaylist())
|
||||
)
|
||||
}
|
||||
|
||||
actionShuffle.setOnClickListener {
|
||||
MusicPlayerRemote.openAndShuffleQueue(SongLoader.getAllSongs(requireActivity()), true)
|
||||
lifecycleScope.launch {
|
||||
MusicPlayerRemote.openAndShuffleQueue(
|
||||
repository.allSongs(),
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
history.setOnClickListener {
|
||||
NavigationUtil.goToPlaylistNew(requireActivity(), HistoryPlaylist(requireActivity()))
|
||||
requireActivity().findNavController(R.id.fragment_container).navigate(
|
||||
R.id.playlistDetailsFragment,
|
||||
bundleOf(EXTRA_PLAYLIST to HistoryPlaylist())
|
||||
)
|
||||
}
|
||||
|
||||
userImage.setOnClickListener {
|
||||
|
@ -101,16 +112,15 @@ 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
|
||||
}
|
||||
|
||||
libraryViewModel.homeLiveData
|
||||
.observe(viewLifecycleOwner, Observer { sections ->
|
||||
homeAdapter.swapData(sections)
|
||||
})
|
||||
libraryViewModel.homeLiveData.observe(viewLifecycleOwner, Observer {
|
||||
homeAdapter.swapData(it)
|
||||
})
|
||||
|
||||
loadProfile()
|
||||
}
|
||||
|
@ -133,8 +143,8 @@ class BannerHomeFragment :
|
|||
const val TAG: String = "BannerHomeFragment"
|
||||
|
||||
@JvmStatic
|
||||
fun newInstance(): BannerHomeFragment {
|
||||
return BannerHomeFragment()
|
||||
fun newInstance(): HomeFragment {
|
||||
return HomeFragment()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package io.github.muntashirakon.music.fragments.library
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.ui.NavigationUI
|
||||
import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.extensions.findNavController
|
||||
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
|
||||
import kotlinx.android.synthetic.main.fragment_library.*
|
||||
|
||||
class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
mainActivity.hideBottomBarVisibility(true)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
mainActivity.supportActionBar?.title = null
|
||||
toolbar.setNavigationOnClickListener {
|
||||
findNavController().navigate(
|
||||
R.id.searchFragment,
|
||||
null,
|
||||
navOptions
|
||||
)
|
||||
}
|
||||
setupNavigationController()
|
||||
}
|
||||
|
||||
private fun setupNavigationController() {
|
||||
val navController = findNavController(R.id.fragment_container)
|
||||
NavigationUI.setupWithNavController(mainActivity.getBottomNavigationView(), navController)
|
||||
}
|
||||
|
||||
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_settings -> findNavController().navigate(
|
||||
R.id.settingsActivity,
|
||||
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
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ import android.os.Bundle
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.NavController
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.extensions.navController
|
||||
import io.github.muntashirakon.music.extensions.findNavController
|
||||
import io.github.muntashirakon.music.fragments.NowPlayingScreen.*
|
||||
import io.github.muntashirakon.music.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)
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import kotlinx.android.synthetic.main.fragment_player_album_cover.*
|
|||
|
||||
class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_player_album_cover),
|
||||
ViewPager.OnPageChangeListener {
|
||||
|
||||
private var callbacks: Callbacks? = null
|
||||
private var currentPosition: Int = 0
|
||||
private val colorReceiver = object : AlbumCoverFragment.ColorReceiver {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package io.github.muntashirakon.music.fragments.player.full
|
||||
|
||||
import android.app.ActivityOptions
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
|
@ -8,31 +7,36 @@ import android.view.View
|
|||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
||||
import com.bumptech.glide.Glide
|
||||
import io.github.muntashirakon.music.EXTRA_ARTIST_ID
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.extensions.findActivityNavController
|
||||
import io.github.muntashirakon.music.extensions.hide
|
||||
import io.github.muntashirakon.music.extensions.show
|
||||
import io.github.muntashirakon.music.extensions.whichFragment
|
||||
import io.github.muntashirakon.music.fragments.base.AbsPlayerFragment
|
||||
import io.github.muntashirakon.music.fragments.player.PlayerAlbumCoverFragment
|
||||
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.helper.MusicProgressViewUpdateHelper
|
||||
import io.github.muntashirakon.music.loaders.ArtistLoader
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.model.lyrics.AbsSynchronizedLyrics
|
||||
import io.github.muntashirakon.music.model.lyrics.Lyrics
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import io.github.muntashirakon.music.repository.ArtistRepository
|
||||
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
||||
import com.bumptech.glide.Glide
|
||||
import kotlinx.android.synthetic.main.fragment_full.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
|
||||
MusicProgressViewUpdateHelper.Callback {
|
||||
private val artistRepository by inject<ArtistRepository>()
|
||||
private lateinit var lyricsLayout: FrameLayout
|
||||
private lateinit var lyricsLine1: TextView
|
||||
private lateinit var lyricsLine2: TextView
|
||||
|
@ -150,30 +154,20 @@ 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
|
||||
mainActivity.collapsePanel()
|
||||
findActivityNavController(R.id.fragment_container)
|
||||
.navigate(
|
||||
R.id.artistDetailsFragment,
|
||||
bundleOf(EXTRA_ARTIST_ID to MusicPlayerRemote.currentSong.artistId)
|
||||
)
|
||||
NavigationUtil.goToArtistOptions(
|
||||
requireActivity(),
|
||||
MusicPlayerRemote.currentSong.artistId,
|
||||
activityOptions
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUpSubFragments() {
|
||||
controlsFragment =
|
||||
childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as FullPlaybackControlsFragment
|
||||
|
||||
val playerAlbumCoverFragment =
|
||||
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
|
||||
playerAlbumCoverFragment.setCallbacks(this)
|
||||
playerAlbumCoverFragment.removeSlideEffect()
|
||||
controlsFragment = whichFragment(R.id.playbackControlsFragment)
|
||||
val coverFragment: PlayerAlbumCoverFragment = whichFragment(R.id.playerAlbumCoverFragment)
|
||||
coverFragment.setCallbacks(this)
|
||||
coverFragment.removeSlideEffect()
|
||||
}
|
||||
|
||||
override fun onShow() {
|
||||
|
@ -228,9 +222,8 @@ class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
|
|||
}
|
||||
|
||||
private fun updateArtistImage() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val artist =
|
||||
ArtistLoader.getArtist(requireContext(), MusicPlayerRemote.currentSong.artistId)
|
||||
lifecycleScope.launch {
|
||||
val artist = artistRepository.artist(MusicPlayerRemote.currentSong.artistId)
|
||||
withContext(Dispatchers.Main) {
|
||||
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
||||
.generatePalette(requireContext())
|
||||
|
|
|
@ -52,7 +52,7 @@ class PlayerPlaybackControlsFragment :
|
|||
showBonceAnimation(playPauseButton)
|
||||
}
|
||||
title.isSelected = true
|
||||
|
||||
text.isSelected = true
|
||||
}
|
||||
|
||||
override fun setColor(color: MediaNotificationProcessor) {
|
||||
|
|
|
@ -1,95 +1,81 @@
|
|||
package io.github.muntashirakon.music.activities.playlist
|
||||
package io.github.muntashirakon.music.fragments.playlists
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
|
||||
import io.github.muntashirakon.music.adapter.song.OrderablePlaylistSongAdapter
|
||||
import io.github.muntashirakon.music.adapter.song.PlaylistSongAdapter
|
||||
import io.github.muntashirakon.music.adapter.song.SongAdapter
|
||||
import io.github.muntashirakon.music.extensions.applyToolbar
|
||||
import io.github.muntashirakon.music.extensions.extraNotNull
|
||||
import io.github.muntashirakon.music.helper.menu.PlaylistMenuHelper
|
||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
||||
import io.github.muntashirakon.music.model.AbsCustomPlaylist
|
||||
import io.github.muntashirakon.music.model.Playlist
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.DensityUtil
|
||||
import io.github.muntashirakon.music.util.PlaylistsUtil
|
||||
import io.github.muntashirakon.music.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
|
||||
import kotlinx.android.synthetic.main.activity_playlist_detail.*
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.song.OrderablePlaylistSongAdapter
|
||||
import io.github.muntashirakon.music.adapter.song.SongAdapter
|
||||
import io.github.muntashirakon.music.extensions.dipToPix
|
||||
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
|
||||
import io.github.muntashirakon.music.helper.menu.PlaylistMenuHelper
|
||||
import io.github.muntashirakon.music.model.AbsCustomPlaylist
|
||||
import io.github.muntashirakon.music.model.Playlist
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.PlaylistsUtil
|
||||
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
|
||||
|
||||
class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||
|
||||
|
||||
class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail) {
|
||||
private val arguments by navArgs<PlaylistDetailsFragmentArgs>()
|
||||
private val viewModel: PlaylistDetailsViewModel by viewModel {
|
||||
parametersOf(extraNotNull<Playlist>(EXTRA_PLAYLIST).value)
|
||||
parametersOf(arguments.extraPlaylist)
|
||||
}
|
||||
|
||||
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 onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
mainActivity.addMusicServiceEventListener(viewModel)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
mainActivity.hideBottomBarVisibility(false)
|
||||
|
||||
playlist = extraNotNull<Playlist>(EXTRA_PLAYLIST).value
|
||||
playlist = arguments.extraPlaylist
|
||||
|
||||
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
|
||||
|
@ -116,58 +102,21 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
})
|
||||
}
|
||||
|
||||
private fun setUpToolBar() {
|
||||
applyToolbar(toolbar)
|
||||
title = playlist.name
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(
|
||||
if (playlist is AbsCustomPlaylist) R.menu.menu_smart_playlist_detail
|
||||
else R.menu.menu_playlist_detail, menu
|
||||
)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
val menuRes = if (playlist is AbsCustomPlaylist)
|
||||
R.menu.menu_smart_playlist_detail
|
||||
else R.menu.menu_playlist_detail
|
||||
inflater.inflate(menuRes, 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()
|
||||
}
|
||||
return PlaylistMenuHelper.handleMenuClick(requireActivity(), playlist, item)
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -181,7 +130,7 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
return String(Character.toChars(unicode))
|
||||
}
|
||||
|
||||
public override fun onPause() {
|
||||
override fun onPause() {
|
||||
if (recyclerViewDragDropManager != null) {
|
||||
recyclerViewDragDropManager!!.cancelDrag()
|
||||
}
|
||||
|
@ -206,7 +155,7 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
super.onDestroy()
|
||||
}
|
||||
|
||||
fun showEmptyView() {
|
||||
private fun showEmptyView() {
|
||||
empty.visibility = View.VISIBLE
|
||||
emptyText.visibility = View.VISIBLE
|
||||
}
|
||||
|
@ -219,7 +168,4 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
|||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var EXTRA_PLAYLIST = "extra_playlist"
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package io.github.muntashirakon.music.activities.playlist
|
||||
package io.github.muntashirakon.music.fragments.playlists
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
@ -6,22 +6,20 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import io.github.muntashirakon.music.App
|
||||
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
||||
import io.github.muntashirakon.music.loaders.PlaylistLoader
|
||||
import io.github.muntashirakon.music.model.AbsCustomPlaylist
|
||||
import io.github.muntashirakon.music.model.Playlist
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.providers.RepositoryImpl
|
||||
import io.github.muntashirakon.music.repository.RealRepository
|
||||
import io.github.muntashirakon.music.util.PlaylistsUtil
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class PlaylistDetailsViewModel(
|
||||
private val repository: RepositoryImpl,
|
||||
private val realRepository: RealRepository,
|
||||
private var playlist: Playlist
|
||||
) : ViewModel(), MusicServiceEventListener {
|
||||
private val _playListSongs = MutableLiveData<List<Song>>()
|
||||
|
||||
private val _playlist = MutableLiveData<Playlist>().apply {
|
||||
postValue(playlist)
|
||||
}
|
||||
|
@ -35,7 +33,7 @@ class PlaylistDetailsViewModel(
|
|||
}
|
||||
|
||||
private fun loadPlaylistSongs(playlist: Playlist) = viewModelScope.launch {
|
||||
val songs = repository.getPlaylistSongs(playlist)
|
||||
val songs = realRepository.getPlaylistSongs(playlist)
|
||||
withContext(Main) { _playListSongs.postValue(songs) }
|
||||
}
|
||||
|
||||
|
@ -50,8 +48,10 @@ class PlaylistDetailsViewModel(
|
|||
val playlistName =
|
||||
PlaylistsUtil.getNameForPlaylist(App.getContext(), playlist.id.toLong())
|
||||
if (playlistName != playlist.name) {
|
||||
playlist = PlaylistLoader.getPlaylist(App.getContext(), playlist.id)
|
||||
_playlist.postValue(playlist)
|
||||
viewModelScope.launch {
|
||||
playlist = realRepository.playlist(playlist.id)
|
||||
_playlist.postValue(playlist)
|
||||
}
|
||||
}
|
||||
}
|
||||
loadPlaylistSongs(playlist)
|
|
@ -1,8 +1,6 @@
|
|||
package io.github.muntashirakon.music.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 io.github.muntashirakon.music.fragments.base.AbsRecyclerViewFragment
|
|||
import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
|
||||
|
||||
class PlaylistsFragment :
|
||||
AbsRecyclerViewFragment<PlaylistAdapter, GridLayoutManager>() ,
|
||||
AbsRecyclerViewFragment<PlaylistAdapter, GridLayoutManager>(),
|
||||
MainActivityFragmentCallbacks {
|
||||
|
||||
override fun handleBackPress(): Boolean {
|
||||
|
@ -21,12 +19,11 @@ class PlaylistsFragment :
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
libraryViewModel.playlisitsLiveData.observe(viewLifecycleOwner, Observer { playlists ->
|
||||
if (playlists.isNotEmpty()) {
|
||||
adapter?.swapDataSet(playlists)
|
||||
} else {
|
||||
libraryViewModel.playlisitsLiveData.observe(viewLifecycleOwner, Observer {
|
||||
if (it.isNotEmpty())
|
||||
adapter?.swapDataSet(it)
|
||||
else
|
||||
adapter?.swapDataSet(listOf())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -39,26 +36,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()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
package io.github.muntashirakon.music.fragments.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.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.TransitionManager
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.SearchAdapter
|
||||
import io.github.muntashirakon.music.extensions.accentColor
|
||||
import io.github.muntashirakon.music.extensions.showToast
|
||||
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
|
||||
import kotlinx.android.synthetic.main.fragment_search.*
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWatcher {
|
||||
companion object {
|
||||
const val QUERY = "query"
|
||||
const val REQ_CODE_SPEECH_INPUT = 9001
|
||||
}
|
||||
|
||||
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)
|
||||
mainActivity.setSupportActionBar(toolbar)
|
||||
mainActivity.hideBottomBarVisibility(false)
|
||||
|
||||
setupRecyclerView()
|
||||
keyboardPopup.accentColor()
|
||||
searchView.addTextChangedListener(this)
|
||||
voiceSearch.setOnClickListener { startMicSearch() }
|
||||
clearText.setOnClickListener { searchView.clearText() }
|
||||
keyboardPopup.setOnClickListener {
|
||||
val inputManager =
|
||||
getSystemService<InputMethodManager>(
|
||||
requireContext(),
|
||||
InputMethodManager::class.java
|
||||
)
|
||||
inputManager?.showSoftInput(searchView, InputMethodManager.SHOW_IMPLICIT)
|
||||
}
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
query = savedInstanceState.getString(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.isVisible = searchAdapter.itemCount < 1
|
||||
}
|
||||
})
|
||||
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()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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.isGone = query.isNotEmpty()
|
||||
clearText.isVisible = query.isNotEmpty()
|
||||
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,
|
||||
REQ_CODE_SPEECH_INPUT
|
||||
)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
e.printStackTrace()
|
||||
showToast(getString(R.string.speech_not_supported))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun TextInputEditText.clearText() {
|
||||
text = null
|
||||
}
|
|
@ -1,22 +1,22 @@
|
|||
package io.github.muntashirakon.music.activities.search
|
||||
package io.github.muntashirakon.music.fragments.search
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import io.github.muntashirakon.music.providers.RepositoryImpl
|
||||
import io.github.muntashirakon.music.repository.RealRepository
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class SearchViewModel(private val repository: RepositoryImpl) : ViewModel() {
|
||||
class SearchViewModel(private val realRepository: RealRepository) : ViewModel() {
|
||||
private val results = MutableLiveData<MutableList<Any>>()
|
||||
|
||||
fun getSearchResult(): LiveData<MutableList<Any>> = results
|
||||
|
||||
fun search(query: String?) = viewModelScope.launch(IO) {
|
||||
val result = repository.search(query)
|
||||
val result = realRepository.search(query)
|
||||
withContext(Main) { results.postValue(result) }
|
||||
}
|
||||
}
|
|
@ -14,17 +14,13 @@
|
|||
|
||||
package io.github.muntashirakon.music.fragments.settings
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
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 io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.SettingsActivity
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import kotlinx.android.synthetic.main.fragment_main_settings.*
|
||||
|
||||
class MainSettingsFragment : Fragment(), View.OnClickListener {
|
||||
|
@ -60,12 +56,4 @@ class MainSettingsFragment : Fragment(), View.OnClickListener {
|
|||
otherSettings.setOnClickListener(this)
|
||||
aboutSettings.setOnClickListener(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
}
|
||||
|
||||
private fun inflateFragment(fragment: Fragment, @StringRes title: Int) {
|
||||
(requireActivity() as SettingsActivity).setupFragment(fragment, title)
|
||||
}
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
package io.github.muntashirakon.music.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 io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.adapter.song.ShuffleButtonSongAdapter
|
||||
import io.github.muntashirakon.music.adapter.song.SongAdapter
|
||||
import io.github.muntashirakon.music.fragments.ReloadType
|
||||
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||
|
@ -24,11 +23,10 @@ class SongsFragment :
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
libraryViewModel.songsLiveData.observe(viewLifecycleOwner, Observer {
|
||||
if (it.isNotEmpty()) {
|
||||
if (it.isNotEmpty())
|
||||
adapter?.swapDataSet(it)
|
||||
} else {
|
||||
else
|
||||
adapter?.swapDataSet(listOf())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -36,26 +34,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 +97,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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public class AlbumGlideRequest {
|
|||
if (ignoreMediaStore) {
|
||||
return requestManager.load(new AudioFileCover(song.getData()));
|
||||
} else {
|
||||
return requestManager.loadFromMediaStore(MusicUtil.getMediaStoreAlbumCoverUri(song.getAlbumId()));
|
||||
return requestManager.loadFromMediaStore(MusicUtil.INSTANCE.getMediaStoreAlbumCoverUri(song.getAlbumId()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public class SongGlideRequest {
|
|||
if (ignoreMediaStore) {
|
||||
return requestManager.load(new AudioFileCover(song.getData()));
|
||||
} else {
|
||||
return requestManager.loadFromMediaStore(MusicUtil.getMediaStoreAlbumCoverUri(song.getAlbumId()));
|
||||
return requestManager.loadFromMediaStore(MusicUtil.INSTANCE.getMediaStoreAlbumCoverUri(song.getAlbumId()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ object M3UWriter : M3UConstants {
|
|||
): File? {
|
||||
if (!dir.exists()) dir.mkdirs()
|
||||
val file = File(dir, playlist.name + "." + M3UConstants.EXTENSION)
|
||||
val songs = playlist.getSongs(context)
|
||||
val songs = playlist.getSongs()
|
||||
if (songs.size > 0) {
|
||||
val bw = BufferedWriter(FileWriter(file))
|
||||
bw.write(M3UConstants.HEADER)
|
||||
|
|
|
@ -23,23 +23,26 @@ import android.os.Build
|
|||
import android.os.Environment
|
||||
import android.os.IBinder
|
||||
import android.provider.DocumentsContract
|
||||
import android.provider.MediaStore
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.loaders.SongLoader
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.repository.SongRepository
|
||||
import io.github.muntashirakon.music.service.MusicService
|
||||
|
||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
object MusicPlayerRemote {
|
||||
object MusicPlayerRemote : KoinComponent {
|
||||
val TAG: String = MusicPlayerRemote::class.java.simpleName
|
||||
private val mConnectionMap = WeakHashMap<Context, ServiceBinder>()
|
||||
var musicService: MusicService? = null
|
||||
|
||||
private val songRepository by inject<SongRepository>()
|
||||
|
||||
|
||||
@JvmStatic
|
||||
val isPlaying: Boolean
|
||||
get() = musicService != null && musicService!!.isPlaying
|
||||
|
@ -413,24 +416,17 @@ object MusicPlayerRemote {
|
|||
songId = uri.lastPathSegment
|
||||
}
|
||||
if (songId != null) {
|
||||
songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
musicService!!,
|
||||
MediaStore.Audio.AudioColumns._ID + "=?",
|
||||
arrayOf(songId)
|
||||
)
|
||||
)
|
||||
songs = songRepository.songs(songId)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (songs == null) {
|
||||
var songFile: File? = null
|
||||
if (uri.authority != null && uri.authority == "com.android.externalstorage.documents") {
|
||||
songFile =
|
||||
File(
|
||||
Environment.getExternalStorageDirectory(),
|
||||
uri.path?.split(":".toRegex(), 2)?.get(1)
|
||||
)
|
||||
songFile = File(
|
||||
Environment.getExternalStorageDirectory(),
|
||||
uri.path?.split(":".toRegex(), 2)?.get(1)
|
||||
)
|
||||
}
|
||||
if (songFile == null) {
|
||||
val path = getFilePathFromUri(musicService!!, uri)
|
||||
|
@ -441,13 +437,7 @@ object MusicPlayerRemote {
|
|||
songFile = File(uri.path)
|
||||
}
|
||||
if (songFile != null) {
|
||||
songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
musicService!!,
|
||||
MediaStore.Audio.AudioColumns.DATA + "=?",
|
||||
arrayOf(songFile.absolutePath)
|
||||
)
|
||||
)
|
||||
songs = songRepository.songsByFilePath(songFile.absolutePath)
|
||||
}
|
||||
}
|
||||
if (songs != null && songs.isNotEmpty()) {
|
||||
|
|
|
@ -18,29 +18,31 @@ import android.app.SearchManager
|
|||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import io.github.muntashirakon.music.loaders.SongLoader
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.repository.RealSongRepository
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
import java.util.*
|
||||
|
||||
object SearchQueryHelper {
|
||||
object SearchQueryHelper : KoinComponent {
|
||||
private const val TITLE_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.TITLE + ") = ?"
|
||||
private const val ALBUM_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ALBUM + ") = ?"
|
||||
private const val ARTIST_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ARTIST + ") = ?"
|
||||
private const val AND = " AND "
|
||||
private val songRepository by inject<RealSongRepository>()
|
||||
var songs = ArrayList<Song>()
|
||||
|
||||
@JvmStatic
|
||||
fun getSongs(context: Context, extras: Bundle): ArrayList<Song> {
|
||||
fun getSongs(context: Context, extras: Bundle): List<Song> {
|
||||
val query = extras.getString(SearchManager.QUERY, null)
|
||||
val artistName = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST, null)
|
||||
val albumName = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM, null)
|
||||
val titleName = extras.getString(MediaStore.EXTRA_MEDIA_TITLE, null)
|
||||
|
||||
var songs = ArrayList<Song>()
|
||||
var songs = listOf<Song>()
|
||||
if (artistName != null && albumName != null && titleName != null) {
|
||||
songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION,
|
||||
arrayOf(
|
||||
artistName.toLowerCase(),
|
||||
|
@ -54,9 +56,8 @@ object SearchQueryHelper {
|
|||
return songs
|
||||
}
|
||||
if (artistName != null && titleName != null) {
|
||||
songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ARTIST_SELECTION + AND + TITLE_SELECTION,
|
||||
arrayOf(artistName.toLowerCase(), titleName.toLowerCase())
|
||||
)
|
||||
|
@ -66,9 +67,8 @@ object SearchQueryHelper {
|
|||
return songs
|
||||
}
|
||||
if (albumName != null && titleName != null) {
|
||||
songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ALBUM_SELECTION + AND + TITLE_SELECTION,
|
||||
arrayOf(albumName.toLowerCase(), titleName.toLowerCase())
|
||||
)
|
||||
|
@ -78,9 +78,8 @@ object SearchQueryHelper {
|
|||
return songs
|
||||
}
|
||||
if (artistName != null) {
|
||||
songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ARTIST_SELECTION,
|
||||
arrayOf(artistName.toLowerCase())
|
||||
)
|
||||
|
@ -90,9 +89,8 @@ object SearchQueryHelper {
|
|||
return songs
|
||||
}
|
||||
if (albumName != null) {
|
||||
songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ALBUM_SELECTION,
|
||||
arrayOf(albumName.toLowerCase())
|
||||
)
|
||||
|
@ -102,9 +100,8 @@ object SearchQueryHelper {
|
|||
return songs
|
||||
}
|
||||
if (titleName != null) {
|
||||
songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
TITLE_SELECTION,
|
||||
arrayOf(titleName.toLowerCase())
|
||||
)
|
||||
|
@ -113,21 +110,18 @@ object SearchQueryHelper {
|
|||
if (songs.isNotEmpty()) {
|
||||
return songs
|
||||
}
|
||||
songs =
|
||||
SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
ARTIST_SELECTION,
|
||||
arrayOf(query.toLowerCase())
|
||||
)
|
||||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ARTIST_SELECTION,
|
||||
arrayOf(query.toLowerCase())
|
||||
)
|
||||
)
|
||||
|
||||
if (songs.isNotEmpty()) {
|
||||
return songs
|
||||
}
|
||||
songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
ALBUM_SELECTION,
|
||||
arrayOf(query.toLowerCase())
|
||||
)
|
||||
|
@ -135,9 +129,8 @@ object SearchQueryHelper {
|
|||
if (songs.isNotEmpty()) {
|
||||
return songs
|
||||
}
|
||||
songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
songs = songRepository.songs(
|
||||
songRepository.makeSongCursor(
|
||||
TITLE_SELECTION,
|
||||
arrayOf(query.toLowerCase())
|
||||
)
|
||||
|
|
|
@ -14,43 +14,43 @@
|
|||
|
||||
package io.github.muntashirakon.music.helper.menu
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.loaders.GenreLoader
|
||||
import io.github.muntashirakon.music.model.Genre
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import java.util.*
|
||||
import io.github.muntashirakon.music.repository.GenreRepository
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
|
||||
object GenreMenuHelper {
|
||||
fun handleMenuClick(activity: AppCompatActivity, genre: Genre, item: MenuItem): Boolean {
|
||||
object GenreMenuHelper : KoinComponent {
|
||||
private val genreRepository by inject<GenreRepository>()
|
||||
fun handleMenuClick(activity: FragmentActivity, genre: Genre, item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_play -> {
|
||||
MusicPlayerRemote.openQueue(getGenreSongs(activity, genre), 0, true)
|
||||
MusicPlayerRemote.openQueue(getGenreSongs(genre), 0, true)
|
||||
return true
|
||||
}
|
||||
R.id.action_play_next -> {
|
||||
MusicPlayerRemote.playNext(getGenreSongs(activity, genre))
|
||||
MusicPlayerRemote.playNext(getGenreSongs(genre))
|
||||
return true
|
||||
}
|
||||
R.id.action_add_to_playlist -> {
|
||||
AddToPlaylistDialog.create(getGenreSongs(activity, genre))
|
||||
AddToPlaylistDialog.create(getGenreSongs(genre))
|
||||
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
||||
return true
|
||||
}
|
||||
R.id.action_add_to_current_playing -> {
|
||||
MusicPlayerRemote.enqueue(getGenreSongs(activity, genre))
|
||||
MusicPlayerRemote.enqueue(getGenreSongs(genre))
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getGenreSongs(activity: Activity, genre: Genre): ArrayList<Song> {
|
||||
return GenreLoader.getSongs(activity, genre.id)
|
||||
private fun getGenreSongs(genre: Genre): List<Song> {
|
||||
return genreRepository.songs(genre.id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,26 +19,24 @@ 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 io.github.muntashirakon.music.App
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
||||
import io.github.muntashirakon.music.dialogs.DeletePlaylistDialog
|
||||
import io.github.muntashirakon.music.dialogs.RenamePlaylistDialog
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.loaders.PlaylistSongsLoader
|
||||
import io.github.muntashirakon.music.misc.WeakContextAsyncTask
|
||||
import io.github.muntashirakon.music.model.AbsCustomPlaylist
|
||||
import io.github.muntashirakon.music.model.Playlist
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.PlaylistsUtil
|
||||
import java.util.*
|
||||
|
||||
|
||||
object PlaylistMenuHelper {
|
||||
|
||||
fun handleMenuClick(
|
||||
activity: AppCompatActivity,
|
||||
activity: FragmentActivity,
|
||||
playlist: Playlist, item: MenuItem
|
||||
): Boolean {
|
||||
when (item.itemId) {
|
||||
|
@ -80,11 +78,11 @@ object PlaylistMenuHelper {
|
|||
private fun getPlaylistSongs(
|
||||
activity: Activity,
|
||||
playlist: Playlist
|
||||
): ArrayList<Song> {
|
||||
): List<Song> {
|
||||
return if (playlist is AbsCustomPlaylist) {
|
||||
playlist.getSongs(activity)
|
||||
playlist.songs()
|
||||
} else {
|
||||
PlaylistSongsLoader.getPlaylistSongList(activity, playlist)
|
||||
playlist.getSongs()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 io.github.muntashirakon.music.EXTRA_ALBUM_ID
|
||||
import io.github.muntashirakon.music.EXTRA_ARTIST_ID
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.activities.tageditor.AbsTagEditorActivity
|
||||
import io.github.muntashirakon.music.activities.tageditor.SongTagEditorActivity
|
||||
|
@ -30,7 +33,6 @@ import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
|||
import io.github.muntashirakon.music.interfaces.PaletteColorHolder
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import io.github.muntashirakon.music.util.NavigationUtil
|
||||
import io.github.muntashirakon.music.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
|
||||
|
|
|
@ -15,19 +15,17 @@
|
|||
package io.github.muntashirakon.music.helper.menu
|
||||
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
||||
import io.github.muntashirakon.music.dialogs.DeleteSongsDialog
|
||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||
import io.github.muntashirakon.music.model.Song
|
||||
import java.util.*
|
||||
|
||||
|
||||
object SongsMenuHelper {
|
||||
fun handleMenuClick(
|
||||
activity: FragmentActivity,
|
||||
songs: ArrayList<Song>,
|
||||
songs: List<Song>,
|
||||
menuItemId: Int
|
||||
): Boolean {
|
||||
when (menuItemId) {
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package io.github.muntashirakon.music.interfaces
|
||||
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import java.io.File
|
||||
|
||||
interface Callbacks {
|
||||
fun onFileSelected(file: File)
|
||||
|
||||
fun onFileMenuClicked(file: File, view: View)
|
||||
|
||||
fun onMultipleItemAction(item: MenuItem, files: ArrayList<File>)
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package io.github.muntashirakon.music.loaders
|
||||
|
||||
import android.content.Context
|
||||
import android.provider.MediaStore.Audio.AudioColumns
|
||||
import io.github.muntashirakon.music.model.Album
|
||||
import io.github.muntashirakon.music.model.Artist
|
||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||
|
||||
object ArtistLoader {
|
||||
private fun getSongLoaderSortOrder(): String {
|
||||
return PreferenceUtil.artistSortOrder + ", " +
|
||||
PreferenceUtil.artistAlbumSortOrder + ", " +
|
||||
PreferenceUtil.artistSongSortOrder
|
||||
}
|
||||
|
||||
fun getAllArtists(context: Context): ArrayList<Artist> {
|
||||
val songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
null, null,
|
||||
getSongLoaderSortOrder()
|
||||
)
|
||||
)
|
||||
return splitIntoArtists(AlbumLoader.splitIntoAlbums(songs))
|
||||
}
|
||||
|
||||
fun getArtists(context: Context, query: String): ArrayList<Artist> {
|
||||
val songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
AudioColumns.ARTIST + " LIKE ?",
|
||||
arrayOf("%$query%"),
|
||||
getSongLoaderSortOrder()
|
||||
)
|
||||
)
|
||||
return splitIntoArtists(AlbumLoader.splitIntoAlbums(songs))
|
||||
}
|
||||
|
||||
fun splitIntoArtists(albums: ArrayList<Album>?): ArrayList<Artist> {
|
||||
val artists = ArrayList<Artist>()
|
||||
if (albums != null) {
|
||||
for (album in albums) {
|
||||
getOrCreateArtist(artists, album.artistId).albums!!.add(album)
|
||||
}
|
||||
}
|
||||
return artists
|
||||
}
|
||||
|
||||
private fun getOrCreateArtist(artists: ArrayList<Artist>, artistId: Int): Artist {
|
||||
for (artist in artists) {
|
||||
if (artist.albums!!.isNotEmpty() && artist.albums[0].songs!!.isNotEmpty() && artist.albums[0].songs!![0].artistId == artistId) {
|
||||
return artist
|
||||
}
|
||||
}
|
||||
val album = Artist()
|
||||
artists.add(album)
|
||||
return album
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getArtist(context: Context, artistId: Int): Artist {
|
||||
val songs = SongLoader.getSongs(
|
||||
SongLoader.makeSongCursor(
|
||||
context,
|
||||
AudioColumns.ARTIST_ID + "=?",
|
||||
arrayOf(artistId.toString()),
|
||||
getSongLoaderSortOrder()
|
||||
)
|
||||
)
|
||||
return Artist(AlbumLoader.splitIntoAlbums(songs))
|
||||
}
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package io.github.muntashirakon.music.loaders
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.provider.BaseColumns
|
||||
import android.provider.MediaStore
|
||||
import android.provider.MediaStore.Audio.PlaylistsColumns
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.model.Playlist
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by hemanths on 16/08/17.
|
||||
*/
|
||||
|
||||
object PlaylistLoader {
|
||||
|
||||
private fun getPlaylist(
|
||||
cursor: Cursor?
|
||||
): Playlist {
|
||||
var playlist = Playlist()
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
playlist = getPlaylistFromCursorImpl(cursor)
|
||||
}
|
||||
cursor?.close()
|
||||
return playlist
|
||||
}
|
||||
|
||||
fun searchPlaylist(context: Context, searchString: String): List<Playlist> {
|
||||
return getAllPlaylists(
|
||||
makePlaylistCursor(
|
||||
context, PlaylistsColumns.NAME + "=?", arrayOf(searchString)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun getPlaylist(
|
||||
context: Context,
|
||||
playlistName: String
|
||||
): Playlist {
|
||||
return getPlaylist(
|
||||
makePlaylistCursor(
|
||||
context,
|
||||
PlaylistsColumns.NAME + "=?",
|
||||
arrayOf(playlistName)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun getAllPlaylists(context: Context): ArrayList<Playlist> {
|
||||
return getAllPlaylists(makePlaylistCursor(context, null, null))
|
||||
}
|
||||
|
||||
fun getFavoritePlaylist(context: Context): ArrayList<Playlist> {
|
||||
return getAllPlaylists(
|
||||
makePlaylistCursor(
|
||||
context,
|
||||
PlaylistsColumns.NAME + "=?",
|
||||
arrayOf(context.getString(R.string.favorites))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun getAllPlaylists(cursor: Cursor?): ArrayList<Playlist> {
|
||||
val playlists = ArrayList<Playlist>()
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
playlists.add(getPlaylistFromCursorImpl(cursor))
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
cursor?.close()
|
||||
return playlists
|
||||
}
|
||||
|
||||
fun deletePlaylists(context: Context, playlistId: Long) {
|
||||
val localUri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI
|
||||
val localStringBuilder = StringBuilder()
|
||||
localStringBuilder.append("_id IN (")
|
||||
localStringBuilder.append(playlistId)
|
||||
localStringBuilder.append(")")
|
||||
context.contentResolver.delete(localUri, localStringBuilder.toString(), null)
|
||||
}
|
||||
|
||||
private fun makePlaylistCursor(
|
||||
context: Context,
|
||||
selection: String?,
|
||||
values: Array<String>?
|
||||
): Cursor? {
|
||||
try {
|
||||
return context.contentResolver.query(
|
||||
MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
|
||||
arrayOf(
|
||||
BaseColumns._ID, /* 0 */
|
||||
PlaylistsColumns.NAME /* 1 */
|
||||
),
|
||||
selection,
|
||||
values,
|
||||
MediaStore.Audio.Playlists.DEFAULT_SORT_ORDER
|
||||
)
|
||||
} catch (e: SecurityException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun getPlaylist(
|
||||
context: Context,
|
||||
playlistId: Int
|
||||
): Playlist {
|
||||
return getPlaylist(
|
||||
makePlaylistCursor(
|
||||
context,
|
||||
BaseColumns._ID + "=?",
|
||||
arrayOf(playlistId.toString())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getPlaylistFromCursorImpl(
|
||||
cursor: Cursor
|
||||
): Playlist {
|
||||
val id = cursor.getInt(0)
|
||||
val name = cursor.getString(1)
|
||||
return Playlist(id, name)
|
||||
}
|
||||
}
|
|
@ -89,11 +89,6 @@ public class LrcView extends View {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
public LrcView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 手势监听器
|
||||
*/
|
||||
|
@ -151,6 +146,10 @@ public class LrcView extends View {
|
|||
}
|
||||
};
|
||||
|
||||
public LrcView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public LrcView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package io.github.muntashirakon.music.model;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
|
||||
public abstract class AbsCustomPlaylist extends Playlist {
|
||||
|
||||
public AbsCustomPlaylist(int id, String name) {
|
||||
super(id, name);
|
||||
}
|
||||
|
||||
public AbsCustomPlaylist() {
|
||||
}
|
||||
|
||||
public AbsCustomPlaylist(Parcel in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public abstract ArrayList<Song> getSongs(@NotNull Context context);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package io.github.muntashirakon.music.model
|
||||
|
||||
import io.github.muntashirakon.music.repository.LastAddedRepository
|
||||
import io.github.muntashirakon.music.repository.SongRepository
|
||||
import io.github.muntashirakon.music.repository.TopPlayedRepository
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
|
||||
abstract class AbsCustomPlaylist(
|
||||
id: Int = -1,
|
||||
name: String = ""
|
||||
) : Playlist(id, name), KoinComponent {
|
||||
|
||||
abstract fun songs(): List<Song>
|
||||
|
||||
protected val songRepository by inject<SongRepository>()
|
||||
|
||||
protected val topPlayedRepository by inject<TopPlayedRepository>()
|
||||
|
||||
protected val lastAddedRepository by inject<LastAddedRepository>()
|
||||
}
|
|
@ -41,6 +41,9 @@ class Album {
|
|||
val songCount: Int
|
||||
get() = songs!!.size
|
||||
|
||||
val albumArtist: String?
|
||||
get() = safeGetFirstSong().albumArtist
|
||||
|
||||
constructor(songs: ArrayList<Song>) {
|
||||
this.songs = songs
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ class Artist {
|
|||
|
||||
val name: String
|
||||
get() {
|
||||
val name = safeGetFirstAlbum().artistName
|
||||
val name = safeGetFirstAlbum().safeGetFirstSong().albumArtist
|
||||
return if (MusicUtil.isArtistNameUnknown(name)) {
|
||||
UNKNOWN_ARTIST_DISPLAY_NAME
|
||||
} else name!!
|
||||
} else safeGetFirstAlbum().safeGetFirstSong().artistName
|
||||
}
|
||||
|
||||
val songCount: Int
|
||||
|
|
|
@ -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_face),
|
||||
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),
|
||||
|
|
|
@ -14,13 +14,10 @@
|
|||
|
||||
package io.github.muntashirakon.music.model
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import io.github.muntashirakon.music.adapter.HomeAdapter.Companion.HomeSection
|
||||
import io.github.muntashirakon.music.HomeSection
|
||||
|
||||
class Home(
|
||||
val arrayList: List<*>,
|
||||
val arrayList: List<Any>,
|
||||
@HomeSection
|
||||
val homeSection: Int,
|
||||
@DrawableRes
|
||||
val icon: Int
|
||||
val homeSection: Int
|
||||
)
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package io.github.muntashirakon.music.model;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.muntashirakon.music.loaders.PlaylistSongsLoader;
|
||||
import io.github.muntashirakon.music.util.MusicUtil;
|
||||
|
||||
|
||||
public class Playlist implements Parcelable {
|
||||
|
||||
public static final Creator<Playlist> CREATOR = new Creator<Playlist>() {
|
||||
public Playlist createFromParcel(Parcel source) {
|
||||
return new Playlist(source);
|
||||
}
|
||||
|
||||
public Playlist[] newArray(int size) {
|
||||
return new Playlist[size];
|
||||
}
|
||||
};
|
||||
|
||||
public final int id;
|
||||
|
||||
public final String name;
|
||||
|
||||
public Playlist(final int id, final String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Playlist() {
|
||||
this.id = -1;
|
||||
this.name = "";
|
||||
}
|
||||
|
||||
protected Playlist(Parcel in) {
|
||||
this.id = in.readInt();
|
||||
this.name = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Playlist playlist = (Playlist) o;
|
||||
|
||||
if (id != playlist.id) {
|
||||
return false;
|
||||
}
|
||||
return name != null ? name.equals(playlist.name) : playlist.name == null;
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ArrayList<Song> getSongs(@NonNull Context context) {
|
||||
// this default implementation covers static playlists
|
||||
return PlaylistSongsLoader.INSTANCE.getPlaylistSongList(context, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = id;
|
||||
result = 31 * result + (name != null ? name.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Playlist{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(this.id);
|
||||
dest.writeString(this.name);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getInfoString(@NonNull Context context) {
|
||||
int songCount = getSongs(context).size();
|
||||
String songCountString = MusicUtil.getSongCountString(context, songCount);
|
||||
|
||||
return MusicUtil.buildInfoString(
|
||||
songCountString,
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package io.github.muntashirakon.music.model
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Parcelable
|
||||
import io.github.muntashirakon.music.repository.RealPlaylistRepository
|
||||
import io.github.muntashirakon.music.util.MusicUtil
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.get
|
||||
|
||||
@Parcelize
|
||||
open class Playlist(
|
||||
val id: Int = -1,
|
||||
val name: String = ""
|
||||
) : Parcelable, KoinComponent {
|
||||
|
||||
// this default implementation covers static playlists
|
||||
fun getSongs(): List<Song> {
|
||||
return RealPlaylistRepository(get()).playlistSongs(id)
|
||||
}
|
||||
|
||||
open fun getInfoString(context: Context): String {
|
||||
val songCount = getSongs().size
|
||||
val songCountString = MusicUtil.getSongCountString(context, songCount)
|
||||
return MusicUtil.buildInfoString(
|
||||
songCountString,
|
||||
""
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
"",
|
||||
"",
|
||||
""
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package io.github.muntashirakon.music.model.smartplaylist;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import io.github.muntashirakon.music.R;
|
||||
import io.github.muntashirakon.music.model.AbsCustomPlaylist;
|
||||
|
||||
|
||||
public abstract class AbsSmartPlaylist extends AbsCustomPlaylist {
|
||||
|
||||
@DrawableRes
|
||||
public final int iconRes;
|
||||
|
||||
public AbsSmartPlaylist(final String name, final int iconRes) {
|
||||
super(-Math.abs(31 * name.hashCode() + (iconRes * name.hashCode() * 31 * 31)), name);
|
||||
this.iconRes = iconRes;
|
||||
}
|
||||
|
||||
public AbsSmartPlaylist() {
|
||||
super();
|
||||
this.iconRes = R.drawable.ic_queue_music;
|
||||
}
|
||||
|
||||
protected AbsSmartPlaylist(Parcel in) {
|
||||
super(in);
|
||||
this.iconRes = in.readInt();
|
||||
}
|
||||
|
||||
public abstract void clear(Context context);
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable final Object obj) {
|
||||
if (super.equals(obj)) {
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final AbsSmartPlaylist other = (AbsSmartPlaylist) obj;
|
||||
return iconRes == other.iconRes;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + iconRes;
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isClearable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(this.iconRes);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package io.github.muntashirakon.music.model.smartplaylist
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import io.github.muntashirakon.music.R
|
||||
import io.github.muntashirakon.music.model.AbsCustomPlaylist
|
||||
|
||||
abstract class AbsSmartPlaylist(
|
||||
name: String = "",
|
||||
@DrawableRes val iconRes: Int = R.drawable.ic_queue_music
|
||||
) : AbsCustomPlaylist(-Math.abs(31 * name.hashCode() + iconRes * name.hashCode() * 31 * 31), name)
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Hemanth Savarala.
|
||||
*
|
||||
* Licensed under the GNU General Public License v3
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
package io.github.muntashirakon.music.model.smartplaylist;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.muntashirakon.music.R;
|
||||
import io.github.muntashirakon.music.loaders.TopAndRecentlyPlayedTracksLoader;
|
||||
import io.github.muntashirakon.music.model.Song;
|
||||
import io.github.muntashirakon.music.providers.HistoryStore;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
public class HistoryPlaylist extends AbsSmartPlaylist {
|
||||
|
||||
public static final Creator<HistoryPlaylist> CREATOR = new Creator<HistoryPlaylist>() {
|
||||
public HistoryPlaylist createFromParcel(Parcel source) {
|
||||
return new HistoryPlaylist(source);
|
||||
}
|
||||
|
||||
public HistoryPlaylist[] newArray(int size) {
|
||||
return new HistoryPlaylist[size];
|
||||
}
|
||||
};
|
||||
|
||||
public HistoryPlaylist(@NonNull Context context) {
|
||||
super(context.getString(R.string.history), R.drawable.ic_history);
|
||||
}
|
||||
|
||||
protected HistoryPlaylist(Parcel in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(@NonNull Context context) {
|
||||
HistoryStore.getInstance(context).clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ArrayList<Song> getSongs(@NotNull @NonNull Context context) {
|
||||
return TopAndRecentlyPlayedTracksLoader.INSTANCE.getRecentlyPlayedTracks(context);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue