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:
|
##### 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.
|
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:
|
##### 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.
|
Now paste the LRC files to the following path : /sdcard/Retromusic/lyrics/
|
||||||
Finally you will be able to see the lyrics working.
|
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.
|
> 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 |
|
| Classic | Adaptive | Blur | Tiny | Peak |
|
||||||
|
|
||||||
### 🧭 Navigation never made easier
|
### 🧭 Navigation never made easier
|
||||||
Self-explanatory interface without overloaded menus
|
Self-explanatory interface without overloaded menus.
|
||||||
|
|
||||||
### 🎨 Colorful
|
### 🎨 Colorful
|
||||||
You can choose between three different main themes: Clearly white, Kind
|
You can choose between three different main themes: Clearly White, Kinda
|
||||||
dark and Just black for AMOLED displays. Select your favorite accent
|
Dark and Just Black for AMOLED displays. Select your favorite accent
|
||||||
color from a color palette.
|
color from a color palette.
|
||||||
|
|
||||||
### 🏠 Home
|
### 🏠 Home
|
||||||
Where you can have your recently/ top played Artists, Albums and
|
Where you can have your recently/top played artists, albums and
|
||||||
Favorite Songs. No other music player has this feature
|
favorite songs. No other music player has this feature.
|
||||||
|
|
||||||
### 📦 Included Features
|
### 📦 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
|
- Choose from 10+ now playing themes
|
||||||
- Drive Mode
|
- Driving Mode
|
||||||
- Headset/Bluetooth support
|
- Headset/Bluetooth support
|
||||||
- Music Duration Filter
|
- Music duration filter
|
||||||
- Folder support - Play song by folder
|
- Folder support - Play song by folder
|
||||||
- Gapless playback
|
- Gapless playback
|
||||||
- Volume controls
|
- Volume controls
|
||||||
- More than 10 Now playing themes
|
|
||||||
- Carousel effect for an album cover
|
- Carousel effect for an album cover
|
||||||
- Home screen Widgets
|
- Home screen widgets
|
||||||
- Lock Screen Playback Controls
|
- Lock screen playback controls
|
||||||
- Lyrics Screen(download and sync with music)
|
- Lyrics screen (download and sync with music)
|
||||||
- Sleep Timer
|
- Sleep Timer
|
||||||
- Home screen Widgets
|
- Easy drag to sort playlist & play queue
|
||||||
- Easy Drag to Sort Playlist & Play Queue
|
|
||||||
- Tag editor
|
- Tag editor
|
||||||
- Create, Edit, Import playlists
|
- Create, edit and import playlists
|
||||||
- Playing queue with reorder
|
- Playing queue with reorder
|
||||||
- User profile
|
- User profile
|
||||||
- 30 Languages support
|
- 30 Languages support
|
||||||
- Browse and play your music by Songs, Albums, Artists, Playlists,
|
- Browse and play your music by songs, albums, artists, playlists and
|
||||||
Genre
|
genre
|
||||||
- Smart Auto Playlists - Recently played/Top Played/History Fully
|
- Smart Auto Playlists - Recently played, most played and history
|
||||||
playlist support & Build your own playlist on the go
|
- Build your own playlist on the go
|
||||||
|
|
||||||
|
|
||||||
We are trying our best to bring you the best user experience. Until now
|
We are trying our best to bring you the best user experience. The app is regulary being updated for bug fixes and new features.
|
||||||
it is a beta version - bug fixes (if any) and more features are on the
|
|
||||||
way. for FAQ's https://goo.gl/DR2mE2
|
|
||||||
|
|
||||||
### 🗂️ License
|
### 🗂️ License
|
||||||
|
|
||||||
Metro is released under the GNU General Public License v3.0
|
Metro is released under the GNU General Public License v3.0
|
||||||
(GPLv3), which can be found here: [License](LICENSE.md)
|
(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.gridlayout:gridlayout:1.0.0"
|
||||||
implementation "androidx.cardview:cardview:1.0.0"
|
implementation "androidx.cardview:cardview:1.0.0"
|
||||||
implementation "androidx.viewpager2:viewpager2:1.1.0-alpha01"
|
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.annotation:annotation:1.1.0'
|
||||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||||
implementation 'androidx.core:core-ktx:1.3.1'
|
implementation 'androidx.core:core-ktx:1.3.1'
|
||||||
implementation 'androidx.fragment:fragment-ktx:1.2.5'
|
implementation 'androidx.fragment:fragment-ktx:1.2.5'
|
||||||
implementation 'androidx.palette:palette-ktx:1.0.0'
|
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 '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'
|
def retrofit_version = '2.9.0'
|
||||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||||
|
@ -144,5 +145,4 @@ dependencies {
|
||||||
def nav_version = "2.3.0"
|
def nav_version = "2.3.0"
|
||||||
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
||||||
implementation "androidx.navigation:navigation-ui-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
|
<application
|
||||||
android:name=".App"
|
android:name=".App"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
android:configChanges="locale|layoutDirection"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:configChanges="locale|layoutDirection"
|
|
||||||
android:theme="@style/Theme.RetroMusic.FollowSystem"
|
android:theme="@style/Theme.RetroMusic.FollowSystem"
|
||||||
android:usesCleartextTraffic="false"
|
android:usesCleartextTraffic="false"
|
||||||
tools:ignore="AllowBackup,GoogleAppIndexingWarning"
|
tools:ignore="AllowBackup,GoogleAppIndexingWarning"
|
||||||
|
@ -104,25 +104,17 @@
|
||||||
<data android:mimeType="vnd.android.cursor.dir/audio" />
|
<data android:mimeType="vnd.android.cursor.dir/audio" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</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.PlayingQueueActivity" />
|
||||||
<activity android:name=".activities.AboutActivity" />
|
<activity android:name=".activities.SettingsActivity" />
|
||||||
<activity android:name=".activities.tageditor.AlbumTagEditorActivity" />
|
<activity android:name=".activities.tageditor.AlbumTagEditorActivity" />
|
||||||
<activity android:name=".activities.tageditor.SongTagEditorActivity" />
|
<activity android:name=".activities.tageditor.SongTagEditorActivity" />
|
||||||
<activity android:name=".activities.SettingsActivity" />
|
|
||||||
<activity android:name=".activities.LyricsActivity" />
|
<activity android:name=".activities.LyricsActivity" />
|
||||||
<activity android:name=".activities.UserInfoActivity" />
|
<activity android:name=".activities.UserInfoActivity" />
|
||||||
<activity android:name=".activities.GenreDetailsActivity" />
|
|
||||||
<activity android:name=".activities.LicenseActivity" />
|
<activity android:name=".activities.LicenseActivity" />
|
||||||
<activity android:name=".activities.WhatsNewActivity" />
|
<activity android:name=".activities.WhatsNewActivity" />
|
||||||
<activity android:name=".activities.bugreport.BugReportActivity" />
|
<activity android:name=".activities.bugreport.BugReportActivity" />
|
||||||
<activity android:name=".activities.ShareInstagramStory" />
|
<activity android:name=".activities.ShareInstagramStory" />
|
||||||
<activity android:name=".activities.DriveModeActivity" />
|
<activity android:name=".activities.DriveModeActivity" />
|
||||||
<activity
|
|
||||||
android:name=".activities.search.SearchActivity"
|
|
||||||
android:windowSoftInputMode="stateVisible" />
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.LockScreenActivity"
|
android:name=".activities.LockScreenActivity"
|
||||||
|
@ -263,5 +255,8 @@
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.android.vending.splits.required"
|
android:name="com.android.vending.splits.required"
|
||||||
android:value="true" />
|
android:value="true" />
|
||||||
|
<meta-data
|
||||||
|
android:name="preloaded_fonts"
|
||||||
|
android:resource="@array/preloaded_fonts" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</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.ALBUM, // 8
|
||||||
MediaStore.Audio.AudioColumns.ARTIST_ID, // 9
|
MediaStore.Audio.AudioColumns.ARTIST_ID, // 9
|
||||||
MediaStore.Audio.AudioColumns.ARTIST,// 10
|
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 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_SONG = "extra_songs"
|
||||||
const val EXTRA_PLAYLIST = "extra_list"
|
|
||||||
const val LIBRARY_CATEGORIES = "library_categories"
|
const val LIBRARY_CATEGORIES = "library_categories"
|
||||||
const val EXTRA_SONG_INFO = "extra_song_info"
|
const val EXTRA_SONG_INFO = "extra_song_info"
|
||||||
const val DESATURATED_COLOR = "desaturated_color"
|
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
|
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.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.Genre
|
||||||
import io.github.muntashirakon.music.model.Playlist
|
import io.github.muntashirakon.music.model.Playlist
|
||||||
import io.github.muntashirakon.music.network.networkModule
|
import io.github.muntashirakon.music.network.networkModule
|
||||||
import io.github.muntashirakon.music.providers.RepositoryImpl
|
import io.github.muntashirakon.music.repository.*
|
||||||
import org.eclipse.egit.github.core.Repository
|
import org.koin.android.ext.koin.androidContext
|
||||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||||
import org.koin.dsl.bind
|
import org.koin.dsl.bind
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
private val dataModule = module {
|
private val dataModule = module {
|
||||||
single {
|
single {
|
||||||
RepositoryImpl(get(), get())
|
RealRepository(get(), get(), get(), get(), get(), get(), get(), get(), get(), get())
|
||||||
} bind Repository::class
|
} 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 {
|
private val viewModules = module {
|
||||||
|
@ -28,19 +74,31 @@ private val viewModules = module {
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel { (albumId: Int) ->
|
viewModel { (albumId: Int) ->
|
||||||
AlbumDetailsViewModel(get(), albumId)
|
AlbumDetailsViewModel(
|
||||||
|
get(),
|
||||||
|
albumId
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel { (artistId: Int) ->
|
viewModel { (artistId: Int) ->
|
||||||
ArtistDetailsViewModel(get(), artistId)
|
ArtistDetailsViewModel(
|
||||||
|
get(),
|
||||||
|
artistId
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel { (playlist: Playlist) ->
|
viewModel { (playlist: Playlist) ->
|
||||||
PlaylistDetailsViewModel(get(), playlist)
|
PlaylistDetailsViewModel(
|
||||||
|
get(),
|
||||||
|
playlist
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel { (genre: Genre) ->
|
viewModel { (genre: Genre) ->
|
||||||
GenreDetailsViewModel(get(), genre)
|
GenreDetailsViewModel(
|
||||||
|
get(),
|
||||||
|
genre
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel {
|
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 {
|
class LyricsActivity : AbsMusicServiceActivity(), MusicProgressViewUpdateHelper.Callback {
|
||||||
private lateinit var updateHelper: MusicProgressViewUpdateHelper
|
private lateinit var updateHelper: MusicProgressViewUpdateHelper
|
||||||
|
|
||||||
|
|
||||||
private lateinit var song: Song
|
private lateinit var song: Song
|
||||||
|
|
||||||
private val googleSearchLrcUrl: String
|
private val googleSearchLrcUrl: String
|
||||||
|
|
|
@ -1,83 +1,44 @@
|
||||||
package io.github.muntashirakon.music.activities
|
package io.github.muntashirakon.music.activities
|
||||||
|
|
||||||
import android.app.ActivityOptions
|
import android.content.Intent
|
||||||
import android.content.*
|
import android.content.SharedPreferences
|
||||||
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Menu
|
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.SubMenu
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.fragment.app.Fragment
|
import io.github.muntashirakon.music.*
|
||||||
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 io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
|
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.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.openAndShuffleQueue
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.openQueue
|
import io.github.muntashirakon.music.helper.MusicPlayerRemote.openQueue
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.playFromUri
|
import io.github.muntashirakon.music.helper.MusicPlayerRemote.playFromUri
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote.shuffleMode
|
import io.github.muntashirakon.music.helper.MusicPlayerRemote.shuffleMode
|
||||||
import io.github.muntashirakon.music.helper.SearchQueryHelper.getSongs
|
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.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.service.MusicService
|
||||||
import io.github.muntashirakon.music.util.AppRater.appLaunched
|
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.PreferenceUtil
|
||||||
import io.github.muntashirakon.music.util.RetroColorUtil
|
import kotlinx.coroutines.Dispatchers
|
||||||
import io.github.muntashirakon.music.util.RetroUtil
|
import kotlinx.coroutines.launch
|
||||||
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 org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class MainActivity : AbsSlidingMusicPanelActivity(),
|
class MainActivity : AbsSlidingMusicPanelActivity(), OnSharedPreferenceChangeListener {
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener, CabHolder {
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "MainActivity"
|
const val TAG = "MainActivity"
|
||||||
const val EXPAND_PANEL = "expand_panel"
|
const val EXPAND_PANEL = "expand_panel"
|
||||||
|
const val APP_UPDATE_REQUEST_CODE = 9002
|
||||||
}
|
}
|
||||||
|
|
||||||
private val libraryViewModel: LibraryViewModel by inject()
|
private val repository by inject<Repository>()
|
||||||
private var cab: MaterialCab? = null
|
private val libraryViewModel by inject<LibraryViewModel>()
|
||||||
private val intentFilter = IntentFilter(Intent.ACTION_SCREEN_OFF)
|
|
||||||
private lateinit var currentFragment: MainActivityFragmentCallbacks
|
|
||||||
private var blockRequestPermissions = false
|
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 {
|
override fun createContentView(): View {
|
||||||
return wrapSlidingMusicPanel(R.layout.activity_main_content)
|
return wrapSlidingMusicPanel(R.layout.activity_main_content)
|
||||||
|
@ -91,29 +52,16 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
|
||||||
setLightNavigationBar(true)
|
setLightNavigationBar(true)
|
||||||
setTaskDescriptionColorAuto()
|
setTaskDescriptionColorAuto()
|
||||||
hideStatusBar()
|
hideStatusBar()
|
||||||
setBottomBarVisibility(View.VISIBLE)
|
|
||||||
|
|
||||||
addMusicServiceEventListener(libraryViewModel)
|
|
||||||
if (savedInstanceState == null) {
|
|
||||||
selectedFragment(PreferenceUtil.lastPage)
|
|
||||||
} else {
|
|
||||||
restoreCurrentFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
appLaunched(this)
|
appLaunched(this)
|
||||||
setupToolbar()
|
addMusicServiceEventListener(libraryViewModel)
|
||||||
updateTabs()
|
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() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
registerReceiver(broadcastReceiver, intentFilter)
|
|
||||||
PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
|
PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
|
||||||
if (intent.hasExtra(EXPAND_PANEL) &&
|
if (intent.hasExtra(EXPAND_PANEL) &&
|
||||||
intent.getBooleanExtra(EXPAND_PANEL, false) &&
|
intent.getBooleanExtra(EXPAND_PANEL, false) &&
|
||||||
|
@ -126,389 +74,9 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
unregisterReceiver(broadcastReceiver)
|
|
||||||
PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this)
|
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() {
|
override fun requestPermissions() {
|
||||||
if (!blockRequestPermissions) {
|
if (!blockRequestPermissions) {
|
||||||
super.requestPermissions()
|
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?) {
|
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
|
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,18 +135,22 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
|
||||||
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
|
} else if (MediaStore.Audio.Albums.CONTENT_TYPE == mimeType) {
|
||||||
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
|
val id = parseIdFromIntent(intent, "albumId", "album").toInt()
|
||||||
if (id >= 0) {
|
if (id >= 0) {
|
||||||
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
val position = intent.getIntExtra("position", 0)
|
val position = intent.getIntExtra("position", 0)
|
||||||
openQueue(getAlbum(this, id).songs!!, position, true)
|
openQueue(repository.albumById(id).songs!!, position, true)
|
||||||
handled = true
|
handled = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
|
} else if (MediaStore.Audio.Artists.CONTENT_TYPE == mimeType) {
|
||||||
val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
|
val id = parseIdFromIntent(intent, "artistId", "artist").toInt()
|
||||||
if (id >= 0) {
|
if (id >= 0) {
|
||||||
|
lifecycleScope.launch {
|
||||||
val position = intent.getIntExtra("position", 0)
|
val position = intent.getIntExtra("position", 0)
|
||||||
openQueue(getArtist(this, id).songs, position, true)
|
openQueue(repository.artistById(id).songs, position, true)
|
||||||
handled = true
|
handled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (handled) {
|
if (handled) {
|
||||||
setIntent(Intent())
|
setIntent(Intent())
|
||||||
}
|
}
|
||||||
|
@ -671,31 +173,4 @@ class MainActivity : AbsSlidingMusicPanelActivity(),
|
||||||
}
|
}
|
||||||
return id
|
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 androidx.recyclerview.widget.RecyclerView
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
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.R
|
||||||
import io.github.muntashirakon.music.activities.base.AbsMusicServiceActivity
|
import io.github.muntashirakon.music.activities.base.AbsMusicServiceActivity
|
||||||
import io.github.muntashirakon.music.adapter.song.PlayingQueueAdapter
|
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.extensions.surfaceColor
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||||
import io.github.muntashirakon.music.util.MusicUtil
|
import io.github.muntashirakon.music.util.MusicUtil
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator
|
import io.github.muntashirakon.music.util.ThemedFastScroller
|
||||||
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 kotlinx.android.synthetic.main.activity_playing_queue.*
|
import kotlinx.android.synthetic.main.activity_playing_queue.*
|
||||||
|
|
||||||
open class PlayingQueueActivity : AbsMusicServiceActivity() {
|
open class PlayingQueueActivity : AbsMusicServiceActivity() {
|
||||||
|
@ -103,7 +104,7 @@ open class PlayingQueueActivity : AbsMusicServiceActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
//ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView)
|
val fastScroller = ThemedFastScroller.create(recyclerView)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkForPadding() {
|
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.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.navigation.NavController
|
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.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||||
|
import com.afollestad.materialdialogs.color.ColorChooserDialog
|
||||||
import io.github.muntashirakon.music.R
|
import io.github.muntashirakon.music.R
|
||||||
import io.github.muntashirakon.music.activities.base.AbsBaseActivity
|
import io.github.muntashirakon.music.activities.base.AbsBaseActivity
|
||||||
import io.github.muntashirakon.music.appshortcuts.DynamicShortcutManager
|
import io.github.muntashirakon.music.appshortcuts.DynamicShortcutManager
|
||||||
import io.github.muntashirakon.music.extensions.applyToolbar
|
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.*
|
import kotlinx.android.synthetic.main.activity_settings.*
|
||||||
|
|
||||||
class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
|
class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
|
||||||
|
|
||||||
private val fragmentManager = supportFragmentManager
|
|
||||||
private lateinit var appBarConfiguration: AppBarConfiguration
|
|
||||||
private lateinit var navController: NavController
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
setDrawUnderStatusBar()
|
setDrawUnderStatusBar()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
@ -35,56 +27,14 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
|
||||||
private fun setupToolbar() {
|
private fun setupToolbar() {
|
||||||
setTitle(R.string.action_settings)
|
setTitle(R.string.action_settings)
|
||||||
applyToolbar(toolbar)
|
applyToolbar(toolbar)
|
||||||
val navHostFragment =
|
val navController: NavController = findNavController(R.id.contentFrame)
|
||||||
supportFragmentManager.findFragmentById(R.id.contentFrame) as NavHostFragment
|
|
||||||
val navController: NavController = navHostFragment.navController
|
|
||||||
navController.addOnDestinationChangedListener { _, _, _ ->
|
navController.addOnDestinationChangedListener { _, _, _ ->
|
||||||
toolbar.title = navController.currentDestination?.label
|
toolbar.title = navController.currentDestination?.label
|
||||||
}
|
}
|
||||||
|
|
||||||
//It removes the back button
|
|
||||||
//appBarConfiguration = AppBarConfiguration(navController.graph)
|
|
||||||
//setupActionBarWithNavController(navController, appBarConfiguration)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSupportNavigateUp(): Boolean {
|
override fun onSupportNavigateUp(): Boolean {
|
||||||
return navController.navigateUp() || super.onSupportNavigateUp()
|
return findNavController(R.id.contentFrame).navigateUp() || super.onSupportNavigateUp()
|
||||||
}
|
|
||||||
|
|
||||||
fun setupFragment(fragment: Fragment, @StringRes titleName: Int) {
|
|
||||||
val fragmentTransaction = fragmentManager
|
|
||||||
.beginTransaction()
|
|
||||||
.setCustomAnimations(
|
|
||||||
R.anim.sliding_in_left,
|
|
||||||
R.anim.sliding_out_right,
|
|
||||||
android.R.anim.slide_in_left,
|
|
||||||
android.R.anim.slide_out_right
|
|
||||||
)
|
|
||||||
fragmentTransaction.replace(R.id.contentFrame, fragment, fragment.tag)
|
|
||||||
fragmentTransaction.addToBackStack(null)
|
|
||||||
fragmentTransaction.commit()
|
|
||||||
setTitle(titleName)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBackPressed() {
|
|
||||||
if (fragmentManager.backStackEntryCount == 0) {
|
|
||||||
super.onBackPressed()
|
|
||||||
} else {
|
|
||||||
setTitle(R.string.action_settings)
|
|
||||||
fragmentManager.popBackStack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
||||||
if (item.itemId == android.R.id.home) {
|
|
||||||
onBackPressed()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TAG: String = "SettingsActivity"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onColorSelection(dialog: ColorChooserDialog, selectedColor: Int) {
|
override fun onColorSelection(dialog: ColorChooserDialog, selectedColor: Int) {
|
||||||
|
@ -101,4 +51,11 @@ class SettingsActivity : AbsBaseActivity(), ColorChooserDialog.ColorCallback {
|
||||||
override fun onColorChooserDismissed(dialog: ColorChooserDialog) {
|
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.view.MenuItem
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
import code.name.monkey.appthemehelper.util.MaterialUtil
|
|
||||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
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_BANNER
|
||||||
import io.github.muntashirakon.music.Constants.USER_PROFILE
|
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.activities.base.AbsBaseActivity
|
||||||
import io.github.muntashirakon.music.extensions.accentColor
|
import io.github.muntashirakon.music.extensions.accentColor
|
||||||
import io.github.muntashirakon.music.extensions.applyToolbar
|
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.glide.UserProfileGlideRequest
|
||||||
import io.github.muntashirakon.music.util.ImageUtil
|
import io.github.muntashirakon.music.util.ImageUtil
|
||||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
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.android.synthetic.main.activity_user_info.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -49,7 +48,7 @@ class UserInfoActivity : AbsBaseActivity() {
|
||||||
setLightNavigationBar(true)
|
setLightNavigationBar(true)
|
||||||
applyToolbar(toolbar)
|
applyToolbar(toolbar)
|
||||||
|
|
||||||
MaterialUtil.setTint(nameContainer, false)
|
nameContainer.accentColor()
|
||||||
name.setText(PreferenceUtil.userName)
|
name.setText(PreferenceUtil.userName)
|
||||||
|
|
||||||
userImage.setOnClickListener {
|
userImage.setOnClickListener {
|
||||||
|
@ -161,7 +160,7 @@ class UserInfoActivity : AbsBaseActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveImage(bitmap: Bitmap, fileName: String) {
|
private fun saveImage(bitmap: Bitmap, fileName: String) {
|
||||||
CoroutineScope(Dispatchers.IO).launch() {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
val appDir = applicationContext.filesDir
|
val appDir = applicationContext.filesDir
|
||||||
val file = File(appDir, fileName)
|
val file = File(appDir, fileName)
|
||||||
var successful = false
|
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.view.ViewTreeObserver
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
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.R
|
||||||
import io.github.muntashirakon.music.RetroBottomSheetBehavior
|
import io.github.muntashirakon.music.RetroBottomSheetBehavior
|
||||||
import io.github.muntashirakon.music.extensions.hide
|
import io.github.muntashirakon.music.extensions.hide
|
||||||
import io.github.muntashirakon.music.extensions.show
|
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.LibraryViewModel
|
||||||
import io.github.muntashirakon.music.fragments.MiniPlayerFragment
|
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.fragments.NowPlayingScreen.*
|
import io.github.muntashirakon.music.fragments.NowPlayingScreen.*
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||||
import io.github.muntashirakon.music.model.CategoryInfo
|
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.util.PreferenceUtil
|
||||||
import io.github.muntashirakon.music.views.BottomNavigationBarTinted
|
import io.github.muntashirakon.music.views.BottomNavigationBarTinted
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
||||||
import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
|
import kotlinx.android.synthetic.main.sliding_music_panel_layout.*
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
|
||||||
abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
|
||||||
companion object {
|
companion object {
|
||||||
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
|
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
|
||||||
}
|
}
|
||||||
|
@ -120,8 +122,9 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
||||||
return slidingMusicPanelLayout
|
return slidingMusicPanelLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collapsePanel() {
|
fun collapsePanel() {
|
||||||
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||||
|
setMiniPlayerAlphaProgress(0f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun expandPanel() {
|
fun expandPanel() {
|
||||||
|
@ -133,9 +136,7 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
||||||
if (miniPlayerFragment?.view == null) return
|
if (miniPlayerFragment?.view == null) return
|
||||||
val alpha = 1 - progress
|
val alpha = 1 - progress
|
||||||
miniPlayerFragment?.view?.alpha = alpha
|
miniPlayerFragment?.view?.alpha = alpha
|
||||||
// necessary to make the views below clickable
|
|
||||||
miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE
|
miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE
|
||||||
|
|
||||||
bottomNavigationView.translationY = progress * 500
|
bottomNavigationView.translationY = progress * 500
|
||||||
bottomNavigationView.alpha = alpha
|
bottomNavigationView.alpha = alpha
|
||||||
}
|
}
|
||||||
|
@ -172,40 +173,31 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
||||||
return bottomNavigationView
|
return bottomNavigationView
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setBottomBarVisibility(visible: Int) {
|
fun hideBottomBarVisibility(visible: Boolean) {
|
||||||
bottomNavigationView.visibility = visible
|
bottomNavigationView.isVisible = visible
|
||||||
hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
|
hideBottomBar(MusicPlayerRemote.playingQueue.isEmpty())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hideBottomBar(hide: Boolean) {
|
private fun hideBottomBar(hide: Boolean) {
|
||||||
val heightOfBar = resources.getDimensionPixelSize(R.dimen.mini_player_height)
|
val heightOfBar = bottomNavigationView.height
|
||||||
val heightOfBarWithTabs =
|
val isBottomBarVisible = bottomNavigationView.isVisible
|
||||||
resources.getDimensionPixelSize(R.dimen.mini_player_height_expanded)
|
|
||||||
|
|
||||||
if (hide) {
|
if (hide) {
|
||||||
behavior.isHideable = true
|
behavior.isHideable = true
|
||||||
behavior.peekHeight = 0
|
behavior.peekHeight = 0
|
||||||
bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat()
|
|
||||||
collapsePanel()
|
collapsePanel()
|
||||||
|
ViewCompat.setElevation(bottomNavigationView, 10f)
|
||||||
} else {
|
} else {
|
||||||
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
|
ViewCompat.setElevation(bottomNavigationView, 10f)
|
||||||
slidingPanel.elevation = DensityUtil.dip2px(this, 10f).toFloat()
|
ViewCompat.setElevation(slidingPanel, 10f)
|
||||||
bottomNavigationView.elevation = DensityUtil.dip2px(this, 10f).toFloat()
|
|
||||||
behavior.isHideable = false
|
behavior.isHideable = false
|
||||||
behavior.peekHeight =
|
behavior.peekHeight = (if (isBottomBarVisible) heightOfBar * 2 else heightOfBar) - 24
|
||||||
if (bottomNavigationView.visibility == View.VISIBLE) {
|
|
||||||
heightOfBarWithTabs
|
|
||||||
} else {
|
|
||||||
heightOfBar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun chooseFragmentForTheme() {
|
private fun chooseFragmentForTheme() {
|
||||||
cps = PreferenceUtil.nowPlayingScreen
|
cps = PreferenceUtil.nowPlayingScreen
|
||||||
miniPlayerFragment =
|
miniPlayerFragment = whichFragment<MiniPlayerFragment>(R.id.miniPlayerFragment)
|
||||||
supportFragmentManager.findFragmentById(R.id.miniPlayerFragment) as MiniPlayerFragment
|
|
||||||
miniPlayerFragment?.view?.setOnClickListener { expandPanel() }
|
miniPlayerFragment?.view?.setOnClickListener { expandPanel() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +224,6 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun handleBackPress(): Boolean {
|
open fun handleBackPress(): Boolean {
|
||||||
|
|
||||||
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
|
if (panelState == BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
collapsePanel()
|
collapsePanel()
|
||||||
return true
|
return true
|
||||||
|
@ -305,6 +296,12 @@ abstract class AbsSlidingMusicPanelActivity() : AbsMusicServiceActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun hideBottomNavigation() {
|
||||||
|
behavior.isHideable = true
|
||||||
|
behavior.peekHeight = 0
|
||||||
|
hideBottomBarVisibility(false)
|
||||||
|
}
|
||||||
|
|
||||||
fun updateTabs() {
|
fun updateTabs() {
|
||||||
bottomNavigationView.menu.clear()
|
bottomNavigationView.menu.clear()
|
||||||
val currentTabs: List<CategoryInfo> = PreferenceUtil.libraryCategory
|
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.View
|
||||||
import android.view.animation.OvershootInterpolator
|
import android.view.animation.OvershootInterpolator
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||||
import code.name.monkey.appthemehelper.util.TintHelper
|
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
|
||||||
import io.github.muntashirakon.music.R.drawable
|
import io.github.muntashirakon.music.R.drawable
|
||||||
import io.github.muntashirakon.music.activities.base.AbsBaseActivity
|
import io.github.muntashirakon.music.activities.base.AbsBaseActivity
|
||||||
import io.github.muntashirakon.music.activities.saf.SAFGuideActivity
|
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.RetroUtil
|
||||||
import io.github.muntashirakon.music.util.SAFUtil
|
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 kotlinx.android.synthetic.main.activity_album_tag_editor.*
|
||||||
import org.jaudiotagger.audio.AudioFile
|
import org.jaudiotagger.audio.AudioFile
|
||||||
import org.jaudiotagger.audio.AudioFileIO
|
import org.jaudiotagger.audio.AudioFileIO
|
||||||
import org.jaudiotagger.tag.FieldKey
|
import org.jaudiotagger.tag.FieldKey
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
||||||
|
val repository by inject<Repository>()
|
||||||
|
|
||||||
|
lateinit var saveFab: MaterialButton
|
||||||
protected var id: Int = 0
|
protected var id: Int = 0
|
||||||
private set
|
private set
|
||||||
private var paletteColorPrimary: Int = 0
|
private var paletteColorPrimary: Int = 0
|
||||||
private var isInNoImageMode: Boolean = false
|
private var isInNoImageMode: Boolean = false
|
||||||
private var songPaths: List<String>? = null
|
private var songPaths: List<String>? = null
|
||||||
lateinit var saveFab: MaterialButton
|
|
||||||
|
|
||||||
private var savedSongPaths: List<String>? = null
|
private var savedSongPaths: List<String>? = null
|
||||||
private val currentSongPath: String? = null
|
private val currentSongPath: String? = null
|
||||||
private var savedTags: Map<FieldKey, String>? = null
|
private var savedTags: Map<FieldKey, String>? = null
|
||||||
|
@ -172,41 +175,35 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(contentViewLayout)
|
setContentView(contentViewLayout)
|
||||||
|
setStatusbarColorAuto()
|
||||||
|
setNavigationbarColorAuto()
|
||||||
|
setTaskDescriptionColorAuto()
|
||||||
|
|
||||||
saveFab = findViewById(R.id.saveTags)
|
saveFab = findViewById(R.id.saveTags)
|
||||||
getIntentExtras()
|
getIntentExtras()
|
||||||
|
|
||||||
|
lifecycleScope.launchWhenCreated {
|
||||||
songPaths = getSongPaths()
|
songPaths = getSongPaths()
|
||||||
if (songPaths!!.isEmpty()) {
|
if (songPaths!!.isEmpty()) {
|
||||||
finish()
|
finish()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
setUpViews()
|
setUpViews()
|
||||||
|
|
||||||
setStatusbarColorAuto()
|
|
||||||
setNavigationbarColorAuto()
|
|
||||||
setTaskDescriptionColorAuto()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpViews() {
|
private fun setUpViews() {
|
||||||
setUpScrollView()
|
|
||||||
setUpFab()
|
setUpFab()
|
||||||
setUpImageView()
|
setUpImageView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpScrollView() {
|
|
||||||
//observableScrollView.setScrollViewCallbacks(observableScrollViewCallbacks);
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var items: List<String>
|
private lateinit var items: List<String>
|
||||||
|
|
||||||
private fun setUpImageView() {
|
private fun setUpImageView() {
|
||||||
loadCurrentImage()
|
loadCurrentImage()
|
||||||
items = listOf(
|
items = listOf(
|
||||||
getString(R.string.pick_from_local_storage),
|
getString(io.github.muntashirakon.music.R.string.pick_from_local_storage),
|
||||||
getString(R.string.web_search),
|
getString(io.github.muntashirakon.music.R.string.web_search),
|
||||||
getString(R.string.remove_cover)
|
getString(io.github.muntashirakon.music.R.string.remove_cover)
|
||||||
)
|
)
|
||||||
editorImage?.setOnClickListener { show }
|
editorImage?.setOnClickListener { show }
|
||||||
}
|
}
|
||||||
|
@ -217,7 +214,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
||||||
startActivityForResult(
|
startActivityForResult(
|
||||||
Intent.createChooser(
|
Intent.createChooser(
|
||||||
intent,
|
intent,
|
||||||
getString(R.string.pick_from_local_storage)
|
getString(io.github.muntashirakon.music.R.string.pick_from_local_storage)
|
||||||
), REQUEST_CODE_SELECT_IMAGE
|
), 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) {
|
protected fun searchWebFor(vararg keys: String) {
|
||||||
val stringBuilder = StringBuilder()
|
val stringBuilder = StringBuilder()
|
||||||
|
@ -336,7 +333,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() {
|
||||||
|
|
||||||
hideFab()
|
hideFab()
|
||||||
|
|
||||||
savedSongPaths = getSongPaths()
|
savedSongPaths = songPaths
|
||||||
savedTags = fieldKeyValueMap
|
savedTags = fieldKeyValueMap
|
||||||
savedArtworkInfo = artworkInfo
|
savedArtworkInfo = artworkInfo
|
||||||
|
|
||||||
|
|
|
@ -14,23 +14,23 @@ import android.transition.Slide
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
import code.name.monkey.appthemehelper.util.MaterialUtil
|
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.Glide
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
import com.bumptech.glide.request.animation.GlideAnimation
|
import com.bumptech.glide.request.animation.GlideAnimation
|
||||||
import com.bumptech.glide.request.target.SimpleTarget
|
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 kotlinx.android.synthetic.main.activity_album_tag_editor.*
|
||||||
import org.jaudiotagger.tag.FieldKey
|
import org.jaudiotagger.tag.FieldKey
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
||||||
|
|
||||||
override val contentViewLayout: Int
|
override val contentViewLayout: Int
|
||||||
get() = R.layout.activity_album_tag_editor
|
get() = R.layout.activity_album_tag_editor
|
||||||
|
|
||||||
|
@ -162,13 +162,13 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
||||||
|
|
||||||
writeValuesToFiles(
|
writeValuesToFiles(
|
||||||
fieldKeyValueMap,
|
fieldKeyValueMap,
|
||||||
if (deleteAlbumArt) AbsTagEditorActivity.ArtworkInfo(id, null)
|
if (deleteAlbumArt) ArtworkInfo(id, null)
|
||||||
else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!)
|
else if (albumArtBitmap == null) null else ArtworkInfo(id, albumArtBitmap!!)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSongPaths(): List<String> {
|
override suspend fun getSongPaths(): List<String> {
|
||||||
val songs = AlbumLoader.getAlbum(this, id).songs
|
val songs = repository.albumById(id).songs
|
||||||
val paths = ArrayList<String>(songs!!.size)
|
val paths = ArrayList<String>(songs!!.size)
|
||||||
for (song in songs) {
|
for (song in songs) {
|
||||||
paths.add(song.data)
|
paths.add(song.data)
|
||||||
|
|
|
@ -8,9 +8,10 @@ import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
import code.name.monkey.appthemehelper.util.MaterialUtil
|
import code.name.monkey.appthemehelper.util.MaterialUtil
|
||||||
import io.github.muntashirakon.music.R
|
import io.github.muntashirakon.music.R
|
||||||
import io.github.muntashirakon.music.extensions.appHandleColor
|
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 kotlinx.android.synthetic.main.activity_song_tag_editor.*
|
||||||
import org.jaudiotagger.tag.FieldKey
|
import org.jaudiotagger.tag.FieldKey
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
||||||
|
@ -18,6 +19,8 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
||||||
override val contentViewLayout: Int
|
override val contentViewLayout: Int
|
||||||
get() = R.layout.activity_song_tag_editor
|
get() = R.layout.activity_song_tag_editor
|
||||||
|
|
||||||
|
private val songRepository by inject<SongRepository>()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
@ -85,9 +88,9 @@ class SongTagEditorActivity : AbsTagEditorActivity(), TextWatcher {
|
||||||
writeValuesToFiles(fieldKeyValueMap, null)
|
writeValuesToFiles(fieldKeyValueMap, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getSongPaths(): List<String> {
|
override suspend fun getSongPaths(): List<String> {
|
||||||
val paths = ArrayList<String>(1)
|
val paths = ArrayList<String>(1)
|
||||||
paths.add(SongLoader.getSong(this, id).data)
|
paths.add(songRepository.song(id).data)
|
||||||
return paths
|
return paths
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
|
||||||
File albumArtFile = null;
|
File albumArtFile = null;
|
||||||
if (info.artworkInfo != null && info.artworkInfo.getArtwork() != null) {
|
if (info.artworkInfo != null && info.artworkInfo.getArtwork() != null) {
|
||||||
try {
|
try {
|
||||||
albumArtFile = MusicUtil.createAlbumArtFile().getCanonicalFile();
|
albumArtFile = MusicUtil.INSTANCE.createAlbumArtFile().getCanonicalFile();
|
||||||
info.artworkInfo.getArtwork()
|
info.artworkInfo.getArtwork()
|
||||||
.compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(albumArtFile));
|
.compress(Bitmap.CompressFormat.PNG, 0, new FileOutputStream(albumArtFile));
|
||||||
artwork = ArtworkFactory.createArtworkFromFile(albumArtFile);
|
artwork = ArtworkFactory.createArtworkFromFile(albumArtFile);
|
||||||
|
@ -120,9 +120,9 @@ public class WriteTagsAsyncTask extends DialogAsyncTask<WriteTagsAsyncTask.Loadi
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
if (wroteArtwork) {
|
if (wroteArtwork) {
|
||||||
MusicUtil.insertAlbumArt(context, info.artworkInfo.getAlbumId(), albumArtFile.getPath());
|
MusicUtil.INSTANCE.insertAlbumArt(context, info.artworkInfo.getAlbumId(), albumArtFile.getPath());
|
||||||
} else if (deletedArtwork) {
|
} 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
|
package io.github.muntashirakon.music.adapter
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.navigation.findNavController
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.github.muntashirakon.music.EXTRA_GENRE
|
||||||
import io.github.muntashirakon.music.R
|
import io.github.muntashirakon.music.R
|
||||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
||||||
import io.github.muntashirakon.music.model.Genre
|
import io.github.muntashirakon.music.model.Genre
|
||||||
import io.github.muntashirakon.music.util.NavigationUtil
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,7 +18,7 @@ import java.util.*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class GenreAdapter(
|
class GenreAdapter(
|
||||||
private val activity: Activity,
|
private val activity: FragmentActivity,
|
||||||
var dataSet: List<Genre>,
|
var dataSet: List<Genre>,
|
||||||
private val mItemLayoutRes: Int
|
private val mItemLayoutRes: Int
|
||||||
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
|
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
|
||||||
|
@ -48,9 +50,10 @@ class GenreAdapter(
|
||||||
|
|
||||||
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
||||||
override fun onClick(v: View?) {
|
override fun onClick(v: View?) {
|
||||||
super.onClick(v)
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
val genre = dataSet[layoutPosition]
|
R.id.genreDetailsFragment,
|
||||||
NavigationUtil.goToGenre(activity, genre)
|
bundleOf(EXTRA_GENRE to dataSet[layoutPosition])
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,37 @@
|
||||||
package io.github.muntashirakon.music.adapter
|
package io.github.muntashirakon.music.adapter
|
||||||
|
|
||||||
import android.util.DisplayMetrics
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.IntDef
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.AppCompatTextView
|
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.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.recyclerview.widget.RecyclerView.HORIZONTAL
|
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
import io.github.muntashirakon.music.PeekingLinearLayoutManager
|
import com.bumptech.glide.Glide
|
||||||
import io.github.muntashirakon.music.R
|
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.album.AlbumAdapter
|
||||||
import io.github.muntashirakon.music.adapter.artist.ArtistAdapter
|
import io.github.muntashirakon.music.adapter.artist.ArtistAdapter
|
||||||
import io.github.muntashirakon.music.adapter.song.SongAdapter
|
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.glide.SongGlideRequest
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
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.*
|
||||||
import io.github.muntashirakon.music.model.Playlist
|
|
||||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.google.android.material.card.MaterialCardView
|
|
||||||
|
|
||||||
class HomeAdapter(
|
class HomeAdapter(
|
||||||
private val activity: AppCompatActivity,
|
private val activity: AppCompatActivity
|
||||||
private val displayMetrics: DisplayMetrics
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), ArtistClickListener, AlbumClickListener {
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
|
||||||
|
|
||||||
private var list = listOf<Home>()
|
private var list = listOf<Home>()
|
||||||
|
|
||||||
|
@ -45,14 +44,9 @@ class HomeAdapter(
|
||||||
.inflate(R.layout.section_recycler_view, parent, false)
|
.inflate(R.layout.section_recycler_view, parent, false)
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
RECENT_ARTISTS, TOP_ARTISTS -> ArtistViewHolder(layout)
|
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)
|
GENRES -> GenreViewHolder(layout)
|
||||||
FAVOURITES -> PlaylistViewHolder(layout)
|
FAVOURITES -> PlaylistViewHolder(layout)
|
||||||
|
TOP_ALBUMS, RECENT_ALBUMS -> AlbumViewHolder(layout)
|
||||||
else -> {
|
else -> {
|
||||||
SuggestionsViewHolder(
|
SuggestionsViewHolder(
|
||||||
LayoutInflater.from(activity).inflate(
|
LayoutInflater.from(activity).inflate(
|
||||||
|
@ -66,48 +60,62 @@ class HomeAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
val home = list[position]
|
||||||
when (getItemViewType(position)) {
|
when (getItemViewType(position)) {
|
||||||
RECENT_ALBUMS -> {
|
RECENT_ALBUMS -> {
|
||||||
val viewHolder = holder as AlbumViewHolder
|
val viewHolder = holder as AlbumViewHolder
|
||||||
viewHolder.bindView(
|
viewHolder.bindView(home.arrayList as List<Album>, R.string.recent_albums)
|
||||||
list[position].arrayList as List<Album>,
|
viewHolder.clickableArea.setOnClickListener {
|
||||||
R.string.recent_albums
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
|
R.id.detailListFragment,
|
||||||
|
bundleOf("type" to RECENT_ALBUMS)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
TOP_ALBUMS -> {
|
TOP_ALBUMS -> {
|
||||||
val viewHolder = holder as AlbumViewHolder
|
val viewHolder = holder as AlbumViewHolder
|
||||||
viewHolder.bindView(
|
viewHolder.bindView(home.arrayList as List<Album>, R.string.top_albums)
|
||||||
list[position].arrayList as List<Album>,
|
viewHolder.clickableArea.setOnClickListener {
|
||||||
R.string.top_albums
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
|
R.id.detailListFragment,
|
||||||
|
bundleOf("type" to TOP_ALBUMS)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
RECENT_ARTISTS -> {
|
RECENT_ARTISTS -> {
|
||||||
val viewHolder = holder as ArtistViewHolder
|
val viewHolder = holder as ArtistViewHolder
|
||||||
viewHolder.bindView(
|
viewHolder.bindView(home.arrayList, R.string.recent_artists)
|
||||||
list[position].arrayList as List<Artist>,
|
viewHolder.clickableArea.setOnClickListener {
|
||||||
R.string.recent_artists
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
|
R.id.detailListFragment,
|
||||||
|
bundleOf("type" to RECENT_ARTISTS)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
TOP_ARTISTS -> {
|
TOP_ARTISTS -> {
|
||||||
val viewHolder = holder as ArtistViewHolder
|
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 -> {
|
SUGGESTIONS -> {
|
||||||
val viewHolder = holder as SuggestionsViewHolder
|
val viewHolder = holder as SuggestionsViewHolder
|
||||||
viewHolder.bindView(
|
viewHolder.bindView(home.arrayList)
|
||||||
list[position].arrayList as List<Song>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
FAVOURITES -> {
|
FAVOURITES -> {
|
||||||
val viewHolder = holder as PlaylistViewHolder
|
val viewHolder = holder as PlaylistViewHolder
|
||||||
viewHolder.bindView(
|
viewHolder.bindView(home.arrayList, R.string.favorites)
|
||||||
list[position].arrayList as List<Playlist>,
|
|
||||||
R.string.favorites
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
GENRES -> {
|
GENRES -> {
|
||||||
val viewHolder = holder as GenreViewHolder
|
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,62 +129,25 @@ class HomeAdapter(
|
||||||
notifyDataSetChanged()
|
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) {
|
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||||
fun bindView(list: List<Album>, titleRes: Int) {
|
fun bindView(albums: 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)
|
title.text = activity.getString(titleRes)
|
||||||
|
recyclerView.apply {
|
||||||
|
adapter = albumAdapter(albums)
|
||||||
|
layoutManager = gridLayoutManager()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
|
private inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||||
fun bindView(list: List<Artist>, titleRes: Int) {
|
fun bindView(artists: List<Any>, titleRes: Int) {
|
||||||
if (list.isNotEmpty()) {
|
|
||||||
val manager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
|
|
||||||
val artistAdapter = ArtistAdapter(
|
|
||||||
activity,
|
|
||||||
list,
|
|
||||||
PreferenceUtil.homeGridStyle,
|
|
||||||
null
|
|
||||||
)
|
|
||||||
recyclerView.apply {
|
recyclerView.apply {
|
||||||
show()
|
layoutManager = linearLayoutManager()
|
||||||
layoutManager = manager
|
adapter = artistsAdapter(artists as List<Artist>)
|
||||||
adapter = artistAdapter
|
|
||||||
}
|
}
|
||||||
title.text = activity.getString(titleRes)
|
title.text = activity.getString(titleRes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private inner class SuggestionsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
private inner class SuggestionsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
private val images = listOf(
|
private val images = listOf(
|
||||||
|
@ -190,52 +161,50 @@ class HomeAdapter(
|
||||||
R.id.image8
|
R.id.image8
|
||||||
)
|
)
|
||||||
|
|
||||||
fun bindView(arrayList: List<Song>) {
|
fun bindView(songs: List<Any>) {
|
||||||
|
songs as List<Song>
|
||||||
val color = ThemeStore.accentColor(activity)
|
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 {
|
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, id ->
|
||||||
images.forEachIndexed { index, i ->
|
itemView.findViewById<View>(id).setOnClickListener {
|
||||||
itemView.findViewById<View>(i).setOnClickListener {
|
MusicPlayerRemote.playNext(songs[index])
|
||||||
MusicPlayerRemote.playNext(arrayList[index])
|
|
||||||
}
|
}
|
||||||
SongGlideRequest.Builder.from(Glide.with(activity), arrayList[index])
|
SongGlideRequest.Builder.from(Glide.with(activity), songs[index])
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.build()
|
.build()
|
||||||
.into(itemView.findViewById(i))
|
.into(itemView.findViewById(id))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
|
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
|
||||||
fun bindView(arrayList: List<Playlist>, titleRes: Int) {
|
fun bindView(songs: List<Any>, titleRes: Int) {
|
||||||
if (arrayList.isNotEmpty()) {
|
arrow.hide()
|
||||||
val songs = PlaylistSongsLoader.getPlaylistSongList(activity, arrayList[0])
|
|
||||||
if (songs.isNotEmpty()) {
|
|
||||||
recyclerView.apply {
|
recyclerView.apply {
|
||||||
show()
|
val songAdapter = SongAdapter(
|
||||||
val songAdapter =
|
activity,
|
||||||
SongAdapter(activity, songs, R.layout.item_album_card, null)
|
songs as MutableList<Song>,
|
||||||
layoutManager =
|
R.layout.item_album_card, null
|
||||||
GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false)
|
)
|
||||||
|
layoutManager = linearLayoutManager()
|
||||||
adapter = songAdapter
|
adapter = songAdapter
|
||||||
}
|
}
|
||||||
title.text = activity.getString(titleRes)
|
title.text = activity.getString(titleRes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class GenreViewHolder(itemView: View) : AbsHomeViewItem(itemView) {
|
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)
|
title.text = activity.getString(titleRes)
|
||||||
recyclerView.apply {
|
recyclerView.apply {
|
||||||
show()
|
layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.HORIZONTAL, false)
|
||||||
layoutManager = GridLayoutManager(activity, 2, GridLayoutManager.HORIZONTAL, false)
|
val genreAdapter =
|
||||||
val genreAdapter = GenreAdapter(activity, genres, R.layout.item_grid_genre)
|
GenreAdapter(activity, genres as List<Genre>, R.layout.item_grid_genre)
|
||||||
adapter = genreAdapter
|
adapter = genreAdapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,5 +213,38 @@ class HomeAdapter(
|
||||||
open inner class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
open inner class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView)
|
val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView)
|
||||||
val title: AppCompatTextView = itemView.findViewById(R.id.title)
|
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
|
package io.github.muntashirakon.music.adapter
|
||||||
|
|
||||||
import android.app.ActivityOptions
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
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 androidx.recyclerview.widget.RecyclerView
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
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.adapter.base.MediaEntryViewHolder
|
||||||
import io.github.muntashirakon.music.glide.AlbumGlideRequest
|
import io.github.muntashirakon.music.glide.AlbumGlideRequest
|
||||||
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||||
import io.github.muntashirakon.music.helper.menu.SongMenuHelper
|
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.*
|
||||||
import io.github.muntashirakon.music.model.smartplaylist.AbsSmartPlaylist
|
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.MusicUtil
|
||||||
import io.github.muntashirakon.music.util.NavigationUtil
|
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import android.util.Pair as UtilPair
|
|
||||||
|
|
||||||
class SearchAdapter(
|
class SearchAdapter(
|
||||||
private val activity: AppCompatActivity,
|
private val activity: FragmentActivity,
|
||||||
private var dataSet: List<Any>?
|
private var dataSet: List<Any>
|
||||||
) : RecyclerView.Adapter<SearchAdapter.ViewHolder>() {
|
) : RecyclerView.Adapter<SearchAdapter.ViewHolder>() {
|
||||||
|
|
||||||
fun swapDataSet(dataSet: MutableList<Any>) {
|
fun swapDataSet(dataSet: MutableList<Any>) {
|
||||||
|
@ -32,11 +31,11 @@ class SearchAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
if (dataSet!![position] is Album) return ALBUM
|
if (dataSet[position] is Album) return ALBUM
|
||||||
if (dataSet!![position] is Artist) return ARTIST
|
if (dataSet[position] is Artist) return ARTIST
|
||||||
if (dataSet!![position] is Genre) return GENRE
|
if (dataSet[position] is Genre) return GENRE
|
||||||
if (dataSet!![position] is Playlist) return PLAYLIST
|
if (dataSet[position] is Playlist) return PLAYLIST
|
||||||
return if (dataSet!![position] is Song) SONG else HEADER
|
return if (dataSet[position] is Song) SONG else HEADER
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
@ -57,35 +56,35 @@ class SearchAdapter(
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
when (getItemViewType(position)) {
|
when (getItemViewType(position)) {
|
||||||
ALBUM -> {
|
ALBUM -> {
|
||||||
val album = dataSet?.get(position) as Album
|
val album = dataSet.get(position) as Album
|
||||||
holder.title?.text = album.title
|
holder.title?.text = album.title
|
||||||
holder.text?.text = album.artistName
|
holder.text?.text = album.artistName
|
||||||
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
|
AlbumGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong())
|
||||||
.checkIgnoreMediaStore(activity).build().into(holder.image)
|
.checkIgnoreMediaStore(activity).build().into(holder.image)
|
||||||
}
|
}
|
||||||
ARTIST -> {
|
ARTIST -> {
|
||||||
val artist = dataSet?.get(position) as Artist
|
val artist = dataSet.get(position) as Artist
|
||||||
holder.title?.text = artist.name
|
holder.title?.text = artist.name
|
||||||
holder.text?.text = MusicUtil.getArtistInfoString(activity, artist)
|
holder.text?.text = MusicUtil.getArtistInfoString(activity, artist)
|
||||||
ArtistGlideRequest.Builder.from(Glide.with(activity), artist).build()
|
ArtistGlideRequest.Builder.from(Glide.with(activity), artist).build()
|
||||||
.into(holder.image)
|
.into(holder.image)
|
||||||
}
|
}
|
||||||
SONG -> {
|
SONG -> {
|
||||||
val song = dataSet?.get(position) as Song
|
val song = dataSet.get(position) as Song
|
||||||
holder.title?.text = song.title
|
holder.title?.text = song.title
|
||||||
holder.text?.text = song.albumName
|
holder.text?.text = song.albumName
|
||||||
}
|
}
|
||||||
GENRE -> {
|
GENRE -> {
|
||||||
val genre = dataSet?.get(position) as Genre
|
val genre = dataSet.get(position) as Genre
|
||||||
holder.title?.text = genre.name
|
holder.title?.text = genre.name
|
||||||
}
|
}
|
||||||
PLAYLIST -> {
|
PLAYLIST -> {
|
||||||
val playlist = dataSet?.get(position) as Playlist
|
val playlist = dataSet.get(position) as Playlist
|
||||||
holder.title?.text = playlist.name
|
holder.title?.text = playlist.name
|
||||||
holder.text?.text = MusicUtil.getPlaylistInfoString(activity, getSongs(playlist))
|
holder.text?.text = MusicUtil.getPlaylistInfoString(activity, getSongs(playlist))
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
holder.title?.text = dataSet?.get(position).toString()
|
holder.title?.text = dataSet.get(position).toString()
|
||||||
holder.title?.setTextColor(ThemeStore.accentColor(activity))
|
holder.title?.setTextColor(ThemeStore.accentColor(activity))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +93,7 @@ class SearchAdapter(
|
||||||
private fun getSongs(playlist: Playlist): java.util.ArrayList<Song> {
|
private fun getSongs(playlist: Playlist): java.util.ArrayList<Song> {
|
||||||
val songs = java.util.ArrayList<Song>()
|
val songs = java.util.ArrayList<Song>()
|
||||||
if (playlist is AbsSmartPlaylist) {
|
if (playlist is AbsSmartPlaylist) {
|
||||||
songs.addAll(playlist.getSongs(activity))
|
songs.addAll(playlist.getSongs())
|
||||||
} else {
|
} else {
|
||||||
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
|
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
|
||||||
}
|
}
|
||||||
|
@ -102,7 +101,7 @@ class SearchAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return dataSet!!.size
|
return dataSet.size
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(itemView: View, itemViewType: Int) : MediaEntryViewHolder(itemView) {
|
inner class ViewHolder(itemView: View, itemViewType: Int) : MediaEntryViewHolder(itemView) {
|
||||||
|
@ -113,7 +112,7 @@ class SearchAdapter(
|
||||||
menu?.visibility = View.VISIBLE
|
menu?.visibility = View.VISIBLE
|
||||||
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
|
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
|
||||||
override val song: Song
|
override val song: Song
|
||||||
get() = dataSet!![layoutPosition] as Song
|
get() = dataSet[layoutPosition] as Song
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
menu?.visibility = View.GONE
|
menu?.visibility = View.GONE
|
||||||
|
@ -130,27 +129,31 @@ class SearchAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClick(v: View?) {
|
override fun onClick(v: View?) {
|
||||||
val item = dataSet!![layoutPosition]
|
val item = dataSet[layoutPosition]
|
||||||
when (itemViewType) {
|
when (itemViewType) {
|
||||||
ALBUM -> {
|
ALBUM -> {
|
||||||
val options = ActivityOptions.makeSceneTransitionAnimation(
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
activity,
|
R.id.albumDetailsFragment,
|
||||||
UtilPair.create(image, activity.getString(R.string.transition_album_art))
|
bundleOf(EXTRA_ALBUM_ID to (item as Album).id)
|
||||||
)
|
)
|
||||||
NavigationUtil.goToAlbumOptions(activity, (item as Album).id, options)
|
|
||||||
}
|
}
|
||||||
ARTIST -> {
|
ARTIST -> {
|
||||||
val options = ActivityOptions.makeSceneTransitionAnimation(
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
activity,
|
R.id.artistDetailsFragment,
|
||||||
UtilPair.create(image, activity.getString(R.string.transition_artist_image))
|
bundleOf(EXTRA_ARTIST_ID to (item as Artist).id)
|
||||||
)
|
)
|
||||||
NavigationUtil.goToArtistOptions(activity, (item as Artist).id, options)
|
|
||||||
}
|
}
|
||||||
GENRE -> {
|
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 -> {
|
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 -> {
|
SONG -> {
|
||||||
val playList = ArrayList<Song>()
|
val playList = ArrayList<Song>()
|
||||||
|
|
|
@ -22,20 +22,20 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
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.R
|
||||||
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
||||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
||||||
import io.github.muntashirakon.music.glide.audiocover.AudioFileCover
|
import io.github.muntashirakon.music.glide.audiocover.AudioFileCover
|
||||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
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.MusicUtil
|
||||||
import io.github.muntashirakon.music.util.RetroUtil
|
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 me.zhanghai.android.fastscroll.PopupTextProvider
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import java.util.*
|
|
||||||
import kotlin.math.log10
|
import kotlin.math.log10
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
@ -135,9 +135,9 @@ class SongFileAdapter(
|
||||||
return getFileTitle(`object`)
|
return getFileTitle(`object`)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<File>) {
|
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<File>) {
|
||||||
if (callbacks == null) return
|
if (callbacks == null) return
|
||||||
callbacks.onMultipleItemAction(menuItem, selection)
|
callbacks.onMultipleItemAction(menuItem, selection as ArrayList<File>)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPopupText(position: Int): String {
|
override fun getPopupText(position: Int): String {
|
||||||
|
@ -148,13 +148,6 @@ class SongFileAdapter(
|
||||||
return MusicUtil.getSectionName(dataSet[position].name)
|
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) {
|
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
package io.github.muntashirakon.music.adapter.album
|
package io.github.muntashirakon.music.adapter.album
|
||||||
|
|
||||||
import android.app.ActivityOptions
|
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
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.R
|
||||||
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
||||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
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.AlbumGlideRequest
|
||||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
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.Album
|
||||||
import io.github.muntashirakon.music.model.Song
|
import io.github.muntashirakon.music.model.Song
|
||||||
import io.github.muntashirakon.music.util.MusicUtil
|
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.PreferenceUtil
|
||||||
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||||
|
|
||||||
open class AlbumAdapter(
|
open class AlbumAdapter(
|
||||||
protected val activity: AppCompatActivity,
|
protected val activity: FragmentActivity,
|
||||||
var dataSet: List<Album>,
|
var dataSet: List<Album>,
|
||||||
protected var itemLayoutRes: Int,
|
protected var itemLayoutRes: Int,
|
||||||
cabHolder: CabHolder?
|
cabHolder: CabHolder?,
|
||||||
|
private val albumClickListener: AlbumClickListener?
|
||||||
) : AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album>(
|
) : AbsMultiSelectAdapter<AlbumAdapter.ViewHolder, Album>(
|
||||||
activity,
|
activity,
|
||||||
cabHolder,
|
cabHolder,
|
||||||
|
@ -129,12 +129,12 @@ open class AlbumAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMultipleItemAction(
|
override fun onMultipleItemAction(
|
||||||
menuItem: MenuItem, selection: ArrayList<Album>
|
menuItem: MenuItem, selection: List<Album>
|
||||||
) {
|
) {
|
||||||
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
|
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>()
|
val songs = ArrayList<Song>()
|
||||||
for (album in albums) {
|
for (album in albums) {
|
||||||
songs.addAll(album.songs!!)
|
songs.addAll(album.songs!!)
|
||||||
|
@ -156,7 +156,6 @@ open class AlbumAdapter(
|
||||||
dataSet[position].year
|
dataSet[position].year
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return MusicUtil.getSectionName(sectionName)
|
return MusicUtil.getSectionName(sectionName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,16 +171,7 @@ open class AlbumAdapter(
|
||||||
if (isInQuickSelectMode) {
|
if (isInQuickSelectMode) {
|
||||||
toggleChecked(layoutPosition)
|
toggleChecked(layoutPosition)
|
||||||
} else {
|
} else {
|
||||||
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
|
image?.let { albumClickListener?.onAlbumClick(dataSet[layoutPosition].id, it) }
|
||||||
activity,
|
|
||||||
imageContainerCard ?: image,
|
|
||||||
activity.getString(R.string.transition_album_art)
|
|
||||||
)
|
|
||||||
NavigationUtil.goToAlbumOptions(
|
|
||||||
activity,
|
|
||||||
dataSet[layoutPosition].id,
|
|
||||||
activityOptions
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package io.github.muntashirakon.music.adapter.album
|
package io.github.muntashirakon.music.adapter.album
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.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.AlbumGlideRequest
|
||||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||||
import io.github.muntashirakon.music.helper.HorizontalAdapterHelper
|
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.model.Album
|
||||||
import io.github.muntashirakon.music.util.MusicUtil
|
import io.github.muntashirakon.music.util.MusicUtil
|
||||||
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
|
|
||||||
class HorizontalAlbumAdapter(
|
class HorizontalAlbumAdapter(
|
||||||
activity: AppCompatActivity,
|
activity: FragmentActivity,
|
||||||
dataSet: List<Album>,
|
dataSet: List<Album>,
|
||||||
cabHolder: CabHolder?
|
cabHolder: CabHolder?,
|
||||||
|
albumClickListener: AlbumClickListener
|
||||||
) : AlbumAdapter(
|
) : AlbumAdapter(
|
||||||
activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, cabHolder
|
activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, cabHolder, albumClickListener
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun createViewHolder(view: View, viewType: Int): ViewHolder {
|
override fun createViewHolder(view: View, viewType: Int): ViewHolder {
|
||||||
|
@ -40,11 +41,6 @@ class HorizontalAlbumAdapter(
|
||||||
.generatePalette(activity)
|
.generatePalette(activity)
|
||||||
.build()
|
.build()
|
||||||
.into(object : RetroMusicColoredTarget(holder.image!!) {
|
.into(object : RetroMusicColoredTarget(holder.image!!) {
|
||||||
override fun onLoadCleared(placeholder: Drawable?) {
|
|
||||||
super.onLoadCleared(placeholder)
|
|
||||||
//setColors(albumArtistFooterColor, holder)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||||
setColors(colors, holder)
|
setColors(colors, holder)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
package io.github.muntashirakon.music.adapter.artist
|
package io.github.muntashirakon.music.adapter.artist
|
||||||
|
|
||||||
import android.app.ActivityOptions
|
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
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.R
|
||||||
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
||||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
||||||
import io.github.muntashirakon.music.extensions.hide
|
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.ArtistGlideRequest
|
||||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||||
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
|
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.Artist
|
||||||
import io.github.muntashirakon.music.model.Song
|
import io.github.muntashirakon.music.model.Song
|
||||||
import io.github.muntashirakon.music.util.MusicUtil
|
import io.github.muntashirakon.music.util.MusicUtil
|
||||||
import io.github.muntashirakon.music.util.NavigationUtil
|
|
||||||
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class ArtistAdapter(
|
class ArtistAdapter(
|
||||||
val activity: AppCompatActivity,
|
val activity: FragmentActivity,
|
||||||
var dataSet: List<Artist>,
|
var dataSet: List<Artist>,
|
||||||
var itemLayoutRes: Int,
|
var itemLayoutRes: Int,
|
||||||
cabHolder: CabHolder?
|
cabHolder: CabHolder?,
|
||||||
|
private val artistClickListener: ArtistClickListener
|
||||||
) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>(
|
) : AbsMultiSelectAdapter<ArtistAdapter.ViewHolder, Artist>(
|
||||||
activity, cabHolder, R.menu.menu_media_selection
|
activity, cabHolder, R.menu.menu_media_selection
|
||||||
), PopupTextProvider {
|
), PopupTextProvider {
|
||||||
|
@ -106,12 +107,12 @@ class ArtistAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMultipleItemAction(
|
override fun onMultipleItemAction(
|
||||||
menuItem: MenuItem, selection: ArrayList<Artist>
|
menuItem: MenuItem, selection: List<Artist>
|
||||||
) {
|
) {
|
||||||
SongsMenuHelper.handleMenuClick(activity, getSongList(selection), menuItem.itemId)
|
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>()
|
val songs = ArrayList<Song>()
|
||||||
for (artist in artists) {
|
for (artist in artists) {
|
||||||
songs.addAll(artist.songs) // maybe async in future?
|
songs.addAll(artist.songs) // maybe async in future?
|
||||||
|
@ -130,7 +131,6 @@ class ArtistAdapter(
|
||||||
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setImageTransitionName(activity.getString(R.string.transition_artist_image))
|
|
||||||
menu?.visibility = View.GONE
|
menu?.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,14 +139,13 @@ class ArtistAdapter(
|
||||||
if (isInQuickSelectMode) {
|
if (isInQuickSelectMode) {
|
||||||
toggleChecked(layoutPosition)
|
toggleChecked(layoutPosition)
|
||||||
} else {
|
} else {
|
||||||
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
|
image?.let {
|
||||||
activity,
|
ViewCompat.setTransitionName(
|
||||||
imageContainerCard ?: image,
|
it,
|
||||||
activity.getString(R.string.transition_artist_image)
|
activity.getString(R.string.transition_artist_image)
|
||||||
)
|
)
|
||||||
NavigationUtil.goToArtistOptions(
|
artistClickListener.onArtist(dataSet[layoutPosition].id, it)
|
||||||
activity, dataSet[layoutPosition].id, activityOptions
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.afollestad.materialcab.MaterialCab;
|
import com.afollestad.materialcab.MaterialCab;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import io.github.muntashirakon.music.R;
|
import io.github.muntashirakon.music.R;
|
||||||
import io.github.muntashirakon.music.interfaces.CabHolder;
|
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 CabHolder cabHolder;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private MaterialCab cab;
|
private MaterialCab cab;
|
||||||
private ArrayList<I> checked;
|
private List<I> checked;
|
||||||
private int menuRes;
|
private int menuRes;
|
||||||
|
|
||||||
public AbsMultiSelectAdapter(@NonNull Context context, @Nullable CabHolder cabHolder, @MenuRes 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();
|
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) {
|
protected void setMultiSelectMenuRes(@MenuRes int menuRes) {
|
||||||
this.menuRes = menuRes;
|
this.menuRes = menuRes;
|
||||||
|
|
|
@ -9,11 +9,14 @@ import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.appcompat.widget.PopupMenu
|
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.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
import code.name.monkey.appthemehelper.util.TintHelper
|
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.R
|
||||||
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
||||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
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.PlaylistMenuHelper
|
||||||
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
|
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper
|
||||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
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.AbsCustomPlaylist
|
||||||
import io.github.muntashirakon.music.model.Playlist
|
import io.github.muntashirakon.music.model.Playlist
|
||||||
import io.github.muntashirakon.music.model.Song
|
import io.github.muntashirakon.music.model.Song
|
||||||
import io.github.muntashirakon.music.model.smartplaylist.AbsSmartPlaylist
|
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.AutoGeneratedPlaylistBitmap
|
||||||
import io.github.muntashirakon.music.util.MusicUtil
|
import io.github.muntashirakon.music.util.MusicUtil
|
||||||
import io.github.muntashirakon.music.util.NavigationUtil
|
|
||||||
import io.github.muntashirakon.music.util.RetroColorUtil
|
import io.github.muntashirakon.music.util.RetroColorUtil
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PlaylistAdapter(
|
class PlaylistAdapter(
|
||||||
private val activity: AppCompatActivity,
|
private val activity: FragmentActivity,
|
||||||
var dataSet: List<Playlist>,
|
var dataSet: List<Playlist>,
|
||||||
private var itemLayoutRes: Int,
|
private var itemLayoutRes: Int,
|
||||||
cabHolder: CabHolder?
|
cabHolder: CabHolder?
|
||||||
|
@ -120,7 +122,7 @@ class PlaylistAdapter(
|
||||||
return playlist.name
|
return playlist.name
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<Playlist>) {
|
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Playlist>) {
|
||||||
when (menuItem.itemId) {
|
when (menuItem.itemId) {
|
||||||
else -> SongsMenuHelper.handleMenuClick(
|
else -> SongsMenuHelper.handleMenuClick(
|
||||||
activity,
|
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>()
|
val songs = ArrayList<Song>()
|
||||||
for (playlist in playlists) {
|
for (playlist in playlists) {
|
||||||
if (playlist is AbsCustomPlaylist) {
|
if (playlist is AbsCustomPlaylist) {
|
||||||
songs.addAll(playlist.getSongs(activity))
|
songs.addAll(playlist.songs())
|
||||||
} else {
|
} else {
|
||||||
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
|
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
|
||||||
}
|
}
|
||||||
|
@ -142,12 +144,12 @@ class PlaylistAdapter(
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSongs(playlist: Playlist): ArrayList<Song> {
|
private fun getSongs(playlist: Playlist): List<Song> {
|
||||||
val songs = ArrayList<Song>()
|
val songs = ArrayList<Song>()
|
||||||
if (playlist is AbsSmartPlaylist) {
|
if (playlist is AbsSmartPlaylist) {
|
||||||
songs.addAll(playlist.getSongs(activity))
|
songs.addAll(playlist.songs())
|
||||||
} else {
|
} else {
|
||||||
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
|
songs.addAll(playlist.getSongs())
|
||||||
}
|
}
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
|
@ -165,9 +167,7 @@ class PlaylistAdapter(
|
||||||
val popupMenu = PopupMenu(activity, view)
|
val popupMenu = PopupMenu(activity, view)
|
||||||
popupMenu.inflate(R.menu.menu_item_playlist)
|
popupMenu.inflate(R.menu.menu_item_playlist)
|
||||||
popupMenu.setOnMenuItemClickListener { item ->
|
popupMenu.setOnMenuItemClickListener { item ->
|
||||||
PlaylistMenuHelper.handleMenuClick(
|
PlaylistMenuHelper.handleMenuClick(activity, dataSet[layoutPosition], item)
|
||||||
activity, dataSet[layoutPosition], item
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
popupMenu.show()
|
popupMenu.show()
|
||||||
}
|
}
|
||||||
|
@ -182,8 +182,10 @@ class PlaylistAdapter(
|
||||||
if (isInQuickSelectMode) {
|
if (isInQuickSelectMode) {
|
||||||
toggleChecked(layoutPosition)
|
toggleChecked(layoutPosition)
|
||||||
} else {
|
} else {
|
||||||
val playlist = dataSet[layoutPosition]
|
activity.findNavController(R.id.fragment_container).navigate(
|
||||||
NavigationUtil.goToPlaylistNew(activity, playlist)
|
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.MenuItem
|
||||||
import android.view.View
|
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
|
||||||
import io.github.muntashirakon.music.R.menu
|
import io.github.muntashirakon.music.R.menu
|
||||||
import io.github.muntashirakon.music.dialogs.RemoveFromPlaylistDialog
|
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.PlaylistSong
|
||||||
import io.github.muntashirakon.music.model.Song
|
import io.github.muntashirakon.music.model.Song
|
||||||
import io.github.muntashirakon.music.util.ViewUtil
|
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(
|
class OrderablePlaylistSongAdapter(
|
||||||
activity: AppCompatActivity,
|
activity: FragmentActivity,
|
||||||
dataSet: ArrayList<Song>,
|
dataSet: ArrayList<Song>,
|
||||||
itemLayoutRes: Int,
|
itemLayoutRes: Int,
|
||||||
cabHolder: CabHolder?,
|
cabHolder: CabHolder?,
|
||||||
private val onMoveItemListener: OnMoveItemListener?
|
private val onMoveItemListener: OnMoveItemListener?
|
||||||
) : PlaylistSongAdapter(
|
) : SongAdapter(
|
||||||
activity, dataSet, itemLayoutRes, cabHolder
|
activity,
|
||||||
|
dataSet,
|
||||||
|
itemLayoutRes,
|
||||||
|
cabHolder
|
||||||
), DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> {
|
), DraggableItemAdapter<OrderablePlaylistSongAdapter.ViewHolder> {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -48,7 +51,7 @@ class OrderablePlaylistSongAdapter(
|
||||||
return long
|
return long
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList<Song>) {
|
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) {
|
||||||
when (menuItem.itemId) {
|
when (menuItem.itemId) {
|
||||||
R.id.action_remove_from_playlist -> {
|
R.id.action_remove_from_playlist -> {
|
||||||
RemoveFromPlaylistDialog.create(selection as ArrayList<PlaylistSong>)
|
RemoveFromPlaylistDialog.create(selection as ArrayList<PlaylistSong>)
|
||||||
|
@ -91,7 +94,7 @@ class OrderablePlaylistSongAdapter(
|
||||||
fun onMoveItem(fromPosition: Int, toPosition: Int)
|
fun onMoveItem(fromPosition: Int, toPosition: Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ViewHolder(itemView: View) : PlaylistSongAdapter.ViewHolder(itemView),
|
inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView),
|
||||||
DraggableItemViewHolder {
|
DraggableItemViewHolder {
|
||||||
@DraggableItemStateFlags
|
@DraggableItemStateFlags
|
||||||
private var mDragStateFlags: Int = 0
|
private var mDragStateFlags: Int = 0
|
||||||
|
@ -132,8 +135,4 @@ class OrderablePlaylistSongAdapter(
|
||||||
mDragStateFlags = flags
|
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.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import io.github.muntashirakon.music.R
|
import androidx.fragment.app.FragmentActivity
|
||||||
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 com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
|
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
|
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags
|
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.SwipeResultActionDefault
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem
|
import com.h6ah4i.android.widget.advrecyclerview.swipeable.action.SwipeResultActionRemoveItem
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.swipeable.annotation.SwipeableItemResults
|
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
|
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||||
|
|
||||||
class PlayingQueueAdapter(
|
class PlayingQueueAdapter(
|
||||||
|
@ -192,7 +193,7 @@ class PlayingQueueAdapter(
|
||||||
internal class SwipedResultActionRemoveItem(
|
internal class SwipedResultActionRemoveItem(
|
||||||
private val adapter: PlayingQueueAdapter,
|
private val adapter: PlayingQueueAdapter,
|
||||||
private val position: Int,
|
private val position: Int,
|
||||||
private val activity: AppCompatActivity
|
private val activity: FragmentActivity
|
||||||
) : SwipeResultActionRemoveItem() {
|
) : SwipeResultActionRemoveItem() {
|
||||||
|
|
||||||
private var songToRemove: Song? = null
|
private var songToRemove: Song? = null
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
package io.github.muntashirakon.music.adapter.song
|
package io.github.muntashirakon.music.adapter.song
|
||||||
|
|
||||||
import android.app.ActivityOptions
|
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
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.R
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
import io.github.muntashirakon.music.interfaces.CabHolder
|
||||||
import io.github.muntashirakon.music.model.Song
|
import io.github.muntashirakon.music.model.Song
|
||||||
import io.github.muntashirakon.music.util.NavigationUtil
|
|
||||||
import com.google.android.material.button.MaterialButton
|
|
||||||
|
|
||||||
open class PlaylistSongAdapter(
|
open class PlaylistSongAdapter(
|
||||||
activity: AppCompatActivity,
|
activity: AppCompatActivity,
|
||||||
|
@ -57,19 +58,14 @@ open class PlaylistSongAdapter(
|
||||||
|
|
||||||
override fun onSongMenuItemClick(item: MenuItem): Boolean {
|
override fun onSongMenuItemClick(item: MenuItem): Boolean {
|
||||||
if (item.itemId == R.id.action_go_to_album) {
|
if (item.itemId == R.id.action_go_to_album) {
|
||||||
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
|
activity.findNavController(R.id.fragment_container)
|
||||||
activity,
|
.navigate(
|
||||||
imageContainerCard ?: image,
|
R.id.albumDetailsFragment,
|
||||||
activity.getString(R.string.transition_album_art)
|
bundleOf(EXTRA_ALBUM_ID to song.albumId)
|
||||||
)
|
)
|
||||||
NavigationUtil.goToAlbumOptions(activity, song.albumId, activityOptions)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return super.onSongMenuItemClick(item)
|
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.LayoutInflater
|
||||||
import android.view.ViewGroup
|
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.interfaces.CabHolder
|
||||||
import io.github.muntashirakon.music.model.Song
|
import io.github.muntashirakon.music.model.Song
|
||||||
import io.github.muntashirakon.music.util.MusicUtil
|
import io.github.muntashirakon.music.util.MusicUtil
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class SimpleSongAdapter(
|
class SimpleSongAdapter(
|
||||||
context: AppCompatActivity,
|
context: FragmentActivity,
|
||||||
songs: ArrayList<Song>,
|
songs: ArrayList<Song>,
|
||||||
layoutRes: Int,
|
layoutRes: Int,
|
||||||
cabHolder: CabHolder?
|
cabHolder: CabHolder?
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
package io.github.muntashirakon.music.adapter.song
|
package io.github.muntashirakon.music.adapter.song
|
||||||
|
|
||||||
import android.app.ActivityOptions
|
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
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.R
|
||||||
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
import io.github.muntashirakon.music.adapter.base.AbsMultiSelectAdapter
|
||||||
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
|
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.interfaces.CabHolder
|
||||||
import io.github.muntashirakon.music.model.Song
|
import io.github.muntashirakon.music.model.Song
|
||||||
import io.github.muntashirakon.music.util.MusicUtil
|
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.PreferenceUtil
|
||||||
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
||||||
import com.afollestad.materialcab.MaterialCab
|
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,7 +35,7 @@ import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||||
*/
|
*/
|
||||||
|
|
||||||
open class SongAdapter(
|
open class SongAdapter(
|
||||||
protected val activity: AppCompatActivity,
|
protected val activity: FragmentActivity,
|
||||||
var dataSet: MutableList<Song>,
|
var dataSet: MutableList<Song>,
|
||||||
protected var itemLayoutRes: Int,
|
protected var itemLayoutRes: Int,
|
||||||
cabHolder: CabHolder?,
|
cabHolder: CabHolder?,
|
||||||
|
@ -132,7 +133,7 @@ open class SongAdapter(
|
||||||
return song.title
|
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)
|
SongsMenuHelper.handleMenuClick(activity, selection, menuItem.itemId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +148,6 @@ open class SongAdapter(
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return MusicUtil.getSectionName(sectionName)
|
return MusicUtil.getSectionName(sectionName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,12 +175,11 @@ open class SongAdapter(
|
||||||
if (image != null && image!!.visibility == View.VISIBLE) {
|
if (image != null && image!!.visibility == View.VISIBLE) {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_go_to_album -> {
|
R.id.action_go_to_album -> {
|
||||||
val activityOptions = ActivityOptions.makeSceneTransitionAnimation(
|
activity.findNavController(R.id.fragment_container)
|
||||||
activity,
|
.navigate(
|
||||||
imageContainerCard ?: image,
|
R.id.albumDetailsFragment,
|
||||||
activity.getString(R.string.transition_album_art)
|
bundleOf(EXTRA_ALBUM_ID to song.albumId)
|
||||||
)
|
)
|
||||||
NavigationUtil.goToAlbumOptions(activity, song.albumId, activityOptions)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,15 +17,13 @@ package io.github.muntashirakon.music.appshortcuts
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
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.LastAddedShortcutType
|
||||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.SearchShortCutType
|
|
||||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.ShuffleAllShortcutType
|
import io.github.muntashirakon.music.appshortcuts.shortcuttype.ShuffleAllShortcutType
|
||||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.TopTracksShortcutType
|
import io.github.muntashirakon.music.appshortcuts.shortcuttype.TopTracksShortcutType
|
||||||
import io.github.muntashirakon.music.model.Playlist
|
import io.github.muntashirakon.music.model.Playlist
|
||||||
import io.github.muntashirakon.music.model.smartplaylist.LastAddedPlaylist
|
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.ShuffleAllPlaylist
|
||||||
|
import io.github.muntashirakon.music.model.smartplaylist.TopTracksPlaylist
|
||||||
import io.github.muntashirakon.music.service.MusicService
|
import io.github.muntashirakon.music.service.MusicService
|
||||||
import io.github.muntashirakon.music.service.MusicService.*
|
import io.github.muntashirakon.music.service.MusicService.*
|
||||||
|
|
||||||
|
@ -45,26 +43,22 @@ class AppShortcutLauncherActivity : Activity() {
|
||||||
when (shortcutType) {
|
when (shortcutType) {
|
||||||
SHORTCUT_TYPE_SHUFFLE_ALL -> {
|
SHORTCUT_TYPE_SHUFFLE_ALL -> {
|
||||||
startServiceWithPlaylist(
|
startServiceWithPlaylist(
|
||||||
MusicService.SHUFFLE_MODE_SHUFFLE, ShuffleAllPlaylist(applicationContext)
|
SHUFFLE_MODE_SHUFFLE, ShuffleAllPlaylist()
|
||||||
)
|
)
|
||||||
DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.id)
|
DynamicShortcutManager.reportShortcutUsed(this, ShuffleAllShortcutType.id)
|
||||||
}
|
}
|
||||||
SHORTCUT_TYPE_TOP_TRACKS -> {
|
SHORTCUT_TYPE_TOP_TRACKS -> {
|
||||||
startServiceWithPlaylist(
|
startServiceWithPlaylist(
|
||||||
MusicService.SHUFFLE_MODE_NONE, MyTopTracksPlaylist(applicationContext)
|
SHUFFLE_MODE_NONE, TopTracksPlaylist()
|
||||||
)
|
)
|
||||||
DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.id)
|
DynamicShortcutManager.reportShortcutUsed(this, TopTracksShortcutType.id)
|
||||||
}
|
}
|
||||||
SHORTCUT_TYPE_LAST_ADDED -> {
|
SHORTCUT_TYPE_LAST_ADDED -> {
|
||||||
startServiceWithPlaylist(
|
startServiceWithPlaylist(
|
||||||
MusicService.SHUFFLE_MODE_NONE, LastAddedPlaylist(applicationContext)
|
SHUFFLE_MODE_NONE, LastAddedPlaylist()
|
||||||
)
|
)
|
||||||
DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.id)
|
DynamicShortcutManager.reportShortcutUsed(this, LastAddedShortcutType.id)
|
||||||
}
|
}
|
||||||
SHORTCUT_TYPE_SEARCH -> {
|
|
||||||
startActivity(Intent(this, SearchActivity::class.java))
|
|
||||||
DynamicShortcutManager.reportShortcutUsed(this, SearchShortCutType.id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
@ -87,7 +81,6 @@ class AppShortcutLauncherActivity : Activity() {
|
||||||
const val SHORTCUT_TYPE_SHUFFLE_ALL = 0
|
const val SHORTCUT_TYPE_SHUFFLE_ALL = 0
|
||||||
const val SHORTCUT_TYPE_TOP_TRACKS = 1
|
const val SHORTCUT_TYPE_TOP_TRACKS = 1
|
||||||
const val SHORTCUT_TYPE_LAST_ADDED = 2
|
const val SHORTCUT_TYPE_LAST_ADDED = 2
|
||||||
const val SHORTCUT_TYPE_SEARCH = 3
|
|
||||||
const val SHORTCUT_TYPE_NONE = 4
|
const val SHORTCUT_TYPE_NONE = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import android.content.pm.ShortcutManager
|
||||||
import android.graphics.drawable.Icon
|
import android.graphics.drawable.Icon
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.LastAddedShortcutType
|
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.ShuffleAllShortcutType
|
||||||
import io.github.muntashirakon.music.appshortcuts.shortcuttype.TopTracksShortcutType
|
import io.github.muntashirakon.music.appshortcuts.shortcuttype.TopTracksShortcutType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -34,11 +33,9 @@ class DynamicShortcutManager(private val context: Context) {
|
||||||
|
|
||||||
private val defaultShortcuts: List<ShortcutInfo>
|
private val defaultShortcuts: List<ShortcutInfo>
|
||||||
get() = Arrays.asList(
|
get() = Arrays.asList(
|
||||||
SearchShortCutType(context).shortcutInfo,
|
|
||||||
ShuffleAllShortcutType(context).shortcutInfo,
|
ShuffleAllShortcutType(context).shortcutInfo,
|
||||||
TopTracksShortcutType(context).shortcutInfo,
|
TopTracksShortcutType(context).shortcutInfo,
|
||||||
LastAddedShortcutType(context).shortcutInfo
|
LastAddedShortcutType(context).shortcutInfo
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun initDynamicShortcuts() {
|
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.colorButtons
|
||||||
import io.github.muntashirakon.music.extensions.extraNotNull
|
import io.github.muntashirakon.music.extensions.extraNotNull
|
||||||
import io.github.muntashirakon.music.extensions.materialDialog
|
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.model.Song
|
||||||
|
import io.github.muntashirakon.music.repository.PlaylistRepository
|
||||||
import io.github.muntashirakon.music.util.PlaylistsUtil
|
import io.github.muntashirakon.music.util.PlaylistsUtil
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
class AddToPlaylistDialog : DialogFragment() {
|
class AddToPlaylistDialog : DialogFragment() {
|
||||||
|
private val playlistRepository by inject<PlaylistRepository>()
|
||||||
override fun onCreateDialog(
|
override fun onCreateDialog(
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): Dialog {
|
): Dialog {
|
||||||
val playlists = PlaylistLoader.getAllPlaylists(requireContext())
|
val playlists = playlistRepository.playlists()
|
||||||
val playlistNames = mutableListOf<String>()
|
val playlistNames = mutableListOf<String>()
|
||||||
playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist))
|
playlistNames.add(requireContext().resources.getString(R.string.action_new_playlist))
|
||||||
for (p in playlists) {
|
for (p in playlists) {
|
||||||
playlistNames.add(p.name)
|
playlistNames.add(p.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return materialDialog(R.string.add_playlist_title)
|
return materialDialog(R.string.add_playlist_title)
|
||||||
.setItems(playlistNames.toTypedArray()) { _, which ->
|
.setItems(playlistNames.toTypedArray()) { _, which ->
|
||||||
val songs = extraNotNull<ArrayList<Song>>(EXTRA_SONG).value
|
val songs = extraNotNull<ArrayList<Song>>(EXTRA_SONG).value
|
||||||
|
|
|
@ -98,7 +98,9 @@ class DeleteSongsDialog : DialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteSongs(songs: List<Song>, safUris: List<Uri>?) {
|
fun deleteSongs(songs: List<Song>, safUris: List<Uri>?) {
|
||||||
MusicUtil.deleteTracks(requireActivity(), songs, safUris) { this.dismiss() }
|
MusicUtil.deleteTracks(requireActivity(), songs, safUris, Runnable {
|
||||||
|
dismiss()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -22,11 +22,17 @@ import android.widget.Button
|
||||||
import android.widget.CheckBox
|
import android.widget.CheckBox
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import androidx.annotation.AttrRes
|
import androidx.annotation.AttrRes
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
import code.name.monkey.appthemehelper.util.ColorUtil
|
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.App
|
||||||
import io.github.muntashirakon.music.R
|
import io.github.muntashirakon.music.R
|
||||||
|
|
||||||
|
@ -84,3 +90,44 @@ fun SeekBar.addAccentColor() {
|
||||||
fun Button.accentTextColor() {
|
fun Button.accentTextColor() {
|
||||||
setTextColor(ThemeStore.accentColor(App.getContext()))
|
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.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.IdRes
|
||||||
import androidx.annotation.IntegerRes
|
import androidx.annotation.IntegerRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
|
@ -51,5 +54,23 @@ fun AppCompatActivity.currentFragment(navHostId: Int): Fragment? {
|
||||||
val navHostFragment: NavHostFragment =
|
val navHostFragment: NavHostFragment =
|
||||||
supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
|
||||||
navHostFragment.targetFragment
|
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.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
|
|
||||||
fun Fragment.navigate(@IdRes id: Int) = findNavController().navigate(id)
|
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
|
val fragment = childFragmentManager.findFragmentById(id) as NavHostFragment
|
||||||
return fragment.navController
|
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
|
val fragment = supportFragmentManager.findFragmentById(id) as NavHostFragment
|
||||||
return fragment.navController
|
return fragment.navController
|
||||||
}
|
}
|
|
@ -14,13 +14,10 @@
|
||||||
|
|
||||||
package io.github.muntashirakon.music.extensions
|
package io.github.muntashirakon.music.extensions
|
||||||
|
|
||||||
import android.content.res.ColorStateList
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.SeekBar
|
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.util.TintHelper
|
import code.name.monkey.appthemehelper.util.TintHelper
|
||||||
|
@ -48,9 +45,3 @@ fun EditText.appHandleColor(): EditText {
|
||||||
TintHelper.colorHandles(this, ThemeStore.accentColor(context))
|
TintHelper.colorHandles(this, ThemeStore.accentColor(context))
|
||||||
return this
|
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.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import io.github.muntashirakon.music.adapter.HomeAdapter
|
|
||||||
import io.github.muntashirakon.music.fragments.ReloadType.*
|
import io.github.muntashirakon.music.fragments.ReloadType.*
|
||||||
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
||||||
import io.github.muntashirakon.music.model.*
|
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.Deferred
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class LibraryViewModel(
|
class LibraryViewModel(
|
||||||
private val repository: RepositoryImpl
|
private val realRepository: RealRepository
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
|
private val paletteColor = MutableLiveData<Int>()
|
||||||
private val albums = MutableLiveData<List<Album>>()
|
private val albums = MutableLiveData<List<Album>>()
|
||||||
private val songs = MutableLiveData<List<Song>>()
|
private val songs = MutableLiveData<List<Song>>()
|
||||||
private val artists = MutableLiveData<List<Artist>>()
|
private val artists = MutableLiveData<List<Artist>>()
|
||||||
private val playlists = MutableLiveData<List<Playlist>>()
|
private val playlists = MutableLiveData<List<Playlist>>()
|
||||||
private val genres = MutableLiveData<List<Genre>>()
|
private val genres = MutableLiveData<List<Genre>>()
|
||||||
private val home = MutableLiveData<List<Home>>()
|
private val home = MutableLiveData<List<Home>>()
|
||||||
private val paletteColor = MutableLiveData<Int>()
|
|
||||||
|
|
||||||
val paletteColorLiveData: LiveData<Int> = paletteColor
|
val paletteColorLiveData: LiveData<Int> = paletteColor
|
||||||
val homeLiveData: LiveData<List<Home>> = home
|
val homeLiveData: LiveData<List<Home>> = home
|
||||||
|
@ -46,59 +45,36 @@ class LibraryViewModel(
|
||||||
artists.value = loadArtists.await()
|
artists.value = loadArtists.await()
|
||||||
playlists.value = loadPlaylists.await()
|
playlists.value = loadPlaylists.await()
|
||||||
genres.value = loadGenres.await()
|
genres.value = loadGenres.await()
|
||||||
loadHomeSections()
|
home.value = loadHome.await()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadHomeSections() = viewModelScope.launch {
|
private val loadHome: Deferred<List<Home>>
|
||||||
val list = mutableListOf<Home>()
|
get() = viewModelScope.async { realRepository.homeSections() }
|
||||||
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 loadSongs: Deferred<List<Song>>
|
private val loadSongs: Deferred<List<Song>>
|
||||||
get() = viewModelScope.async(IO) {
|
get() = viewModelScope.async(IO) { realRepository.allSongs() }
|
||||||
repository.allSongs()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val loadAlbums: Deferred<List<Album>>
|
private val loadAlbums: Deferred<List<Album>>
|
||||||
get() = viewModelScope.async(IO) {
|
get() = viewModelScope.async(IO) {
|
||||||
repository.allAlbums()
|
realRepository.allAlbums()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val loadArtists: Deferred<List<Artist>>
|
private val loadArtists: Deferred<List<Artist>>
|
||||||
get() = viewModelScope.async(IO) {
|
get() = viewModelScope.async(IO) {
|
||||||
repository.allArtists()
|
realRepository.albumArtists()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val loadPlaylists: Deferred<List<Playlist>>
|
private val loadPlaylists: Deferred<List<Playlist>>
|
||||||
get() = viewModelScope.async(IO) {
|
get() = viewModelScope.async(IO) {
|
||||||
repository.allPlaylists()
|
realRepository.allPlaylists()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val loadGenres: Deferred<List<Genre>>
|
private val loadGenres: Deferred<List<Genre>>
|
||||||
get() = viewModelScope.async(IO) {
|
get() = viewModelScope.async(IO) {
|
||||||
repository.allGenres()
|
realRepository.allGenres()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun forceReload(reloadType: ReloadType) = viewModelScope.launch {
|
fun forceReload(reloadType: ReloadType) = viewModelScope.launch {
|
||||||
when (reloadType) {
|
when (reloadType) {
|
||||||
Songs -> songs.value = loadSongs.await()
|
Songs -> songs.value = loadSongs.await()
|
||||||
|
@ -114,15 +90,37 @@ class LibraryViewModel(
|
||||||
|
|
||||||
override fun onMediaStoreChanged() {
|
override fun onMediaStoreChanged() {
|
||||||
loadLibraryContent()
|
loadLibraryContent()
|
||||||
|
println("onMediaStoreChanged")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceConnected() {}
|
|
||||||
override fun onServiceDisconnected() {}
|
override fun onServiceConnected() {
|
||||||
override fun onQueueChanged() {}
|
println("onServiceConnected")
|
||||||
override fun onPlayingMetaChanged() {}
|
}
|
||||||
override fun onPlayStateChanged() {}
|
|
||||||
override fun onRepeatModeChanged() {}
|
override fun onServiceDisconnected() {
|
||||||
override fun onShuffleModeChanged() {}
|
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.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.app.ShareCompat
|
import androidx.core.app.ShareCompat
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
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.Gson
|
||||||
import com.google.gson.reflect.TypeToken
|
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_credit.*
|
||||||
import kotlinx.android.synthetic.main.card_other.*
|
import kotlinx.android.synthetic.main.card_other.*
|
||||||
import kotlinx.android.synthetic.main.card_retro_info.*
|
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.io.IOException
|
||||||
import java.nio.charset.StandardCharsets
|
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?
|
private val contributorsJson: String?
|
||||||
get() {
|
get() {
|
||||||
val json: String
|
val json: String
|
||||||
try {
|
try {
|
||||||
val inputStream = assets.open("contributors.json")
|
val inputStream = requireActivity().assets.open("contributors.json")
|
||||||
val size = inputStream.available()
|
val size = inputStream.available()
|
||||||
val buffer = ByteArray(size)
|
val buffer = ByteArray(size)
|
||||||
inputStream.read(buffer)
|
inputStream.read(buffer)
|
||||||
|
@ -53,27 +48,6 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
||||||
return json
|
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) {
|
private fun openUrl(url: String) {
|
||||||
val i = Intent(Intent.ACTION_VIEW)
|
val i = Intent(Intent.ACTION_VIEW)
|
||||||
|
@ -89,6 +63,7 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
||||||
appRate.setOnClickListener(this)
|
appRate.setOnClickListener(this)
|
||||||
appTranslation.setOnClickListener(this)
|
appTranslation.setOnClickListener(this)
|
||||||
appShare.setOnClickListener(this)
|
appShare.setOnClickListener(this)
|
||||||
|
donateLink.setOnClickListener(this)
|
||||||
instagramLink.setOnClickListener(this)
|
instagramLink.setOnClickListener(this)
|
||||||
twitterLink.setOnClickListener(this)
|
twitterLink.setOnClickListener(this)
|
||||||
changelog.setOnClickListener(this)
|
changelog.setOnClickListener(this)
|
||||||
|
@ -99,25 +74,26 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
||||||
|
|
||||||
override fun onClick(view: View) {
|
override fun onClick(view: View) {
|
||||||
when (view.id) {
|
when (view.id) {
|
||||||
R.id.pinterestLink -> openUrl(PINTEREST)
|
R.id.pinterestLink -> openUrl(Constants.PINTEREST)
|
||||||
R.id.faqLink -> openUrl(FAQ_LINK)
|
R.id.faqLink -> openUrl(Constants.FAQ_LINK)
|
||||||
R.id.telegramLink -> openUrl(APP_TELEGRAM_LINK)
|
R.id.telegramLink -> openUrl(Constants.APP_TELEGRAM_LINK)
|
||||||
R.id.appGithub -> openUrl(GITHUB_PROJECT)
|
R.id.appGithub -> openUrl(Constants.GITHUB_PROJECT)
|
||||||
R.id.appTranslation -> openUrl(TRANSLATE)
|
R.id.appTranslation -> openUrl(Constants.TRANSLATE)
|
||||||
R.id.appRate -> openUrl(RATE_ON_GOOGLE_PLAY)
|
R.id.appRate -> openUrl(Constants.RATE_ON_GOOGLE_PLAY)
|
||||||
R.id.appShare -> shareApp()
|
R.id.appShare -> shareApp()
|
||||||
R.id.instagramLink -> openUrl(APP_INSTAGRAM_LINK)
|
R.id.instagramLink -> openUrl(Constants.APP_INSTAGRAM_LINK)
|
||||||
R.id.twitterLink -> openUrl(APP_TWITTER_LINK)
|
R.id.twitterLink -> openUrl(Constants.APP_TWITTER_LINK)
|
||||||
R.id.changelog -> openUrl(TELEGRAM_CHANGE_LOG)
|
R.id.changelog -> openUrl(Constants.TELEGRAM_CHANGE_LOG)
|
||||||
R.id.openSource -> NavigationUtil.goToOpenSource(this)
|
R.id.openSource -> NavigationUtil.goToOpenSource(requireActivity())
|
||||||
R.id.bugReportLink -> NavigationUtil.bugReport(this)
|
R.id.bugReportLink -> NavigationUtil.bugReport(requireActivity())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAppVersion(): String {
|
private fun getAppVersion(): String {
|
||||||
return try {
|
return try {
|
||||||
val isPro = "Pro"
|
val isPro = "Pro"
|
||||||
val packageInfo = packageManager.getPackageInfo(packageName, 0)
|
val packageInfo =
|
||||||
|
requireActivity().packageManager.getPackageInfo(requireActivity().packageName, 0)
|
||||||
"${packageInfo.versionName} $isPro"
|
"${packageInfo.versionName} $isPro"
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
@ -126,9 +102,10 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shareApp() {
|
private fun shareApp() {
|
||||||
ShareCompat.IntentBuilder.from(this).setType("text/plain")
|
ShareCompat.IntentBuilder.from(requireActivity()).setType("text/plain")
|
||||||
.setChooserTitle(R.string.share_app)
|
.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() {
|
private fun loadContributors() {
|
||||||
|
@ -138,8 +115,10 @@ class AboutActivity : AbsBaseActivity(), View.OnClickListener {
|
||||||
val contributors = Gson().fromJson<List<Contributor>>(contributorsJson, type)
|
val contributors = Gson().fromJson<List<Contributor>>(contributorsJson, type)
|
||||||
|
|
||||||
val contributorAdapter = ContributorAdapter(contributors)
|
val contributorAdapter = ContributorAdapter(contributors)
|
||||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
recyclerView.apply {
|
||||||
recyclerView.itemAnimator = DefaultItemAnimator()
|
layoutManager = LinearLayoutManager(requireContext())
|
||||||
recyclerView.adapter = contributorAdapter
|
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.app.ActivityOptions
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.transition.Slide
|
import android.view.*
|
||||||
import android.view.Menu
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import android.view.MenuItem
|
import androidx.core.os.bundleOf
|
||||||
import android.view.SubMenu
|
import androidx.lifecycle.Observer
|
||||||
import android.view.View
|
import androidx.navigation.findNavController
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import code.name.monkey.appthemehelper.common.ATHToolbarActivity.getToolbarBackgroundColor
|
||||||
import code.name.monkey.appthemehelper.util.MaterialUtil
|
|
||||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
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.R
|
||||||
import io.github.muntashirakon.music.activities.base.AbsSlidingMusicPanelActivity
|
|
||||||
import io.github.muntashirakon.music.activities.tageditor.AbsTagEditorActivity
|
import io.github.muntashirakon.music.activities.tageditor.AbsTagEditorActivity
|
||||||
import io.github.muntashirakon.music.activities.tageditor.AlbumTagEditorActivity
|
import io.github.muntashirakon.music.activities.tageditor.AlbumTagEditorActivity
|
||||||
import io.github.muntashirakon.music.adapter.album.HorizontalAlbumAdapter
|
import io.github.muntashirakon.music.adapter.album.HorizontalAlbumAdapter
|
||||||
import io.github.muntashirakon.music.adapter.song.SimpleSongAdapter
|
import io.github.muntashirakon.music.adapter.song.SimpleSongAdapter
|
||||||
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
||||||
import io.github.muntashirakon.music.dialogs.DeleteSongsDialog
|
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.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.AlbumGlideRequest
|
||||||
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
||||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||||
import io.github.muntashirakon.music.helper.SortOrder.AlbumSongSortOrder
|
import io.github.muntashirakon.music.helper.SortOrder
|
||||||
import io.github.muntashirakon.music.interfaces.CabHolder
|
|
||||||
import io.github.muntashirakon.music.model.Album
|
import io.github.muntashirakon.music.model.Album
|
||||||
import io.github.muntashirakon.music.model.Artist
|
import io.github.muntashirakon.music.model.Artist
|
||||||
import io.github.muntashirakon.music.network.model.LastFmAlbum
|
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 io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
||||||
import com.afollestad.materialcab.MaterialCab
|
import kotlinx.android.synthetic.main.fragment_album_content.*
|
||||||
import com.bumptech.glide.Glide
|
import kotlinx.android.synthetic.main.fragment_album_details.*
|
||||||
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.androidx.viewmodel.ext.android.viewModel
|
||||||
import org.koin.core.parameter.parametersOf
|
import org.koin.core.parameter.parametersOf
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import android.util.Pair as UtilPair
|
|
||||||
|
|
||||||
class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_details),
|
||||||
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
|
AlbumClickListener {
|
||||||
cab?.let {
|
|
||||||
if (it.isActive) it.finish()
|
|
||||||
}
|
|
||||||
cab = MaterialCab(this, R.id.cab_stub)
|
|
||||||
.setMenu(menuRes)
|
|
||||||
.setCloseDrawableRes(R.drawable.ic_close)
|
|
||||||
.setBackgroundColor(
|
|
||||||
RetroColorUtil.shiftBackgroundColorForLightText(
|
|
||||||
ATHUtil.resolveColor(
|
|
||||||
this,
|
|
||||||
R.attr.colorSurface
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.start(callback)
|
|
||||||
return cab as MaterialCab
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private val arguments by navArgs<AlbumDetailsFragmentArgs>()
|
||||||
private val detailsViewModel by viewModel<AlbumDetailsViewModel> {
|
private val detailsViewModel by viewModel<AlbumDetailsViewModel> {
|
||||||
parametersOf(extraNotNull<Int>(EXTRA_ALBUM_ID).value)
|
parametersOf(arguments.extraAlbumId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var simpleSongAdapter: SimpleSongAdapter
|
private lateinit var simpleSongAdapter: SimpleSongAdapter
|
||||||
private lateinit var album: Album
|
private lateinit var album: Album
|
||||||
private var cab: MaterialCab? = null
|
|
||||||
private val savedSortOrder: String
|
private val savedSortOrder: String
|
||||||
get() = PreferenceUtil.albumDetailSongSortOrder
|
get() = PreferenceUtil.albumDetailSongSortOrder
|
||||||
|
|
||||||
override fun createContentView(): View {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
return wrapSlidingMusicPanel(R.layout.activity_album)
|
super.onActivityCreated(savedInstanceState)
|
||||||
}
|
setHasOptionsMenu(true)
|
||||||
|
mainActivity.hideBottomBarVisibility(false)
|
||||||
|
mainActivity.addMusicServiceEventListener(detailsViewModel)
|
||||||
|
mainActivity.setSupportActionBar(toolbar)
|
||||||
|
|
||||||
private fun windowEnterTransition() {
|
toolbar.title = null
|
||||||
val slide = Slide()
|
|
||||||
slide.excludeTarget(R.id.appBarLayout, true)
|
|
||||||
slide.excludeTarget(R.id.status_bar, true)
|
|
||||||
slide.excludeTarget(android.R.id.statusBarBackground, true)
|
|
||||||
slide.excludeTarget(android.R.id.navigationBarBackground, true)
|
|
||||||
window.enterTransition = slide
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
postponeEnterTransition()
|
||||||
setDrawUnderStatusBar()
|
detailsViewModel.getAlbum().observe(viewLifecycleOwner, Observer {
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setStatusbarColorAuto()
|
|
||||||
setNavigationbarColorAuto()
|
|
||||||
setTaskDescriptionColorAuto()
|
|
||||||
setLightNavigationBar(true)
|
|
||||||
setBottomBarVisibility(View.GONE)
|
|
||||||
window.sharedElementsUseOverlay = true
|
|
||||||
windowEnterTransition()
|
|
||||||
toolbar.setBackgroundColor(surfaceColor())
|
|
||||||
|
|
||||||
addMusicServiceEventListener(detailsViewModel)
|
|
||||||
ActivityCompat.postponeEnterTransition(this)
|
|
||||||
|
|
||||||
detailsViewModel.getAlbum().observe(this, androidx.lifecycle.Observer {
|
|
||||||
ActivityCompat.startPostponedEnterTransition(this@AlbumDetailsActivity)
|
|
||||||
showAlbum(it)
|
showAlbum(it)
|
||||||
|
startPostponedEnterTransition()
|
||||||
})
|
})
|
||||||
detailsViewModel.getArtist().observe(this, androidx.lifecycle.Observer {
|
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
|
||||||
loadArtistImage(it)
|
loadArtistImage(it)
|
||||||
})
|
})
|
||||||
detailsViewModel.getMoreAlbums().observe(this, androidx.lifecycle.Observer {
|
detailsViewModel.getMoreAlbums().observe(viewLifecycleOwner, Observer {
|
||||||
moreAlbums(it)
|
moreAlbums(it)
|
||||||
})
|
})
|
||||||
detailsViewModel.getAlbumInfo().observe(this, androidx.lifecycle.Observer {
|
detailsViewModel.getAlbumInfo().observe(viewLifecycleOwner, Observer {
|
||||||
aboutAlbum(it)
|
aboutAlbum(it)
|
||||||
})
|
})
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
artistImage.setOnClickListener {
|
artistImage.setOnClickListener {
|
||||||
val artistPairs = ActivityOptions.makeSceneTransitionAnimation(
|
requireActivity().findNavController(R.id.fragment_container)
|
||||||
this,
|
.navigate(
|
||||||
UtilPair.create(
|
R.id.artistDetailsFragment,
|
||||||
artistImage,
|
bundleOf(EXTRA_ARTIST_ID to album.artistId)
|
||||||
getString(R.string.transition_artist_image)
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
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 {
|
aboutAlbumText.setOnClickListener {
|
||||||
|
@ -141,12 +107,26 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
aboutAlbumText.maxLines = 4
|
aboutAlbumText.maxLines = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
image.apply {
|
||||||
|
transitionName = getString(R.string.transition_album_art)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
playerActivity?.removeMusicServiceEventListener(detailsViewModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
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 {
|
recyclerView.apply {
|
||||||
layoutManager = LinearLayoutManager(this@AlbumDetailsActivity)
|
layoutManager = LinearLayoutManager(requireContext())
|
||||||
itemAnimator = DefaultItemAnimator()
|
itemAnimator = DefaultItemAnimator()
|
||||||
isNestedScrollingEnabled = false
|
isNestedScrollingEnabled = false
|
||||||
adapter = simpleSongAdapter
|
adapter = simpleSongAdapter
|
||||||
|
@ -155,7 +135,6 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
|
|
||||||
private fun showAlbum(album: Album) {
|
private fun showAlbum(album: Album) {
|
||||||
if (album.songs!!.isEmpty()) {
|
if (album.songs!!.isEmpty()) {
|
||||||
finish()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.album = album
|
this.album = album
|
||||||
|
@ -194,9 +173,10 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
moreRecyclerView.show()
|
moreRecyclerView.show()
|
||||||
moreTitle.text = String.format(getString(R.string.label_more_from), album.artistName)
|
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(
|
moreRecyclerView.layoutManager = GridLayoutManager(
|
||||||
this,
|
requireContext(),
|
||||||
1,
|
1,
|
||||||
GridLayoutManager.HORIZONTAL,
|
GridLayoutManager.HORIZONTAL,
|
||||||
false
|
false
|
||||||
|
@ -226,8 +206,8 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadArtistImage(artist: Artist) {
|
private fun loadArtistImage(artist: Artist) {
|
||||||
ArtistGlideRequest.Builder.from(Glide.with(this), artist)
|
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
||||||
.generatePalette(this)
|
.generatePalette(requireContext())
|
||||||
.build()
|
.build()
|
||||||
.dontAnimate()
|
.dontAnimate()
|
||||||
.dontTransform()
|
.dontTransform()
|
||||||
|
@ -238,10 +218,10 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadAlbumCover() {
|
private fun loadAlbumCover() {
|
||||||
AlbumGlideRequest.Builder.from(Glide.with(this), album.safeGetFirstSong())
|
AlbumGlideRequest.Builder.from(Glide.with(requireContext()), album.safeGetFirstSong())
|
||||||
.checkIgnoreMediaStore(this)
|
.checkIgnoreMediaStore(requireContext())
|
||||||
.ignoreMediaStore(PreferenceUtil.isIgnoreMediaStoreArtwork)
|
.ignoreMediaStore(PreferenceUtil.isIgnoreMediaStoreArtwork)
|
||||||
.generatePalette(this)
|
.generatePalette(requireContext())
|
||||||
.build()
|
.build()
|
||||||
.dontAnimate()
|
.dontAnimate()
|
||||||
.dontTransform()
|
.dontTransform()
|
||||||
|
@ -253,32 +233,28 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setColors(color: MediaNotificationProcessor) {
|
private fun setColors(color: MediaNotificationProcessor) {
|
||||||
MaterialUtil.tintColor(
|
shuffleAction.applyColor(color.backgroundColor)
|
||||||
button = shuffleAction,
|
playAction.applyColor(color.backgroundColor)
|
||||||
textColor = color.primaryTextColor,
|
|
||||||
backgroundColor = color.backgroundColor
|
|
||||||
)
|
|
||||||
MaterialUtil.tintColor(
|
|
||||||
button = playAction,
|
|
||||||
textColor = color.primaryTextColor,
|
|
||||||
backgroundColor = color.backgroundColor
|
|
||||||
)
|
|
||||||
|
|
||||||
setSupportActionBar(toolbar)
|
|
||||||
supportActionBar?.title = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onAlbumClick(albumId: Int, view: View) {
|
||||||
menuInflater.inflate(R.menu.menu_album_detail, menu)
|
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)
|
val sortOrder = menu.findItem(R.id.action_sort_order)
|
||||||
setUpSortOrderMenu(sortOrder.subMenu)
|
setUpSortOrderMenu(sortOrder.subMenu)
|
||||||
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
|
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
|
||||||
this,
|
requireContext(),
|
||||||
toolbar,
|
toolbar,
|
||||||
menu,
|
menu,
|
||||||
getToolbarBackgroundColor(toolbar)
|
getToolbarBackgroundColor(toolbar)
|
||||||
)
|
)
|
||||||
return super.onCreateOptionsMenu(menu)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
@ -289,6 +265,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
var sortOrder: String? = null
|
var sortOrder: String? = null
|
||||||
val songs = simpleSongAdapter.dataSet
|
val songs = simpleSongAdapter.dataSet
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
|
android.R.id.home -> findNavController().navigateUp()
|
||||||
R.id.action_play_next -> {
|
R.id.action_play_next -> {
|
||||||
MusicPlayerRemote.playNext(songs)
|
MusicPlayerRemote.playNext(songs)
|
||||||
return true
|
return true
|
||||||
|
@ -298,22 +275,18 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_add_to_playlist -> {
|
R.id.action_add_to_playlist -> {
|
||||||
AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
|
AddToPlaylistDialog.create(songs).show(childFragmentManager, "ADD_PLAYLIST")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_delete_from_device -> {
|
R.id.action_delete_from_device -> {
|
||||||
DeleteSongsDialog.create(songs).show(supportFragmentManager, "DELETE_SONGS")
|
DeleteSongsDialog.create(songs).show(childFragmentManager, "DELETE_SONGS")
|
||||||
return true
|
|
||||||
}
|
|
||||||
android.R.id.home -> {
|
|
||||||
super.onBackPressed()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_tag_editor -> {
|
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)
|
intent.putExtra(AbsTagEditorActivity.EXTRA_ID, album.id)
|
||||||
val options = ActivityOptions.makeSceneTransitionAnimation(
|
val options = ActivityOptions.makeSceneTransitionAnimation(
|
||||||
this,
|
requireActivity(),
|
||||||
albumCoverContainer,
|
albumCoverContainer,
|
||||||
"${getString(R.string.transition_album_art)}_${album.id}"
|
"${getString(R.string.transition_album_art)}_${album.id}"
|
||||||
)
|
)
|
||||||
|
@ -324,11 +297,12 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
/*Sort*/
|
/*Sort*/
|
||||||
R.id.action_sort_order_title -> sortOrder = AlbumSongSortOrder.SONG_A_Z
|
R.id.action_sort_order_title -> sortOrder = SortOrder.AlbumSongSortOrder.SONG_A_Z
|
||||||
R.id.action_sort_order_title_desc -> sortOrder = AlbumSongSortOrder.SONG_Z_A
|
R.id.action_sort_order_title_desc -> sortOrder = SortOrder.AlbumSongSortOrder.SONG_Z_A
|
||||||
R.id.action_sort_order_track_list -> sortOrder = AlbumSongSortOrder.SONG_TRACK_LIST
|
R.id.action_sort_order_track_list -> sortOrder =
|
||||||
|
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST
|
||||||
R.id.action_sort_order_artist_song_duration ->
|
R.id.action_sort_order_artist_song_duration ->
|
||||||
sortOrder = AlbumSongSortOrder.SONG_DURATION
|
sortOrder = SortOrder.AlbumSongSortOrder.SONG_DURATION
|
||||||
}
|
}
|
||||||
if (sortOrder != null) {
|
if (sortOrder != null) {
|
||||||
item.isChecked = true
|
item.isChecked = true
|
||||||
|
@ -339,13 +313,13 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
|
|
||||||
private fun setUpSortOrderMenu(sortOrder: SubMenu) {
|
private fun setUpSortOrderMenu(sortOrder: SubMenu) {
|
||||||
when (savedSortOrder) {
|
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
|
.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
|
.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
|
.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
|
.isChecked = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,22 +327,22 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
private fun setSaveSortOrder(sortOrder: String) {
|
private fun setSaveSortOrder(sortOrder: String) {
|
||||||
PreferenceUtil.albumDetailSongSortOrder = sortOrder
|
PreferenceUtil.albumDetailSongSortOrder = sortOrder
|
||||||
when (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(
|
o1.trackNumber.compareTo(
|
||||||
o2.trackNumber
|
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(
|
o1.title.compareTo(
|
||||||
o2.title
|
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(
|
o2.title.compareTo(
|
||||||
o1.title
|
o1.title
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 ->
|
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs?.sortWith(Comparator { o1, o2 ->
|
||||||
o1.duration.compareTo(
|
o1.duration.compareTo(
|
||||||
o2.duration
|
o2.duration
|
||||||
)
|
)
|
||||||
|
@ -377,23 +351,7 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
album.songs?.let { simpleSongAdapter.swapDataSet(it) }
|
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 {
|
companion object {
|
||||||
|
const val TAG_EDITOR_REQUEST = 9002
|
||||||
const val EXTRA_ALBUM_ID = "extra_album_id"
|
|
||||||
private const val TAG_EDITOR_REQUEST = 2001
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
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.Album
|
||||||
import io.github.muntashirakon.music.model.Artist
|
import io.github.muntashirakon.music.model.Artist
|
||||||
import io.github.muntashirakon.music.network.model.LastFmAlbum
|
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.Deferred
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.lang.Exception
|
|
||||||
|
|
||||||
class AlbumDetailsViewModel(
|
class AlbumDetailsViewModel(
|
||||||
private val repository: RepositoryImpl,
|
private val realRepository: RealRepository,
|
||||||
private val albumId: Int
|
private val albumId: Int
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
|
@ -41,7 +40,7 @@ class AlbumDetailsViewModel(
|
||||||
|
|
||||||
fun loadAlbumInfo(album: Album) = viewModelScope.launch(Dispatchers.IO) {
|
fun loadAlbumInfo(album: Album) = viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val lastFmAlbum = repository.albumInfo(
|
val lastFmAlbum = realRepository.albumInfo(
|
||||||
album.artistName ?: "-", album.title ?: "-"
|
album.artistName ?: "-", album.title ?: "-"
|
||||||
)
|
)
|
||||||
_lastFmAlbum.postValue(lastFmAlbum)
|
_lastFmAlbum.postValue(lastFmAlbum)
|
||||||
|
@ -49,7 +48,7 @@ class AlbumDetailsViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadArtist(artistId: Int) = viewModelScope.launch(Dispatchers.IO) {
|
fun loadArtist(artistId: Int) = viewModelScope.launch(Dispatchers.IO) {
|
||||||
val artist = repository.artistById(artistId)
|
val artist = realRepository.artistById(artistId)
|
||||||
_artist.postValue(artist)
|
_artist.postValue(artist)
|
||||||
|
|
||||||
artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
|
artist.albums?.filter { item -> item.id != albumId }?.let { albums ->
|
||||||
|
@ -59,7 +58,7 @@ class AlbumDetailsViewModel(
|
||||||
|
|
||||||
private val loadAlbumAsync: Deferred<Album?>
|
private val loadAlbumAsync: Deferred<Album?>
|
||||||
get() = viewModelScope.async(Dispatchers.IO) {
|
get() = viewModelScope.async(Dispatchers.IO) {
|
||||||
repository.albumById(albumId)
|
realRepository.albumById(albumId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMediaStoreChanged() {
|
override fun onMediaStoreChanged() {
|
|
@ -2,29 +2,27 @@ package io.github.muntashirakon.music.fragments.albums
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.navigation.findNavController
|
||||||
|
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import io.github.muntashirakon.music.EXTRA_ALBUM_ID
|
||||||
import io.github.muntashirakon.music.R
|
import io.github.muntashirakon.music.R
|
||||||
import io.github.muntashirakon.music.adapter.album.AlbumAdapter
|
import io.github.muntashirakon.music.adapter.album.AlbumAdapter
|
||||||
import io.github.muntashirakon.music.fragments.ReloadType
|
import io.github.muntashirakon.music.fragments.ReloadType
|
||||||
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
|
|
||||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||||
|
|
||||||
class AlbumsFragment :
|
class AlbumsFragment :
|
||||||
AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
|
AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridLayoutManager>(),
|
||||||
MainActivityFragmentCallbacks {
|
AlbumClickListener {
|
||||||
|
|
||||||
override fun handleBackPress(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.albumsLiveData
|
libraryViewModel.albumsLiveData.observe(viewLifecycleOwner, Observer {
|
||||||
.observe(viewLifecycleOwner, Observer { albums ->
|
if (it.isNotEmpty())
|
||||||
if (albums.isNotEmpty())
|
adapter?.swapDataSet(it)
|
||||||
adapter?.swapDataSet(albums)
|
|
||||||
else
|
else
|
||||||
adapter?.swapDataSet(listOf())
|
adapter?.swapDataSet(listOf())
|
||||||
})
|
})
|
||||||
|
@ -40,10 +38,11 @@ class AlbumsFragment :
|
||||||
override fun createAdapter(): AlbumAdapter {
|
override fun createAdapter(): AlbumAdapter {
|
||||||
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
|
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
|
||||||
return AlbumAdapter(
|
return AlbumAdapter(
|
||||||
mainActivity,
|
requireActivity(),
|
||||||
dataSet,
|
dataSet,
|
||||||
itemLayoutRes(),
|
R.layout.item_grid,
|
||||||
mainActivity
|
null,
|
||||||
|
this
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,12 +89,24 @@ class AlbumsFragment :
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField
|
|
||||||
var TAG: String = AlbumsFragment::class.java.simpleName
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun newInstance(): AlbumsFragment {
|
fun newInstance(): AlbumsFragment {
|
||||||
return 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.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.transition.Slide
|
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.app.ActivityCompat
|
|
||||||
import androidx.core.text.HtmlCompat
|
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.DefaultItemAnimator
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import code.name.monkey.appthemehelper.util.ATHUtil
|
import com.bumptech.glide.Glide
|
||||||
import code.name.monkey.appthemehelper.util.MaterialUtil
|
|
||||||
import io.github.muntashirakon.music.R
|
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.album.HorizontalAlbumAdapter
|
||||||
import io.github.muntashirakon.music.adapter.song.SimpleSongAdapter
|
import io.github.muntashirakon.music.adapter.song.SimpleSongAdapter
|
||||||
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
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.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.ArtistGlideRequest
|
||||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
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.model.Artist
|
||||||
import io.github.muntashirakon.music.network.model.LastFmArtist
|
import io.github.muntashirakon.music.network.model.LastFmArtist
|
||||||
import io.github.muntashirakon.music.util.CustomArtistImageUtil
|
import io.github.muntashirakon.music.util.CustomArtistImageUtil
|
||||||
import io.github.muntashirakon.music.util.MusicUtil
|
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.RetroUtil
|
||||||
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
import io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
||||||
import com.afollestad.materialcab.MaterialCab
|
import kotlinx.android.synthetic.main.fragment_artist_content.*
|
||||||
import com.bumptech.glide.Glide
|
import kotlinx.android.synthetic.main.fragment_artist_details.*
|
||||||
import kotlinx.android.synthetic.main.activity_artist_content.*
|
|
||||||
import kotlinx.android.synthetic.main.activity_artist_details.*
|
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
import org.koin.core.parameter.parametersOf
|
import org.koin.core.parameter.parametersOf
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_details),
|
||||||
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
|
AlbumClickListener {
|
||||||
cab?.let {
|
private val arguments by navArgs<ArtistDetailsFragmentArgs>()
|
||||||
if (it.isActive) it.finish()
|
private val detailsViewModel: ArtistDetailsViewModel by viewModel {
|
||||||
}
|
parametersOf(arguments.extraArtistId)
|
||||||
cab = MaterialCab(this, R.id.cab_stub)
|
|
||||||
.setMenu(menuRes)
|
|
||||||
.setCloseDrawableRes(R.drawable.ic_close)
|
|
||||||
.setBackgroundColor(
|
|
||||||
RetroColorUtil.shiftBackgroundColorForLightText(
|
|
||||||
ATHUtil.resolveColor(
|
|
||||||
this,
|
|
||||||
R.attr.colorSurface
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.start(callback)
|
|
||||||
return cab as MaterialCab
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var cab: MaterialCab? = null
|
|
||||||
private var biography: Spanned? = null
|
|
||||||
private lateinit var artist: Artist
|
private lateinit var artist: Artist
|
||||||
private lateinit var songAdapter: SimpleSongAdapter
|
private lateinit var songAdapter: SimpleSongAdapter
|
||||||
private lateinit var albumAdapter: HorizontalAlbumAdapter
|
private lateinit var albumAdapter: HorizontalAlbumAdapter
|
||||||
private var forceDownload: Boolean = false
|
private var forceDownload: Boolean = false
|
||||||
private val detailsViewModel: ArtistDetailsViewModel by viewModel {
|
private var lang: String? = null
|
||||||
parametersOf(extraNotNull<Int>(EXTRA_ARTIST_ID).value)
|
private var biography: Spanned? = null
|
||||||
}
|
|
||||||
|
|
||||||
override fun createContentView(): View {
|
|
||||||
return wrapSlidingMusicPanel(R.layout.activity_artist_details)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun windowEnterTransition() {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
val slide = Slide()
|
super.onActivityCreated(savedInstanceState)
|
||||||
slide.excludeTarget(R.id.appBarLayout, true)
|
setHasOptionsMenu(true)
|
||||||
slide.excludeTarget(R.id.status_bar, true)
|
mainActivity.setSupportActionBar(toolbar)
|
||||||
slide.excludeTarget(android.R.id.statusBarBackground, true)
|
mainActivity.hideBottomBarVisibility(false)
|
||||||
slide.excludeTarget(android.R.id.navigationBarBackground, true)
|
toolbar.title = null
|
||||||
window.enterTransition = slide
|
setupRecyclerView()
|
||||||
}
|
postponeEnterTransition()
|
||||||
|
detailsViewModel.getArtist().observe(viewLifecycleOwner, Observer {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
showArtist(it)
|
||||||
setDrawUnderStatusBar()
|
startPostponedEnterTransition()
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
setStatusbarColorAuto()
|
|
||||||
setNavigationbarColorAuto()
|
|
||||||
setTaskDescriptionColorAuto()
|
|
||||||
setLightNavigationBar(true)
|
|
||||||
setBottomBarVisibility(View.GONE)
|
|
||||||
window.sharedElementsUseOverlay = true
|
|
||||||
windowEnterTransition()
|
|
||||||
toolbar.setBackgroundColor(surfaceColor())
|
|
||||||
|
|
||||||
addMusicServiceEventListener(detailsViewModel)
|
|
||||||
|
|
||||||
ActivityCompat.postponeEnterTransition(this)
|
|
||||||
detailsViewModel.getArtist().observe(this, androidx.lifecycle.Observer {
|
|
||||||
ActivityCompat.startPostponedEnterTransition(this@ArtistDetailActivity)
|
|
||||||
artist(it)
|
|
||||||
})
|
})
|
||||||
detailsViewModel.getArtistInfo().observe(this, androidx.lifecycle.Observer {
|
detailsViewModel.getArtistInfo().observe(viewLifecycleOwner, Observer {
|
||||||
artistInfo(it)
|
artistInfo(it)
|
||||||
})
|
})
|
||||||
setupRecyclerView()
|
|
||||||
playAction.apply {
|
playAction.apply {
|
||||||
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
|
setOnClickListener { MusicPlayerRemote.openQueue(artist.songs, 0, true) }
|
||||||
}
|
}
|
||||||
|
@ -127,13 +91,13 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
albumAdapter = HorizontalAlbumAdapter(this, ArrayList(), null)
|
albumAdapter = HorizontalAlbumAdapter(requireActivity(), ArrayList(), null, this)
|
||||||
albumRecyclerView.apply {
|
albumRecyclerView.apply {
|
||||||
itemAnimator = DefaultItemAnimator()
|
itemAnimator = DefaultItemAnimator()
|
||||||
layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false)
|
layoutManager = GridLayoutManager(this.context, 1, GridLayoutManager.HORIZONTAL, false)
|
||||||
adapter = albumAdapter
|
adapter = albumAdapter
|
||||||
}
|
}
|
||||||
songAdapter = SimpleSongAdapter(this, ArrayList(), R.layout.item_song, this)
|
songAdapter = SimpleSongAdapter(requireActivity(), ArrayList(), R.layout.item_song, null)
|
||||||
recyclerView.apply {
|
recyclerView.apply {
|
||||||
itemAnimator = DefaultItemAnimator()
|
itemAnimator = DefaultItemAnimator()
|
||||||
layoutManager = LinearLayoutManager(this.context)
|
layoutManager = LinearLayoutManager(this.context)
|
||||||
|
@ -141,33 +105,16 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
fun showArtist(artist: Artist) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
when (requestCode) {
|
|
||||||
REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
|
|
||||||
data?.data?.let {
|
|
||||||
CustomArtistImageUtil.getInstance(this).setCustomArtistImage(artist, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> if (resultCode == Activity.RESULT_OK) {
|
|
||||||
//reload()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun artist(artist: Artist) {
|
|
||||||
if (artist.songs.isEmpty()) {
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
this.artist = artist
|
this.artist = artist
|
||||||
loadArtistImage(artist)
|
loadArtistImage(artist)
|
||||||
if (RetroUtil.isAllowedToDownloadMetadata(this)) {
|
if (RetroUtil.isAllowedToDownloadMetadata(requireContext())) {
|
||||||
loadBiography(artist.name)
|
loadBiography(artist.name)
|
||||||
}
|
}
|
||||||
artistTitle.text = artist.name
|
artistTitle.text = artist.name
|
||||||
text.text = String.format(
|
text.text = String.format(
|
||||||
"%s • %s",
|
"%s • %s",
|
||||||
MusicUtil.getArtistInfoString(this, artist),
|
MusicUtil.getArtistInfoString(requireContext(), artist),
|
||||||
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(artist.songs))
|
MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(artist.songs))
|
||||||
)
|
)
|
||||||
val songText =
|
val songText =
|
||||||
|
@ -184,7 +131,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
)
|
)
|
||||||
songTitle.text = songText
|
songTitle.text = songText
|
||||||
albumTitle.text = albumText
|
albumTitle.text = albumText
|
||||||
songAdapter.swapDataSet(artist.songs)
|
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
|
||||||
artist.albums?.let { albumAdapter.swapDataSet(it) }
|
artist.albums?.let { albumAdapter.swapDataSet(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,31 +171,32 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lang: String? = null
|
|
||||||
|
|
||||||
private fun loadArtistImage(artist: Artist) {
|
private fun loadArtistImage(artist: Artist) {
|
||||||
ArtistGlideRequest.Builder.from(Glide.with(this), artist)
|
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
||||||
.generatePalette(this).build()
|
.generatePalette(requireContext()).build()
|
||||||
.dontAnimate().into(object : RetroMusicColoredTarget(image) {
|
.dontAnimate().into(object : RetroMusicColoredTarget(image) {
|
||||||
override fun onColorReady(colors: MediaNotificationProcessor) {
|
override fun onColorReady(colors: MediaNotificationProcessor) {
|
||||||
|
startPostponedEnterTransition()
|
||||||
setColors(colors)
|
setColors(colors)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setColors(color: MediaNotificationProcessor) {
|
private fun setColors(color: MediaNotificationProcessor) {
|
||||||
MaterialUtil.tintColor(
|
shuffleAction.applyColor(color.backgroundColor)
|
||||||
button = shuffleAction,
|
playAction.applyColor(color.backgroundColor)
|
||||||
textColor = color.primaryTextColor,
|
}
|
||||||
backgroundColor = 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 {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
@ -258,10 +206,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
|
private fun handleSortOrderMenuItem(item: MenuItem): Boolean {
|
||||||
val songs = artist.songs
|
val songs = artist.songs
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
android.R.id.home -> {
|
android.R.id.home -> findNavController().navigateUp()
|
||||||
super.onBackPressed()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
R.id.action_play_next -> {
|
R.id.action_play_next -> {
|
||||||
MusicPlayerRemote.playNext(songs)
|
MusicPlayerRemote.playNext(songs)
|
||||||
return true
|
return true
|
||||||
|
@ -271,7 +216,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_add_to_playlist -> {
|
R.id.action_add_to_playlist -> {
|
||||||
AddToPlaylistDialog.create(songs).show(supportFragmentManager, "ADD_PLAYLIST")
|
AddToPlaylistDialog.create(songs).show(childFragmentManager, "ADD_PLAYLIST")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_set_artist_image -> {
|
R.id.action_set_artist_image -> {
|
||||||
|
@ -284,14 +229,8 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_reset_artist_image -> {
|
R.id.action_reset_artist_image -> {
|
||||||
Toast.makeText(
|
showToast(resources.getString(R.string.updating))
|
||||||
this@ArtistDetailActivity,
|
CustomArtistImageUtil.getInstance(requireContext()).resetCustomArtistImage(artist)
|
||||||
resources.getString(R.string.updating),
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
)
|
|
||||||
.show()
|
|
||||||
CustomArtistImageUtil.getInstance(this@ArtistDetailActivity)
|
|
||||||
.resetCustomArtistImage(artist)
|
|
||||||
forceDownload = true
|
forceDownload = true
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -299,26 +238,12 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
menuInflater.inflate(R.menu.menu_artist_detail, menu)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
return super.onCreateOptionsMenu(menu)
|
inflater.inflate(R.menu.menu_artist_detail, menu)
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBackPressed() {
|
|
||||||
if (cab != null && cab!!.isActive) {
|
|
||||||
cab?.finish()
|
|
||||||
} else {
|
|
||||||
super.onBackPressed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
removeMusicServiceEventListener(detailsViewModel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val EXTRA_ARTIST_ID = "extra_artist_id"
|
const val REQUEST_CODE_SELECT_IMAGE = 9002
|
||||||
const val REQUEST_CODE_SELECT_IMAGE = 9003
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
@ -6,21 +6,21 @@ import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
||||||
import io.github.muntashirakon.music.model.Artist
|
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.network.model.LastFmArtist
|
||||||
|
import io.github.muntashirakon.music.repository.RealRepository
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class ArtistDetailsViewModel(
|
class ArtistDetailsViewModel(
|
||||||
private val repository: RepositoryImpl,
|
private val realRepository: RealRepository,
|
||||||
private val artistId: Int
|
private val artistId: Int
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
private val loadArtistDetailsAsync: Deferred<Artist?>
|
private val loadArtistDetailsAsync: Deferred<Artist?>
|
||||||
get() = viewModelScope.async(Dispatchers.IO) {
|
get() = viewModelScope.async(Dispatchers.IO) {
|
||||||
repository.artistById(artistId)
|
realRepository.artistById(artistId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _artist = MutableLiveData<Artist>()
|
private val _artist = MutableLiveData<Artist>()
|
||||||
|
@ -40,7 +40,7 @@ class ArtistDetailsViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadBiography(name: String, lang: String?, cache: String?) = viewModelScope.launch {
|
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)
|
_lastFmArtist.postValue(info)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,14 @@ package io.github.muntashirakon.music.fragments.artists
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import io.github.muntashirakon.music.EXTRA_ARTIST_ID
|
||||||
import io.github.muntashirakon.music.R
|
import io.github.muntashirakon.music.R
|
||||||
import io.github.muntashirakon.music.adapter.artist.ArtistAdapter
|
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.ReloadType
|
||||||
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
|
import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
|
||||||
|
@ -13,7 +17,7 @@ import io.github.muntashirakon.music.util.PreferenceUtil
|
||||||
|
|
||||||
class ArtistsFragment :
|
class ArtistsFragment :
|
||||||
AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
|
AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
|
||||||
MainActivityFragmentCallbacks {
|
MainActivityFragmentCallbacks, ArtistClickListener {
|
||||||
|
|
||||||
override fun handleBackPress(): Boolean {
|
override fun handleBackPress(): Boolean {
|
||||||
return false
|
return false
|
||||||
|
@ -22,13 +26,11 @@ class ArtistsFragment :
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.artistsLiveData
|
libraryViewModel.artistsLiveData.observe(viewLifecycleOwner, Observer {
|
||||||
.observe(viewLifecycleOwner, Observer { artists ->
|
if (it.isNotEmpty())
|
||||||
if (artists.isNotEmpty()) {
|
adapter?.swapDataSet(it)
|
||||||
adapter?.swapDataSet(artists)
|
else
|
||||||
} else {
|
|
||||||
adapter?.swapDataSet(listOf())
|
adapter?.swapDataSet(listOf())
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,10 +48,11 @@ class ArtistsFragment :
|
||||||
override fun createAdapter(): ArtistAdapter {
|
override fun createAdapter(): ArtistAdapter {
|
||||||
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
|
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
|
||||||
return ArtistAdapter(
|
return ArtistAdapter(
|
||||||
mainActivity,
|
requireActivity(),
|
||||||
dataSet,
|
dataSet,
|
||||||
itemLayoutRes(),
|
R.layout.item_grid_circle,
|
||||||
mainActivity
|
null,
|
||||||
|
this
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,12 +94,18 @@ class ArtistsFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmField
|
|
||||||
val TAG: String = ArtistsFragment::class.java.simpleName
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun newInstance(): ArtistsFragment {
|
fun newInstance(): ArtistsFragment {
|
||||||
return 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 android.webkit.MimeTypeMap
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import androidx.fragment.app.Fragment
|
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.activities.base.AbsMusicServiceActivity
|
||||||
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
||||||
import io.github.muntashirakon.music.model.Song
|
import io.github.muntashirakon.music.model.Song
|
||||||
|
@ -23,6 +25,21 @@ import java.util.*
|
||||||
open class AbsMusicServiceFragment(@LayoutRes layout: Int) : Fragment(layout),
|
open class AbsMusicServiceFragment(@LayoutRes layout: Int) : Fragment(layout),
|
||||||
MusicServiceEventListener {
|
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
|
var playerActivity: AbsMusicServiceActivity? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,10 @@ import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import androidx.appcompat.widget.Toolbar
|
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.R
|
||||||
import io.github.muntashirakon.music.activities.tageditor.AbsTagEditorActivity
|
import io.github.muntashirakon.music.activities.tageditor.AbsTagEditorActivity
|
||||||
import io.github.muntashirakon.music.activities.tageditor.SongTagEditorActivity
|
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 org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
|
|
||||||
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragment(layout),
|
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragment(layout),
|
||||||
Toolbar.OnMenuItemClickListener,
|
Toolbar.OnMenuItemClickListener, PaletteColorHolder, PlayerAlbumCoverFragment.Callbacks {
|
||||||
PaletteColorHolder,
|
|
||||||
PlayerAlbumCoverFragment.Callbacks {
|
|
||||||
|
|
||||||
|
|
||||||
private var updateIsFavoriteTask: AsyncTask<*, *, *>? = null
|
private var updateIsFavoriteTask: AsyncTask<*, *, *>? = null
|
||||||
private var updateLyricsAsyncTask: AsyncTask<*, *, *>? = null
|
private var updateLyricsAsyncTask: AsyncTask<*, *, *>? = null
|
||||||
|
@ -86,11 +87,19 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_go_to_album -> {
|
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
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_go_to_artist -> {
|
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
|
return true
|
||||||
}
|
}
|
||||||
R.id.now_playing -> {
|
R.id.now_playing -> {
|
||||||
|
@ -254,11 +263,6 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
|
||||||
statusBarShadow?.hide()
|
statusBarShadow?.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Callbacks {
|
|
||||||
|
|
||||||
fun onPaletteColorChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val TAG: String = AbsPlayerFragment::class.java.simpleName
|
val TAG: String = AbsPlayerFragment::class.java.simpleName
|
||||||
const val VISIBILITY_ANIM_DURATION: Long = 300
|
const val VISIBILITY_ANIM_DURATION: Long = 300
|
||||||
|
|
|
@ -6,26 +6,24 @@ import android.view.ViewGroup
|
||||||
import androidx.annotation.NonNull
|
import androidx.annotation.NonNull
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
import io.github.muntashirakon.music.R
|
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.fragments.LibraryViewModel
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||||
import io.github.muntashirakon.music.util.DensityUtil
|
import io.github.muntashirakon.music.util.DensityUtil
|
||||||
import io.github.muntashirakon.music.util.ThemedFastScroller.create
|
import io.github.muntashirakon.music.util.ThemedFastScroller.create
|
||||||
import io.github.muntashirakon.music.views.ScrollingViewOnApplyWindowInsetsListener
|
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 kotlinx.android.synthetic.main.fragment_main_activity_recycler_view.*
|
||||||
import me.zhanghai.android.fastscroll.FastScroller
|
import me.zhanghai.android.fastscroll.FastScroller
|
||||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
|
|
||||||
abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : RecyclerView.LayoutManager> :
|
abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : RecyclerView.LayoutManager> :
|
||||||
AbsMusicServiceFragment(R.layout.fragment_main_activity_recycler_view),
|
AbsMusicServiceFragment(R.layout.fragment_main_activity_recycler_view),
|
||||||
AppBarLayout.OnOffsetChangedListener {
|
AppBarLayout.OnOffsetChangedListener {
|
||||||
|
|
||||||
val libraryViewModel: LibraryViewModel by sharedViewModel()
|
val libraryViewModel: LibraryViewModel by sharedViewModel()
|
||||||
val mainActivity: MainActivity
|
|
||||||
get() = requireActivity() as MainActivity
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
@ -38,22 +36,23 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
mainActivity.addOnAppBarOffsetChangedListener(this)
|
|
||||||
initLayoutManager()
|
initLayoutManager()
|
||||||
initAdapter()
|
initAdapter()
|
||||||
setUpRecyclerView()
|
setUpRecyclerView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpRecyclerView() {
|
private fun setUpRecyclerView() {
|
||||||
recyclerView.layoutManager = layoutManager
|
recyclerView.apply {
|
||||||
recyclerView.adapter = adapter
|
layoutManager = this@AbsRecyclerViewFragment.layoutManager
|
||||||
val fastScroller = create(recyclerView)
|
adapter = this@AbsRecyclerViewFragment.adapter
|
||||||
recyclerView.setOnApplyWindowInsetsListener(
|
val fastScroller = create(this)
|
||||||
|
setOnApplyWindowInsetsListener(
|
||||||
ScrollingViewOnApplyWindowInsetsListener(
|
ScrollingViewOnApplyWindowInsetsListener(
|
||||||
recyclerView,
|
recyclerView,
|
||||||
fastScroller
|
fastScroller
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
checkForPadding()
|
checkForPadding()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +111,7 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
|
||||||
container.paddingLeft,
|
container.paddingLeft,
|
||||||
container.paddingTop,
|
container.paddingTop,
|
||||||
container.paddingRight,
|
container.paddingRight,
|
||||||
mainActivity.getTotalAppBarScrollingRange() + i
|
i
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,11 +136,6 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
|
||||||
recyclerView.adapter = adapter
|
recyclerView.adapter = adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
super.onDestroyView()
|
|
||||||
mainActivity.removeOnAppBarOffsetChangedListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun recyclerView(): RecyclerView {
|
fun recyclerView(): RecyclerView {
|
||||||
return 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.SongMenuHelper;
|
||||||
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper;
|
import io.github.muntashirakon.music.helper.menu.SongsMenuHelper;
|
||||||
import io.github.muntashirakon.music.interfaces.CabHolder;
|
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.interfaces.MainActivityFragmentCallbacks;
|
||||||
import io.github.muntashirakon.music.misc.DialogAsyncTask;
|
import io.github.muntashirakon.music.misc.DialogAsyncTask;
|
||||||
import io.github.muntashirakon.music.misc.UpdateToastMediaScannerCompletionListener;
|
import io.github.muntashirakon.music.misc.UpdateToastMediaScannerCompletionListener;
|
||||||
|
@ -76,7 +77,9 @@ import me.zhanghai.android.fastscroll.FastScroller;
|
||||||
|
|
||||||
public class FoldersFragment extends AbsMainActivityFragment implements
|
public class FoldersFragment extends AbsMainActivityFragment implements
|
||||||
MainActivityFragmentCallbacks,
|
MainActivityFragmentCallbacks,
|
||||||
CabHolder, BreadCrumbLayout.SelectionCallback, SongFileAdapter.Callbacks,
|
CabHolder,
|
||||||
|
BreadCrumbLayout.SelectionCallback,
|
||||||
|
Callbacks,
|
||||||
LoaderManager.LoaderCallbacks<List<File>> {
|
LoaderManager.LoaderCallbacks<List<File>> {
|
||||||
|
|
||||||
public static final String TAG = FoldersFragment.class.getSimpleName();
|
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, "audio/*", MimeTypeMap.getSingleton()) ||
|
||||||
FileUtil.fileIsMimeType(file, "application/opus", MimeTypeMap.getSingleton()) ||
|
FileUtil.fileIsMimeType(file, "application/opus", MimeTypeMap.getSingleton()) ||
|
||||||
FileUtil.fileIsMimeType(file, "application/ogg", MimeTypeMap.getSingleton()));
|
FileUtil.fileIsMimeType(file, "application/ogg", MimeTypeMap.getSingleton()));
|
||||||
public static final String PATH = "path";
|
|
||||||
private static final String CRUMBS = "crumbs";
|
private static final String CRUMBS = "crumbs";
|
||||||
private static final int LOADER_ID = 5;
|
private static final int LOADER_ID = 5;
|
||||||
private SongFileAdapter adapter;
|
private SongFileAdapter adapter;
|
||||||
|
@ -125,18 +128,6 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
||||||
return startFolder;
|
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) {
|
private static File tryGetCanonicalFile(File file) {
|
||||||
try {
|
try {
|
||||||
return file.getCanonicalFile();
|
return file.getCanonicalFile();
|
||||||
|
@ -171,7 +162,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
setCrumb(new BreadCrumbLayout.Crumb(FileUtil.safeGetCanonicalFile((File) requireArguments().getSerializable(PATH))), true);
|
setCrumb(new BreadCrumbLayout.Crumb(FileUtil.safeGetCanonicalFile(PreferenceUtil.INSTANCE.getStartDirectory())), true);
|
||||||
} else {
|
} else {
|
||||||
breadCrumbs.restoreFromStateWrapper(savedInstanceState.getParcelable(CRUMBS));
|
breadCrumbs.restoreFromStateWrapper(savedInstanceState.getParcelable(CRUMBS));
|
||||||
getLoaderManager().initLoader(LOADER_ID, null, this);
|
getLoaderManager().initLoader(LOADER_ID, null, this);
|
||||||
|
@ -299,7 +290,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (startIndex > -1) {
|
if (startIndex > -1) {
|
||||||
MusicPlayerRemote.INSTANCE.openQueue(songs, startIndex, true);
|
MusicPlayerRemote.openQueue(songs, startIndex, true);
|
||||||
} else {
|
} else {
|
||||||
final File finalFile = file1;
|
final File finalFile = file1;
|
||||||
Snackbar.make(coordinatorLayout, Html.fromHtml(
|
Snackbar.make(coordinatorLayout, Html.fromHtml(
|
||||||
|
@ -619,7 +610,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ListSongsAsyncTask
|
private static class ListSongsAsyncTask
|
||||||
extends ListingFilesDialogAsyncTask<ListSongsAsyncTask.LoadingInfo, Void, ArrayList<Song>> {
|
extends ListingFilesDialogAsyncTask<ListSongsAsyncTask.LoadingInfo, Void, List<Song>> {
|
||||||
|
|
||||||
private final Object extra;
|
private final Object extra;
|
||||||
private WeakReference<OnSongsListedCallback> callbackWeakReference;
|
private WeakReference<OnSongsListedCallback> callbackWeakReference;
|
||||||
|
@ -633,7 +624,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ArrayList<Song> doInBackground(LoadingInfo... params) {
|
protected List<Song> doInBackground(LoadingInfo... params) {
|
||||||
try {
|
try {
|
||||||
LoadingInfo info = params[0];
|
LoadingInfo info = params[0];
|
||||||
List<File> files = FileUtil.listFilesDeep(info.files, info.fileFilter);
|
List<File> files = FileUtil.listFilesDeep(info.files, info.fileFilter);
|
||||||
|
@ -659,7 +650,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(ArrayList<Song> songs) {
|
protected void onPostExecute(List<Song> songs) {
|
||||||
super.onPostExecute(songs);
|
super.onPostExecute(songs);
|
||||||
OnSongsListedCallback callback = checkCallbackReference();
|
OnSongsListedCallback callback = checkCallbackReference();
|
||||||
if (songs != null && callback != null) {
|
if (songs != null && callback != null) {
|
||||||
|
@ -692,7 +683,7 @@ public class FoldersFragment extends AbsMainActivityFragment implements
|
||||||
|
|
||||||
public interface OnSongsListedCallback {
|
public interface OnSongsListedCallback {
|
||||||
|
|
||||||
void onSongsListed(@NonNull ArrayList<Song> songs, Object extra);
|
void onSongsListed(@NonNull List<Song> songs, Object extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class LoadingInfo {
|
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.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
@ -7,13 +7,13 @@ import androidx.lifecycle.viewModelScope
|
||||||
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
||||||
import io.github.muntashirakon.music.model.Genre
|
import io.github.muntashirakon.music.model.Genre
|
||||||
import io.github.muntashirakon.music.model.Song
|
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.Dispatchers.Main
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class GenreDetailsViewModel(
|
class GenreDetailsViewModel(
|
||||||
private val repository: RepositoryImpl,
|
private val realRepository: RealRepository,
|
||||||
private val genre: Genre
|
private val genre: Genre
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ class GenreDetailsViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadGenreSongs(genre: Genre) = viewModelScope.launch {
|
private fun loadGenreSongs(genre: Genre) = viewModelScope.launch {
|
||||||
val songs = repository.getGenre(genre.id)
|
val songs = realRepository.getGenre(genre.id)
|
||||||
withContext(Main) { _playListSongs.postValue(songs) }
|
withContext(Main) { _playListSongs.postValue(songs) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,13 +32,11 @@ class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.genresLiveData
|
libraryViewModel.genresLiveData.observe(viewLifecycleOwner, Observer {
|
||||||
.observe(viewLifecycleOwner, Observer { genres ->
|
if (it.isNotEmpty())
|
||||||
if (genres.isNotEmpty()) {
|
adapter?.swapDataSet(it)
|
||||||
adapter?.swapDataSet(genres)
|
else
|
||||||
} else {
|
|
||||||
adapter?.swapDataSet(listOf())
|
adapter?.swapDataSet(listOf())
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +47,7 @@ class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager
|
||||||
|
|
||||||
override fun createAdapter(): GenreAdapter {
|
override fun createAdapter(): GenreAdapter {
|
||||||
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
|
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
|
override val emptyMessage: Int
|
||||||
|
|
|
@ -18,36 +18,38 @@ import android.app.ActivityOptions
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.navigation.findNavController
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
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.R
|
||||||
import io.github.muntashirakon.music.adapter.HomeAdapter
|
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.LibraryViewModel
|
||||||
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
|
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
|
||||||
import io.github.muntashirakon.music.glide.ProfileBannerGlideRequest
|
import io.github.muntashirakon.music.glide.ProfileBannerGlideRequest
|
||||||
import io.github.muntashirakon.music.glide.UserProfileGlideRequest
|
import io.github.muntashirakon.music.glide.UserProfileGlideRequest
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
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.HistoryPlaylist
|
||||||
import io.github.muntashirakon.music.model.smartplaylist.LastAddedPlaylist
|
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.NavigationUtil
|
||||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import kotlinx.android.synthetic.main.abs_playlists.*
|
import kotlinx.android.synthetic.main.abs_playlists.*
|
||||||
import kotlinx.android.synthetic.main.fragment_banner_home.*
|
import kotlinx.android.synthetic.main.fragment_banner_home.*
|
||||||
import kotlinx.android.synthetic.main.home_content.*
|
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
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
class BannerHomeFragment :
|
class HomeFragment :
|
||||||
AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home),
|
AbsMainActivityFragment(if (PreferenceUtil.isHomeBanner) R.layout.fragment_banner_home else R.layout.fragment_home) {
|
||||||
MainActivityFragmentCallbacks {
|
|
||||||
|
|
||||||
override fun handleBackPress(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private val repository by inject<Repository>()
|
||||||
private val libraryViewModel: LibraryViewModel by sharedViewModel()
|
private val libraryViewModel: LibraryViewModel by sharedViewModel()
|
||||||
|
|
||||||
private val displayMetrics: DisplayMetrics
|
private val displayMetrics: DisplayMetrics
|
||||||
|
@ -60,9 +62,7 @@ class BannerHomeFragment :
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
setStatusBarColorAuto(view)
|
setStatusBarColorAuto(view)
|
||||||
|
|
||||||
bannerImage?.setOnClickListener {
|
bannerImage?.setOnClickListener {
|
||||||
val options = ActivityOptions.makeSceneTransitionAnimation(
|
val options = ActivityOptions.makeSceneTransitionAnimation(
|
||||||
mainActivity,
|
mainActivity,
|
||||||
|
@ -73,22 +73,33 @@ class BannerHomeFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
lastAdded.setOnClickListener {
|
lastAdded.setOnClickListener {
|
||||||
NavigationUtil.goToPlaylistNew(requireActivity(), LastAddedPlaylist(requireActivity()))
|
findActivityNavController(R.id.fragment_container).navigate(
|
||||||
|
R.id.playlistDetailsFragment,
|
||||||
|
bundleOf(EXTRA_PLAYLIST to LastAddedPlaylist())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
topPlayed.setOnClickListener {
|
topPlayed.setOnClickListener {
|
||||||
NavigationUtil.goToPlaylistNew(
|
findActivityNavController(R.id.fragment_container).navigate(
|
||||||
requireActivity(),
|
R.id.playlistDetailsFragment,
|
||||||
MyTopTracksPlaylist(requireActivity())
|
bundleOf(EXTRA_PLAYLIST to TopTracksPlaylist())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
actionShuffle.setOnClickListener {
|
actionShuffle.setOnClickListener {
|
||||||
MusicPlayerRemote.openAndShuffleQueue(SongLoader.getAllSongs(requireActivity()), true)
|
lifecycleScope.launch {
|
||||||
|
MusicPlayerRemote.openAndShuffleQueue(
|
||||||
|
repository.allSongs(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
history.setOnClickListener {
|
history.setOnClickListener {
|
||||||
NavigationUtil.goToPlaylistNew(requireActivity(), HistoryPlaylist(requireActivity()))
|
requireActivity().findNavController(R.id.fragment_container).navigate(
|
||||||
|
R.id.playlistDetailsFragment,
|
||||||
|
bundleOf(EXTRA_PLAYLIST to HistoryPlaylist())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
userImage.setOnClickListener {
|
userImage.setOnClickListener {
|
||||||
|
@ -101,15 +112,14 @@ class BannerHomeFragment :
|
||||||
}
|
}
|
||||||
titleWelcome?.text = String.format("%s", PreferenceUtil.userName)
|
titleWelcome?.text = String.format("%s", PreferenceUtil.userName)
|
||||||
|
|
||||||
val homeAdapter = HomeAdapter(mainActivity, displayMetrics)
|
val homeAdapter = HomeAdapter(mainActivity)
|
||||||
recyclerView.apply {
|
recyclerView.apply {
|
||||||
layoutManager = LinearLayoutManager(mainActivity)
|
layoutManager = LinearLayoutManager(mainActivity)
|
||||||
adapter = homeAdapter
|
adapter = homeAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryViewModel.homeLiveData
|
libraryViewModel.homeLiveData.observe(viewLifecycleOwner, Observer {
|
||||||
.observe(viewLifecycleOwner, Observer { sections ->
|
homeAdapter.swapData(it)
|
||||||
homeAdapter.swapData(sections)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
loadProfile()
|
loadProfile()
|
||||||
|
@ -133,8 +143,8 @@ class BannerHomeFragment :
|
||||||
const val TAG: String = "BannerHomeFragment"
|
const val TAG: String = "BannerHomeFragment"
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun newInstance(): BannerHomeFragment {
|
fun newInstance(): HomeFragment {
|
||||||
return BannerHomeFragment()
|
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.fragment.app.Fragment
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import io.github.muntashirakon.music.R
|
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.fragments.NowPlayingScreen.*
|
||||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
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?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
val navController = navController(R.id.playerFragmentContainer)
|
val navController = findNavController(R.id.playerFragmentContainer)
|
||||||
updateNowPlaying(navController)
|
updateNowPlaying(navController)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import kotlinx.android.synthetic.main.fragment_player_album_cover.*
|
||||||
|
|
||||||
class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_player_album_cover),
|
class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_player_album_cover),
|
||||||
ViewPager.OnPageChangeListener {
|
ViewPager.OnPageChangeListener {
|
||||||
|
|
||||||
private var callbacks: Callbacks? = null
|
private var callbacks: Callbacks? = null
|
||||||
private var currentPosition: Int = 0
|
private var currentPosition: Int = 0
|
||||||
private val colorReceiver = object : AlbumCoverFragment.ColorReceiver {
|
private val colorReceiver = object : AlbumCoverFragment.ColorReceiver {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package io.github.muntashirakon.music.fragments.player.full
|
package io.github.muntashirakon.music.fragments.player.full
|
||||||
|
|
||||||
import android.app.ActivityOptions
|
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -8,31 +7,36 @@ import android.view.View
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
|
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.R
|
||||||
|
import io.github.muntashirakon.music.extensions.findActivityNavController
|
||||||
import io.github.muntashirakon.music.extensions.hide
|
import io.github.muntashirakon.music.extensions.hide
|
||||||
import io.github.muntashirakon.music.extensions.show
|
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.base.AbsPlayerFragment
|
||||||
import io.github.muntashirakon.music.fragments.player.PlayerAlbumCoverFragment
|
import io.github.muntashirakon.music.fragments.player.PlayerAlbumCoverFragment
|
||||||
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
import io.github.muntashirakon.music.glide.ArtistGlideRequest
|
||||||
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
import io.github.muntashirakon.music.glide.RetroMusicColoredTarget
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||||
import io.github.muntashirakon.music.helper.MusicProgressViewUpdateHelper
|
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.Song
|
||||||
import io.github.muntashirakon.music.model.lyrics.AbsSynchronizedLyrics
|
import io.github.muntashirakon.music.model.lyrics.AbsSynchronizedLyrics
|
||||||
import io.github.muntashirakon.music.model.lyrics.Lyrics
|
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 io.github.muntashirakon.music.util.color.MediaNotificationProcessor
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import kotlinx.android.synthetic.main.fragment_full.*
|
import kotlinx.android.synthetic.main.fragment_full.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
|
class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
|
||||||
MusicProgressViewUpdateHelper.Callback {
|
MusicProgressViewUpdateHelper.Callback {
|
||||||
|
private val artistRepository by inject<ArtistRepository>()
|
||||||
private lateinit var lyricsLayout: FrameLayout
|
private lateinit var lyricsLayout: FrameLayout
|
||||||
private lateinit var lyricsLine1: TextView
|
private lateinit var lyricsLine1: TextView
|
||||||
private lateinit var lyricsLine2: TextView
|
private lateinit var lyricsLine2: TextView
|
||||||
|
@ -150,30 +154,20 @@ class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
|
||||||
|
|
||||||
private fun setupArtist() {
|
private fun setupArtist() {
|
||||||
artistImage.setOnClickListener {
|
artistImage.setOnClickListener {
|
||||||
val transitionName =
|
mainActivity.collapsePanel()
|
||||||
"${getString(R.string.transition_artist_image)}_${MusicPlayerRemote.currentSong.artistId}"
|
findActivityNavController(R.id.fragment_container)
|
||||||
val activityOptions =
|
.navigate(
|
||||||
ActivityOptions.makeSceneTransitionAnimation(
|
R.id.artistDetailsFragment,
|
||||||
requireActivity(),
|
bundleOf(EXTRA_ARTIST_ID to MusicPlayerRemote.currentSong.artistId)
|
||||||
artistImage,
|
|
||||||
transitionName
|
|
||||||
)
|
|
||||||
NavigationUtil.goToArtistOptions(
|
|
||||||
requireActivity(),
|
|
||||||
MusicPlayerRemote.currentSong.artistId,
|
|
||||||
activityOptions
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpSubFragments() {
|
private fun setUpSubFragments() {
|
||||||
controlsFragment =
|
controlsFragment = whichFragment(R.id.playbackControlsFragment)
|
||||||
childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as FullPlaybackControlsFragment
|
val coverFragment: PlayerAlbumCoverFragment = whichFragment(R.id.playerAlbumCoverFragment)
|
||||||
|
coverFragment.setCallbacks(this)
|
||||||
val playerAlbumCoverFragment =
|
coverFragment.removeSlideEffect()
|
||||||
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
|
|
||||||
playerAlbumCoverFragment.setCallbacks(this)
|
|
||||||
playerAlbumCoverFragment.removeSlideEffect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onShow() {
|
override fun onShow() {
|
||||||
|
@ -228,9 +222,8 @@ class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full),
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateArtistImage() {
|
private fun updateArtistImage() {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
lifecycleScope.launch {
|
||||||
val artist =
|
val artist = artistRepository.artist(MusicPlayerRemote.currentSong.artistId)
|
||||||
ArtistLoader.getArtist(requireContext(), MusicPlayerRemote.currentSong.artistId)
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
ArtistGlideRequest.Builder.from(Glide.with(requireContext()), artist)
|
||||||
.generatePalette(requireContext())
|
.generatePalette(requireContext())
|
||||||
|
|
|
@ -52,7 +52,7 @@ class PlayerPlaybackControlsFragment :
|
||||||
showBonceAnimation(playPauseButton)
|
showBonceAnimation(playPauseButton)
|
||||||
}
|
}
|
||||||
title.isSelected = true
|
title.isSelected = true
|
||||||
|
text.isSelected = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setColor(color: MediaNotificationProcessor) {
|
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.os.Bundle
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
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.animator.RefactoredDefaultItemAnimator
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
|
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
|
||||||
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils
|
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.androidx.viewmodel.ext.android.viewModel
|
||||||
import org.koin.core.parameter.parametersOf
|
import org.koin.core.parameter.parametersOf
|
||||||
|
|
||||||
|
class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail) {
|
||||||
class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
private val arguments by navArgs<PlaylistDetailsFragmentArgs>()
|
||||||
|
|
||||||
|
|
||||||
private val viewModel: PlaylistDetailsViewModel by viewModel {
|
private val viewModel: PlaylistDetailsViewModel by viewModel {
|
||||||
parametersOf(extraNotNull<Playlist>(EXTRA_PLAYLIST).value)
|
parametersOf(arguments.extraPlaylist)
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var playlist: Playlist
|
private lateinit var playlist: Playlist
|
||||||
private var cab: MaterialCab? = null
|
|
||||||
private lateinit var adapter: SongAdapter
|
private lateinit var adapter: SongAdapter
|
||||||
|
|
||||||
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
|
private var wrappedAdapter: RecyclerView.Adapter<*>? = null
|
||||||
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
|
private var recyclerViewDragDropManager: RecyclerViewDragDropManager? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
setDrawUnderStatusBar()
|
super.onActivityCreated(savedInstanceState)
|
||||||
super.onCreate(savedInstanceState)
|
setHasOptionsMenu(true)
|
||||||
setStatusbarColorAuto()
|
mainActivity.addMusicServiceEventListener(viewModel)
|
||||||
setNavigationbarColorAuto()
|
mainActivity.setSupportActionBar(toolbar)
|
||||||
setTaskDescriptionColorAuto()
|
mainActivity.hideBottomBarVisibility(false)
|
||||||
setLightNavigationBar(true)
|
|
||||||
setBottomBarVisibility(View.GONE)
|
|
||||||
|
|
||||||
playlist = extraNotNull<Playlist>(EXTRA_PLAYLIST).value
|
playlist = arguments.extraPlaylist
|
||||||
|
|
||||||
setUpToolBar()
|
|
||||||
setUpRecyclerView()
|
setUpRecyclerView()
|
||||||
|
|
||||||
viewModel.getSongs().observe(this, Observer {
|
viewModel.getSongs().observe(viewLifecycleOwner, Observer {
|
||||||
songs(it)
|
songs(it)
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.getPlaylist().observe(this, Observer {
|
viewModel.getPlaylist().observe(viewLifecycleOwner, Observer {
|
||||||
playlist = it
|
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() {
|
private fun setUpRecyclerView() {
|
||||||
recyclerView.layoutManager = LinearLayoutManager(this)
|
recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
if (playlist is AbsCustomPlaylist) {
|
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
|
recyclerView.adapter = adapter
|
||||||
} else {
|
} else {
|
||||||
recyclerViewDragDropManager = RecyclerViewDragDropManager()
|
recyclerViewDragDropManager = RecyclerViewDragDropManager()
|
||||||
val animator = RefactoredDefaultItemAnimator()
|
val animator = RefactoredDefaultItemAnimator()
|
||||||
adapter = OrderablePlaylistSongAdapter(this,
|
adapter = OrderablePlaylistSongAdapter(
|
||||||
|
requireActivity(),
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
R.layout.item_list,
|
R.layout.item_list,
|
||||||
this,
|
null,
|
||||||
object : OrderablePlaylistSongAdapter.OnMoveItemListener {
|
object : OrderablePlaylistSongAdapter.OnMoveItemListener {
|
||||||
override fun onMoveItem(fromPosition: Int, toPosition: Int) {
|
override fun onMoveItem(fromPosition: Int, toPosition: Int) {
|
||||||
if (PlaylistsUtil.moveItem(
|
if (PlaylistsUtil.moveItem(
|
||||||
this@PlaylistDetailActivity,
|
requireContext(),
|
||||||
playlist.id,
|
playlist.id,
|
||||||
fromPosition,
|
fromPosition,
|
||||||
toPosition
|
toPosition
|
||||||
|
@ -116,58 +102,21 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpToolBar() {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
applyToolbar(toolbar)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
title = playlist.name
|
val menuRes = if (playlist is AbsCustomPlaylist)
|
||||||
}
|
R.menu.menu_smart_playlist_detail
|
||||||
|
else R.menu.menu_playlist_detail
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
inflater.inflate(menuRes, menu)
|
||||||
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 onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
return PlaylistMenuHelper.handleMenuClick(requireActivity(), playlist, item)
|
||||||
android.R.id.home -> {
|
|
||||||
onBackPressed()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PlaylistMenuHelper.handleMenuClick(this, playlist, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun openCab(menuRes: Int, callback: MaterialCab.Callback): MaterialCab {
|
|
||||||
if (cab != null && cab!!.isActive) {
|
|
||||||
cab!!.finish()
|
|
||||||
}
|
|
||||||
cab = MaterialCab(this, R.id.cab_stub).setMenu(menuRes)
|
|
||||||
.setCloseDrawableRes(R.drawable.ic_close)
|
|
||||||
.setBackgroundColor(
|
|
||||||
RetroColorUtil.shiftBackgroundColorForLightText(
|
|
||||||
ATHUtil.resolveColor(
|
|
||||||
this,
|
|
||||||
R.attr.colorSurface
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).start(callback)
|
|
||||||
return cab!!
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBackPressed() {
|
|
||||||
if (cab != null && cab!!.isActive) {
|
|
||||||
cab!!.finish()
|
|
||||||
} else {
|
|
||||||
recyclerView!!.stopScroll()
|
|
||||||
super.onBackPressed()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkForPadding() {
|
private fun checkForPadding() {
|
||||||
val height = DensityUtil.dip2px(this, 52f)
|
val height = dipToPix(52f)
|
||||||
recyclerView.setPadding(0, 0, 0, (height))
|
recyclerView.setPadding(0, 0, 0, height.toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkIsEmpty() {
|
private fun checkIsEmpty() {
|
||||||
|
@ -181,7 +130,7 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
return String(Character.toChars(unicode))
|
return String(Character.toChars(unicode))
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun onPause() {
|
override fun onPause() {
|
||||||
if (recyclerViewDragDropManager != null) {
|
if (recyclerViewDragDropManager != null) {
|
||||||
recyclerViewDragDropManager!!.cancelDrag()
|
recyclerViewDragDropManager!!.cancelDrag()
|
||||||
}
|
}
|
||||||
|
@ -206,7 +155,7 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showEmptyView() {
|
private fun showEmptyView() {
|
||||||
empty.visibility = View.VISIBLE
|
empty.visibility = View.VISIBLE
|
||||||
emptyText.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.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
@ -6,22 +6,20 @@ import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import io.github.muntashirakon.music.App
|
import io.github.muntashirakon.music.App
|
||||||
import io.github.muntashirakon.music.interfaces.MusicServiceEventListener
|
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.AbsCustomPlaylist
|
||||||
import io.github.muntashirakon.music.model.Playlist
|
import io.github.muntashirakon.music.model.Playlist
|
||||||
import io.github.muntashirakon.music.model.Song
|
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 io.github.muntashirakon.music.util.PlaylistsUtil
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class PlaylistDetailsViewModel(
|
class PlaylistDetailsViewModel(
|
||||||
private val repository: RepositoryImpl,
|
private val realRepository: RealRepository,
|
||||||
private var playlist: Playlist
|
private var playlist: Playlist
|
||||||
) : ViewModel(), MusicServiceEventListener {
|
) : ViewModel(), MusicServiceEventListener {
|
||||||
private val _playListSongs = MutableLiveData<List<Song>>()
|
private val _playListSongs = MutableLiveData<List<Song>>()
|
||||||
|
|
||||||
private val _playlist = MutableLiveData<Playlist>().apply {
|
private val _playlist = MutableLiveData<Playlist>().apply {
|
||||||
postValue(playlist)
|
postValue(playlist)
|
||||||
}
|
}
|
||||||
|
@ -35,7 +33,7 @@ class PlaylistDetailsViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadPlaylistSongs(playlist: Playlist) = viewModelScope.launch {
|
private fun loadPlaylistSongs(playlist: Playlist) = viewModelScope.launch {
|
||||||
val songs = repository.getPlaylistSongs(playlist)
|
val songs = realRepository.getPlaylistSongs(playlist)
|
||||||
withContext(Main) { _playListSongs.postValue(songs) }
|
withContext(Main) { _playListSongs.postValue(songs) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,10 +48,12 @@ class PlaylistDetailsViewModel(
|
||||||
val playlistName =
|
val playlistName =
|
||||||
PlaylistsUtil.getNameForPlaylist(App.getContext(), playlist.id.toLong())
|
PlaylistsUtil.getNameForPlaylist(App.getContext(), playlist.id.toLong())
|
||||||
if (playlistName != playlist.name) {
|
if (playlistName != playlist.name) {
|
||||||
playlist = PlaylistLoader.getPlaylist(App.getContext(), playlist.id)
|
viewModelScope.launch {
|
||||||
|
playlist = realRepository.playlist(playlist.id)
|
||||||
_playlist.postValue(playlist)
|
_playlist.postValue(playlist)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
loadPlaylistSongs(playlist)
|
loadPlaylistSongs(playlist)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package io.github.muntashirakon.music.fragments.playlists
|
package io.github.muntashirakon.music.fragments.playlists
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.Menu
|
|
||||||
import android.view.MenuInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
@ -12,7 +10,7 @@ import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewFragment
|
||||||
import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
|
import io.github.muntashirakon.music.interfaces.MainActivityFragmentCallbacks
|
||||||
|
|
||||||
class PlaylistsFragment :
|
class PlaylistsFragment :
|
||||||
AbsRecyclerViewFragment<PlaylistAdapter, GridLayoutManager>() ,
|
AbsRecyclerViewFragment<PlaylistAdapter, GridLayoutManager>(),
|
||||||
MainActivityFragmentCallbacks {
|
MainActivityFragmentCallbacks {
|
||||||
|
|
||||||
override fun handleBackPress(): Boolean {
|
override fun handleBackPress(): Boolean {
|
||||||
|
@ -21,12 +19,11 @@ class PlaylistsFragment :
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.playlisitsLiveData.observe(viewLifecycleOwner, Observer { playlists ->
|
libraryViewModel.playlisitsLiveData.observe(viewLifecycleOwner, Observer {
|
||||||
if (playlists.isNotEmpty()) {
|
if (it.isNotEmpty())
|
||||||
adapter?.swapDataSet(playlists)
|
adapter?.swapDataSet(it)
|
||||||
} else {
|
else
|
||||||
adapter?.swapDataSet(listOf())
|
adapter?.swapDataSet(listOf())
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,26 +36,14 @@ class PlaylistsFragment :
|
||||||
|
|
||||||
override fun createAdapter(): PlaylistAdapter {
|
override fun createAdapter(): PlaylistAdapter {
|
||||||
return PlaylistAdapter(
|
return PlaylistAdapter(
|
||||||
mainActivity,
|
requireActivity(),
|
||||||
ArrayList(),
|
ArrayList(),
|
||||||
R.layout.item_list,
|
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 {
|
companion object {
|
||||||
@JvmField
|
|
||||||
val TAG: String = PlaylistsFragment::class.java.simpleName
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun newInstance(): PlaylistsFragment {
|
fun newInstance(): PlaylistsFragment {
|
||||||
return 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.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
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.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class SearchViewModel(private val repository: RepositoryImpl) : ViewModel() {
|
class SearchViewModel(private val realRepository: RealRepository) : ViewModel() {
|
||||||
private val results = MutableLiveData<MutableList<Any>>()
|
private val results = MutableLiveData<MutableList<Any>>()
|
||||||
|
|
||||||
fun getSearchResult(): LiveData<MutableList<Any>> = results
|
fun getSearchResult(): LiveData<MutableList<Any>> = results
|
||||||
|
|
||||||
fun search(query: String?) = viewModelScope.launch(IO) {
|
fun search(query: String?) = viewModelScope.launch(IO) {
|
||||||
val result = repository.search(query)
|
val result = realRepository.search(query)
|
||||||
withContext(Main) { results.postValue(result) }
|
withContext(Main) { results.postValue(result) }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,17 +14,13 @@
|
||||||
|
|
||||||
package io.github.muntashirakon.music.fragments.settings
|
package io.github.muntashirakon.music.fragments.settings
|
||||||
|
|
||||||
import android.content.res.ColorStateList
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import io.github.muntashirakon.music.R
|
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.*
|
import kotlinx.android.synthetic.main.fragment_main_settings.*
|
||||||
|
|
||||||
class MainSettingsFragment : Fragment(), View.OnClickListener {
|
class MainSettingsFragment : Fragment(), View.OnClickListener {
|
||||||
|
@ -60,12 +56,4 @@ class MainSettingsFragment : Fragment(), View.OnClickListener {
|
||||||
otherSettings.setOnClickListener(this)
|
otherSettings.setOnClickListener(this)
|
||||||
aboutSettings.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
|
package io.github.muntashirakon.music.fragments.songs
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.*
|
import android.view.View
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import io.github.muntashirakon.music.R
|
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.adapter.song.SongAdapter
|
||||||
import io.github.muntashirakon.music.fragments.ReloadType
|
import io.github.muntashirakon.music.fragments.ReloadType
|
||||||
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
|
@ -24,11 +23,10 @@ class SongsFragment :
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.songsLiveData.observe(viewLifecycleOwner, Observer {
|
libraryViewModel.songsLiveData.observe(viewLifecycleOwner, Observer {
|
||||||
if (it.isNotEmpty()) {
|
if (it.isNotEmpty())
|
||||||
adapter?.swapDataSet(it)
|
adapter?.swapDataSet(it)
|
||||||
} else {
|
else
|
||||||
adapter?.swapDataSet(listOf())
|
adapter?.swapDataSet(listOf())
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,26 +34,16 @@ class SongsFragment :
|
||||||
get() = R.string.no_songs
|
get() = R.string.no_songs
|
||||||
|
|
||||||
override fun createLayoutManager(): GridLayoutManager {
|
override fun createLayoutManager(): GridLayoutManager {
|
||||||
return GridLayoutManager(requireActivity(), getGridSize()).apply {
|
return GridLayoutManager(requireActivity(), getGridSize())
|
||||||
spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
|
|
||||||
override fun getSpanSize(position: Int): Int {
|
|
||||||
return if (position == 0) {
|
|
||||||
getGridSize()
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createAdapter(): SongAdapter {
|
override fun createAdapter(): SongAdapter {
|
||||||
val dataSet = if (adapter == null) mutableListOf() else adapter!!.dataSet
|
val dataSet = if (adapter == null) mutableListOf() else adapter!!.dataSet
|
||||||
return ShuffleButtonSongAdapter(
|
return SongAdapter(
|
||||||
mainActivity,
|
requireActivity(),
|
||||||
dataSet,
|
dataSet,
|
||||||
itemLayoutRes(),
|
R.layout.item_list,
|
||||||
mainActivity
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,72 +97,4 @@ class SongsFragment :
|
||||||
return 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) {
|
if (ignoreMediaStore) {
|
||||||
return requestManager.load(new AudioFileCover(song.getData()));
|
return requestManager.load(new AudioFileCover(song.getData()));
|
||||||
} else {
|
} 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) {
|
if (ignoreMediaStore) {
|
||||||
return requestManager.load(new AudioFileCover(song.getData()));
|
return requestManager.load(new AudioFileCover(song.getData()));
|
||||||
} else {
|
} else {
|
||||||
return requestManager.loadFromMediaStore(MusicUtil.getMediaStoreAlbumCoverUri(song.getAlbumId()));
|
return requestManager.loadFromMediaStore(MusicUtil.INSTANCE.getMediaStoreAlbumCoverUri(song.getAlbumId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ object M3UWriter : M3UConstants {
|
||||||
): File? {
|
): File? {
|
||||||
if (!dir.exists()) dir.mkdirs()
|
if (!dir.exists()) dir.mkdirs()
|
||||||
val file = File(dir, playlist.name + "." + M3UConstants.EXTENSION)
|
val file = File(dir, playlist.name + "." + M3UConstants.EXTENSION)
|
||||||
val songs = playlist.getSongs(context)
|
val songs = playlist.getSongs()
|
||||||
if (songs.size > 0) {
|
if (songs.size > 0) {
|
||||||
val bw = BufferedWriter(FileWriter(file))
|
val bw = BufferedWriter(FileWriter(file))
|
||||||
bw.write(M3UConstants.HEADER)
|
bw.write(M3UConstants.HEADER)
|
||||||
|
|
|
@ -23,23 +23,26 @@ import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.provider.DocumentsContract
|
import android.provider.DocumentsContract
|
||||||
import android.provider.MediaStore
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import io.github.muntashirakon.music.R
|
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.model.Song
|
||||||
|
import io.github.muntashirakon.music.repository.SongRepository
|
||||||
import io.github.muntashirakon.music.service.MusicService
|
import io.github.muntashirakon.music.service.MusicService
|
||||||
|
|
||||||
import io.github.muntashirakon.music.util.PreferenceUtil
|
import io.github.muntashirakon.music.util.PreferenceUtil
|
||||||
|
import org.koin.core.KoinComponent
|
||||||
|
import org.koin.core.inject
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object MusicPlayerRemote {
|
object MusicPlayerRemote : KoinComponent {
|
||||||
val TAG: String = MusicPlayerRemote::class.java.simpleName
|
val TAG: String = MusicPlayerRemote::class.java.simpleName
|
||||||
private val mConnectionMap = WeakHashMap<Context, ServiceBinder>()
|
private val mConnectionMap = WeakHashMap<Context, ServiceBinder>()
|
||||||
var musicService: MusicService? = null
|
var musicService: MusicService? = null
|
||||||
|
|
||||||
|
private val songRepository by inject<SongRepository>()
|
||||||
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val isPlaying: Boolean
|
val isPlaying: Boolean
|
||||||
get() = musicService != null && musicService!!.isPlaying
|
get() = musicService != null && musicService!!.isPlaying
|
||||||
|
@ -413,21 +416,14 @@ object MusicPlayerRemote {
|
||||||
songId = uri.lastPathSegment
|
songId = uri.lastPathSegment
|
||||||
}
|
}
|
||||||
if (songId != null) {
|
if (songId != null) {
|
||||||
songs = SongLoader.getSongs(
|
songs = songRepository.songs(songId)
|
||||||
SongLoader.makeSongCursor(
|
|
||||||
musicService!!,
|
|
||||||
MediaStore.Audio.AudioColumns._ID + "=?",
|
|
||||||
arrayOf(songId)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (songs == null) {
|
if (songs == null) {
|
||||||
var songFile: File? = null
|
var songFile: File? = null
|
||||||
if (uri.authority != null && uri.authority == "com.android.externalstorage.documents") {
|
if (uri.authority != null && uri.authority == "com.android.externalstorage.documents") {
|
||||||
songFile =
|
songFile = File(
|
||||||
File(
|
|
||||||
Environment.getExternalStorageDirectory(),
|
Environment.getExternalStorageDirectory(),
|
||||||
uri.path?.split(":".toRegex(), 2)?.get(1)
|
uri.path?.split(":".toRegex(), 2)?.get(1)
|
||||||
)
|
)
|
||||||
|
@ -441,13 +437,7 @@ object MusicPlayerRemote {
|
||||||
songFile = File(uri.path)
|
songFile = File(uri.path)
|
||||||
}
|
}
|
||||||
if (songFile != null) {
|
if (songFile != null) {
|
||||||
songs = SongLoader.getSongs(
|
songs = songRepository.songsByFilePath(songFile.absolutePath)
|
||||||
SongLoader.makeSongCursor(
|
|
||||||
musicService!!,
|
|
||||||
MediaStore.Audio.AudioColumns.DATA + "=?",
|
|
||||||
arrayOf(songFile.absolutePath)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (songs != null && songs.isNotEmpty()) {
|
if (songs != null && songs.isNotEmpty()) {
|
||||||
|
|
|
@ -18,29 +18,31 @@ import android.app.SearchManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import io.github.muntashirakon.music.loaders.SongLoader
|
|
||||||
import io.github.muntashirakon.music.model.Song
|
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.*
|
import java.util.*
|
||||||
|
|
||||||
object SearchQueryHelper {
|
object SearchQueryHelper : KoinComponent {
|
||||||
private const val TITLE_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.TITLE + ") = ?"
|
private const val TITLE_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.TITLE + ") = ?"
|
||||||
private const val ALBUM_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ALBUM + ") = ?"
|
private const val ALBUM_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ALBUM + ") = ?"
|
||||||
private const val ARTIST_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ARTIST + ") = ?"
|
private const val ARTIST_SELECTION = "lower(" + MediaStore.Audio.AudioColumns.ARTIST + ") = ?"
|
||||||
private const val AND = " AND "
|
private const val AND = " AND "
|
||||||
|
private val songRepository by inject<RealSongRepository>()
|
||||||
var songs = ArrayList<Song>()
|
var songs = ArrayList<Song>()
|
||||||
|
|
||||||
@JvmStatic
|
@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 query = extras.getString(SearchManager.QUERY, null)
|
||||||
val artistName = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST, null)
|
val artistName = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST, null)
|
||||||
val albumName = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM, null)
|
val albumName = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM, null)
|
||||||
val titleName = extras.getString(MediaStore.EXTRA_MEDIA_TITLE, 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) {
|
if (artistName != null && albumName != null && titleName != null) {
|
||||||
songs = SongLoader.getSongs(
|
songs = songRepository.songs(
|
||||||
SongLoader.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
context,
|
|
||||||
ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION,
|
ARTIST_SELECTION + AND + ALBUM_SELECTION + AND + TITLE_SELECTION,
|
||||||
arrayOf(
|
arrayOf(
|
||||||
artistName.toLowerCase(),
|
artistName.toLowerCase(),
|
||||||
|
@ -54,9 +56,8 @@ object SearchQueryHelper {
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
if (artistName != null && titleName != null) {
|
if (artistName != null && titleName != null) {
|
||||||
songs = SongLoader.getSongs(
|
songs = songRepository.songs(
|
||||||
SongLoader.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
context,
|
|
||||||
ARTIST_SELECTION + AND + TITLE_SELECTION,
|
ARTIST_SELECTION + AND + TITLE_SELECTION,
|
||||||
arrayOf(artistName.toLowerCase(), titleName.toLowerCase())
|
arrayOf(artistName.toLowerCase(), titleName.toLowerCase())
|
||||||
)
|
)
|
||||||
|
@ -66,9 +67,8 @@ object SearchQueryHelper {
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
if (albumName != null && titleName != null) {
|
if (albumName != null && titleName != null) {
|
||||||
songs = SongLoader.getSongs(
|
songs = songRepository.songs(
|
||||||
SongLoader.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
context,
|
|
||||||
ALBUM_SELECTION + AND + TITLE_SELECTION,
|
ALBUM_SELECTION + AND + TITLE_SELECTION,
|
||||||
arrayOf(albumName.toLowerCase(), titleName.toLowerCase())
|
arrayOf(albumName.toLowerCase(), titleName.toLowerCase())
|
||||||
)
|
)
|
||||||
|
@ -78,9 +78,8 @@ object SearchQueryHelper {
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
if (artistName != null) {
|
if (artistName != null) {
|
||||||
songs = SongLoader.getSongs(
|
songs = songRepository.songs(
|
||||||
SongLoader.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
context,
|
|
||||||
ARTIST_SELECTION,
|
ARTIST_SELECTION,
|
||||||
arrayOf(artistName.toLowerCase())
|
arrayOf(artistName.toLowerCase())
|
||||||
)
|
)
|
||||||
|
@ -90,9 +89,8 @@ object SearchQueryHelper {
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
if (albumName != null) {
|
if (albumName != null) {
|
||||||
songs = SongLoader.getSongs(
|
songs = songRepository.songs(
|
||||||
SongLoader.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
context,
|
|
||||||
ALBUM_SELECTION,
|
ALBUM_SELECTION,
|
||||||
arrayOf(albumName.toLowerCase())
|
arrayOf(albumName.toLowerCase())
|
||||||
)
|
)
|
||||||
|
@ -102,9 +100,8 @@ object SearchQueryHelper {
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
if (titleName != null) {
|
if (titleName != null) {
|
||||||
songs = SongLoader.getSongs(
|
songs = songRepository.songs(
|
||||||
SongLoader.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
context,
|
|
||||||
TITLE_SELECTION,
|
TITLE_SELECTION,
|
||||||
arrayOf(titleName.toLowerCase())
|
arrayOf(titleName.toLowerCase())
|
||||||
)
|
)
|
||||||
|
@ -113,10 +110,8 @@ object SearchQueryHelper {
|
||||||
if (songs.isNotEmpty()) {
|
if (songs.isNotEmpty()) {
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
songs =
|
songs = songRepository.songs(
|
||||||
SongLoader.getSongs(
|
songRepository.makeSongCursor(
|
||||||
SongLoader.makeSongCursor(
|
|
||||||
context,
|
|
||||||
ARTIST_SELECTION,
|
ARTIST_SELECTION,
|
||||||
arrayOf(query.toLowerCase())
|
arrayOf(query.toLowerCase())
|
||||||
)
|
)
|
||||||
|
@ -125,9 +120,8 @@ object SearchQueryHelper {
|
||||||
if (songs.isNotEmpty()) {
|
if (songs.isNotEmpty()) {
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
songs = SongLoader.getSongs(
|
songs = songRepository.songs(
|
||||||
SongLoader.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
context,
|
|
||||||
ALBUM_SELECTION,
|
ALBUM_SELECTION,
|
||||||
arrayOf(query.toLowerCase())
|
arrayOf(query.toLowerCase())
|
||||||
)
|
)
|
||||||
|
@ -135,9 +129,8 @@ object SearchQueryHelper {
|
||||||
if (songs.isNotEmpty()) {
|
if (songs.isNotEmpty()) {
|
||||||
return songs
|
return songs
|
||||||
}
|
}
|
||||||
songs = SongLoader.getSongs(
|
songs = songRepository.songs(
|
||||||
SongLoader.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
context,
|
|
||||||
TITLE_SELECTION,
|
TITLE_SELECTION,
|
||||||
arrayOf(query.toLowerCase())
|
arrayOf(query.toLowerCase())
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,43 +14,43 @@
|
||||||
|
|
||||||
package io.github.muntashirakon.music.helper.menu
|
package io.github.muntashirakon.music.helper.menu
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.view.MenuItem
|
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.R
|
||||||
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
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.Genre
|
||||||
import io.github.muntashirakon.music.model.Song
|
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 {
|
object GenreMenuHelper : KoinComponent {
|
||||||
fun handleMenuClick(activity: AppCompatActivity, genre: Genre, item: MenuItem): Boolean {
|
private val genreRepository by inject<GenreRepository>()
|
||||||
|
fun handleMenuClick(activity: FragmentActivity, genre: Genre, item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_play -> {
|
R.id.action_play -> {
|
||||||
MusicPlayerRemote.openQueue(getGenreSongs(activity, genre), 0, true)
|
MusicPlayerRemote.openQueue(getGenreSongs(genre), 0, true)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_play_next -> {
|
R.id.action_play_next -> {
|
||||||
MusicPlayerRemote.playNext(getGenreSongs(activity, genre))
|
MusicPlayerRemote.playNext(getGenreSongs(genre))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_add_to_playlist -> {
|
R.id.action_add_to_playlist -> {
|
||||||
AddToPlaylistDialog.create(getGenreSongs(activity, genre))
|
AddToPlaylistDialog.create(getGenreSongs(genre))
|
||||||
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
.show(activity.supportFragmentManager, "ADD_PLAYLIST")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_add_to_current_playing -> {
|
R.id.action_add_to_current_playing -> {
|
||||||
MusicPlayerRemote.enqueue(getGenreSongs(activity, genre))
|
MusicPlayerRemote.enqueue(getGenreSongs(genre))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGenreSongs(activity: Activity, genre: Genre): ArrayList<Song> {
|
private fun getGenreSongs(genre: Genre): List<Song> {
|
||||||
return GenreLoader.getSongs(activity, genre.id)
|
return genreRepository.songs(genre.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,26 +19,24 @@ import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.widget.Toast
|
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.App
|
||||||
import io.github.muntashirakon.music.R
|
import io.github.muntashirakon.music.R
|
||||||
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
||||||
import io.github.muntashirakon.music.dialogs.DeletePlaylistDialog
|
import io.github.muntashirakon.music.dialogs.DeletePlaylistDialog
|
||||||
import io.github.muntashirakon.music.dialogs.RenamePlaylistDialog
|
import io.github.muntashirakon.music.dialogs.RenamePlaylistDialog
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
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.misc.WeakContextAsyncTask
|
||||||
import io.github.muntashirakon.music.model.AbsCustomPlaylist
|
import io.github.muntashirakon.music.model.AbsCustomPlaylist
|
||||||
import io.github.muntashirakon.music.model.Playlist
|
import io.github.muntashirakon.music.model.Playlist
|
||||||
import io.github.muntashirakon.music.model.Song
|
import io.github.muntashirakon.music.model.Song
|
||||||
import io.github.muntashirakon.music.util.PlaylistsUtil
|
import io.github.muntashirakon.music.util.PlaylistsUtil
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
object PlaylistMenuHelper {
|
object PlaylistMenuHelper {
|
||||||
|
|
||||||
fun handleMenuClick(
|
fun handleMenuClick(
|
||||||
activity: AppCompatActivity,
|
activity: FragmentActivity,
|
||||||
playlist: Playlist, item: MenuItem
|
playlist: Playlist, item: MenuItem
|
||||||
): Boolean {
|
): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
|
@ -80,11 +78,11 @@ object PlaylistMenuHelper {
|
||||||
private fun getPlaylistSongs(
|
private fun getPlaylistSongs(
|
||||||
activity: Activity,
|
activity: Activity,
|
||||||
playlist: Playlist
|
playlist: Playlist
|
||||||
): ArrayList<Song> {
|
): List<Song> {
|
||||||
return if (playlist is AbsCustomPlaylist) {
|
return if (playlist is AbsCustomPlaylist) {
|
||||||
playlist.getSongs(activity)
|
playlist.songs()
|
||||||
} else {
|
} else {
|
||||||
PlaylistSongsLoader.getPlaylistSongList(activity, playlist)
|
playlist.getSongs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,11 @@ import android.content.Intent
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.FragmentActivity
|
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.R
|
||||||
import io.github.muntashirakon.music.activities.tageditor.AbsTagEditorActivity
|
import io.github.muntashirakon.music.activities.tageditor.AbsTagEditorActivity
|
||||||
import io.github.muntashirakon.music.activities.tageditor.SongTagEditorActivity
|
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.interfaces.PaletteColorHolder
|
||||||
import io.github.muntashirakon.music.model.Song
|
import io.github.muntashirakon.music.model.Song
|
||||||
import io.github.muntashirakon.music.util.MusicUtil
|
import io.github.muntashirakon.music.util.MusicUtil
|
||||||
import io.github.muntashirakon.music.util.NavigationUtil
|
|
||||||
import io.github.muntashirakon.music.util.RingtoneManager
|
import io.github.muntashirakon.music.util.RingtoneManager
|
||||||
|
|
||||||
object SongMenuHelper {
|
object SongMenuHelper {
|
||||||
|
@ -89,18 +91,24 @@ object SongMenuHelper {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_go_to_album -> {
|
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
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_go_to_artist -> {
|
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 true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class OnClickSongMenu protected constructor(private val activity: AppCompatActivity) :
|
abstract class OnClickSongMenu(private val activity: FragmentActivity) :
|
||||||
View.OnClickListener, PopupMenu.OnMenuItemClickListener {
|
View.OnClickListener, PopupMenu.OnMenuItemClickListener {
|
||||||
|
|
||||||
open val menuRes: Int
|
open val menuRes: Int
|
||||||
|
|
|
@ -15,19 +15,17 @@
|
||||||
package io.github.muntashirakon.music.helper.menu
|
package io.github.muntashirakon.music.helper.menu
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
|
||||||
import io.github.muntashirakon.music.R
|
import io.github.muntashirakon.music.R
|
||||||
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
import io.github.muntashirakon.music.dialogs.AddToPlaylistDialog
|
||||||
import io.github.muntashirakon.music.dialogs.DeleteSongsDialog
|
import io.github.muntashirakon.music.dialogs.DeleteSongsDialog
|
||||||
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
import io.github.muntashirakon.music.helper.MusicPlayerRemote
|
||||||
import io.github.muntashirakon.music.model.Song
|
import io.github.muntashirakon.music.model.Song
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
object SongsMenuHelper {
|
object SongsMenuHelper {
|
||||||
fun handleMenuClick(
|
fun handleMenuClick(
|
||||||
activity: FragmentActivity,
|
activity: FragmentActivity,
|
||||||
songs: ArrayList<Song>,
|
songs: List<Song>,
|
||||||
menuItemId: Int
|
menuItemId: Int
|
||||||
): Boolean {
|
): Boolean {
|
||||||
when (menuItemId) {
|
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) {
|
public LrcView(Context context, AttributeSet attrs) {
|
||||||
this(context, attrs, 0);
|
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
|
val songCount: Int
|
||||||
get() = songs!!.size
|
get() = songs!!.size
|
||||||
|
|
||||||
|
val albumArtist: String?
|
||||||
|
get() = safeGetFirstSong().albumArtist
|
||||||
|
|
||||||
constructor(songs: ArrayList<Song>) {
|
constructor(songs: ArrayList<Song>) {
|
||||||
this.songs = songs
|
this.songs = songs
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,10 @@ class Artist {
|
||||||
|
|
||||||
val name: String
|
val name: String
|
||||||
get() {
|
get() {
|
||||||
val name = safeGetFirstAlbum().artistName
|
val name = safeGetFirstAlbum().safeGetFirstSong().albumArtist
|
||||||
return if (MusicUtil.isArtistNameUnknown(name)) {
|
return if (MusicUtil.isArtistNameUnknown(name)) {
|
||||||
UNKNOWN_ARTIST_DISPLAY_NAME
|
UNKNOWN_ARTIST_DISPLAY_NAME
|
||||||
} else name!!
|
} else safeGetFirstAlbum().safeGetFirstSong().artistName
|
||||||
}
|
}
|
||||||
|
|
||||||
val songCount: Int
|
val songCount: Int
|
||||||
|
|
|
@ -59,9 +59,9 @@ public class CategoryInfo implements Parcelable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Category {
|
public enum Category {
|
||||||
Home(R.id.action_home, R.string.home, R.drawable.asld_home),
|
Home(R.id.action_home, R.string.for_you, R.drawable.ic_face),
|
||||||
Songs(R.id.action_song, R.string.songs, R.drawable.asld_music_note),
|
Songs(R.id.action_song, R.string.songs, R.drawable.ic_audiotrack),
|
||||||
Albums(R.id.action_album, R.string.albums, R.drawable.asld_album),
|
Albums(R.id.action_album, R.string.albums, R.drawable.ic_album),
|
||||||
Artists(R.id.action_artist, R.string.artists, R.drawable.ic_artist),
|
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),
|
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),
|
Genres(R.id.action_genre, R.string.genres, R.drawable.ic_guitar),
|
||||||
|
|
|
@ -14,13 +14,10 @@
|
||||||
|
|
||||||
package io.github.muntashirakon.music.model
|
package io.github.muntashirakon.music.model
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import io.github.muntashirakon.music.HomeSection
|
||||||
import io.github.muntashirakon.music.adapter.HomeAdapter.Companion.HomeSection
|
|
||||||
|
|
||||||
class Home(
|
class Home(
|
||||||
val arrayList: List<*>,
|
val arrayList: List<Any>,
|
||||||
@HomeSection
|
@HomeSection
|
||||||
val homeSection: Int,
|
val homeSection: Int
|
||||||
@DrawableRes
|
|
||||||
val icon: 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