Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bfa3231823 | |||
| abe5d0b378 | |||
| 7b1138c428 | |||
|
|
b2b12c473c | ||
|
|
20cdcddd36 | ||
| c79fa89c1d | |||
|
|
2a995364a2 | ||
|
|
0f017a781f | ||
|
|
3e251a9b7a | ||
|
|
5c7257de3f | ||
|
|
873505776b | ||
| 6dc89ff95e | |||
|
|
013a7127e7 | ||
|
|
ed050ec2f7 | ||
|
|
e37cfc391f | ||
|
|
777fbcdf4d | ||
| 749d6dfb3f | |||
| 45f972c0b4 | |||
|
|
a344495893 | ||
|
|
c654b89cc0 | ||
|
|
b897faf071 | ||
|
|
7843db0c9c | ||
|
|
395a829621 | ||
| 9b0bef4f0d | |||
| 0e0cd3ea07 |
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -59,7 +59,7 @@ body:
|
|||||||
If your bug includes a crash, please use `adb logcat` or other ways to provide logs.
|
If your bug includes a crash, please use `adb logcat` or other ways to provide logs.
|
||||||
|
|
||||||
- type: input
|
- type: input
|
||||||
id: vimusic-version
|
id: muza-version
|
||||||
attributes:
|
attributes:
|
||||||
label: ViMusic version
|
label: ViMusic version
|
||||||
placeholder: |
|
placeholder: |
|
||||||
|
|||||||
33
README.md
@@ -1,21 +1,37 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="./app/src/main/ic_launcher-playstore.png" width="128" height="128" style="display: block; margin: 0 auto"/>
|
<img src="./app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp" width="128" height="128" style="display: block; margin: 0 auto"/>
|
||||||
<h1>Muza</h1>
|
<h1>Muza</h1>
|
||||||
<p>Стриминговый музыкальный плеер на Android</p>
|
<p>Стриминговый музыкальный плеер на Android</p>
|
||||||
|
<img alt="GitHub all releases" src="https://img.shields.io/github/downloads/hammsterr/muza/total?style=plastic&logo=github&logoColor=rgb&label=%D0%97%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BE%D0%BA&labelColor=rgb&color=rgb">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg" width="30%" />
|
<img src="./ScreenShots/01.jpg" width="30%" />
|
||||||
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg" width="30%" />
|
<img src="./ScreenShots/1.jpg" width="30%" />
|
||||||
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg" width="30%" />
|
<img src="./ScreenShots/2.jpg" width="30%" />
|
||||||
|
|
||||||
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/4.jpg" width="30%" />
|
<img src="./ScreenShots/3.jpg" width="30%" />
|
||||||
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/5.jpg" width="30%" />
|
<img src="./ScreenShots/4.jpg" width="30%" />
|
||||||
<img src="./fastlane/metadata/android/en-US/images/phoneScreenshots/6.jpg" width="30%" />
|
<img src="./ScreenShots/5.jpg" width="30%" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
Muza - это удобное и простое в использовании музыкальное приложение, которое позволяет слушать любимую музыку бесплатно и без каких-либо ограничений.
|
||||||
|
|
||||||
|
С помощью Muza вы можете создавать плейлисты, составлять музыкальные коллекции и наслаждаться звучанием того, что действительно нравится.
|
||||||
|
|
||||||
|
Мы предоставляем доступ к миллионам треков разных жанров и стилей, чтобы каждый пользователь мог найти здесь что-то для себя.
|
||||||
|
|
||||||
|
Кроме того, в приложении доступна функция чтения текстов песен, которая поможет подпевать и понимать глубинный смысл написанных слов.
|
||||||
|
|
||||||
|
С Muza с каждым днем вы будете открывать для себя что-то новое и интересное и делиться своими впечатлениями с друзьями.
|
||||||
|
Будьте на связи с любимой музыкой везде и всегда с Muza!
|
||||||
|
|
||||||
|
|
||||||
## Функции
|
## Функции
|
||||||
- Воспроизведение (почти) любой песни или видео с YouTube Music
|
- Воспроизведение (почти) любой песни или видео с YouTube Music
|
||||||
- Фоновое воспроизведение
|
- Фоновое воспроизведение
|
||||||
@@ -37,6 +53,7 @@
|
|||||||
|
|
||||||
## Скачать
|
## Скачать
|
||||||
|
|
||||||
|
[<img src="https://i.ibb.co/jMwfXFd/rustore-light.png" alt="Скачать из RuStore" height="60">](https://apps.rustore.ru/app/it.hamy.muza)
|
||||||
[<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png"
|
[<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png"
|
||||||
alt="Скачать из Гитхаба"
|
alt="Скачать из Гитхаба"
|
||||||
height="80">](https://github.com/hammsterr/muza/releases/latest)
|
height="80">](https://github.com/hammsterr/muza/releases/latest)
|
||||||
|
|||||||
BIN
ScreenShots/01.jpg
Normal file
|
After Width: | Height: | Size: 249 KiB |
BIN
ScreenShots/1.jpg
Normal file
|
After Width: | Height: | Size: 411 KiB |
BIN
ScreenShots/2.jpg
Normal file
|
After Width: | Height: | Size: 273 KiB |
BIN
ScreenShots/3.jpg
Normal file
|
After Width: | Height: | Size: 271 KiB |
BIN
ScreenShots/4.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
ScreenShots/5.jpg
Normal file
|
After Width: | Height: | Size: 129 KiB |
@@ -8,11 +8,11 @@ android {
|
|||||||
compileSdk = 33
|
compileSdk = 33
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "it.vfsfitvnm.vimusic"
|
applicationId = "it.hamy.muza"
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 33
|
targetSdk = 33
|
||||||
versionCode = 20
|
versionCode = 20
|
||||||
versionName = "0.5.4"
|
versionName = "0.5.4.1rus"
|
||||||
}
|
}
|
||||||
|
|
||||||
splits {
|
splits {
|
||||||
@@ -22,7 +22,7 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace = "it.vfsfitvnm.vimusic"
|
namespace = "it.hamy.muza"
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
@@ -33,7 +33,7 @@ android {
|
|||||||
release {
|
release {
|
||||||
isMinifyEnabled = true
|
isMinifyEnabled = true
|
||||||
isShrinkResources = true
|
isShrinkResources = true
|
||||||
manifestPlaceholders["appName"] = "ViMusic"
|
manifestPlaceholders["appName"] = "Muza"
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||||
}
|
}
|
||||||
@@ -74,6 +74,8 @@ dependencies {
|
|||||||
implementation(projects.composeRouting)
|
implementation(projects.composeRouting)
|
||||||
implementation(projects.composeReordering)
|
implementation(projects.composeReordering)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
implementation(libs.compose.activity)
|
implementation(libs.compose.activity)
|
||||||
implementation(libs.compose.foundation)
|
implementation(libs.compose.foundation)
|
||||||
implementation(libs.compose.ui)
|
implementation(libs.compose.ui)
|
||||||
@@ -85,8 +87,14 @@ dependencies {
|
|||||||
implementation(libs.palette)
|
implementation(libs.palette)
|
||||||
|
|
||||||
implementation(libs.exoplayer)
|
implementation(libs.exoplayer)
|
||||||
|
implementation(libs.exoplayer.okhttp)
|
||||||
|
|
||||||
implementation(libs.room)
|
implementation(libs.room)
|
||||||
|
implementation("androidx.media3:media3-datasource-okhttp:1.0.0-alpha03")
|
||||||
|
|
||||||
|
implementation ("com.yandex.android:mobileads:6.4.0")
|
||||||
|
implementation("com.google.android.gms:play-services-ads-identifier:18.0.1")
|
||||||
|
|
||||||
kapt(libs.room.compiler)
|
kapt(libs.room.compiler)
|
||||||
|
|
||||||
implementation(projects.innertube)
|
implementation(projects.innertube)
|
||||||
|
|||||||
4
app/proguard-rules.pro
vendored
@@ -31,4 +31,6 @@
|
|||||||
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
|
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
|
||||||
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
|
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
|
||||||
-dontwarn org.openjsse.net.ssl.OpenJSSE
|
-dontwarn org.openjsse.net.ssl.OpenJSSE
|
||||||
-dontwarn org.slf4j.impl.StaticLoggerBinder
|
-dontwarn org.slf4j.impl.StaticLoggerBinder
|
||||||
|
|
||||||
|
-keep class com.yandex** { *; }
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
|
<uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove"/>
|
||||||
|
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic
|
package it.hamy.muza
|
||||||
|
|
||||||
import android.content.ContentValues
|
import android.content.ContentValues
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
@@ -31,30 +31,31 @@ import androidx.room.migration.Migration
|
|||||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
import androidx.sqlite.db.SupportSQLiteQuery
|
import androidx.sqlite.db.SupportSQLiteQuery
|
||||||
import it.vfsfitvnm.vimusic.enums.AlbumSortBy
|
import it.hamy.muza.enums.AlbumSortBy
|
||||||
import it.vfsfitvnm.vimusic.enums.ArtistSortBy
|
import it.hamy.muza.enums.ArtistSortBy
|
||||||
import it.vfsfitvnm.vimusic.enums.PlaylistSortBy
|
import it.hamy.muza.enums.PlaylistSortBy
|
||||||
import it.vfsfitvnm.vimusic.enums.SongSortBy
|
import it.hamy.muza.enums.SongSortBy
|
||||||
import it.vfsfitvnm.vimusic.enums.SortOrder
|
import it.hamy.muza.enums.SortOrder
|
||||||
import it.vfsfitvnm.vimusic.models.Album
|
import it.hamy.muza.models.Album
|
||||||
import it.vfsfitvnm.vimusic.models.Artist
|
import it.hamy.muza.models.Artist
|
||||||
import it.vfsfitvnm.vimusic.models.SongWithContentLength
|
import it.hamy.muza.models.SongWithContentLength
|
||||||
import it.vfsfitvnm.vimusic.models.Event
|
import it.hamy.muza.models.Event
|
||||||
import it.vfsfitvnm.vimusic.models.Format
|
import it.hamy.muza.models.Format
|
||||||
import it.vfsfitvnm.vimusic.models.Info
|
import it.hamy.muza.models.Info
|
||||||
import it.vfsfitvnm.vimusic.models.Lyrics
|
import it.hamy.muza.models.Lyrics
|
||||||
import it.vfsfitvnm.vimusic.models.Playlist
|
import it.hamy.muza.models.Playlist
|
||||||
import it.vfsfitvnm.vimusic.models.PlaylistPreview
|
import it.hamy.muza.models.PlaylistPreview
|
||||||
import it.vfsfitvnm.vimusic.models.PlaylistWithSongs
|
import it.hamy.muza.models.PlaylistWithSongs
|
||||||
import it.vfsfitvnm.vimusic.models.QueuedMediaItem
|
import it.hamy.muza.models.QueuedMediaItem
|
||||||
import it.vfsfitvnm.vimusic.models.SearchQuery
|
import it.hamy.muza.models.SearchQuery
|
||||||
import it.vfsfitvnm.vimusic.models.Song
|
import it.hamy.muza.models.Song
|
||||||
import it.vfsfitvnm.vimusic.models.SongAlbumMap
|
import it.hamy.muza.models.SongAlbumMap
|
||||||
import it.vfsfitvnm.vimusic.models.SongArtistMap
|
import it.hamy.muza.models.SongArtistMap
|
||||||
import it.vfsfitvnm.vimusic.models.SongPlaylistMap
|
import it.hamy.muza.models.SongPlaylistMap
|
||||||
import it.vfsfitvnm.vimusic.models.SortedSongPlaylistMap
|
import it.hamy.muza.models.SortedSongPlaylistMap
|
||||||
import kotlin.jvm.Throws
|
import kotlin.jvm.Throws
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import it.hamy.muza.models.EventWithSong
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface Database {
|
interface Database {
|
||||||
@@ -316,6 +317,11 @@ interface Database {
|
|||||||
@RewriteQueriesToDropUnusedColumns
|
@RewriteQueriesToDropUnusedColumns
|
||||||
fun trending(now: Long = System.currentTimeMillis()): Flow<Song?>
|
fun trending(now: Long = System.currentTimeMillis()): Flow<Song?>
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
@Query("SELECT * FROM Event ORDER BY timestamp DESC")
|
||||||
|
fun events(): Flow<List<EventWithSong>>
|
||||||
|
|
||||||
|
|
||||||
@Query("SELECT COUNT (*) FROM Event")
|
@Query("SELECT COUNT (*) FROM Event")
|
||||||
fun eventsCount(): Flow<Int>
|
fun eventsCount(): Flow<Int>
|
||||||
|
|
||||||
14
app/src/main/kotlin/it/hamy/muza/Dependencies.kt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package it.hamy.muza
|
||||||
|
|
||||||
|
import it.hamy.muza.preferences.PreferencesHolder
|
||||||
|
|
||||||
|
object Dependencies {
|
||||||
|
lateinit var application: MainApplication
|
||||||
|
private set
|
||||||
|
|
||||||
|
internal fun init(application: MainApplication) {
|
||||||
|
this.application = application
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class GlobalPreferencesHolder : PreferencesHolder(Dependencies.application, "preferences")
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic
|
package it.hamy.muza
|
||||||
|
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
@@ -58,42 +58,52 @@ import androidx.media3.common.MediaItem
|
|||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
import com.valentinilk.shimmer.LocalShimmerTheme
|
import com.valentinilk.shimmer.LocalShimmerTheme
|
||||||
import com.valentinilk.shimmer.defaultShimmerTheme
|
import com.valentinilk.shimmer.defaultShimmerTheme
|
||||||
import it.vfsfitvnm.compose.persist.PersistMap
|
import it.hamy.compose.persist.PersistMap
|
||||||
import it.vfsfitvnm.compose.persist.PersistMapOwner
|
import it.hamy.compose.persist.PersistMapOwner
|
||||||
import it.vfsfitvnm.innertube.Innertube
|
|
||||||
import it.vfsfitvnm.innertube.models.bodies.BrowseBody
|
import it.hamy.innertube.utils.ProxyPreferenceItem
|
||||||
import it.vfsfitvnm.innertube.requests.playlistPage
|
import it.hamy.innertube.utils.ProxyPreferences
|
||||||
import it.vfsfitvnm.innertube.requests.song
|
import it.hamy.muza.utils.isProxyEnabledKey
|
||||||
import it.vfsfitvnm.vimusic.enums.ColorPaletteMode
|
import it.hamy.muza.utils.proxyHostNameKey
|
||||||
import it.vfsfitvnm.vimusic.enums.ColorPaletteName
|
import it.hamy.muza.utils.proxyModeKey
|
||||||
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
|
import it.hamy.muza.utils.proxyPortKey
|
||||||
import it.vfsfitvnm.vimusic.service.PlayerService
|
import java.net.Proxy
|
||||||
import it.vfsfitvnm.vimusic.ui.components.BottomSheetMenu
|
|
||||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
|
||||||
import it.vfsfitvnm.vimusic.ui.components.rememberBottomSheetState
|
import it.hamy.innertube.Innertube
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.albumRoute
|
import it.hamy.innertube.models.bodies.BrowseBody
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.artistRoute
|
import it.hamy.innertube.requests.playlistPage
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.home.HomeScreen
|
import it.hamy.innertube.requests.song
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.player.Player
|
import it.hamy.muza.enums.ColorPaletteMode
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.playlistRoute
|
import it.hamy.muza.enums.ColorPaletteName
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Appearance
|
import it.hamy.muza.enums.ThumbnailRoundness
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.hamy.muza.service.PlayerService
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.components.BottomSheetMenu
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.colorPaletteOf
|
import it.hamy.muza.ui.components.LocalMenuState
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.dynamicColorPaletteOf
|
import it.hamy.muza.ui.components.rememberBottomSheetState
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.typographyOf
|
import it.hamy.muza.ui.screens.albumRoute
|
||||||
import it.vfsfitvnm.vimusic.utils.applyFontPaddingKey
|
import it.hamy.muza.ui.screens.artistRoute
|
||||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
import it.hamy.muza.ui.screens.home.HomeScreen
|
||||||
import it.vfsfitvnm.vimusic.utils.colorPaletteModeKey
|
import it.hamy.muza.ui.screens.player.Player
|
||||||
import it.vfsfitvnm.vimusic.utils.colorPaletteNameKey
|
import it.hamy.muza.ui.screens.playlistRoute
|
||||||
import it.vfsfitvnm.vimusic.utils.forcePlay
|
import it.hamy.muza.ui.styling.Appearance
|
||||||
import it.vfsfitvnm.vimusic.utils.getEnum
|
import it.hamy.muza.ui.styling.Dimensions
|
||||||
import it.vfsfitvnm.vimusic.utils.intent
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid6
|
import it.hamy.muza.ui.styling.colorPaletteOf
|
||||||
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid8
|
import it.hamy.muza.ui.styling.dynamicColorPaletteOf
|
||||||
import it.vfsfitvnm.vimusic.utils.preferences
|
import it.hamy.muza.ui.styling.typographyOf
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnailRoundnessKey
|
import it.hamy.muza.utils.applyFontPaddingKey
|
||||||
import it.vfsfitvnm.vimusic.utils.useSystemFontKey
|
import it.hamy.muza.utils.asMediaItem
|
||||||
|
import it.hamy.muza.utils.colorPaletteModeKey
|
||||||
|
import it.hamy.muza.utils.colorPaletteNameKey
|
||||||
|
import it.hamy.muza.utils.forcePlay
|
||||||
|
import it.hamy.muza.utils.getEnum
|
||||||
|
import it.hamy.muza.utils.intent
|
||||||
|
import it.hamy.muza.utils.isAtLeastAndroid6
|
||||||
|
import it.hamy.muza.utils.isAtLeastAndroid8
|
||||||
|
import it.hamy.muza.utils.preferences
|
||||||
|
import it.hamy.muza.utils.thumbnailRoundnessKey
|
||||||
|
import it.hamy.muza.utils.useSystemFontKey
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
@@ -118,6 +128,7 @@ class MainActivity : ComponentActivity(), PersistMapOwner {
|
|||||||
|
|
||||||
override lateinit var persistMap: PersistMap
|
override lateinit var persistMap: PersistMap
|
||||||
|
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
bindService(intent<PlayerService>(), serviceConnection, Context.BIND_AUTO_CREATE)
|
bindService(intent<PlayerService>(), serviceConnection, Context.BIND_AUTO_CREATE)
|
||||||
@@ -127,6 +138,7 @@ class MainActivity : ComponentActivity(), PersistMapOwner {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION", "UNCHECKED_CAST")
|
@Suppress("DEPRECATION", "UNCHECKED_CAST")
|
||||||
persistMap = lastCustomNonConfigurationInstance as? PersistMap ?: PersistMap()
|
persistMap = lastCustomNonConfigurationInstance as? PersistMap ?: PersistMap()
|
||||||
|
|
||||||
@@ -134,6 +146,17 @@ class MainActivity : ComponentActivity(), PersistMapOwner {
|
|||||||
|
|
||||||
val launchedFromNotification = intent?.extras?.getBoolean("expandPlayerBottomSheet") == true
|
val launchedFromNotification = intent?.extras?.getBoolean("expandPlayerBottomSheet") == true
|
||||||
|
|
||||||
|
with(preferences){
|
||||||
|
if(getBoolean(isProxyEnabledKey,false)) {
|
||||||
|
val hostName = getString(proxyHostNameKey,null)
|
||||||
|
val proxyPort = getInt(proxyPortKey, 8080)
|
||||||
|
val proxyMode = getEnum(proxyModeKey, Proxy.Type.HTTP)
|
||||||
|
hostName?.let { hName->
|
||||||
|
ProxyPreferences.preference = ProxyPreferenceItem(hName,proxyPort,proxyMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val isSystemInDarkTheme = isSystemInDarkTheme()
|
val isSystemInDarkTheme = isSystemInDarkTheme()
|
||||||
@@ -146,7 +169,7 @@ class MainActivity : ComponentActivity(), PersistMapOwner {
|
|||||||
val colorPaletteName = getEnum(colorPaletteNameKey, ColorPaletteName.Dynamic)
|
val colorPaletteName = getEnum(colorPaletteNameKey, ColorPaletteName.Dynamic)
|
||||||
val colorPaletteMode = getEnum(colorPaletteModeKey, ColorPaletteMode.System)
|
val colorPaletteMode = getEnum(colorPaletteModeKey, ColorPaletteMode.System)
|
||||||
val thumbnailRoundness =
|
val thumbnailRoundness =
|
||||||
getEnum(thumbnailRoundnessKey, ThumbnailRoundness.Light)
|
getEnum(thumbnailRoundnessKey, ThumbnailRoundness.Слабое)
|
||||||
|
|
||||||
val useSystemFont = getBoolean(useSystemFontKey, false)
|
val useSystemFont = getBoolean(useSystemFontKey, false)
|
||||||
val applyFontPadding = getBoolean(applyFontPaddingKey, false)
|
val applyFontPadding = getBoolean(applyFontPaddingKey, false)
|
||||||
@@ -245,7 +268,7 @@ class MainActivity : ComponentActivity(), PersistMapOwner {
|
|||||||
|
|
||||||
thumbnailRoundnessKey -> {
|
thumbnailRoundnessKey -> {
|
||||||
val thumbnailRoundness =
|
val thumbnailRoundness =
|
||||||
sharedPreferences.getEnum(key, ThumbnailRoundness.Light)
|
sharedPreferences.getEnum(key, ThumbnailRoundness.Слабое)
|
||||||
|
|
||||||
appearance = appearance.copy(
|
appearance = appearance.copy(
|
||||||
thumbnailShape = thumbnailRoundness.shape()
|
thumbnailShape = thumbnailRoundness.shape()
|
||||||
@@ -1,18 +1,25 @@
|
|||||||
package it.vfsfitvnm.vimusic
|
package it.hamy.muza
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.ImageLoaderFactory
|
import coil.ImageLoaderFactory
|
||||||
import coil.disk.DiskCache
|
import coil.disk.DiskCache
|
||||||
import it.vfsfitvnm.vimusic.enums.CoilDiskCacheMaxSize
|
import com.yandex.mobile.ads.common.MobileAds
|
||||||
import it.vfsfitvnm.vimusic.utils.coilDiskCacheMaxSizeKey
|
import it.hamy.muza.enums.CoilDiskCacheMaxSize
|
||||||
import it.vfsfitvnm.vimusic.utils.getEnum
|
import it.hamy.muza.utils.coilDiskCacheMaxSizeKey
|
||||||
import it.vfsfitvnm.vimusic.utils.preferences
|
import it.hamy.muza.utils.getEnum
|
||||||
|
import it.hamy.muza.utils.preferences
|
||||||
|
|
||||||
class MainApplication : Application(), ImageLoaderFactory {
|
class MainApplication : Application(), ImageLoaderFactory {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
DatabaseInitializer()
|
DatabaseInitializer()
|
||||||
|
Dependencies.init(this)
|
||||||
|
MobileAds.initialize(this) {
|
||||||
|
/**
|
||||||
|
* Инициализация либы яндекса
|
||||||
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun newImageLoader(): ImageLoader {
|
override fun newImageLoader(): ImageLoader {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.enums
|
package it.hamy.muza.enums
|
||||||
|
|
||||||
enum class AlbumSortBy {
|
enum class AlbumSortBy {
|
||||||
Title,
|
Title,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.enums
|
package it.hamy.muza.enums
|
||||||
|
|
||||||
enum class ArtistSortBy {
|
enum class ArtistSortBy {
|
||||||
Name,
|
Name,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.enums
|
package it.hamy.muza.enums
|
||||||
|
|
||||||
enum class BuiltInPlaylist {
|
enum class BuiltInPlaylist {
|
||||||
Favorites,
|
Favorites,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.enums
|
package it.hamy.muza.enums
|
||||||
|
|
||||||
enum class CoilDiskCacheMaxSize {
|
enum class CoilDiskCacheMaxSize {
|
||||||
`128MB`,
|
`128MB`,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.enums
|
package it.hamy.muza.enums
|
||||||
|
|
||||||
enum class ColorPaletteMode {
|
enum class ColorPaletteMode {
|
||||||
Light,
|
Light,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.enums
|
package it.hamy.muza.enums
|
||||||
|
|
||||||
enum class ColorPaletteName {
|
enum class ColorPaletteName {
|
||||||
Default,
|
Default,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.enums
|
package it.hamy.muza.enums
|
||||||
|
|
||||||
enum class ExoPlayerDiskCacheMaxSize {
|
enum class ExoPlayerDiskCacheMaxSize {
|
||||||
`32MB`,
|
`32MB`,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.enums
|
package it.hamy.muza.enums
|
||||||
|
|
||||||
enum class PlaylistSortBy {
|
enum class PlaylistSortBy {
|
||||||
Name,
|
Name,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.enums
|
package it.hamy.muza.enums
|
||||||
|
|
||||||
enum class SongSortBy {
|
enum class SongSortBy {
|
||||||
PlayTime,
|
PlayTime,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.enums
|
package it.hamy.muza.enums
|
||||||
|
|
||||||
enum class SortOrder {
|
enum class SortOrder {
|
||||||
Ascending,
|
Ascending,
|
||||||
24
app/src/main/kotlin/it/hamy/muza/enums/ThumbnailRoundness.kt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package it.hamy.muza.enums
|
||||||
|
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.ui.graphics.RectangleShape
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
enum class ThumbnailRoundness {
|
||||||
|
Отключено,
|
||||||
|
Слабое,
|
||||||
|
Среднее,
|
||||||
|
Сильное,
|
||||||
|
Максимальное;
|
||||||
|
|
||||||
|
fun shape(): Shape {
|
||||||
|
return when (this) {
|
||||||
|
Отключено -> RectangleShape
|
||||||
|
Слабое -> RoundedCornerShape(2.dp)
|
||||||
|
Среднее -> RoundedCornerShape(4.dp)
|
||||||
|
Сильное -> RoundedCornerShape(8.dp)
|
||||||
|
Максимальное -> RoundedCornerShape(14.dp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
16
app/src/main/kotlin/it/hamy/muza/models/EventWithSong.kt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package it.hamy.muza.models
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.room.Embedded
|
||||||
|
import androidx.room.Relation
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class EventWithSong(
|
||||||
|
@Embedded val event: Event,
|
||||||
|
@Relation(
|
||||||
|
entity = Song::class,
|
||||||
|
parentColumn = "songId",
|
||||||
|
entityColumn = "id"
|
||||||
|
)
|
||||||
|
val song: Song
|
||||||
|
)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
data class Info(
|
data class Info(
|
||||||
val id: String,
|
val id: String,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.Embedded
|
import androidx.room.Embedded
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.Embedded
|
import androidx.room.Embedded
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.Embedded
|
import androidx.room.Embedded
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.models
|
package it.hamy.muza.models
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package it.hamy.muza.preferences
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import it.hamy.muza.GlobalPreferencesHolder
|
||||||
|
import it.hamy.muza.R
|
||||||
|
import kotlin.time.Duration
|
||||||
|
import kotlin.time.Duration.Companion.days
|
||||||
|
|
||||||
|
object DataPreferences : GlobalPreferencesHolder() {
|
||||||
|
var topListLength by int(10)
|
||||||
|
var topListPeriod by enum(TopListPeriod.AllTime)
|
||||||
|
var quickPicksSource by enum(QuickPicksSource.Trending)
|
||||||
|
|
||||||
|
enum class TopListPeriod(val displayName: @Composable () -> String, val duration: Duration? = null) {
|
||||||
|
PastDay(displayName = { "Day" }, duration = 1.days),
|
||||||
|
PastWeek(displayName = { "Week" }, duration = 7.days),
|
||||||
|
PastMonth(displayName = { "Month" }, duration = 30.days),
|
||||||
|
PastYear(displayName = { "Year" }, 365.days),
|
||||||
|
AllTime(displayName = { "AllTime" })
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class QuickPicksSource(val displayName: @Composable () -> String) {
|
||||||
|
Trending(displayName = { "Trend" }),
|
||||||
|
LastInteraction(displayName = { "LastInteraction" })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package it.hamy.muza.preferences
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.snapshots.Snapshot
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
private val coroutineScope = CoroutineScope(Dispatchers.IO)
|
||||||
|
|
||||||
|
fun <T : Any> sharedPreferencesProperty(
|
||||||
|
getValue: SharedPreferences.(key: String) -> T,
|
||||||
|
setValue: SharedPreferences.Editor.(key: String, value: T) -> Unit,
|
||||||
|
defaultValue: T
|
||||||
|
) = object : ReadWriteProperty<PreferencesHolder, T> {
|
||||||
|
private var state = mutableStateOf(defaultValue)
|
||||||
|
private var listener: OnSharedPreferenceChangeListener? = null
|
||||||
|
|
||||||
|
override fun getValue(thisRef: PreferencesHolder, property: KProperty<*>): T {
|
||||||
|
if (listener == null && !Snapshot.current.readOnly) {
|
||||||
|
state.value = thisRef.getValue(property.name)
|
||||||
|
listener = OnSharedPreferenceChangeListener { preferences, key ->
|
||||||
|
if (key == property.name) preferences.getValue(property.name)
|
||||||
|
.let { if (it != state && !Snapshot.current.readOnly) state.value = it }
|
||||||
|
}
|
||||||
|
thisRef.registerOnSharedPreferenceChangeListener(listener)
|
||||||
|
}
|
||||||
|
return state.value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: PreferencesHolder, property: KProperty<*>, value: T) =
|
||||||
|
coroutineScope.launch {
|
||||||
|
thisRef.edit(commit = true) {
|
||||||
|
setValue(property.name, value)
|
||||||
|
}
|
||||||
|
}.let { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A snapshottable, thread-safe, compose-first, extensible SharedPreferences wrapper that supports
|
||||||
|
* virtually all types, and if it doesn't, one could simply type `fun myNewType(...) = sharedPreferencesProperty(...)`
|
||||||
|
* and start implementing. Starts off as given defaultValue until we are allowed to subscribe to SharedPreferences
|
||||||
|
* @sample AppearancePreferences
|
||||||
|
*/
|
||||||
|
open class PreferencesHolder(
|
||||||
|
application: Application,
|
||||||
|
name: String,
|
||||||
|
mode: Int = Context.MODE_PRIVATE
|
||||||
|
) : SharedPreferences by application.getSharedPreferences(name, mode) {
|
||||||
|
fun boolean(defaultValue: Boolean) = sharedPreferencesProperty(
|
||||||
|
getValue = { getBoolean(it, defaultValue) },
|
||||||
|
setValue = { k, v -> putBoolean(k, v) },
|
||||||
|
defaultValue
|
||||||
|
)
|
||||||
|
|
||||||
|
fun string(defaultValue: String) = sharedPreferencesProperty(
|
||||||
|
getValue = { getString(it, null) ?: defaultValue },
|
||||||
|
setValue = { k, v -> putString(k, v) },
|
||||||
|
defaultValue
|
||||||
|
)
|
||||||
|
|
||||||
|
fun int(defaultValue: Int) = sharedPreferencesProperty(
|
||||||
|
getValue = { getInt(it, defaultValue) },
|
||||||
|
setValue = { k, v -> putInt(k, v) },
|
||||||
|
defaultValue
|
||||||
|
)
|
||||||
|
|
||||||
|
fun float(defaultValue: Float) = sharedPreferencesProperty(
|
||||||
|
getValue = { getFloat(it, defaultValue) },
|
||||||
|
setValue = { k, v -> putFloat(k, v) },
|
||||||
|
defaultValue
|
||||||
|
)
|
||||||
|
|
||||||
|
fun long(defaultValue: Long) = sharedPreferencesProperty(
|
||||||
|
getValue = { getLong(it, defaultValue) },
|
||||||
|
setValue = { k, v -> putLong(k, v) },
|
||||||
|
defaultValue
|
||||||
|
)
|
||||||
|
|
||||||
|
inline fun <reified T : Enum<T>> enum(defaultValue: T) = sharedPreferencesProperty(
|
||||||
|
getValue = {
|
||||||
|
getString(it, null)?.let { runCatching { enumValueOf<T>(it) }.getOrNull() } ?: defaultValue
|
||||||
|
},
|
||||||
|
setValue = { k, v -> putString(k, v.name) },
|
||||||
|
defaultValue
|
||||||
|
)
|
||||||
|
|
||||||
|
fun stringSet(defaultValue: Set<String>) = sharedPreferencesProperty(
|
||||||
|
getValue = { getStringSet(it, null) ?: defaultValue },
|
||||||
|
setValue = { k, v -> putStringSet(k, v) },
|
||||||
|
defaultValue
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.service
|
package it.hamy.muza.service
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
@@ -9,7 +9,7 @@ import androidx.core.graphics.applyCanvas
|
|||||||
import coil.imageLoader
|
import coil.imageLoader
|
||||||
import coil.request.Disposable
|
import coil.request.Disposable
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
import it.hamy.muza.utils.thumbnail
|
||||||
|
|
||||||
context(Context)
|
context(Context)
|
||||||
class BitmapProvider(
|
class BitmapProvider(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.service
|
package it.hamy.muza.service
|
||||||
|
|
||||||
import androidx.media3.common.PlaybackException
|
import androidx.media3.common.PlaybackException
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.service
|
package it.hamy.muza.service
|
||||||
|
|
||||||
import android.media.MediaDescription as BrowserMediaDescription
|
import android.media.MediaDescription as BrowserMediaDescription
|
||||||
import android.media.browse.MediaBrowser.MediaItem as BrowserMediaItem
|
import android.media.browse.MediaBrowser.MediaItem as BrowserMediaItem
|
||||||
@@ -17,17 +17,17 @@ import androidx.core.net.toUri
|
|||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
import androidx.media3.datasource.cache.Cache
|
import androidx.media3.datasource.cache.Cache
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.hamy.muza.Database
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.hamy.muza.R
|
||||||
import it.vfsfitvnm.vimusic.models.Album
|
import it.hamy.muza.models.Album
|
||||||
import it.vfsfitvnm.vimusic.models.PlaylistPreview
|
import it.hamy.muza.models.PlaylistPreview
|
||||||
import it.vfsfitvnm.vimusic.models.Song
|
import it.hamy.muza.models.Song
|
||||||
import it.vfsfitvnm.vimusic.models.SongWithContentLength
|
import it.hamy.muza.models.SongWithContentLength
|
||||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
import it.hamy.muza.utils.asMediaItem
|
||||||
import it.vfsfitvnm.vimusic.utils.forcePlayAtIndex
|
import it.hamy.muza.utils.forcePlayAtIndex
|
||||||
import it.vfsfitvnm.vimusic.utils.forceSeekToNext
|
import it.hamy.muza.utils.forceSeekToNext
|
||||||
import it.vfsfitvnm.vimusic.utils.forceSeekToPrevious
|
import it.hamy.muza.utils.forceSeekToPrevious
|
||||||
import it.vfsfitvnm.vimusic.utils.intent
|
import it.hamy.muza.utils.intent
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.service
|
package it.hamy.muza.service
|
||||||
|
|
||||||
import android.os.Binder as AndroidBinder
|
import android.os.Binder as AndroidBinder
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
@@ -43,7 +43,14 @@ import androidx.media3.common.Player
|
|||||||
import androidx.media3.common.Timeline
|
import androidx.media3.common.Timeline
|
||||||
import androidx.media3.database.StandaloneDatabaseProvider
|
import androidx.media3.database.StandaloneDatabaseProvider
|
||||||
import androidx.media3.datasource.DataSource
|
import androidx.media3.datasource.DataSource
|
||||||
import androidx.media3.datasource.DefaultHttpDataSource
|
|
||||||
|
import androidx.media3.datasource.okhttp.OkHttpDataSource
|
||||||
|
import it.hamy.innertube.utils.ProxyPreferences
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import java.net.InetSocketAddress
|
||||||
|
import java.net.Proxy
|
||||||
|
import java.time.Duration
|
||||||
|
|
||||||
import androidx.media3.datasource.ResolvingDataSource
|
import androidx.media3.datasource.ResolvingDataSource
|
||||||
import androidx.media3.datasource.cache.Cache
|
import androidx.media3.datasource.cache.Cache
|
||||||
import androidx.media3.datasource.cache.CacheDataSource
|
import androidx.media3.datasource.cache.CacheDataSource
|
||||||
@@ -67,45 +74,45 @@ import androidx.media3.exoplayer.source.MediaSource
|
|||||||
import androidx.media3.extractor.ExtractorsFactory
|
import androidx.media3.extractor.ExtractorsFactory
|
||||||
import androidx.media3.extractor.mkv.MatroskaExtractor
|
import androidx.media3.extractor.mkv.MatroskaExtractor
|
||||||
import androidx.media3.extractor.mp4.FragmentedMp4Extractor
|
import androidx.media3.extractor.mp4.FragmentedMp4Extractor
|
||||||
import it.vfsfitvnm.innertube.Innertube
|
import it.hamy.innertube.Innertube
|
||||||
import it.vfsfitvnm.innertube.models.NavigationEndpoint
|
import it.hamy.innertube.models.NavigationEndpoint
|
||||||
import it.vfsfitvnm.innertube.models.bodies.PlayerBody
|
import it.hamy.innertube.models.bodies.PlayerBody
|
||||||
import it.vfsfitvnm.innertube.requests.player
|
import it.hamy.innertube.requests.player
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.hamy.muza.Database
|
||||||
import it.vfsfitvnm.vimusic.MainActivity
|
import it.hamy.muza.MainActivity
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.hamy.muza.R
|
||||||
import it.vfsfitvnm.vimusic.enums.ExoPlayerDiskCacheMaxSize
|
import it.hamy.muza.enums.ExoPlayerDiskCacheMaxSize
|
||||||
import it.vfsfitvnm.vimusic.models.Event
|
import it.hamy.muza.models.Event
|
||||||
import it.vfsfitvnm.vimusic.models.QueuedMediaItem
|
import it.hamy.muza.models.QueuedMediaItem
|
||||||
import it.vfsfitvnm.vimusic.query
|
import it.hamy.muza.query
|
||||||
import it.vfsfitvnm.vimusic.utils.InvincibleService
|
import it.hamy.muza.utils.InvincibleService
|
||||||
import it.vfsfitvnm.vimusic.utils.RingBuffer
|
import it.hamy.muza.utils.RingBuffer
|
||||||
import it.vfsfitvnm.vimusic.utils.TimerJob
|
import it.hamy.muza.utils.TimerJob
|
||||||
import it.vfsfitvnm.vimusic.utils.YouTubeRadio
|
import it.hamy.muza.utils.YouTubeRadio
|
||||||
import it.vfsfitvnm.vimusic.utils.activityPendingIntent
|
import it.hamy.muza.utils.activityPendingIntent
|
||||||
import it.vfsfitvnm.vimusic.utils.broadCastPendingIntent
|
import it.hamy.muza.utils.broadCastPendingIntent
|
||||||
import it.vfsfitvnm.vimusic.utils.exoPlayerDiskCacheMaxSizeKey
|
import it.hamy.muza.utils.exoPlayerDiskCacheMaxSizeKey
|
||||||
import it.vfsfitvnm.vimusic.utils.findNextMediaItemById
|
import it.hamy.muza.utils.findNextMediaItemById
|
||||||
import it.vfsfitvnm.vimusic.utils.forcePlayFromBeginning
|
import it.hamy.muza.utils.forcePlayFromBeginning
|
||||||
import it.vfsfitvnm.vimusic.utils.forceSeekToNext
|
import it.hamy.muza.utils.forceSeekToNext
|
||||||
import it.vfsfitvnm.vimusic.utils.forceSeekToPrevious
|
import it.hamy.muza.utils.forceSeekToPrevious
|
||||||
import it.vfsfitvnm.vimusic.utils.getEnum
|
import it.hamy.muza.utils.getEnum
|
||||||
import it.vfsfitvnm.vimusic.utils.intent
|
import it.hamy.muza.utils.intent
|
||||||
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid13
|
import it.hamy.muza.utils.isAtLeastAndroid13
|
||||||
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid6
|
import it.hamy.muza.utils.isAtLeastAndroid6
|
||||||
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid8
|
import it.hamy.muza.utils.isAtLeastAndroid8
|
||||||
import it.vfsfitvnm.vimusic.utils.isInvincibilityEnabledKey
|
import it.hamy.muza.utils.isInvincibilityEnabledKey
|
||||||
import it.vfsfitvnm.vimusic.utils.isShowingThumbnailInLockscreenKey
|
import it.hamy.muza.utils.isShowingThumbnailInLockscreenKey
|
||||||
import it.vfsfitvnm.vimusic.utils.mediaItems
|
import it.hamy.muza.utils.mediaItems
|
||||||
import it.vfsfitvnm.vimusic.utils.persistentQueueKey
|
import it.hamy.muza.utils.persistentQueueKey
|
||||||
import it.vfsfitvnm.vimusic.utils.preferences
|
import it.hamy.muza.utils.preferences
|
||||||
import it.vfsfitvnm.vimusic.utils.queueLoopEnabledKey
|
import it.hamy.muza.utils.queueLoopEnabledKey
|
||||||
import it.vfsfitvnm.vimusic.utils.resumePlaybackWhenDeviceConnectedKey
|
import it.hamy.muza.utils.resumePlaybackWhenDeviceConnectedKey
|
||||||
import it.vfsfitvnm.vimusic.utils.shouldBePlaying
|
import it.hamy.muza.utils.shouldBePlaying
|
||||||
import it.vfsfitvnm.vimusic.utils.skipSilenceKey
|
import it.hamy.muza.utils.skipSilenceKey
|
||||||
import it.vfsfitvnm.vimusic.utils.timer
|
import it.hamy.muza.utils.timer
|
||||||
import it.vfsfitvnm.vimusic.utils.trackLoopEnabledKey
|
import it.hamy.muza.utils.trackLoopEnabledKey
|
||||||
import it.vfsfitvnm.vimusic.utils.volumeNormalizationKey
|
import it.hamy.muza.utils.volumeNormalizationKey
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -737,12 +744,24 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun okHttpClient() : OkHttpClient{
|
||||||
|
ProxyPreferences.preference?.let{
|
||||||
|
return OkHttpClient.Builder()
|
||||||
|
.proxy(Proxy(it.proxyMode,InetSocketAddress(it.proxyHost,it.proxyPort)))
|
||||||
|
.connectTimeout(Duration.ofSeconds(16))
|
||||||
|
.readTimeout(Duration.ofSeconds(8))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
return OkHttpClient.Builder()
|
||||||
|
.connectTimeout(Duration.ofSeconds(16))
|
||||||
|
.readTimeout(Duration.ofSeconds(8))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
private fun createCacheDataSource(): DataSource.Factory {
|
private fun createCacheDataSource(): DataSource.Factory {
|
||||||
return CacheDataSource.Factory().setCache(cache).apply {
|
return CacheDataSource.Factory().setCache(cache).apply {
|
||||||
setUpstreamDataSourceFactory(
|
setUpstreamDataSourceFactory(
|
||||||
DefaultHttpDataSource.Factory()
|
OkHttpDataSource.Factory(okHttpClient())
|
||||||
.setConnectTimeoutMs(16000)
|
|
||||||
.setReadTimeoutMs(8000)
|
|
||||||
.setUserAgent("Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0")
|
.setUserAgent("Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -791,7 +810,7 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
|||||||
mediaItem?.let(Database::insert)
|
mediaItem?.let(Database::insert)
|
||||||
|
|
||||||
Database.insert(
|
Database.insert(
|
||||||
it.vfsfitvnm.vimusic.models.Format(
|
it.hamy.muza.models.Format(
|
||||||
songId = videoId,
|
songId = videoId,
|
||||||
itag = format.itag,
|
itag = format.itag,
|
||||||
mimeType = format.mimeType,
|
mimeType = format.mimeType,
|
||||||
@@ -991,10 +1010,10 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
|||||||
)
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val pause = Action("it.vfsfitvnm.vimusic.pause")
|
val pause = Action("it.hamy.muza.pause")
|
||||||
val play = Action("it.vfsfitvnm.vimusic.play")
|
val play = Action("it.hamy.muza.play")
|
||||||
val next = Action("it.vfsfitvnm.vimusic.next")
|
val next = Action("it.hamy.muza.next")
|
||||||
val previous = Action("it.vfsfitvnm.vimusic.previous")
|
val previous = Action("it.hamy.muza.previous")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components
|
package it.hamy.muza.ui.components
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.animation.core.Animatable
|
import androidx.compose.animation.core.Animatable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components
|
package it.hamy.muza.ui.components
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components
|
package it.hamy.muza.ui.components
|
||||||
|
|
||||||
import androidx.compose.animation.core.Animatable
|
import androidx.compose.animation.core.Animatable
|
||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components
|
package it.hamy.muza.ui.components
|
||||||
|
|
||||||
import androidx.compose.animation.core.MutableTransitionState
|
import androidx.compose.animation.core.MutableTransitionState
|
||||||
import androidx.compose.animation.core.animateDp
|
import androidx.compose.animation.core.animateDp
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components
|
package it.hamy.muza.ui.components
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package it.hamy.muza.ui.components
|
||||||
|
|
||||||
|
import android.os.CountDownTimer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import com.yandex.mobile.ads.banner.BannerAdEventListener
|
||||||
|
import com.yandex.mobile.ads.banner.BannerAdSize
|
||||||
|
import com.yandex.mobile.ads.banner.BannerAdView
|
||||||
|
import com.yandex.mobile.ads.common.AdRequest
|
||||||
|
import com.yandex.mobile.ads.common.AdRequestError
|
||||||
|
import com.yandex.mobile.ads.common.AdTheme
|
||||||
|
import com.yandex.mobile.ads.common.ImpressionData
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun YandexAdsBanner(id: String) {
|
||||||
|
AndroidView(modifier = Modifier.fillMaxSize(), factory = { context ->
|
||||||
|
BannerAdView(context).apply {
|
||||||
|
/**
|
||||||
|
* ID блока рекламы
|
||||||
|
*/
|
||||||
|
setAdUnitId(id)
|
||||||
|
/**
|
||||||
|
* Размер блока рекламы
|
||||||
|
*/
|
||||||
|
setAdSize(BannerAdSize.inlineSize(context, 110, 110))
|
||||||
|
/**
|
||||||
|
* Билдер запроса
|
||||||
|
*/
|
||||||
|
val adRequest = AdRequest.Builder()
|
||||||
|
.setPreferredTheme(AdTheme.DARK)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
|
||||||
|
val timer = object : CountDownTimer(4000, 1000) {
|
||||||
|
override fun onTick(millisUntilFinished: Long) {
|
||||||
|
// Здесь можно выполнить действия, которые нужно сделать каждую секунду
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFinish() {
|
||||||
|
// Здесь вызывается метод loadAd(adRequest) после истечения таймера
|
||||||
|
loadAd(adRequest)
|
||||||
|
// Здесь можно повторить таймер, чтобы он всегда повторялся
|
||||||
|
//start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Слушатель экшнов
|
||||||
|
*/
|
||||||
|
setBannerAdEventListener(object : BannerAdEventListener {
|
||||||
|
override fun onAdLoaded() {
|
||||||
|
// Запускаем таймер
|
||||||
|
timer.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAdFailedToLoad(p0: AdRequestError) {
|
||||||
|
/**
|
||||||
|
* Тут дебажим ошибки
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAdClicked() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLeftApplication() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReturnedToApplication() {
|
||||||
|
loadAd(adRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onImpression(p0: ImpressionData?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* Запуск баннера
|
||||||
|
*/
|
||||||
|
loadAd(adRequest)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package it.hamy.muza.ui.components
|
||||||
|
|
||||||
|
import android.os.CountDownTimer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import com.yandex.mobile.ads.banner.BannerAdEventListener
|
||||||
|
import com.yandex.mobile.ads.banner.BannerAdSize
|
||||||
|
import com.yandex.mobile.ads.banner.BannerAdView
|
||||||
|
import com.yandex.mobile.ads.common.AdRequest
|
||||||
|
import com.yandex.mobile.ads.common.AdRequestError
|
||||||
|
import com.yandex.mobile.ads.common.AdTheme
|
||||||
|
import com.yandex.mobile.ads.common.ImpressionData
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun YandexAdsBannerQuickPicksCenter(id: String) {
|
||||||
|
AndroidView(modifier = Modifier.fillMaxSize(), factory = { context ->
|
||||||
|
BannerAdView(context).apply {
|
||||||
|
/**
|
||||||
|
* ID блока рекламы
|
||||||
|
*/
|
||||||
|
setAdUnitId(id)
|
||||||
|
/**
|
||||||
|
* Размер блока рекламы
|
||||||
|
*/
|
||||||
|
setAdSize(BannerAdSize.inlineSize(context, 260, 60))
|
||||||
|
/**
|
||||||
|
* Билдер запроса
|
||||||
|
*/
|
||||||
|
val adRequest = AdRequest.Builder()
|
||||||
|
.setPreferredTheme(AdTheme.DARK)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
|
||||||
|
val timer = object : CountDownTimer(4000, 1000) {
|
||||||
|
override fun onTick(millisUntilFinished: Long) {
|
||||||
|
// Здесь можно выполнить действия, которые нужно сделать каждую секунду
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFinish() {
|
||||||
|
// Здесь вызывается метод loadAd(adRequest) после истечения таймера
|
||||||
|
loadAd(adRequest)
|
||||||
|
// Здесь можно повторить таймер, чтобы он всегда повторялся
|
||||||
|
//start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Слушатель экшнов
|
||||||
|
*/
|
||||||
|
setBannerAdEventListener(object : BannerAdEventListener {
|
||||||
|
override fun onAdLoaded() {
|
||||||
|
// Запускаем таймер
|
||||||
|
timer.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAdFailedToLoad(p0: AdRequestError) {
|
||||||
|
/**
|
||||||
|
* Тут дебажим ошибки
|
||||||
|
*/
|
||||||
|
loadAd(adRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAdClicked() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLeftApplication() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReturnedToApplication() {
|
||||||
|
loadAd(adRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onImpression(p0: ImpressionData?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Запуск баннера
|
||||||
|
*/
|
||||||
|
loadAd(adRequest)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
@@ -48,12 +48,12 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.utils.center
|
import it.hamy.muza.utils.center
|
||||||
import it.vfsfitvnm.vimusic.utils.drawCircle
|
import it.hamy.muza.utils.drawCircle
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.hamy.muza.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.hamy.muza.utils.secondary
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.hamy.muza.utils.semiBold
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -62,8 +62,8 @@ fun TextFieldDialog(
|
|||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onDone: (String) -> Unit,
|
onDone: (String) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
cancelText: String = "Cancel",
|
cancelText: String = "Отмена",
|
||||||
doneText: String = "Done",
|
doneText: String = "Готово",
|
||||||
initialTextInput: String = "",
|
initialTextInput: String = "",
|
||||||
singleLine: Boolean = true,
|
singleLine: Boolean = true,
|
||||||
maxLines: Int = 1,
|
maxLines: Int = 1,
|
||||||
@@ -167,8 +167,8 @@ fun ConfirmationDialog(
|
|||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onConfirm: () -> Unit,
|
onConfirm: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
cancelText: String = "Cancel",
|
cancelText: String = "Отменить",
|
||||||
confirmText: String = "Confirm",
|
confirmText: String = "Продолжить",
|
||||||
onCancel: () -> Unit = onDismiss
|
onCancel: () -> Unit = onDismiss
|
||||||
) {
|
) {
|
||||||
val (_, typography) = LocalAppearance.current
|
val (_, typography) = LocalAppearance.current
|
||||||
@@ -324,7 +324,7 @@ inline fun <T> ValueSelectorDialog(
|
|||||||
.padding(end = 24.dp)
|
.padding(end = 24.dp)
|
||||||
) {
|
) {
|
||||||
DialogTextButton(
|
DialogTextButton(
|
||||||
text = "Cancel",
|
text = "Отмена",
|
||||||
onClick = onDismiss,
|
onClick = onDismiss,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
)
|
)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
@@ -10,9 +10,9 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.utils.color
|
import it.hamy.muza.utils.color
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.hamy.muza.utils.medium
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DialogTextButton(
|
fun DialogTextButton(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
@@ -24,11 +24,11 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerAwareWindowInsets
|
import it.hamy.muza.LocalPlayerAwareWindowInsets
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.hamy.muza.R
|
||||||
import it.vfsfitvnm.vimusic.utils.ScrollingInfo
|
import it.hamy.muza.utils.ScrollingInfo
|
||||||
import it.vfsfitvnm.vimusic.utils.scrollingInfo
|
import it.hamy.muza.utils.scrollingInfo
|
||||||
import it.vfsfitvnm.vimusic.utils.smoothScrollToTop
|
import it.hamy.muza.utils.smoothScrollToTop
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@@ -16,10 +16,10 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.hamy.muza.ui.styling.Dimensions
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.shimmer
|
import it.hamy.muza.ui.styling.shimmer
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.hamy.muza.utils.medium
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
@@ -14,11 +14,11 @@ import androidx.compose.ui.graphics.Shape
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import com.valentinilk.shimmer.shimmer
|
import com.valentinilk.shimmer.shimmer
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.hamy.muza.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.shimmer
|
import it.hamy.muza.ui.styling.shimmer
|
||||||
import it.vfsfitvnm.vimusic.utils.isLandscape
|
import it.hamy.muza.utils.isLandscape
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
import it.hamy.muza.utils.thumbnail
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
inline fun LayoutWithAdaptiveThumbnail(
|
inline fun LayoutWithAdaptiveThumbnail(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
@@ -43,34 +43,33 @@ import androidx.compose.ui.res.painterResource
|
|||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
import it.vfsfitvnm.innertube.models.NavigationEndpoint
|
import it.hamy.innertube.models.NavigationEndpoint
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.hamy.muza.Database
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
import it.hamy.muza.LocalPlayerServiceBinder
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.hamy.muza.R
|
||||||
import it.vfsfitvnm.vimusic.enums.PlaylistSortBy
|
import it.hamy.muza.enums.PlaylistSortBy
|
||||||
import it.vfsfitvnm.vimusic.enums.SortOrder
|
import it.hamy.muza.enums.SortOrder
|
||||||
import it.vfsfitvnm.vimusic.models.Info
|
import it.hamy.muza.models.Info
|
||||||
import it.vfsfitvnm.vimusic.models.Playlist
|
import it.hamy.muza.models.Playlist
|
||||||
import it.vfsfitvnm.vimusic.models.Song
|
import it.hamy.muza.models.Song
|
||||||
import it.vfsfitvnm.vimusic.models.SongPlaylistMap
|
import it.hamy.muza.models.SongPlaylistMap
|
||||||
import it.vfsfitvnm.vimusic.query
|
import it.hamy.muza.query
|
||||||
import it.vfsfitvnm.vimusic.transaction
|
import it.hamy.muza.transaction
|
||||||
import it.vfsfitvnm.vimusic.ui.items.SongItem
|
import it.hamy.muza.ui.items.SongItem
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.albumRoute
|
import it.hamy.muza.ui.screens.albumRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.artistRoute
|
import it.hamy.muza.ui.screens.artistRoute
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.hamy.muza.ui.styling.Dimensions
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.favoritesIcon
|
import it.hamy.muza.ui.styling.favoritesIcon
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.hamy.muza.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.utils.addNext
|
import it.hamy.muza.utils.addNext
|
||||||
import it.vfsfitvnm.vimusic.utils.asMediaItem
|
import it.hamy.muza.utils.asMediaItem
|
||||||
import it.vfsfitvnm.vimusic.utils.enqueue
|
import it.hamy.muza.utils.enqueue
|
||||||
import it.vfsfitvnm.vimusic.utils.forcePlay
|
import it.hamy.muza.utils.forcePlay
|
||||||
import it.vfsfitvnm.vimusic.utils.formatAsDuration
|
import it.hamy.muza.utils.formatAsDuration
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.hamy.muza.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.hamy.muza.utils.semiBold
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
import it.hamy.muza.utils.thumbnail
|
||||||
import kotlin.system.measureTimeMillis
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@@ -90,7 +89,7 @@ fun InHistoryMediaItemMenu(
|
|||||||
|
|
||||||
if (isHiding) {
|
if (isHiding) {
|
||||||
ConfirmationDialog(
|
ConfirmationDialog(
|
||||||
text = "Do you really want to hide this song? Its playback time and cache will be wiped.\nThis action is irreversible.",
|
text = "Вы действительно хотите скрыть эту песню? Время воспроизведения и кэш будут удалены.\n" + "Это действие необратимо",
|
||||||
onDismiss = { isHiding = false },
|
onDismiss = { isHiding = false },
|
||||||
onConfirm = {
|
onConfirm = {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
@@ -331,7 +330,7 @@ fun MediaItemMenu(
|
|||||||
|
|
||||||
if (isCreatingNewPlaylist && onAddToPlaylist != null) {
|
if (isCreatingNewPlaylist && onAddToPlaylist != null) {
|
||||||
TextFieldDialog(
|
TextFieldDialog(
|
||||||
hintText = "Enter the playlist name",
|
hintText = "Введите название плейлиста",
|
||||||
onDismiss = { isCreatingNewPlaylist = false },
|
onDismiss = { isCreatingNewPlaylist = false },
|
||||||
onDone = { text ->
|
onDone = { text ->
|
||||||
onDismiss()
|
onDismiss()
|
||||||
@@ -366,7 +365,7 @@ fun MediaItemMenu(
|
|||||||
|
|
||||||
if (onAddToPlaylist != null) {
|
if (onAddToPlaylist != null) {
|
||||||
SecondaryTextButton(
|
SecondaryTextButton(
|
||||||
text = "New playlist",
|
text = "Новый плейлист",
|
||||||
onClick = { isCreatingNewPlaylist = true },
|
onClick = { isCreatingNewPlaylist = true },
|
||||||
alternative = true
|
alternative = true
|
||||||
)
|
)
|
||||||
@@ -378,7 +377,7 @@ fun MediaItemMenu(
|
|||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.playlist,
|
icon = R.drawable.playlist,
|
||||||
text = playlistPreview.playlist.name,
|
text = playlistPreview.playlist.name,
|
||||||
secondaryText = "${playlistPreview.songCount} songs",
|
secondaryText = "${playlistPreview.songCount} песен",
|
||||||
onClick = {
|
onClick = {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
onAddToPlaylist(playlistPreview.playlist, playlistPreview.songCount)
|
onAddToPlaylist(playlistPreview.playlist, playlistPreview.songCount)
|
||||||
@@ -464,7 +463,7 @@ fun MediaItemMenu(
|
|||||||
onStartRadio?.let { onStartRadio ->
|
onStartRadio?.let { onStartRadio ->
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.radio,
|
icon = R.drawable.radio,
|
||||||
text = "Start radio",
|
text = "Включить радио",
|
||||||
onClick = {
|
onClick = {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
onStartRadio()
|
onStartRadio()
|
||||||
@@ -475,7 +474,7 @@ fun MediaItemMenu(
|
|||||||
onPlayNext?.let { onPlayNext ->
|
onPlayNext?.let { onPlayNext ->
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.play_skip_forward,
|
icon = R.drawable.play_skip_forward,
|
||||||
text = "Play next",
|
text = "Следующая",
|
||||||
onClick = {
|
onClick = {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
onPlayNext()
|
onPlayNext()
|
||||||
@@ -486,7 +485,7 @@ fun MediaItemMenu(
|
|||||||
onEnqueue?.let { onEnqueue ->
|
onEnqueue?.let { onEnqueue ->
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.enqueue,
|
icon = R.drawable.enqueue,
|
||||||
text = "Enqueue",
|
text = "В очередь",
|
||||||
onClick = {
|
onClick = {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
onEnqueue()
|
onEnqueue()
|
||||||
@@ -497,7 +496,7 @@ fun MediaItemMenu(
|
|||||||
onGoToEqualizer?.let { onGoToEqualizer ->
|
onGoToEqualizer?.let { onGoToEqualizer ->
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.equalizer,
|
icon = R.drawable.equalizer,
|
||||||
text = "Equalizer",
|
text = "Эквалайзер",
|
||||||
onClick = {
|
onClick = {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
onGoToEqualizer()
|
onGoToEqualizer()
|
||||||
@@ -521,9 +520,9 @@ fun MediaItemMenu(
|
|||||||
if (isShowingSleepTimerDialog) {
|
if (isShowingSleepTimerDialog) {
|
||||||
if (sleepTimerMillisLeft != null) {
|
if (sleepTimerMillisLeft != null) {
|
||||||
ConfirmationDialog(
|
ConfirmationDialog(
|
||||||
text = "Do you want to stop the sleep timer?",
|
text = "Вы хотите отключить таймер сна?",
|
||||||
cancelText = "No",
|
cancelText = "нет",
|
||||||
confirmText = "Stop",
|
confirmText = "отключить",
|
||||||
onDismiss = { isShowingSleepTimerDialog = false },
|
onDismiss = { isShowingSleepTimerDialog = false },
|
||||||
onConfirm = {
|
onConfirm = {
|
||||||
binder?.cancelSleepTimer()
|
binder?.cancelSleepTimer()
|
||||||
@@ -539,7 +538,7 @@ fun MediaItemMenu(
|
|||||||
}
|
}
|
||||||
|
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "Set sleep timer",
|
text = "Установить таймер сна",
|
||||||
style = typography.s.semiBold,
|
style = typography.s.semiBold,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(vertical = 8.dp, horizontal = 24.dp)
|
.padding(vertical = 8.dp, horizontal = 24.dp)
|
||||||
@@ -571,13 +570,13 @@ fun MediaItemMenu(
|
|||||||
|
|
||||||
Box(contentAlignment = Alignment.Center) {
|
Box(contentAlignment = Alignment.Center) {
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "88h 88m",
|
text = "88ч 88м",
|
||||||
style = typography.s.semiBold,
|
style = typography.s.semiBold,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.alpha(0f)
|
.alpha(0f)
|
||||||
)
|
)
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "${amount / 6}h ${(amount % 6) * 10}m",
|
text = "${amount / 6}ч ${(amount % 6) * 10}м",
|
||||||
style = typography.s.semiBold
|
style = typography.s.semiBold
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -604,12 +603,12 @@ fun MediaItemMenu(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
DialogTextButton(
|
DialogTextButton(
|
||||||
text = "Cancel",
|
text = "Отмена",
|
||||||
onClick = { isShowingSleepTimerDialog = false }
|
onClick = { isShowingSleepTimerDialog = false }
|
||||||
)
|
)
|
||||||
|
|
||||||
DialogTextButton(
|
DialogTextButton(
|
||||||
text = "Set",
|
text = "Установить",
|
||||||
enabled = amount > 0,
|
enabled = amount > 0,
|
||||||
primary = true,
|
primary = true,
|
||||||
onClick = {
|
onClick = {
|
||||||
@@ -624,12 +623,12 @@ fun MediaItemMenu(
|
|||||||
|
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.alarm,
|
icon = R.drawable.alarm,
|
||||||
text = "Sleep timer",
|
text = "Таймер сна",
|
||||||
onClick = { isShowingSleepTimerDialog = true },
|
onClick = { isShowingSleepTimerDialog = true },
|
||||||
trailingContent = sleepTimerMillisLeft?.let {
|
trailingContent = sleepTimerMillisLeft?.let {
|
||||||
{
|
{
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "${formatAsDuration(it)} left",
|
text = "Осталось ${formatAsDuration(it)}",
|
||||||
style = typography.xxs.medium,
|
style = typography.xxs.medium,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.background(
|
.background(
|
||||||
@@ -647,7 +646,7 @@ fun MediaItemMenu(
|
|||||||
if (onAddToPlaylist != null) {
|
if (onAddToPlaylist != null) {
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.playlist,
|
icon = R.drawable.playlist,
|
||||||
text = "Add to playlist",
|
text = "Добавить в плейлист",
|
||||||
onClick = { isViewingPlaylists = true },
|
onClick = { isViewingPlaylists = true },
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
Image(
|
Image(
|
||||||
@@ -667,7 +666,7 @@ fun MediaItemMenu(
|
|||||||
albumInfo?.let { (albumId) ->
|
albumInfo?.let { (albumId) ->
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.disc,
|
icon = R.drawable.disc,
|
||||||
text = "Go to album",
|
text = "Перейти в альбом",
|
||||||
onClick = {
|
onClick = {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
onGoToAlbum(albumId)
|
onGoToAlbum(albumId)
|
||||||
@@ -680,7 +679,7 @@ fun MediaItemMenu(
|
|||||||
artistsInfo?.forEach { (authorId, authorName) ->
|
artistsInfo?.forEach { (authorId, authorName) ->
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.person,
|
icon = R.drawable.person,
|
||||||
text = "More of $authorName",
|
text = "Больше от $authorName",
|
||||||
onClick = {
|
onClick = {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
onGoToArtist(authorId)
|
onGoToArtist(authorId)
|
||||||
@@ -692,7 +691,7 @@ fun MediaItemMenu(
|
|||||||
onRemoveFromQueue?.let { onRemoveFromQueue ->
|
onRemoveFromQueue?.let { onRemoveFromQueue ->
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.trash,
|
icon = R.drawable.trash,
|
||||||
text = "Remove from queue",
|
text = "Убрать из очереди",
|
||||||
onClick = {
|
onClick = {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
onRemoveFromQueue()
|
onRemoveFromQueue()
|
||||||
@@ -703,7 +702,7 @@ fun MediaItemMenu(
|
|||||||
onRemoveFromPlaylist?.let { onRemoveFromPlaylist ->
|
onRemoveFromPlaylist?.let { onRemoveFromPlaylist ->
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.trash,
|
icon = R.drawable.trash,
|
||||||
text = "Remove from playlist",
|
text = "Удалить из плейлиста",
|
||||||
onClick = {
|
onClick = {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
onRemoveFromPlaylist()
|
onRemoveFromPlaylist()
|
||||||
@@ -714,7 +713,7 @@ fun MediaItemMenu(
|
|||||||
onHideFromDatabase?.let { onHideFromDatabase ->
|
onHideFromDatabase?.let { onHideFromDatabase ->
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.trash,
|
icon = R.drawable.trash,
|
||||||
text = "Hide",
|
text = "Скрыть",
|
||||||
onClick = onHideFromDatabase
|
onClick = onHideFromDatabase
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -722,7 +721,7 @@ fun MediaItemMenu(
|
|||||||
onRemoveFromQuickPicks?.let {
|
onRemoveFromQuickPicks?.let {
|
||||||
MenuEntry(
|
MenuEntry(
|
||||||
icon = R.drawable.trash,
|
icon = R.drawable.trash,
|
||||||
text = "Hide from \"Quick picks\"",
|
text = "Скрыть из \"Обзора\"",
|
||||||
onClick = {
|
onClick = {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
onRemoveFromQuickPicks()
|
onRemoveFromQuickPicks()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
@@ -22,9 +22,9 @@ import androidx.compose.ui.draw.alpha
|
|||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.hamy.muza.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.hamy.muza.utils.secondary
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
inline fun Menu(
|
inline fun Menu(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.compose.animation.animateColor
|
import androidx.compose.animation.animateColor
|
||||||
import androidx.compose.animation.core.animateFloat
|
import androidx.compose.animation.core.animateFloat
|
||||||
@@ -32,13 +32,13 @@ import androidx.compose.ui.graphics.graphicsLayer
|
|||||||
import androidx.compose.ui.layout.layout
|
import androidx.compose.ui.layout.layout
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.LocalPlayerAwareWindowInsets
|
import it.hamy.muza.LocalPlayerAwareWindowInsets
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.hamy.muza.ui.styling.Dimensions
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.utils.center
|
import it.hamy.muza.utils.center
|
||||||
import it.vfsfitvnm.vimusic.utils.color
|
import it.hamy.muza.utils.color
|
||||||
import it.vfsfitvnm.vimusic.utils.isLandscape
|
import it.hamy.muza.utils.isLandscape
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.hamy.muza.utils.semiBold
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
inline fun NavigationRail(
|
inline fun NavigationRail(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
@@ -14,8 +14,8 @@ import androidx.compose.ui.draw.clip
|
|||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.primaryButton
|
import it.hamy.muza.ui.styling.primaryButton
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PrimaryButton(
|
fun PrimaryButton(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.AnimatedContentScope
|
import androidx.compose.animation.AnimatedContentScope
|
||||||
@@ -15,7 +15,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
@@ -14,8 +14,8 @@ import androidx.compose.ui.draw.clip
|
|||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.primaryButton
|
import it.hamy.muza.ui.styling.primaryButton
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SecondaryButton(
|
fun SecondaryButton(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
@@ -9,9 +9,9 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.primaryButton
|
import it.hamy.muza.ui.styling.primaryButton
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.hamy.muza.utils.medium
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SecondaryTextButton(
|
fun SecondaryTextButton(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.compose.animation.animateColor
|
import androidx.compose.animation.animateColor
|
||||||
import androidx.compose.animation.core.animateDp
|
import androidx.compose.animation.core.animateDp
|
||||||
@@ -14,8 +14,8 @@ import androidx.compose.ui.geometry.center
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.Shadow
|
import androidx.compose.ui.graphics.Shadow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.utils.drawCircle
|
import it.hamy.muza.utils.drawCircle
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Switch(
|
fun Switch(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.components.themed
|
package it.hamy.muza.ui.components.themed
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
@@ -10,8 +10,8 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.shimmer
|
import it.hamy.muza.ui.styling.shimmer
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.items
|
package it.hamy.muza.ui.items
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
@@ -13,14 +13,14 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import it.vfsfitvnm.vimusic.models.Album
|
import it.hamy.muza.models.Album
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
import it.hamy.muza.ui.components.themed.TextPlaceholder
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.shimmer
|
import it.hamy.muza.ui.styling.shimmer
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.hamy.muza.utils.secondary
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.hamy.muza.utils.semiBold
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
import it.hamy.muza.utils.thumbnail
|
||||||
import it.vfsfitvnm.innertube.Innertube
|
import it.hamy.innertube.Innertube
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AlbumItem(
|
fun AlbumItem(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.items
|
package it.hamy.muza.ui.items
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
@@ -15,14 +15,14 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import it.vfsfitvnm.vimusic.models.Artist
|
import it.hamy.muza.models.Artist
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
import it.hamy.muza.ui.components.themed.TextPlaceholder
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.shimmer
|
import it.hamy.muza.ui.styling.shimmer
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.hamy.muza.utils.secondary
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.hamy.muza.utils.semiBold
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
import it.hamy.muza.utils.thumbnail
|
||||||
import it.vfsfitvnm.innertube.Innertube
|
import it.hamy.innertube.Innertube
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ArtistItem(
|
fun ArtistItem(
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.items
|
package it.hamy.muza.ui.items
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.RowScope
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
@@ -13,7 +12,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
import it.hamy.muza.ui.styling.Dimensions
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
inline fun ItemContainer(
|
inline fun ItemContainer(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.items
|
package it.hamy.muza.ui.items
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
@@ -27,19 +27,19 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.hamy.muza.Database
|
||||||
import it.vfsfitvnm.vimusic.models.PlaylistPreview
|
import it.hamy.muza.models.PlaylistPreview
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.TextPlaceholder
|
import it.hamy.muza.ui.components.themed.TextPlaceholder
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.hamy.muza.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.onOverlay
|
import it.hamy.muza.ui.styling.onOverlay
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.overlay
|
import it.hamy.muza.ui.styling.overlay
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.shimmer
|
import it.hamy.muza.ui.styling.shimmer
|
||||||
import it.vfsfitvnm.vimusic.utils.color
|
import it.hamy.muza.utils.color
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.hamy.muza.utils.medium
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.hamy.muza.utils.secondary
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.hamy.muza.utils.semiBold
|
||||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
import it.hamy.muza.utils.thumbnail
|
||||||
import it.vfsfitvnm.innertube.Innertube
|
import it.hamy.innertube.Innertube
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||