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
42
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
42
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve. Please write in English only.
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Have you read the [FAQ](https://www.github.com/h4h13/RetroMusicPlayer/tree/dev/FAQ.md)?**
|
||||
[Yes/No]
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**How To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Crash log**
|
||||
If the app is crashing, add a crash log
|
||||
<details>
|
||||
<summary>Click to view logs</summary>
|
||||
PASTE YOUR LOGS HERE.
|
||||
</details>
|
||||
|
||||
**Device info:**
|
||||
- Device: [e.g. OnePlus 7]
|
||||
- Android version: [e.g. Android 9]
|
||||
- App version [e.g. 3.5.300_0517]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project. Please write in English only.
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
76
CODE_OF_CONDUCT.md
Normal file
76
CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,76 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at retromusicapp@gmail.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
35
CONTRIBUTING.md
Normal file
35
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
# Contributing
|
||||
|
||||
## Using the issue tracker
|
||||
The [issue tracker](https://github.com/h4h13/RetroMusicPlayer/issues) is the preferred channel for bug reports, feature requests and submitting pull requests, but please follow these rules:
|
||||
|
||||
* Please **do not** derail or troll issues. Keep the discussion on topic and respect the opinions of others.
|
||||
|
||||
* Please **do not** post comments consisting solely of "+1" or "👍". Use [GitHub's "reactions" feature](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) instead.
|
||||
|
||||
* Please **do not** write [enhancement]/[bug]/[feature request] or similar stuff in the title of issues, as there are labels for that purpose that will be added by devs or collaborators.
|
||||
|
||||
## Bug reports
|
||||
A bug is a _demonstrable problem_. Good bug reports are extremely helpful, so thanks!
|
||||
|
||||
Guidelines for bug reports:
|
||||
|
||||
* Use the GitHub issue search, check if the issue has already been reported both in the open issues and in the closed ones, if there are some missing details, add them in issue comments, without creating a new one
|
||||
* Check if the issue has been fixed — try to reproduce it using the latest available build
|
||||
* Isolate the problem — ideally create a reproducible scenario and a live example
|
||||
* Do not report multiple bugs in a single ticket, otherwise it will be confusing.
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you up for more information. Please try to be as detailed as possible in your report.
|
||||
|
||||
|
||||
## Feature requests
|
||||
Feature requests are welcome, please make sure to be as detailed as possible and use screenshots, videos, GIFs, to demonstrate it better, if possible.
|
||||
|
||||
|
||||
## Pull requests
|
||||
**Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code), otherwise you risk spending a lot of time working on something that developers might not want to merge into the project. To avoid that, you can join the official [Telegram group](https://t.me/retromusicapp) or open an issue.
|
||||
|
||||
## License
|
||||
By contributing your code, you agree to license your contribution under the [GNU General Public License](https://github.com/h4h13/RetroMusicPlayer/blob/dev/LICENSE.md).
|
||||
|
||||
Please note we have a code of conduct, please follow it in all your interactions with the project.
|
5
FAQ.md
5
FAQ.md
|
@ -31,8 +31,9 @@ A ".lrc" is like a text file which contains the time stamped lyrics for example,
|
|||
##### STEP 3:
|
||||
Now you have to rename the file you created in this way: <song_name> - <artist_name>.lrc or for better matching copy the <song_name> and the <artist_name> from the tag editor and then rename the file.
|
||||
##### STEP 4:
|
||||
You have to copy or move this file into a location on the SD Card: whatever_sdcard/RetroMusic/lyrics/ and paste it there.
|
||||
Finally you will be able to see the lyrics working.
|
||||
Now paste the LRC files to the following path : /sdcard/Retromusic/lyrics/
|
||||
Here sdcard is your internal storage.
|
||||
|
||||
> If you want to skip to particular time stamp, simply scroll to the time stamp from where you want to start from and a 'Play' icon will appear left to the particular stamp. Tap on play button to play from there.
|
||||
|
||||
|
||||
|
|
44
README.md
44
README.md
|
@ -29,50 +29,50 @@ Material Design music player for Android music lovers
|
|||
| Classic | Adaptive | Blur | Tiny | Peak |
|
||||
|
||||
### 🧭 Navigation never made easier
|
||||
Self-explanatory interface without overloaded menus
|
||||
Self-explanatory interface without overloaded menus.
|
||||
|
||||
### 🎨 Colorful
|
||||
You can choose between three different main themes: Clearly white, Kind
|
||||
dark and Just black for AMOLED displays. Select your favorite accent
|
||||
You can choose between three different main themes: Clearly White, Kinda
|
||||
Dark and Just Black for AMOLED displays. Select your favorite accent
|
||||
color from a color palette.
|
||||
|
||||
### 🏠 Home
|
||||
Where you can have your recently/ top played Artists, Albums and
|
||||
Favorite Songs. No other music player has this feature
|
||||
Where you can have your recently/top played artists, albums and
|
||||
favorite songs. No other music player has this feature.
|
||||
|
||||
### 📦 Included Features
|
||||
- Base 3 themes (Clearly white, Kinda dark and Just Black)
|
||||
- Base 3 themes (Clearly White, Kinda Dark and Just Black)
|
||||
- Choose from 10+ now playing themes
|
||||
- Drive Mode
|
||||
- Driving Mode
|
||||
- Headset/Bluetooth support
|
||||
- Music Duration Filter
|
||||
- Music duration filter
|
||||
- Folder support - Play song by folder
|
||||
- Gapless playback
|
||||
- Volume controls
|
||||
- More than 10 Now playing themes
|
||||
- Carousel effect for an album cover
|
||||
- Home screen Widgets
|
||||
- Lock Screen Playback Controls
|
||||
- Lyrics Screen(download and sync with music)
|
||||
- Home screen widgets
|
||||
- Lock screen playback controls
|
||||
- Lyrics screen (download and sync with music)
|
||||
- Sleep Timer
|
||||
- Home screen Widgets
|
||||
- Easy Drag to Sort Playlist & Play Queue
|
||||
- Easy drag to sort playlist & play queue
|
||||
- Tag editor
|
||||
- Create, Edit, Import playlists
|
||||
- Create, edit and import playlists
|
||||
- Playing queue with reorder
|
||||
- User profile
|
||||
- 30 Languages support
|
||||
- Browse and play your music by Songs, Albums, Artists, Playlists,
|
||||
Genre
|
||||
- Smart Auto Playlists - Recently played/Top Played/History Fully
|
||||
playlist support & Build your own playlist on the go
|
||||
- Browse and play your music by songs, albums, artists, playlists and
|
||||
genre
|
||||
- Smart Auto Playlists - Recently played, most played and history
|
||||
- Build your own playlist on the go
|
||||
|
||||
|
||||
We are trying our best to bring you the best user experience. Until now
|
||||
it is a beta version - bug fixes (if any) and more features are on the
|
||||
way. for FAQ's https://goo.gl/DR2mE2
|
||||
We are trying our best to bring you the best user experience. The app is regulary being updated for bug fixes and new features.
|
||||
|
||||
### 🗂️ License
|
||||
|
||||
Metro is released under the GNU General Public License v3.0
|
||||
(GPLv3), which can be found here: [License](LICENSE.md)
|
||||
|
||||
|
||||
>Please note: Retro Music player is an offline music player app. It
|
||||
>doesn't support music downloading or online music streaming.
|
||||
|
|
|
@ -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() {
|
||||
|
|
65
app/src/main/java/io/github/muntashirakon/music/activities/SettingsActivity.kt
Executable file → Normal file
65
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
|
||||
|
||||
|
@ -84,3 +90,44 @@ 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,
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
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