Skip to content

Releases: Arturo254/InnerTune

0.6.7

30 Jun 23:12
Compare
Choose a tag to compare

InnerTune 0.6.7

Nueva Actualizacion

CAMBIOS:

  • Se actualizo la API de YM

  • Se actualizo a kotlin multiplataform

  • Se soluciono un bug en las listas de reporduccion

0.6.6

23 Jun 23:50
636756c
Compare
Choose a tag to compare

InnerTune 0.6.6

Nueva Actualizacion

CAMBIOS:

  • Se actualizo la API de YM

  • Se soluciono un bug en las listas de reporduccion

0.6.5

19 Jun 02:42
636756c
Compare
Choose a tag to compare
0.6.5 Pre-release
Pre-release

6.0.5 RELEASE

Diseño sin título

Cambios:

  • Solucion de errores de traduccion
  • Nuevas funciones Beta Agregadas
  • Cambio de iconos
  • Generacion de playlist mediante IA

Important

Esta funcion esta en fase experimental y puede ser removida

  • En esta nueva version se gregaron mas traducciones a InnerTune
  • Boton de donacion

0.6.4

17 Jun 03:24
636756c
Compare
Choose a tag to compare

InnerTune 0.6.4

CAMBIOS:

  • Se agregaron mas funciones beta
  • Se optimizo el codigo de la aplicación
  • Se agrego el apartado de contribuidores
  • Se agrego la opcion de donacion

Screenshot_20240616-211910


Screenshot_20240616-211920

Dependencias:

PreferenceEntry(
            title = { Text(stringResource(R.string.Donate)) },
            icon = { Icon(painterResource(R.drawable.donatebuy), null) },
            onClick = { uriHandler.openUri("https://buymeacoffee.com/arturocervantes") }
        )

Contribuiciones:

Spacer(Modifier.height(20.dp))
        Row(
            verticalAlignment = Alignment.Top,
        ) {
            Text(
                text = "Contributors:",
                style = MaterialTheme.typography.headlineSmall,
                fontWeight = FontWeight.Bold,
                modifier = Modifier.padding(top = 8.dp, bottom = 4.dp)
            )


        }
// Users:

        // Arturo254
        Spacer(Modifier.height(20.dp))
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .height(100.dp),
            colors = CardDefaults.cardColors(
                containerColor = MaterialTheme.colorScheme.surface,
            ),
            border = BorderStroke(1.dp, Color.Gray),
            onClick = { uriHandler.openUri("https://github.com/Arturo254") }
        ) {
            Row(
                modifier = Modifier.padding(26.dp),
                verticalAlignment = Alignment.CenterVertically
            ) {
                Image(
                    painter = rememberAsyncImagePainter(
                        model = "https://avatars.githubusercontent.com/u/87346871?v=4",

                        ),
                    contentDescription = null,
                    modifier = Modifier
                        .clip(CircleShape)
                        .background(
                            MaterialTheme.colorScheme.surfaceColorAtElevation(
                                NavigationBarDefaults.Elevation
                            )
                        )
                        .clickable { }
                )

                Text(
                    text = "  \uD835\uDE08\uD835\uDE33\uD835\uDE35\uD835\uDE36\uD835\uDE33\uD835\uDE30254:",
                    textAlign = TextAlign.Center,
                    style = MaterialTheme.typography.bodyLarge,
                    color = MaterialTheme.colorScheme.onSurface
                )
                Spacer(modifier = Modifier.height(4.dp))  // Espacio entre el nombre y otros elementos

                Text(
                    text = "   \uD835\uDE47\uD835\uDE5A\uD835\uDE56\uD835\uDE59 \uD835\uDE3F\uD835\uDE5A\uD835\uDE6B\uD835\uDE5A\uD835\uDE61\uD835\uDE64\uD835\uDE65\uD835\uDE5A\uD835\uDE67",
                    style = MaterialTheme.typography.bodyMedium,
                    color = MaterialTheme.colorScheme.onSurface
                )


            }


        }

        // Tom Bulled

        Spacer(Modifier.height(20.dp))
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .height(100.dp),
            colors = CardDefaults.cardColors(
                containerColor = MaterialTheme.colorScheme.surface,
            ),
            border = BorderStroke(1.dp, Color.Gray),
            onClick = { uriHandler.openUri("https://github.com/tombulled") }
        ) {
            Row(
                modifier = Modifier.padding(26.dp),
                verticalAlignment = Alignment.CenterVertically
            ) {
                Image(
                    painter = rememberAsyncImagePainter(
                        model = "https://avatars.githubusercontent.com/u/26026015?v=4",

                        ),
                    contentDescription = null,
                    modifier = Modifier
                        .clip(CircleShape)
                        .background(
                            MaterialTheme.colorScheme.surfaceColorAtElevation(
                                NavigationBarDefaults.Elevation
                            )
                        )
                        .clickable { }
                )

                Text(
                    text = "  \uD835\uDE1B\uD835\uDE30\uD835\uDE2E \uD835\uDE09\uD835\uDE36\uD835\uDE2D\uD835\uDE2D\uD835\uDE26\uD835\uDE25:",
                    textAlign = TextAlign.Center,
                    style = MaterialTheme.typography.bodyLarge,
                    color = MaterialTheme.colorScheme.onSurface
                )
                Spacer(modifier = Modifier.height(4.dp))  // Espacio entre el nombre y otros elementos

                Text(
                    text = " \uD835\uDE3C\uD835\uDE4B\uD835\uDE44 \uD835\uDE54\uD835\uDE64\uD835\uDE6A\uD835\uDE69\uD835\uDE6A\uD835\uDE57\uD835\uDE5A \uD835\uDE48\uD835\uDE6A\uD835\uDE68\uD835\uDE5E\uD835\uDE58",
                    style = MaterialTheme.typography.bodyMedium,
                    color = MaterialTheme.colorScheme.onSurface
                )


            }


        }
        Spacer(Modifier.height(20.dp))
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .height(100.dp),
            colors = CardDefaults.cardColors(
                containerColor = MaterialTheme.colorScheme.surface,
            ),
            border = BorderStroke(1.dp, Color.Gray),
            onClick = { uriHandler.openUri("https://github.com/Fabito02/") }
        ) {
            Row(
                modifier = Modifier.padding(26.dp),
                verticalAlignment = Alignment.CenterVertically
            ) {
                Image(
                    painter = rememberAsyncImagePainter(
                        model = "https://avatars.githubusercontent.com/u/138934847?v=4",

                        ),
                    contentDescription = null,
                    modifier = Modifier
                        .clip(CircleShape)
                        .background(MaterialTheme.colorScheme.surfaceColorAtElevation(NavigationBarDefaults.Elevation))
                        .clickable { }
                )

                Text(
                    text = "  \uD835\uDE0D\uD835\uDE22\uD835\uDE23\uD835\uDE2A\uD835\uDE35\uD835\uDE3002",
                    textAlign = TextAlign.Center,
                    style = MaterialTheme.typography.bodyLarge,
                    color = MaterialTheme.colorScheme.onSurface
                )
                Spacer(modifier = Modifier.height(4.dp))  // Espacio entre el nombre y otros elementos

                Text(
                    text = "  \uD835\uDE4F\uD835\uDE67\uD835\uDE56\uD835\uDE59\uD835\uDE6A\uD835\uDE58\uD835\uDE69\uD835\uDE64\uD835\uDE67 (\uD835\uDE4B\uD835\uDE67-\uD835\uDE3D\uD835\uDE4D)",
                    style = MaterialTheme.typography.bodyMedium,
                    color = MaterialTheme.colorScheme.onSurface
                )



            }


        }

        // Contribution by:

        Spacer(Modifier.height(20.dp))
        Card(
            modifier = Modifier
                .fillMaxWidth()
                .height(100.dp),
            colors = CardDefaults.cardColors(
                containerColor = MaterialTheme.colorScheme.surface,
            ),
            border = BorderStroke(1.dp, Color.Gray),
            onClick = { uriHandler.openUri("https://github.com/Arturo254/InnerTune/new/master") } // Reemplaza con el enlace correcto de WhatsApp si deseas
        ) {
            Column(
                modifier = Modifier.padding(16.dp),
                verticalArrangement = Arrangement.Center
            ) {

                Text(
                    text = "\uD835\uDDD6\uD835\uDDFC\uD835\uDDFB\uD835\uDE01\uD835\uDDFF\uD835\uDDF6\uD835\uDDEF\uD835\uDE02\uD835\uDE01\uD835\uDDF2?",
                    textAlign = TextAlign.Center,
                    style = MaterialTheme.typography.bodyLarge,
                    color = MaterialTheme.colorScheme.onSurface
                )

                Text(
                    text = "\uD835\uDE10\uD835\uDE27 \uD835\uDE3A\uD835\uDE30\uD835\uDE36 \uD835\uDE38\uD835\uDE22\uD835\uDE2F\uD835\uDE35 \uD835\uDE35\uD835\uDE30 \uD835\uDE24\uD835\uDE30\uD835\uDE2F\uD835\uDE35\uD835\uDE33\uD835\uDE2A\uD835\uDE23\uD835\uDE36\uD835\uDE35\uD835\uDE26, \uD835\uDE24\uD835\uDE2D\uD835\uDE2A\uD835\uDE24\uD835\uDE2C \uD835\uDE29\uD835\uDE26\uD835\uDE33\uD835\uDE26",
                    style = MaterialTheme.typography.bodyMedium,
                    color = MaterialTheme.colorScheme.onSurface
                )

            }
        }




    }

0.6.3

12 Jun 00:32
94e3c2f
Compare
Choose a tag to compare

InnerTune

A brief description of what this project does and who it's for

Logo

Authors

Contributions:

API Reference

Get all items

  GET /api/items
Parameter Type Description
api_key string Required. Your API key

Get item

  GET /api/items/${id}
Parameter Type Description
id string Required. Id of item to fetch

add(num1, num2)

Takes two numbers and returns the sum.

Changes:

  • An improvement was made to the UI of the Settings section

  • Added translations to strings.xml:
    (Pt-rBR)
    (ES-mx)

  • Bugs fixed

  • Code changes

  • Code optimization

Support

For support, email [email protected]
or join our Slack channel.

0.6.2

09 Jun 22:04
94e3c2f
Compare
Choose a tag to compare
0.6.2 Pre-release
Pre-release

InnerTune 0.6.1

CAMBIOS:

  • Se agregaron mas funciones beta
  • Se optimizo el codigo de la aplicación
  • Se agregaron tarjetas en el apartado de "Ajustes"
  • Se soluciono el error que aparecia en el apartado de playlist. (Desaparecian las Canciones)

Cards

image

Ahora aparecen cards aleatoriamente en el apartado de settings

var isBetaFunEnabled by remember { mutableStateOf(false) }
    val backgroundImages = listOf(
        R.drawable.cardbg1,
        R.drawable.cardbg2,
        R.drawable.cardbg3,
        R.drawable.cardbg4,
        R.drawable.cardbg5,
        R.drawable.cardbg6,
        R.drawable.cardbg7,
        R.drawable.cardbg8,
        R.drawable.cardbg9,




        // ...
    )
    var currentImageIndex by remember { mutableStateOf(0) }


    fun changeBackgroundImage(offset: Int) {
        currentImageIndex = (currentImageIndex + offset + backgroundImages.size) % backgroundImages.size
    }


    Column(
        modifier = Modifier
            .windowInsetsPadding(LocalPlayerAwareWindowInsets.current)
            .verticalScroll(rememberScrollState())
    ) {
        Box(
            modifier = Modifier
                .height(220.dp)
                .clip(RoundedCornerShape(cornerRadius))
                .background(color = Color.Transparent)
                .pointerInput(Unit) {
                    detectHorizontalDragGestures { _, dragAmount ->
                        if (dragAmount > 100f) {
                            changeBackgroundImage(-1) // Change Image to previous
                        } else if (dragAmount < -100f) {
                            changeBackgroundImage(1) // Change Image to next
                        }
                    }
                }
        ) {


            Image(

                painter = painterResource(id = backgroundImages[currentImageIndex]),
                contentDescription = "Image Background",
                contentScale = ContentScale.Crop,
                modifier = Modifier.fillMaxSize(),

            )
            Icon(
                painter = painterResource(R.drawable.launcher_monochrome),
                contentDescription = null,
                tint = Color.White,
                modifier = Modifier.padding( 1.dp, 20.dp, 12.dp),

            )

            Text(
                text = "InnerTune",
                color = Color.White,
                fontSize = 26.sp,
                modifier = Modifier.padding(16.dp),
                style = MaterialTheme.typography.titleSmall,

            )




        }

Dependencias:

dependencies {
    implementation "com.squareup.okhttp3:okhttp:4.9.3"
    implementation "com.squareup.okhttp3:logging-interceptor:4.9.3"
    implementation "com.google.code.gson:gson:2.8.8"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
}

solicitud HTTP:

import com.google.gson.Gson
import okhttp3.OkHttpClient
import okhttp3.Request
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.IOException

data class GitHubRelease(
    val tag_name: String,
    val assets: List<Asset>
)

data class Asset(
    val browser_download_url: String
)

private val client = OkHttpClient()
private val gson = Gson()

suspend fun getLatestRelease(): GitHubRelease? = withContext(Dispatchers.IO) {
    val request = Request.Builder()
        .url("https://api.github.com/repos/Arturo254/InnerTune/releases/latest")
        .build()

    try {
        val response = client.newCall(request).execute()
        if (response.isSuccessful) {
            response.body?.string()?.let { responseBody ->
                return@withContext gson.fromJson(responseBody, GitHubRelease::class.java)
            }
        }
    } catch (e: IOException) {
        // Handle network error
    }
    return@withContext null
}

0.6.1

19 May 14:24
84d3317
Compare
Choose a tag to compare

InnerTune 0.6.1

Ya disponible la version beta y la version experimental 😎

CAMBIOS:

  • Se agregaron mas funciones beta
  • Se optimizo el codigo de la aplicación
  • Se agregaron targetas en el apartado de "Ajustes"

Cards

image

Optimizacion de Codigo:

var isBetaFunEnabled by remember { mutableStateOf(false) }
    val backgroundImages = listOf(
        R.drawable.cardbg1,
        R.drawable.cardbg2,
        R.drawable.cardbg3,
        R.drawable.cardbg4,
        R.drawable.cardbg5,
        R.drawable.cardbg6,
        R.drawable.cardbg7,
        R.drawable.cardbg8,
        R.drawable.cardbg9,




        // ...
    )
    var currentImageIndex by remember { mutableStateOf(0) }


    fun changeBackgroundImage(offset: Int) {
        currentImageIndex = (currentImageIndex + offset + backgroundImages.size) % backgroundImages.size
    }


    Column(
        modifier = Modifier
            .windowInsetsPadding(LocalPlayerAwareWindowInsets.current)
            .verticalScroll(rememberScrollState())
    ) {
        Box(
            modifier = Modifier
                .height(220.dp)
                .clip(RoundedCornerShape(cornerRadius))
                .background(color = Color.Transparent)
                .pointerInput(Unit) {
                    detectHorizontalDragGestures { _, dragAmount ->
                        if (dragAmount > 100f) {
                            changeBackgroundImage(-1) // Change Image to previous
                        } else if (dragAmount < -100f) {
                            changeBackgroundImage(1) // Change Image to next
                        }
                    }
                }
        ) {


            Image(

                painter = painterResource(id = backgroundImages[currentImageIndex]),
                contentDescription = "Image Background",
                contentScale = ContentScale.Crop,
                modifier = Modifier.fillMaxSize(),

            )
            Icon(
                painter = painterResource(R.drawable.launcher_monochrome),
                contentDescription = null,
                tint = Color.White,
                modifier = Modifier.padding( 1.dp, 20.dp, 12.dp),

            )

            Text(
                text = "InnerTune",
                color = Color.White,
                fontSize = 26.sp,
                modifier = Modifier.padding(16.dp),
                style = MaterialTheme.typography.titleSmall,

            )




        }

Dependencias:

dependencies {
    implementation "com.squareup.okhttp3:okhttp:4.9.3"
    implementation "com.squareup.okhttp3:logging-interceptor:4.9.3"
    implementation "com.google.code.gson:gson:2.8.8"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
}

solicitud HTTP:

import com.google.gson.Gson
import okhttp3.OkHttpClient
import okhttp3.Request
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.IOException

data class GitHubRelease(
    val tag_name: String,
    val assets: List<Asset>
)

data class Asset(
    val browser_download_url: String
)

private val client = OkHttpClient()
private val gson = Gson()

suspend fun getLatestRelease(): GitHubRelease? = withContext(Dispatchers.IO) {
    val request = Request.Builder()
        .url("https://api.github.com/repos/Arturo254/InnerTune/releases/latest")
        .build()

    try {
        val response = client.newCall(request).execute()
        if (response.isSuccessful) {
            response.body?.string()?.let { responseBody ->
                return@withContext gson.fromJson(responseBody, GitHubRelease::class.java)
            }
        }
    } catch (e: IOException) {
        // Handle network error
    }
    return@withContext null
}

0.6.0

09 May 03:05
Compare
Choose a tag to compare

InnerTune Update V6

Llego la nueva version 0.6.0 de InnerTune

Cambios :

  • Ligero rediseño del reproductor.
  • Nueva pestaña "Explorar"
  • Optimizacion de codigo
  • Nuevas Funciones Beta
  • Cambio de diseño de las tarjetas:
colors = CardDefaults.cardColors(
                containerColor = MaterialTheme.colorScheme.surface,
            ),
            border = BorderStroke(1.dp, Color.Gray),

Cualquier Problema o sujerencia lo puedes reportar en la seccion de Issues

Gracias por su apoyo. ❤️😊


0.5.9

06 May 02:45
bfc788a
Compare
Choose a tag to compare

InnerTune Update

Se ha lanzado la nueva version de InnerTune.
En la cual se realizaron cambios de codigo y optimizacion

Cambios :


Se agrego un nuevo swich para activar funciones beta . el cual no realiza cambios esteticos. solo cambios en la API y en el buscador (search bar )



Gracias a todos por sus comentarios. cada dia se mejora mas la aplicacion.

Gracias a todos por sus donaciones ❤️

Important

SE CAMBIO EL NOMBRE DEL PAQUETE. HAZ UN BACKUP Y BORRA LA APLICACION ANTERIOR Y REESTABLECE EL BACKUP.

0.5.8

20 Apr 15:23
f63462c
Compare
Choose a tag to compare

InnerTune

image

Update.

Cambios:

  • Se agreg o un nuevo boton a la pantalla de inicio
    image

  • Se reescribio el codigo de "HomeScreen.kt : "

package com.zionhuang.music.ui.screens

import android.annotation.SuppressLint
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import com.google.accompanist.swiperefresh.SwipeRefresh
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
import com.zionhuang.innertube.models.Artist
import com.zionhuang.innertube.models.ArtistItem
import com.zionhuang.innertube.models.PlaylistItem
import com.zionhuang.innertube.models.WatchEndpoint
import com.zionhuang.innertube.utils.parseCookieString
import com.zionhuang.music.LocalDatabase
import com.zionhuang.music.LocalPlayerAwareWindowInsets
import com.zionhuang.music.LocalPlayerConnection
import com.zionhuang.music.R
import com.zionhuang.music.constants.GridThumbnailHeight
import com.zionhuang.music.constants.InnerTubeCookieKey
import com.zionhuang.music.constants.ListItemHeight
import com.zionhuang.music.extensions.togglePlayPause
import com.zionhuang.music.models.toMediaMetadata
import com.zionhuang.music.playback.queues.YouTubeAlbumRadio
import com.zionhuang.music.playback.queues.YouTubeQueue
import com.zionhuang.music.ui.component.AlbumSmallGridItem
import com.zionhuang.music.ui.component.ArtistSmallGridItem
import com.zionhuang.music.ui.component.HideOnScrollFAB
import com.zionhuang.music.ui.component.LocalMenuState
import com.zionhuang.music.ui.component.NavigationTile
import com.zionhuang.music.ui.component.NavigationTitle
import com.zionhuang.music.ui.component.SongListItem
import com.zionhuang.music.ui.component.SongSmallGridItem
import com.zionhuang.music.ui.component.YouTubeGridItem
import com.zionhuang.music.ui.component.YouTubeSmallGridItem
import com.zionhuang.music.ui.menu.ArtistMenu
import com.zionhuang.music.ui.menu.SongMenu
import com.zionhuang.music.ui.menu.YouTubeAlbumMenu
import com.zionhuang.music.ui.menu.YouTubePlaylistMenu
import com.zionhuang.music.ui.utils.SnapLayoutInfoProvider
import com.zionhuang.music.utils.rememberPreference
import com.zionhuang.music.viewmodels.HomeViewModel
import kotlin.random.Random

@SuppressLint("UnrememberedMutableState")
@Suppress("DEPRECATION")
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
@Composable
fun HomeScreen(
    navController: NavController,
    viewModel: HomeViewModel = hiltViewModel(),
) {
    val menuState = LocalMenuState.current
    val database = LocalDatabase.current
    val playerConnection = LocalPlayerConnection.current ?: return
    val isPlaying by playerConnection.isPlaying.collectAsState()
    val mediaMetadata by playerConnection.mediaMetadata.collectAsState()

    val quickPicks by viewModel.quickPicks.collectAsState()
    val explorePage by viewModel.explorePage.collectAsState()

    val forgottenFavorite by viewModel.forgottenFavorite.collectAsState()
    val homeFirstAlbumRecommendation by viewModel.homeFirstAlbumRecommendation.collectAsState()
    val homeSecondAlbumRecommendation by viewModel.homeSecondAlbumRecommendation.collectAsState()

    val homeFirstArtistRecommendation by viewModel.homeFirstArtistRecommendation.collectAsState()
    val homeSecondArtistRecommendation by viewModel.homeSecondArtistRecommendation.collectAsState()
    val homeThirdArtistRecommendation by viewModel.homeThirdArtistRecommendation.collectAsState()
    val home by viewModel.home.collectAsState()

    val keepListeningSongs by viewModel.keepListeningSongs.collectAsState()
    val keepListeningAlbums by viewModel.keepListeningAlbums.collectAsState()
    val keepListeningArtists by viewModel.keepListeningArtists.collectAsState()
    val keepListening by viewModel.keepListening.collectAsState()

    val homeFirstContinuation by viewModel.homeFirstContinuation.collectAsState()
    val homeSecondContinuation by viewModel.homeSecondContinuation.collectAsState()
    val homeThirdContinuation by viewModel.homeThirdContinuation.collectAsState()
    val uriHandler = LocalUriHandler.current

    val isRefreshing by viewModel.isRefreshing.collectAsState()
    val mostPlayedLazyGridState = rememberLazyGridState()

    val forgottenFavoritesLazyGridState = rememberLazyGridState()

    val listenAgainLazyGridState = rememberLazyGridState()

    val innerTubeCookie by rememberPreference(InnerTubeCookieKey, "")
    val isLoggedIn = remember(innerTubeCookie) {
        "SAPISID" in parseCookieString(innerTubeCookie)
    }

    val coroutineScope = rememberCoroutineScope()
    val scrollState = rememberScrollState()

    SwipeRefresh(
        state = rememberSwipeRefreshState(isRefreshing),
        onRefresh = viewModel::refresh,
        indicatorPadding = LocalPlayerAwareWindowInsets.current.asPaddingValues()
    ) {
        BoxWithConstraints(
            modifier = Modifier.fillMaxSize()
        ) {
            val horizontalLazyGridItemWidthFactor = if (maxWidth * 0.475f >= 320.dp) 0.475f else 0.9f
            val horizontalLazyGridItemWidth = maxWidth * horizontalLazyGridItemWidthFactor
            val snapLayoutInfoProviderQuickPicks = remember(mostPlayedLazyGridState) {
                SnapLayoutInfoProvider(
                    lazyGridState = mostPlayedLazyGridState,
                    positionInLayout = { layoutSize, itemSize ->
                        (layoutSize * horizontalLazyGridItemWidthFactor / 2f - itemSize / 2f)
                    }
                )
            }
            val snapLayoutInfoProviderForgottenFavorite = remember(forgottenFavoritesLazyGridState) {
                SnapLayoutInfoProvider(
                    lazyGridState = forgottenFavoritesLazyGridState,
                    positionInLayout = { layoutSize, itemSize ->
                        (layoutSize * horizontalLazyGridItemWidthFactor / 2f - itemSize / 2f)
                    }
                )
            }

            Column(
                modifier = Modifier.verticalScroll(scrollState)
            ) {

                Spacer(Modifier.height(LocalPlayerAwareWindowInsets.current.asPaddingValues().calculateTopPadding()))

                Row(
                    modifier = Modifier
                        .windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Horizontal))
                        .padding(horizontal = 12.dp, vertical = 6.dp)
                        .fillMaxWidth()
                ) {
                    NavigationTile(
                        title = stringResource(R.string.history),
                        icon = R.drawable.history,
                        onClick = { navController.navigate("history") },
                        modifier = Modifier.weight(1f)
                    )

                    NavigationTile(
                        title = stringResource(R.string.stats),
                        icon = R.drawable.trending_up,
                        onClick = { navController.navigate("stats") },
                        modifier = Modifier.weight(1f)
                    )

                    NavigationTile(
                        title = stringResource(R.string.tutoxd),
                        icon = R.drawable.corcircu,
                        onClick = { navController.navigate("auto_playlist/liked") },
                        modifier = Modifier.weight(1f)
...
Read more